Commit fb2fbbffb8a4cf7d1bc6ec9691682f9136ada3cc

Authored by YunaiV
2 parents a1b7697e 4a322ed7

Merge branch 'master' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into feature/multi-datasource

 Conflicts:
	pom.xml
	src/main/resources/application-local.yaml
Showing 158 changed files with 8755 additions and 286 deletions

Too many changes.

To preserve performance only 100 of 158 files are displayed.

README.md
@@ -102,9 +102,9 @@ @@ -102,9 +102,9 @@
102 | [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.1.7 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) | 102 | [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.1.7 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
103 | [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) | 103 | [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
104 | [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.2 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) | 104 | [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.2 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
105 -| [Resilience4j](https://github.com/quartz-scheduler) | 服务保障组件 | 1.7.0 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) | 105 +| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.0 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |
106 | [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) | 106 | [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
107 -| [Spring Boot Admin](https://github.com/skywalking) | Spring Boot 监控平台 | 8.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) | 107 +| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 8.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
108 | [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.11.4 | | 108 | [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.11.4 | |
109 | [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.4.1 | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) | 109 | [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.4.1 | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
110 | [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.16.14 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) | 110 | [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.16.14 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
@@ -30,6 +30,7 @@ @@ -30,6 +30,7 @@
30 <mysql-connector-java.version>5.1.46</mysql-connector-java.version> 30 <mysql-connector-java.version>5.1.46</mysql-connector-java.version>
31 <druid.version>1.2.4</druid.version> 31 <druid.version>1.2.4</druid.version>
32 <mybatis-plus.version>3.4.2</mybatis-plus.version> 32 <mybatis-plus.version>3.4.2</mybatis-plus.version>
  33 + <dynamic-datasource.version>3.3.2</dynamic-datasource.version>
33 <redisson.version>3.15.1</redisson.version> 34 <redisson.version>3.15.1</redisson.version>
34 <!-- Config 配置中心相关 --> 35 <!-- Config 配置中心相关 -->
35 <apollo.version>1.7.0</apollo.version> 36 <apollo.version>1.7.0</apollo.version>
@@ -46,7 +47,12 @@ @@ -46,7 +47,12 @@
46 <easyexcel.verion>2.2.7</easyexcel.verion> 47 <easyexcel.verion>2.2.7</easyexcel.verion>
47 <velocity.version>2.2</velocity.version> 48 <velocity.version>2.2</velocity.version>
48 <screw.version>1.0.5</screw.version> 49 <screw.version>1.0.5</screw.version>
49 - <dynamic-datasource.version>3.3.2</dynamic-datasource.version> 50 + <podam.version>7.2.6.RELEASE</podam.version>
  51 + <jedis-mock.version>0.1.16</jedis-mock.version>
  52 + <!-- 三方云服务相关 -->
  53 + <aliyun-java-sdk-core.version>4.5.18</aliyun-java-sdk-core.version>
  54 + <aliyun-java-sdk-dysmsapi.version>2.1.0</aliyun-java-sdk-dysmsapi.version>
  55 + <yunpian-java-sdk.version>1.2.7</yunpian-java-sdk.version>
50 </properties> 56 </properties>
51 57
52 <!-- 依赖声明 --> 58 <!-- 依赖声明 -->
@@ -134,6 +140,11 @@ @@ -134,6 +140,11 @@
134 <artifactId>mybatis-plus-boot-starter</artifactId> 140 <artifactId>mybatis-plus-boot-starter</artifactId>
135 <version>${mybatis-plus.version}</version> 141 <version>${mybatis-plus.version}</version>
136 </dependency> 142 </dependency>
  143 + <dependency>
  144 + <groupId>com.baomidou</groupId>
  145 + <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <!-- 多数据源 -->
  146 + <version>${dynamic-datasource.version}</version>
  147 + </dependency>
137 148
138 <dependency> 149 <dependency>
139 <groupId>org.redisson</groupId> 150 <groupId>org.redisson</groupId>
@@ -213,14 +224,14 @@ @@ -213,14 +224,14 @@
213 <dependency> 224 <dependency>
214 <groupId>com.github.fppt</groupId> <!-- 单元测试,我们采用内嵌的 Redis 数据库 --> 225 <groupId>com.github.fppt</groupId> <!-- 单元测试,我们采用内嵌的 Redis 数据库 -->
215 <artifactId>jedis-mock</artifactId> 226 <artifactId>jedis-mock</artifactId>
216 - <version>0.1.16</version> 227 + <version>${jedis-mock.version}</version>
217 <scope>test</scope> 228 <scope>test</scope>
218 </dependency> 229 </dependency>
219 230
220 <dependency> 231 <dependency>
221 <groupId>uk.co.jemos.podam</groupId> <!-- 单元测试,随机生成 POJO 类 --> 232 <groupId>uk.co.jemos.podam</groupId> <!-- 单元测试,随机生成 POJO 类 -->
222 <artifactId>podam</artifactId> 233 <artifactId>podam</artifactId>
223 - <version>7.2.6.RELEASE</version> 234 + <version>${podam.version}</version>
224 <scope>test</scope> 235 <scope>test</scope>
225 </dependency> 236 </dependency>
226 237
@@ -272,13 +283,26 @@ @@ -272,13 +283,26 @@
272 <version>${screw.version}</version> 283 <version>${screw.version}</version>
273 </dependency> 284 </dependency>
274 285
275 - <!-- 多数据源 --> 286 + <!-- 三方云服务相关 -->
  287 +
  288 + <!-- SMS SDK begin -->
276 <dependency> 289 <dependency>
277 - <groupId>com.baomidou</groupId>  
278 - <artifactId>dynamic-datasource-spring-boot-starter</artifactId>  
279 - <version>${dynamic-datasource.version}</version> 290 + <groupId>com.yunpian.sdk</groupId>
  291 + <artifactId>yunpian-java-sdk</artifactId>
  292 + <version>${yunpian-java-sdk.version}</version>
280 </dependency> 293 </dependency>
281 294
  295 + <dependency>
  296 + <groupId>com.aliyun</groupId>
  297 + <artifactId>aliyun-java-sdk-core</artifactId>
  298 + <version>${aliyun-java-sdk-core.version}</version>
  299 + </dependency>
  300 + <dependency>
  301 + <groupId>com.aliyun</groupId>
  302 + <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
  303 + <version>${aliyun-java-sdk-dysmsapi.version}</version>
  304 + </dependency>
  305 + <!-- SMS SDK end -->
282 306
283 </dependencies> 307 </dependencies>
284 308
ruoyi-ui/.env.demo1024 0 → 100644
  1 +NODE_ENV = production
  2 +
  3 +# 测试环境配置
  4 +ENV = 'staging'
  5 +
  6 +# 芋道管理系统/测试环境
  7 +VUE_APP_BASE_API = 'http://127.0.0.1:48080'
ruoyi-ui/package.json
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 "dev": "vue-cli-service serve", 8 "dev": "vue-cli-service serve",
9 "build:prod": "vue-cli-service build", 9 "build:prod": "vue-cli-service build",
10 "build:stage": "vue-cli-service build --mode staging", 10 "build:stage": "vue-cli-service build --mode staging",
  11 + "build:demo1024": "vue-cli-service build --mode demo1024",
11 "preview": "node build/index.js --preview", 12 "preview": "node build/index.js --preview",
12 "lint": "eslint --ext .js,.vue src" 13 "lint": "eslint --ext .js,.vue src"
13 }, 14 },
ruoyi-ui/src/api/system/sms/smsChannel.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 创建短信渠道
  4 +export function createSmsChannel(data) {
  5 + return request({
  6 + url: '/system/sms-channel/create',
  7 + method: 'post',
  8 + data: data
  9 + })
  10 +}
  11 +
  12 +// 更新短信渠道
  13 +export function updateSmsChannel(data) {
  14 + return request({
  15 + url: '/system/sms-channel/update',
  16 + method: 'put',
  17 + data: data
  18 + })
  19 +}
  20 +
  21 +// 删除短信渠道
  22 +export function deleteSmsChannel(id) {
  23 + return request({
  24 + url: '/system/sms-channel/delete?id=' + id,
  25 + method: 'delete'
  26 + })
  27 +}
  28 +
  29 +// 获得短信渠道
  30 +export function getSmsChannel(id) {
  31 + return request({
  32 + url: '/system/sms-channel/get?id=' + id,
  33 + method: 'get'
  34 + })
  35 +}
  36 +
  37 +// 获得短信渠道分页
  38 +export function getSmsChannelPage(query) {
  39 + return request({
  40 + url: '/system/sms-channel/page',
  41 + method: 'get',
  42 + params: query
  43 + })
  44 +}
  45 +
  46 +// 获得短信渠道精简列表
  47 +export function getSimpleSmsChannels() {
  48 + return request({
  49 + url: '/system/sms-channel/list-all-simple',
  50 + method: 'get',
  51 + })
  52 +}
ruoyi-ui/src/api/system/sms/smsLog.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 获得短信日志分页
  4 +export function getSmsLogPage(query) {
  5 + return request({
  6 + url: '/system/sms-log/page',
  7 + method: 'get',
  8 + params: query
  9 + })
  10 +}
  11 +
  12 +// 导出短信日志 Excel
  13 +export function exportSmsLogExcel(query) {
  14 + return request({
  15 + url: '/system/sms-log/export-excel',
  16 + method: 'get',
  17 + params: query,
  18 + responseType: 'blob'
  19 + })
  20 +}
ruoyi-ui/src/api/system/sms/smsTemplate.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 创建短信模板
  4 +export function createSmsTemplate(data) {
  5 + return request({
  6 + url: '/system/sms-template/create',
  7 + method: 'post',
  8 + data: data
  9 + })
  10 +}
  11 +
  12 +// 更新短信模板
  13 +export function updateSmsTemplate(data) {
  14 + return request({
  15 + url: '/system/sms-template/update',
  16 + method: 'put',
  17 + data: data
  18 + })
  19 +}
  20 +
  21 +// 删除短信模板
  22 +export function deleteSmsTemplate(id) {
  23 + return request({
  24 + url: '/system/sms-template/delete?id=' + id,
  25 + method: 'delete'
  26 + })
  27 +}
  28 +
  29 +// 获得短信模板
  30 +export function getSmsTemplate(id) {
  31 + return request({
  32 + url: '/system/sms-template/get?id=' + id,
  33 + method: 'get'
  34 + })
  35 +}
  36 +
  37 +// 获得短信模板分页
  38 +export function getSmsTemplatePage(query) {
  39 + return request({
  40 + url: '/system/sms-template/page',
  41 + method: 'get',
  42 + params: query
  43 + })
  44 +}
  45 +
  46 +// 创建短信模板
  47 +export function sendSms(data) {
  48 + return request({
  49 + url: '/system/sms-template/send-sms',
  50 + method: 'post',
  51 + data: data
  52 + })
  53 +}
  54 +
  55 +// 导出短信模板 Excel
  56 +export function exportSmsTemplateExcel(query) {
  57 + return request({
  58 + url: '/system/sms-template/export-excel',
  59 + method: 'get',
  60 + params: query,
  61 + responseType: 'blob'
  62 + })
  63 +}
  64 +
ruoyi-ui/src/utils/dict.js
@@ -17,6 +17,10 @@ export const DICT_TYPE = { @@ -17,6 +17,10 @@ export const DICT_TYPE = {
17 SYS_OPERATE_TYPE: 'sys_operate_type', 17 SYS_OPERATE_TYPE: 'sys_operate_type',
18 SYS_LOGIN_RESULT: 'sys_login_result', 18 SYS_LOGIN_RESULT: 'sys_login_result',
19 SYS_CONFIG_TYPE: 'sys_config_type', 19 SYS_CONFIG_TYPE: 'sys_config_type',
  20 + SYS_SMS_CHANNEL_CODE: 'sys_sms_channel_code',
  21 + SYS_SMS_TEMPLATE_TYPE: 'sys_sms_template_type',
  22 + SYS_SMS_SEND_STATUS: 'sys_sms_send_status',
  23 + SYS_SMS_RECEIVE_STATUS: 'sys_sms_receive_status',
20 24
21 INF_REDIS_TIMEOUT_TYPE: 'inf_redis_timeout_type', 25 INF_REDIS_TIMEOUT_TYPE: 'inf_redis_timeout_type',
22 INF_JOB_STATUS: 'inf_job_status', 26 INF_JOB_STATUS: 'inf_job_status',
ruoyi-ui/src/utils/request.js
@@ -73,6 +73,18 @@ service.interceptors.response.use(res =&gt; { @@ -73,6 +73,18 @@ service.interceptors.response.use(res =&gt; {
73 type: 'error' 73 type: 'error'
74 }) 74 })
75 return Promise.reject(new Error(msg)) 75 return Promise.reject(new Error(msg))
  76 + } else if (code === 901) {
  77 + Message({
  78 + type: 'error',
  79 + duration: 0,
  80 + dangerouslyUseHTMLString: true,
  81 + message: '<div>演示模式,不发进行写操作</div>'
  82 + + '<div> &nbsp; </div>'
  83 + + '<div>参考 https://www.iocoder.cn/Yudao/build-debugger-environment 教程</div>'
  84 + + '<div> &nbsp; </div>'
  85 + + '<div>5 分钟搭建本地环境</div>',
  86 + })
  87 + return Promise.reject(new Error(msg))
76 } else if (code !== 200) { 88 } else if (code !== 200) {
77 Notification.error({ 89 Notification.error({
78 title: msg 90 title: msg
ruoyi-ui/src/views/system/operatelog/index.vue
@@ -163,7 +163,6 @@ export default { @@ -163,7 +163,6 @@ export default {
163 businessType: undefined, 163 businessType: undefined,
164 status: undefined 164 status: undefined
165 }, 165 },
166 -  
167 }; 166 };
168 }, 167 },
169 created() { 168 created() {
ruoyi-ui/src/views/system/sms/smsChannel.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
  6 + <el-form-item label="短信签名" prop="signature">
  7 + <el-input v-model="queryParams.signature" placeholder="请输入短信签名" clearable size="small" @keyup.enter.native="handleQuery"/>
  8 + </el-form-item>
  9 + <el-form-item label="启用状态" prop="status">
  10 + <el-select v-model="queryParams.status" placeholder="请选择启用状态" clearable size="small">
  11 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
  12 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  13 + </el-select>
  14 + </el-form-item>
  15 + <el-form-item label="创建时间">
  16 + <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  17 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  18 + </el-form-item>
  19 + <el-form-item>
  20 + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  21 + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  22 + </el-form-item>
  23 + </el-form>
  24 +
  25 + <!-- 操作工具栏 -->
  26 + <el-row :gutter="10" class="mb8">
  27 + <el-col :span="1.5">
  28 + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
  29 + v-hasPermi="['system:sms-channel:create']">新增</el-button>
  30 + </el-col>
  31 + <el-col :span="1.5">
  32 + <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
  33 + v-hasPermi="['system:sms-channel:export']">导出</el-button>
  34 + </el-col>
  35 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  36 + </el-row>
  37 +
  38 + <!-- 列表 -->
  39 + <el-table v-loading="loading" :data="list">
  40 + <el-table-column label="编号" align="center" prop="id" />
  41 + <el-table-column label="短信签名" align="center" prop="signature" />
  42 + <el-table-column label="渠道编码" align="center" prop="code">
  43 + <template slot-scope="scope">
  44 + <span>{{ getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, scope.row.code) }}</span>
  45 + </template>
  46 + </el-table-column>>
  47 + <el-table-column label="启用状态" align="center" prop="status">
  48 + <template slot-scope="scope">
  49 + <span>{{ getDictDataLabel(DICT_TYPE.SYS_COMMON_STATUS, scope.row.status) }}</span>
  50 + </template>
  51 + </el-table-column>>
  52 + <el-table-column label="备注" align="center" prop="remark" />
  53 + <el-table-column label="短信 API 的账号" align="center" prop="apiKey" />
  54 + <el-table-column label="短信 API 的秘钥" align="center" prop="apiSecret" />
  55 + <el-table-column label="短信发送回调 URL" align="center" prop="callbackUrl" />
  56 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  57 + <template slot-scope="scope">
  58 + <span>{{ parseTime(scope.row.createTime) }}</span>
  59 + </template>
  60 + </el-table-column>
  61 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  62 + <template slot-scope="scope">
  63 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  64 + v-hasPermi="['system:sms-channel:update']">修改</el-button>
  65 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  66 + v-hasPermi="['system:sms-channel:delete']">删除</el-button>
  67 + </template>
  68 + </el-table-column>
  69 + </el-table>
  70 + <!-- 分页组件 -->
  71 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  72 + @pagination="getList"/>
  73 +
  74 + <!-- 对话框(添加 / 修改) -->
  75 + <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
  76 + <el-form ref="form" :model="form" :rules="rules" label-width="80px">
  77 + <el-form-item label="短信签名" prop="signature">
  78 + <el-input v-model="form.signature" placeholder="请输入短信签名" />
  79 + </el-form-item>
  80 + <el-form-item label="渠道编码" prop="code">
  81 + <el-input v-model="form.code" placeholder="请输入渠道编码" />
  82 + </el-form-item>
  83 + <el-form-item label="启用状态">
  84 + <el-radio-group v-model="form.status">
  85 + <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
  86 + :key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
  87 + </el-radio-group>
  88 + </el-form-item>
  89 + <el-form-item label="备注" prop="remark">
  90 + <el-input v-model="form.remark" placeholder="请输入备注" />
  91 + </el-form-item>
  92 + <el-form-item label="短信 API 的账号" prop="apiKey">
  93 + <el-input v-model="form.apiKey" placeholder="请输入短信 API 的账号" />
  94 + </el-form-item>
  95 + <el-form-item label="短信 API 的秘钥" prop="apiSecret">
  96 + <el-input v-model="form.apiSecret" placeholder="请输入短信 API 的秘钥" />
  97 + </el-form-item>
  98 + <el-form-item label="短信发送回调 URL" prop="callbackUrl">
  99 + <el-input v-model="form.callbackUrl" placeholder="请输入短信发送回调 URL" />
  100 + </el-form-item>
  101 + </el-form>
  102 + <div slot="footer" class="dialog-footer">
  103 + <el-button type="primary" @click="submitForm">确 定</el-button>
  104 + <el-button @click="cancel">取 消</el-button>
  105 + </div>
  106 + </el-dialog>
  107 + </div>
  108 +</template>
  109 +
  110 +<script>
  111 +import { createSmsChannel, updateSmsChannel, deleteSmsChannel, getSmsChannel, getSmsChannelPage,
  112 + getSimpleSmsChannels } from "@/api/system/sms/smsChannel";
  113 +
  114 +export default {
  115 + name: "SmsChannel",
  116 + components: {
  117 + },
  118 + data() {
  119 + return {
  120 + // 遮罩层
  121 + loading: true,
  122 + // 显示搜索条件
  123 + showSearch: true,
  124 + // 总条数
  125 + total: 0,
  126 + // 短信渠道列表
  127 + list: [],
  128 + // 弹出层标题
  129 + title: "",
  130 + // 是否显示弹出层
  131 + open: false,
  132 + dateRangeCreateTime: [],
  133 + // 查询参数
  134 + queryParams: {
  135 + pageNo: 1,
  136 + pageSize: 10,
  137 + signature: null,
  138 + status: null,
  139 + },
  140 + // 表单参数
  141 + form: {},
  142 + // 表单校验
  143 + rules: {
  144 + signature: [{ required: true, message: "短信签名不能为空", trigger: "blur" }],
  145 + code: [{ required: true, message: "渠道编码不能为空", trigger: "blur" }],
  146 + status: [{ required: true, message: "启用状态不能为空", trigger: "blur" }],
  147 + apiKey: [{ required: true, message: "短信 API 的账号不能为空", trigger: "blur" }],
  148 + },
  149 + };
  150 + },
  151 + created() {
  152 + this.getList();
  153 + },
  154 + methods: {
  155 + /** 查询列表 */
  156 + getList() {
  157 + this.loading = true;
  158 + // 处理查询参数
  159 + let params = {...this.queryParams};
  160 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  161 + // 执行查询
  162 + getSmsChannelPage(params).then(response => {
  163 + this.list = response.data.list;
  164 + this.total = response.data.total;
  165 + this.loading = false;
  166 + });
  167 + },
  168 + /** 取消按钮 */
  169 + cancel() {
  170 + this.open = false;
  171 + this.reset();
  172 + },
  173 + /** 表单重置 */
  174 + reset() {
  175 + this.form = {
  176 + id: undefined,
  177 + signature: undefined,
  178 + code: undefined,
  179 + status: undefined,
  180 + remark: undefined,
  181 + apiKey: undefined,
  182 + apiSecret: undefined,
  183 + callbackUrl: undefined,
  184 + };
  185 + this.resetForm("form");
  186 + },
  187 + /** 搜索按钮操作 */
  188 + handleQuery() {
  189 + this.queryParams.pageNo = 1;
  190 + this.getList();
  191 + },
  192 + /** 重置按钮操作 */
  193 + resetQuery() {
  194 + this.dateRangeCreateTime = [];
  195 + this.resetForm("queryForm");
  196 + this.handleQuery();
  197 + },
  198 + /** 新增按钮操作 */
  199 + handleAdd() {
  200 + this.reset();
  201 + this.open = true;
  202 + this.title = "添加短信渠道";
  203 + },
  204 + /** 修改按钮操作 */
  205 + handleUpdate(row) {
  206 + this.reset();
  207 + const id = row.id;
  208 + getSmsChannel(id).then(response => {
  209 + this.form = response.data;
  210 + this.open = true;
  211 + this.title = "修改短信渠道";
  212 + });
  213 + },
  214 + /** 提交按钮 */
  215 + submitForm() {
  216 + this.$refs["form"].validate(valid => {
  217 + if (!valid) {
  218 + return;
  219 + }
  220 + // 修改的提交
  221 + if (this.form.id != null) {
  222 + updateSmsChannel(this.form).then(response => {
  223 + this.msgSuccess("修改成功");
  224 + this.open = false;
  225 + this.getList();
  226 + });
  227 + return;
  228 + }
  229 + // 添加的提交
  230 + createSmsChannel(this.form).then(response => {
  231 + this.msgSuccess("新增成功");
  232 + this.open = false;
  233 + this.getList();
  234 + });
  235 + });
  236 + },
  237 + /** 删除按钮操作 */
  238 + handleDelete(row) {
  239 + const id = row.id;
  240 + this.$confirm('是否确认删除短信渠道编号为"' + id + '"的数据项?', "警告", {
  241 + confirmButtonText: "确定",
  242 + cancelButtonText: "取消",
  243 + type: "warning"
  244 + }).then(function() {
  245 + return deleteSmsChannel(id);
  246 + }).then(() => {
  247 + this.getList();
  248 + this.msgSuccess("删除成功");
  249 + })
  250 + },
  251 + /** 导出按钮操作 */
  252 + handleExport() {
  253 + // 处理查询参数
  254 + let params = {...this.queryParams};
  255 + params.pageNo = undefined;
  256 + params.pageSize = undefined;
  257 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  258 + // 执行导出
  259 + this.$confirm('是否确认导出所有短信渠道数据项?', "警告", {
  260 + confirmButtonText: "确定",
  261 + cancelButtonText: "取消",
  262 + type: "warning"
  263 + }).then(function() {
  264 + return exportSmsChannelExcel(params);
  265 + }).then(response => {
  266 + this.downloadExcel(response, '短信渠道.xls');
  267 + })
  268 + }
  269 + }
  270 +};
  271 +</script><template>
  272 + <div class="app-container">
  273 +
  274 + <!-- 搜索工作栏 -->
  275 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
  276 + <el-form-item label="短信签名" prop="signature">
  277 + <el-input v-model="queryParams.signature" placeholder="请输入短信签名" clearable size="small" @keyup.enter.native="handleQuery"/>
  278 + </el-form-item>
  279 + <el-form-item label="启用状态" prop="status">
  280 + <el-select v-model="queryParams.status" placeholder="请选择启用状态" clearable size="small">
  281 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
  282 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  283 + </el-select>
  284 + </el-form-item>
  285 + <el-form-item label="创建时间">
  286 + <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  287 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  288 + </el-form-item>
  289 + <el-form-item>
  290 + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  291 + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  292 + </el-form-item>
  293 + </el-form>
  294 +
  295 + <!-- 操作工具栏 -->
  296 + <el-row :gutter="10" class="mb8">
  297 + <el-col :span="1.5">
  298 + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
  299 + v-hasPermi="['system:sms-channel:create']">新增</el-button>
  300 + </el-col>
  301 + <el-col :span="1.5">
  302 + <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
  303 + v-hasPermi="['system:sms-channel:export']">导出</el-button>
  304 + </el-col>
  305 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  306 + </el-row>
  307 +
  308 + <!-- 列表 -->
  309 + <el-table v-loading="loading" :data="list">
  310 + <el-table-column label="编号" align="center" prop="id" />
  311 + <el-table-column label="短信签名" align="center" prop="signature" />
  312 + <el-table-column label="渠道编码" align="center" prop="code">
  313 + <template slot-scope="scope">
  314 + <span>{{ getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, scope.row.code) }}</span>
  315 + </template>
  316 + </el-table-column>>
  317 + <el-table-column label="启用状态" align="center" prop="status">
  318 + <template slot-scope="scope">
  319 + <span>{{ getDictDataLabel(DICT_TYPE.SYS_COMMON_STATUS, scope.row.status) }}</span>
  320 + </template>
  321 + </el-table-column>>
  322 + <el-table-column label="备注" align="center" prop="remark" />
  323 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  324 + <template slot-scope="scope">
  325 + <span>{{ parseTime(scope.row.createTime) }}</span>
  326 + </template>
  327 + </el-table-column>
  328 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  329 + <template slot-scope="scope">
  330 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  331 + v-hasPermi="['system:sms-channel:update']">修改</el-button>
  332 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  333 + v-hasPermi="['system:sms-channel:delete']">删除</el-button>
  334 + </template>
  335 + </el-table-column>
  336 + </el-table>
  337 + <!-- 分页组件 -->
  338 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  339 + @pagination="getList"/>
  340 +
  341 + <!-- 对话框(添加 / 修改) -->
  342 + <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
  343 + <el-form ref="form" :model="form" :rules="rules" label-width="130px">
  344 + <el-form-item label="短信签名" prop="signature">
  345 + <el-input v-model="form.signature" placeholder="请输入短信签名" />
  346 + </el-form-item>
  347 + <el-form-item label="渠道编码" prop="code">
  348 + <el-select v-model="form.code" placeholder="请选择渠道编码" :disabled="form.id > 0">
  349 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_SMS_CHANNEL_CODE)"
  350 + :key="dict.value" :label="dict.label" :value="dict.value" />
  351 + </el-select>
  352 + </el-form-item>
  353 + <el-form-item label="启用状态">
  354 + <el-radio-group v-model="form.status">
  355 + <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
  356 + :key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
  357 + </el-radio-group>
  358 + </el-form-item>
  359 + <el-form-item label="备注" prop="remark">
  360 + <el-input v-model="form.remark" placeholder="请输入备注" />
  361 + </el-form-item>
  362 + <el-form-item label="短信 API 的账号" prop="apiKey">
  363 + <el-input v-model="form.apiKey" placeholder="请输入短信 API 的账号" />
  364 + </el-form-item>
  365 + <el-form-item v-if="form.code !== 'YUN_PIAN'" label="短信 API 的秘钥" prop="apiSecret">
  366 + <el-input v-model="form.apiSecret" placeholder="请输入短信 API 的秘钥" />
  367 + </el-form-item>
  368 + <el-form-item label="短信发送回调 URL" prop="callbackUrl">
  369 + <el-input v-model="form.callbackUrl" placeholder="请输入短信发送回调 URL" />
  370 + </el-form-item>
  371 + </el-form>
  372 + <div slot="footer" class="dialog-footer">
  373 + <el-button type="primary" @click="submitForm">确 定</el-button>
  374 + <el-button @click="cancel">取 消</el-button>
  375 + </div>
  376 + </el-dialog>
  377 + </div>
  378 +</template>
  379 +
  380 +<script>
  381 +import { createSmsChannel, updateSmsChannel, deleteSmsChannel, getSmsChannel, getSmsChannelPage } from "@/api/system/sms/smsChannel";
  382 +
  383 +export default {
  384 + name: "SmsChannel",
  385 + components: {
  386 + },
  387 + data() {
  388 + return {
  389 + // 遮罩层
  390 + loading: true,
  391 + // 显示搜索条件
  392 + showSearch: true,
  393 + // 总条数
  394 + total: 0,
  395 + // 短信渠道列表
  396 + list: [],
  397 + // 弹出层标题
  398 + title: "",
  399 + // 是否显示弹出层
  400 + open: false,
  401 + dateRangeCreateTime: [],
  402 + // 查询参数
  403 + queryParams: {
  404 + pageNo: 1,
  405 + pageSize: 10,
  406 + signature: null,
  407 + status: null,
  408 + },
  409 + // 表单参数
  410 + form: {},
  411 + // 表单校验
  412 + apiKeyEnableChannelCodes: ['YUN_PIAN'],
  413 + rules: {
  414 + signature: [{ required: true, message: "短信签名不能为空", trigger: "blur" }],
  415 + code: [{ required: true, message: "渠道编码不能为空", trigger: "blur" }],
  416 + status: [{ required: true, message: "启用状态不能为空", trigger: "blur" }],
  417 + apiKey: [{ required: true, message: "短信 API 的账号不能为空", trigger: "blur" }],
  418 + apiSecret: [{ required: true, message: "短信 API 的秘钥不能为空", trigger: "blur" }],
  419 + }
  420 + };
  421 + },
  422 + created() {
  423 + this.getList();
  424 + },
  425 + methods: {
  426 + /** 查询列表 */
  427 + getList() {
  428 + this.loading = true;
  429 + // 处理查询参数
  430 + let params = {...this.queryParams};
  431 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  432 + // 执行查询
  433 + getSmsChannelPage(params).then(response => {
  434 + this.list = response.data.list;
  435 + this.total = response.data.total;
  436 + this.loading = false;
  437 + });
  438 + },
  439 + /** 取消按钮 */
  440 + cancel() {
  441 + this.open = false;
  442 + this.reset();
  443 + },
  444 + /** 表单重置 */
  445 + reset() {
  446 + this.form = {
  447 + id: undefined,
  448 + signature: undefined,
  449 + code: undefined,
  450 + status: undefined,
  451 + remark: undefined,
  452 + apiKey: undefined,
  453 + apiSecret: undefined,
  454 + callbackUrl: undefined,
  455 + };
  456 + this.resetForm("form");
  457 + },
  458 + /** 搜索按钮操作 */
  459 + handleQuery() {
  460 + this.queryParams.pageNo = 1;
  461 + this.getList();
  462 + },
  463 + /** 重置按钮操作 */
  464 + resetQuery() {
  465 + this.dateRangeCreateTime = [];
  466 + this.resetForm("queryForm");
  467 + this.handleQuery();
  468 + },
  469 + /** 新增按钮操作 */
  470 + handleAdd() {
  471 + this.reset();
  472 + this.open = true;
  473 + this.title = "添加短信渠道";
  474 + },
  475 + /** 修改按钮操作 */
  476 + handleUpdate(row) {
  477 + this.reset();
  478 + const id = row.id;
  479 + getSmsChannel(id).then(response => {
  480 + this.form = response.data;
  481 + this.open = true;
  482 + this.title = "修改短信渠道";
  483 + });
  484 + },
  485 + /** 提交按钮 */
  486 + submitForm() {
  487 + this.$refs["form"].validate(valid => {
  488 + if (!valid) {
  489 + return;
  490 + }
  491 + // 修改的提交
  492 + if (this.form.id != null) {
  493 + updateSmsChannel(this.form).then(response => {
  494 + this.msgSuccess("修改成功");
  495 + this.open = false;
  496 + this.getList();
  497 + });
  498 + return;
  499 + }
  500 + // 添加的提交
  501 + createSmsChannel(this.form).then(response => {
  502 + this.msgSuccess("新增成功");
  503 + this.open = false;
  504 + this.getList();
  505 + });
  506 + });
  507 + },
  508 + /** 删除按钮操作 */
  509 + handleDelete(row) {
  510 + const id = row.id;
  511 + this.$confirm('是否确认删除短信渠道编号为"' + id + '"的数据项?', "警告", {
  512 + confirmButtonText: "确定",
  513 + cancelButtonText: "取消",
  514 + type: "warning"
  515 + }).then(function() {
  516 + return deleteSmsChannel(id);
  517 + }).then(() => {
  518 + this.getList();
  519 + this.msgSuccess("删除成功");
  520 + })
  521 + },
  522 + /** 导出按钮操作 */
  523 + handleExport() {
  524 + // 处理查询参数
  525 + let params = {...this.queryParams};
  526 + params.pageNo = undefined;
  527 + params.pageSize = undefined;
  528 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  529 + // 执行导出
  530 + this.$confirm('是否确认导出所有短信渠道数据项?', "警告", {
  531 + confirmButtonText: "确定",
  532 + cancelButtonText: "取消",
  533 + type: "warning"
  534 + }).then(function() {
  535 + return exportSmsChannelExcel(params);
  536 + }).then(response => {
  537 + this.downloadExcel(response, '短信渠道.xls');
  538 + })
  539 + }
  540 + }
  541 +};
  542 +</script>
ruoyi-ui/src/views/system/sms/smsLog.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
  6 + <el-form-item label="手机号" prop="mobile">
  7 + <el-input v-model="queryParams.mobile" placeholder="请输入手机号" clearable size="small" @keyup.enter.native="handleQuery"/>
  8 + </el-form-item>
  9 + <el-form-item label="短信渠道" prop="channelId">
  10 + <el-select v-model="queryParams.channelId" placeholder="请选择短信渠道" clearable size="small">
  11 + <el-option v-for="channel in channelOptions"
  12 + :key="channel.id" :value="channel.id"
  13 + :label="channel.signature + '【' + getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, channel.code) + '】'" />
  14 + </el-select>
  15 + </el-form-item>
  16 + <el-form-item label="模板编号" prop="templateId">
  17 + <el-input v-model="queryParams.templateId" placeholder="请输入模板编号" clearable size="small" @keyup.enter.native="handleQuery"/>
  18 + </el-form-item>
  19 + <el-form-item label="发送状态" prop="sendStatus">
  20 + <el-select v-model="queryParams.sendStatus" placeholder="请选择发送状态" clearable size="small">
  21 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_SMS_SEND_STATUS)"
  22 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  23 + </el-select>
  24 + </el-form-item>
  25 + <el-form-item label="发送时间">
  26 + <el-date-picker v-model="dateRangeSendTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  27 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  28 + </el-form-item>
  29 + <el-form-item label="接收状态" prop="receiveStatus">
  30 + <el-select v-model="queryParams.receiveStatus" placeholder="请选择接收状态" clearable size="small">
  31 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_SMS_RECEIVE_STATUS)"
  32 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  33 + </el-select>
  34 + </el-form-item>
  35 + <el-form-item label="接收时间">
  36 + <el-date-picker v-model="dateRangeReceiveTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  37 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  38 + </el-form-item>
  39 + <el-form-item>
  40 + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  41 + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  42 + </el-form-item>
  43 + </el-form>
  44 +
  45 + <!-- 操作工具栏 -->
  46 + <el-row :gutter="10" class="mb8">
  47 + <el-col :span="1.5">
  48 + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
  49 + v-hasPermi="['system:sms-log:create']">新增</el-button>
  50 + </el-col>
  51 + <el-col :span="1.5">
  52 + <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
  53 + v-hasPermi="['system:sms-log:export']">导出</el-button>
  54 + </el-col>
  55 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  56 + </el-row>
  57 +
  58 + <!-- 列表 -->
  59 + <el-table v-loading="loading" :data="list">
  60 + <el-table-column label="编号" align="center" prop="id" />
  61 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  62 + <template slot-scope="scope">
  63 + <span>{{ parseTime(scope.row.createTime) }}</span>
  64 + </template>
  65 + </el-table-column>
  66 + <el-table-column label="手机号" align="center" prop="mobile" width="120">
  67 + <template slot-scope="scope">
  68 + <div>{{ scope.row.mobile }}</div>
  69 + <div v-if="scope.row.userType && scope.row.userId">
  70 + {{ getDictDataLabel(DICT_TYPE.USER_TYPE, scope.row.userType) + '(' + scope.row.userId + ')' }}
  71 + </div>
  72 + </template>
  73 + </el-table-column>
  74 + <el-table-column label="短信内容" align="center" prop="templateContent" width="300" />
  75 + <el-table-column label="发送状态" align="center" width="180">
  76 + <template slot-scope="scope">
  77 + <div>{{ getDictDataLabel(DICT_TYPE.SYS_SMS_SEND_STATUS, scope.row.sendStatus) }}</div>
  78 + <div>{{ parseTime(scope.row.sendTime) }}</div>
  79 + </template>
  80 + </el-table-column>
  81 + <el-table-column label="接收状态" align="center" width="180">
  82 + <template slot-scope="scope">
  83 + <div>{{ getDictDataLabel(DICT_TYPE.SYS_SMS_RECEIVE_STATUS, scope.row.receiveStatus) }}</div>
  84 + <div>{{ parseTime(scope.row.receiveTime) }}</div>
  85 + </template>
  86 + </el-table-column>
  87 + <el-table-column label="短信渠道" align="center" width="120">
  88 + <template slot-scope="scope">
  89 + <div>{{ formatChannelSignature(scope.row.channelId) }}</div>
  90 + <div>【{{ getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, scope.row.channelCode) }}】</div>
  91 + </template>
  92 + </el-table-column>
  93 + <el-table-column label="模板编号" align="center" prop="templateId" />
  94 + <el-table-column label="短信类型" align="center" prop="templateType">
  95 + <template slot-scope="scope">
  96 + <span>{{ getDictDataLabel(DICT_TYPE.SYS_SMS_TEMPLATE_TYPE, scope.row.templateType) }}</span>
  97 + </template>
  98 + </el-table-column>
  99 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  100 + <template slot-scope="scope">
  101 + <el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row,scope.index)"
  102 + v-hasPermi="['system:sms-log:query']">详细</el-button>
  103 + </template>
  104 + </el-table-column>
  105 + </el-table>
  106 + <!-- 分页组件 -->
  107 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  108 + @pagination="getList"/>
  109 +
  110 + <!-- 短信日志详细 -->
  111 + <el-dialog title="短信日志详细" :visible.sync="open" width="700px" append-to-body>
  112 + <el-form ref="form" :model="form" label-width="140px" size="mini">
  113 + <el-row>
  114 + <el-col :span="24">
  115 + <el-form-item label="日志主键:">{{ form.id }}</el-form-item>
  116 + </el-col>
  117 + <el-col :span="24">
  118 + <el-form-item label="短信渠道:">
  119 + {{ formatChannelSignature(form.channelId) }}【{{ getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, form.channelCode) }}】
  120 + </el-form-item>
  121 + </el-col>
  122 + <el-col :span="24">
  123 + <el-form-item label="短信模板:">
  124 + {{ form.templateId }} | {{ form.templateCode}} | {{ getDictDataLabel(DICT_TYPE.SYS_SMS_TEMPLATE_TYPE, form.templateType) }}
  125 + </el-form-item>
  126 + </el-col>
  127 + <el-col :span="24">
  128 + <el-form-item label="API 的模板编号:">{{ form.apiTemplateId }}</el-form-item>
  129 + </el-col>
  130 + <el-col :span="24">
  131 + <el-form-item label="用户信息:">{{ form.mobile }}
  132 + <span v-if="form.userType && form.userId"> | {{ getDictDataLabel(DICT_TYPE.USER_TYPE, form.userType) }} | {{ form.userId }}</span>
  133 + </el-form-item>
  134 + </el-col>
  135 + <el-col :span="24">
  136 + <el-form-item label="短信内容:">{{ form.templateContent }}</el-form-item>
  137 + </el-col>
  138 + <el-col :span="24">
  139 + <el-form-item label="短信参数:">{{ form.templateParams }}</el-form-item>
  140 + </el-col>
  141 + <el-col :span="24">
  142 + <el-form-item label="创建时间:">{{ parseTime(form.createTime) }}</el-form-item>
  143 + </el-col>
  144 + <el-col :span="24">
  145 + <el-form-item label="发送状态:">{{ getDictDataLabel(DICT_TYPE.SYS_SMS_SEND_STATUS, form.sendStatus) }}</el-form-item>
  146 + </el-col>
  147 + <el-col :span="24">
  148 + <el-form-item label="发送时间:">{{ parseTime(form.sendTime) }}</el-form-item>
  149 + </el-col>
  150 + <el-col :span="24">
  151 + <el-form-item label="发送结果:">{{ form.sendCode }} | {{ form.sendMsg }}
  152 + </el-form-item>
  153 + </el-col>
  154 + <el-col :span="24">
  155 + <el-form-item label="API 发送结果:">{{ form.apiSendCode }} | {{ form.apiSendMsg }}</el-form-item>
  156 + </el-col>
  157 + <el-col :span="24">
  158 + <el-form-item label="API 短信编号:">{{ form.apiSerialNo }}</el-form-item>
  159 + </el-col>
  160 + <el-col :span="24">
  161 + <el-form-item label="API 请求编号:">{{ form.apiRequestId }}</el-form-item>
  162 + </el-col>
  163 + <el-col :span="24">
  164 + <el-form-item label="接收状态:">{{ getDictDataLabel(DICT_TYPE.SYS_SMS_RECEIVE_STATUS, form.receiveStatus) }}</el-form-item>
  165 + </el-col>
  166 + <el-col :span="24">
  167 + <el-form-item label="接收时间:">{{ parseTime(form.receiveTime) }}</el-form-item>
  168 + </el-col>
  169 + <el-col :span="24">
  170 + <el-form-item label="API 接收结果:">{{ form.apiReceiveCode }} | {{ form.apiReceiveMsg }}
  171 + </el-form-item>
  172 + </el-col>
  173 + </el-row>
  174 + </el-form>
  175 + <div slot="footer" class="dialog-footer">
  176 + <el-button @click="open = false">关 闭</el-button>
  177 + </div>
  178 + </el-dialog>
  179 +
  180 + </div>
  181 +</template>
  182 +
  183 +<script>
  184 +import { getSmsLogPage, exportSmsLogExcel } from "@/api/system/sms/smsLog";
  185 +import { getSimpleSmsChannels } from "@/api/system/sms/smsChannel";
  186 +
  187 +export default {
  188 + name: "SmsLog",
  189 + components: {
  190 + },
  191 + data() {
  192 + return {
  193 + // 遮罩层
  194 + loading: true,
  195 + // 显示搜索条件
  196 + showSearch: true,
  197 + // 总条数
  198 + total: 0,
  199 + // 短信日志列表
  200 + list: [],
  201 + // 弹出层标题
  202 + title: "",
  203 + // 是否显示弹出层
  204 + open: false,
  205 + dateRangeSendTime: [],
  206 + dateRangeReceiveTime: [],
  207 + // 表单参数
  208 + form: {},
  209 + // 查询参数
  210 + queryParams: {
  211 + pageNo: 1,
  212 + pageSize: 10,
  213 + channelId: null,
  214 + templateId: null,
  215 + mobile: null,
  216 + sendStatus: null,
  217 + receiveStatus: null,
  218 + },
  219 + // 短信渠道
  220 + channelOptions: [],
  221 + };
  222 + },
  223 + created() {
  224 + this.getList();
  225 + // 获得短信渠道
  226 + getSimpleSmsChannels().then(response => {
  227 + this.channelOptions = response.data;
  228 + })
  229 + },
  230 + methods: {
  231 + /** 查询列表 */
  232 + getList() {
  233 + this.loading = true;
  234 + // 处理查询参数
  235 + let params = {...this.queryParams};
  236 + this.addBeginAndEndTime(params, this.dateRangeSendTime, 'sendTime');
  237 + this.addBeginAndEndTime(params, this.dateRangeReceiveTime, 'receiveTime');
  238 + // 执行查询
  239 + getSmsLogPage(params).then(response => {
  240 + this.list = response.data.list;
  241 + this.total = response.data.total;
  242 + this.loading = false;
  243 + });
  244 + },
  245 + /** 取消按钮 */
  246 + cancel() {
  247 + this.open = false;
  248 + this.reset();
  249 + },
  250 + /** 搜索按钮操作 */
  251 + handleQuery() {
  252 + this.queryParams.pageNo = 1;
  253 + this.getList();
  254 + },
  255 + /** 重置按钮操作 */
  256 + resetQuery() {
  257 + this.dateRangeSendTime = [];
  258 + this.dateRangeReceiveTime = [];
  259 + this.resetForm("queryForm");
  260 + this.handleQuery();
  261 + },
  262 + /** 导出按钮操作 */
  263 + handleExport() {
  264 + // 处理查询参数
  265 + let params = {...this.queryParams};
  266 + params.pageNo = undefined;
  267 + params.pageSize = undefined;
  268 + this.addBeginAndEndTime(params, this.dateRangeSendTime, 'sendTime');
  269 + this.addBeginAndEndTime(params, this.dateRangeReceiveTime, 'receiveTime');
  270 + // 执行导出
  271 + this.$confirm('是否确认导出所有短信日志数据项?', "警告", {
  272 + confirmButtonText: "确定",
  273 + cancelButtonText: "取消",
  274 + type: "warning"
  275 + }).then(function() {
  276 + return exportSmsLogExcel(params);
  277 + }).then(response => {
  278 + this.downloadExcel(response, '短信日志.xls');
  279 + })
  280 + },
  281 + /** 详细按钮操作 */
  282 + handleView(row) {
  283 + this.open = true;
  284 + this.form = row;
  285 + },
  286 + /** 格式化短信渠道 */
  287 + formatChannelSignature(channelId) {
  288 + for (const channel of this.channelOptions) {
  289 + if (channel.id === channelId) {
  290 + return channel.signature;
  291 + }
  292 + }
  293 + return '找不到签名:' + channelId;
  294 + }
  295 + }
  296 +};
  297 +</script>
ruoyi-ui/src/views/system/sms/smsTemplate.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="150px">
  6 + <el-form-item label="短信类型" prop="type">
  7 + <el-select v-model="queryParams.type" placeholder="请选择短信类型" clearable size="small">
  8 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_SMS_TEMPLATE_TYPE)"
  9 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  10 + </el-select>
  11 + </el-form-item>
  12 + <el-form-item label="开启状态" prop="status">
  13 + <el-select v-model="queryParams.status" placeholder="请选择开启状态" clearable size="small">
  14 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
  15 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  16 + </el-select>
  17 + </el-form-item>
  18 + <el-form-item label="模板编码" prop="code">
  19 + <el-input v-model="queryParams.code" placeholder="请输入模板编码" clearable size="small" @keyup.enter.native="handleQuery"/>
  20 + </el-form-item>
  21 + <el-form-item label="短信 API 的模板编号" prop="apiTemplateId">
  22 + <el-input v-model="queryParams.apiTemplateId" placeholder="请输入短信 API 的模板编号" clearable size="small" @keyup.enter.native="handleQuery"/>
  23 + </el-form-item>
  24 + <el-form-item label="短信渠道" prop="channelId">
  25 + <el-select v-model="queryParams.channelId" placeholder="请选择短信渠道" clearable size="small">
  26 + <el-option v-for="channel in channelOptions"
  27 + :key="channel.id" :value="channel.id"
  28 + :label="channel.signature + '【' + getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, channel.code) + '】'" />
  29 + </el-select>
  30 + </el-form-item>
  31 + <el-form-item label="创建时间">
  32 + <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  33 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  34 + </el-form-item>
  35 + <el-form-item>
  36 + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  37 + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  38 + </el-form-item>
  39 + </el-form>
  40 +
  41 + <!-- 操作工具栏 -->
  42 + <el-row :gutter="10" class="mb8">
  43 + <el-col :span="1.5">
  44 + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
  45 + v-hasPermi="['system:sms-template:create']">新增</el-button>
  46 + </el-col>
  47 + <el-col :span="1.5">
  48 + <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
  49 + v-hasPermi="['system:sms-template:export']">导出</el-button>
  50 + </el-col>
  51 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  52 + </el-row>
  53 +
  54 + <!-- 列表 -->
  55 + <el-table v-loading="loading" :data="list">
  56 + <el-table-column label="模板编码" align="center" prop="code" />
  57 + <el-table-column label="模板名称" align="center" prop="name" />
  58 + <el-table-column label="模板内容" align="center" prop="content" width="300" />
  59 + <el-table-column label="短信类型" align="center" prop="type">
  60 + <template slot-scope="scope">
  61 + <span>{{ getDictDataLabel(DICT_TYPE.SYS_SMS_TEMPLATE_TYPE, scope.row.type) }}</span>
  62 + </template>
  63 + </el-table-column>
  64 + <el-table-column label="开启状态" align="center" prop="status">
  65 + <template slot-scope="scope">
  66 + <span>{{ getDictDataLabel(DICT_TYPE.SYS_COMMON_STATUS, scope.row.status) }}</span>
  67 + </template>
  68 + </el-table-column>
  69 + <el-table-column label="备注" align="center" prop="remark" />
  70 + <el-table-column label="短信 API 的模板编号" align="center" prop="apiTemplateId" width="180" />
  71 + <el-table-column label="短信渠道" align="center" width="120">
  72 + <template slot-scope="scope">
  73 + <div>{{ formatChannelSignature(scope.row.channelId) }}</div>
  74 + <div>【{{ getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, scope.row.channelCode) }}】</div>
  75 + </template>
  76 + </el-table-column>
  77 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  78 + <template slot-scope="scope">
  79 + <span>{{ parseTime(scope.row.createTime) }}</span>
  80 + </template>
  81 + </el-table-column>
  82 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="150">
  83 + <template slot-scope="scope">
  84 + <el-button size="mini" type="text" icon="el-icon-share" @click="handleSendSms(scope.row)"
  85 + v-hasPermi="['system:sms-template:send-sms']">测试</el-button>
  86 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  87 + v-hasPermi="['system:sms-template:update']">修改</el-button>
  88 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  89 + v-hasPermi="['system:sms-template:delete']">删除</el-button>
  90 + </template>
  91 + </el-table-column>
  92 + </el-table>
  93 + <!-- 分页组件 -->
  94 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  95 + @pagination="getList"/>
  96 +
  97 + <!-- 对话框(添加 / 修改) -->
  98 + <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
  99 + <el-form ref="form" :model="form" :rules="rules" label-width="140px">
  100 + <el-form-item label="短信渠道编号" prop="channelId">
  101 + <el-select v-model="form.channelId" placeholder="请选择短信渠道编号">
  102 + <el-option v-for="channel in channelOptions"
  103 + :key="channel.id" :value="channel.id"
  104 + :label="channel.signature + '【' + getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, channel.code) + '】'" />
  105 + </el-select>
  106 + </el-form-item>
  107 + <el-form-item label="短信类型" prop="type">
  108 + <el-select v-model="form.type" placeholder="请选择短信类型">
  109 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_SMS_TEMPLATE_TYPE)"
  110 + :key="dict.value" :label="dict.label" :value="parseInt(dict.value)" />
  111 + </el-select>
  112 + </el-form-item>
  113 + <el-form-item label="模板编号" prop="code">
  114 + <el-input v-model="form.code" placeholder="请输入模板编号" />
  115 + </el-form-item>
  116 + <el-form-item label="模板名称" prop="name">
  117 + <el-input v-model="form.name" placeholder="请输入模板名称" />
  118 + </el-form-item>
  119 + <el-form-item label="模板内容" prop="content">
  120 + <el-input type="textarea" v-model="form.content" placeholder="请输入模板内容" />
  121 + </el-form-item>
  122 + <el-form-item label="开启状态" prop="status">
  123 + <el-radio-group v-model="form.status">
  124 + <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
  125 + :key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
  126 + </el-radio-group>
  127 + </el-form-item>
  128 + <el-form-item label="短信 API 模板编号" prop="apiTemplateId">
  129 + <el-input v-model="form.apiTemplateId" placeholder="请输入短信 API 的模板编号" />
  130 + </el-form-item>
  131 + <el-form-item label="备注" prop="remark">
  132 + <el-input v-model="form.remark" placeholder="请输入备注" />
  133 + </el-form-item>
  134 + </el-form>
  135 + <div slot="footer" class="dialog-footer">
  136 + <el-button type="primary" @click="submitForm">确 定</el-button>
  137 + <el-button @click="cancel">取 消</el-button>
  138 + </div>
  139 + </el-dialog>
  140 +
  141 + <!-- 对话框(发送短信) -->
  142 + <el-dialog title="测试发送短信" :visible.sync="sendSmsOpen" width="500px" append-to-body>
  143 + <el-form ref="sendSmsForm" :model="sendSmsForm" :rules="sendSmsRules" label-width="140px">
  144 + <el-form-item label="模板内容" prop="content">
  145 + <el-input v-model="sendSmsForm.content" type="textarea" placeholder="请输入模板内容" readonly />
  146 + </el-form-item>
  147 + <el-form-item label="手机号" prop="mobile">
  148 + <el-input v-model="sendSmsForm.mobile" placeholder="请输入手机号" />
  149 + </el-form-item>
  150 + <el-form-item v-for="param in sendSmsForm.params" :label="'参数 {' + param + '}'" :prop="'templateParams.' + param">
  151 + <el-input v-model="sendSmsForm.templateParams[param]" :placeholder="'请输入 ' + param + ' 参数'" />
  152 + </el-form-item>
  153 + </el-form>
  154 + <div slot="footer" class="dialog-footer">
  155 + <el-button type="primary" @click="submitSendSmsForm">确 定</el-button>
  156 + <el-button @click="cancelSendSms">取 消</el-button>
  157 + </div>
  158 + </el-dialog>
  159 +
  160 + </div>
  161 +</template>
  162 +
  163 +<script>
  164 +import { createSmsTemplate, updateSmsTemplate, deleteSmsTemplate, getSmsTemplate, getSmsTemplatePage,
  165 + exportSmsTemplateExcel, sendSms } from "@/api/system/sms/smsTemplate";
  166 +import { getSimpleSmsChannels } from "@/api/system/sms/smsChannel";
  167 +
  168 +export default {
  169 + name: "SmsTemplate",
  170 + data() {
  171 + return {
  172 + // 遮罩层
  173 + loading: true,
  174 + // 显示搜索条件
  175 + showSearch: true,
  176 + // 总条数
  177 + total: 0,
  178 + // 短信模板列表
  179 + list: [],
  180 + // 弹出层标题
  181 + title: "",
  182 + // 是否显示弹出层
  183 + open: false,
  184 + dateRangeCreateTime: [],
  185 + // 查询参数
  186 + queryParams: {
  187 + pageNo: 1,
  188 + pageSize: 10,
  189 + type: null,
  190 + status: null,
  191 + code: null,
  192 + content: null,
  193 + apiTemplateId: null,
  194 + channelId: null,
  195 + },
  196 + // 表单参数
  197 + form: {},
  198 + // 表单校验
  199 + rules: {
  200 + type: [{ required: true, message: "短信类型不能为空", trigger: "change" }],
  201 + status: [{ required: true, message: "开启状态不能为空", trigger: "blur" }],
  202 + code: [{ required: true, message: "模板编码不能为空", trigger: "blur" }],
  203 + name: [{ required: true, message: "模板名称不能为空", trigger: "blur" }],
  204 + content: [{ required: true, message: "模板内容不能为空", trigger: "blur" }],
  205 + apiTemplateId: [{ required: true, message: "短信 API 的模板编号不能为空", trigger: "blur" }],
  206 + channelId: [{ required: true, message: "短信渠道编号不能为空", trigger: "change" }],
  207 + },
  208 + // 短信渠道
  209 + channelOptions: [],
  210 + // 发送短信
  211 + sendSmsOpen: false,
  212 + sendSmsForm: {
  213 + params: [], // 模板的参数列表
  214 + },
  215 + sendSmsRules: {
  216 + mobile: [{ required: true, message: "手机不能为空", trigger: "blur" }],
  217 + templateCode: [{ required: true, message: "手机不能为空", trigger: "blur" }],
  218 + templateParams: { }
  219 + }
  220 + };
  221 + },
  222 + created() {
  223 + this.getList();
  224 + // 获得短信渠道
  225 + getSimpleSmsChannels().then(response => {
  226 + this.channelOptions = response.data;
  227 + })
  228 + },
  229 + methods: {
  230 + /** 查询列表 */
  231 + getList() {
  232 + this.loading = true;
  233 + // 处理查询参数
  234 + let params = {...this.queryParams};
  235 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  236 + // 执行查询
  237 + getSmsTemplatePage(params).then(response => {
  238 + this.list = response.data.list;
  239 + this.total = response.data.total;
  240 + this.loading = false;
  241 + });
  242 + },
  243 + /** 取消按钮 */
  244 + cancel() {
  245 + this.open = false;
  246 + this.reset();
  247 + },
  248 + /** 表单重置 */
  249 + reset() {
  250 + this.form = {
  251 + id: undefined,
  252 + type: undefined,
  253 + status: undefined,
  254 + code: undefined,
  255 + name: undefined,
  256 + content: undefined,
  257 + remark: undefined,
  258 + apiTemplateId: undefined,
  259 + channelId: undefined,
  260 + };
  261 + this.resetForm("form");
  262 + },
  263 + /** 搜索按钮操作 */
  264 + handleQuery() {
  265 + this.queryParams.pageNo = 1;
  266 + this.getList();
  267 + },
  268 + /** 重置按钮操作 */
  269 + resetQuery() {
  270 + this.dateRangeCreateTime = [];
  271 + this.resetForm("queryForm");
  272 + this.handleQuery();
  273 + },
  274 + /** 新增按钮操作 */
  275 + handleAdd() {
  276 + this.reset();
  277 + this.open = true;
  278 + this.title = "添加短信模板";
  279 + },
  280 + /** 修改按钮操作 */
  281 + handleUpdate(row) {
  282 + this.reset();
  283 + const id = row.id;
  284 + getSmsTemplate(id).then(response => {
  285 + this.form = response.data;
  286 + this.open = true;
  287 + this.title = "修改短信模板";
  288 + });
  289 + },
  290 + /** 提交按钮 */
  291 + submitForm() {
  292 + this.$refs["form"].validate(valid => {
  293 + if (!valid) {
  294 + return;
  295 + }
  296 + // 修改的提交
  297 + if (this.form.id != null) {
  298 + updateSmsTemplate(this.form).then(response => {
  299 + this.msgSuccess("修改成功");
  300 + this.open = false;
  301 + this.getList();
  302 + });
  303 + return;
  304 + }
  305 + // 添加的提交
  306 + createSmsTemplate(this.form).then(response => {
  307 + this.msgSuccess("新增成功");
  308 + this.open = false;
  309 + this.getList();
  310 + });
  311 + });
  312 + },
  313 + /** 删除按钮操作 */
  314 + handleDelete(row) {
  315 + const id = row.id;
  316 + this.$confirm('是否确认删除短信模板编号为"' + id + '"的数据项?', "警告", {
  317 + confirmButtonText: "确定",
  318 + cancelButtonText: "取消",
  319 + type: "warning"
  320 + }).then(function() {
  321 + return deleteSmsTemplate(id);
  322 + }).then(() => {
  323 + this.getList();
  324 + this.msgSuccess("删除成功");
  325 + })
  326 + },
  327 + /** 导出按钮操作 */
  328 + handleExport() {
  329 + // 处理查询参数
  330 + let params = {...this.queryParams};
  331 + params.pageNo = undefined;
  332 + params.pageSize = undefined;
  333 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  334 + // 执行导出
  335 + this.$confirm('是否确认导出所有短信模板数据项?', "警告", {
  336 + confirmButtonText: "确定",
  337 + cancelButtonText: "取消",
  338 + type: "warning"
  339 + }).then(function() {
  340 + return exportSmsTemplateExcel(params);
  341 + }).then(response => {
  342 + this.downloadExcel(response, '短信模板.xls');
  343 + })
  344 + },
  345 + /** 发送短息按钮 */
  346 + handleSendSms(row) {
  347 + this.resetSendSms(row);
  348 + // 设置参数
  349 + this.sendSmsForm.content = row.content;
  350 + this.sendSmsForm.params = row.params;
  351 + this.sendSmsForm.templateCode = row.code;
  352 + this.sendSmsForm.templateParams = row.params.reduce(function(obj, item) {
  353 + obj[item] = undefined;
  354 + return obj;
  355 + }, {});
  356 + // 根据 row 重置 rules
  357 + this.sendSmsRules.templateParams = row.params.reduce(function(obj, item) {
  358 + obj[item] = { required: true, message: '参数 ' + item + " 不能为空", trigger: "change" };
  359 + return obj;
  360 + }, {});
  361 + // 设置打开
  362 + this.sendSmsOpen = true;
  363 + },
  364 + /** 重置发送短信的表单 */
  365 + resetSendSms() {
  366 + // 根据 row 重置表单
  367 + this.sendSmsForm = {
  368 + content: undefined,
  369 + params: undefined,
  370 + mobile: undefined,
  371 + templateCode: undefined,
  372 + templateParams: {}
  373 + };
  374 + this.resetForm("sendSmsForm");
  375 + },
  376 + /** 取消发送短信 */
  377 + cancelSendSms() {
  378 + this.sendSmsOpen = false;
  379 + this.resetSendSms();
  380 + },
  381 + /** 提交按钮 */
  382 + submitSendSmsForm() {
  383 + this.$refs["sendSmsForm"].validate(valid => {
  384 + if (!valid) {
  385 + return;
  386 + }
  387 + // 添加的提交
  388 + sendSms(this.sendSmsForm).then(response => {
  389 + this.msgSuccess("提交发送成功!发送结果,见发送日志编号:" + response.data);
  390 + this.sendSmsOpen = false;
  391 + });
  392 + });
  393 + },
  394 + /** 格式化短信渠道 */
  395 + formatChannelSignature(channelId) {
  396 + for (const channel of this.channelOptions) {
  397 + if (channel.id === channelId) {
  398 + return channel.signature;
  399 + }
  400 + }
  401 + return '找不到签名:' + channelId;
  402 + }
  403 + }
  404 +};
  405 +</script>
ruoyi-ui/src/views/system/user/index.vue
@@ -362,7 +362,7 @@ export default { @@ -362,7 +362,7 @@ export default {
362 created() { 362 created() {
363 this.getList(); 363 this.getList();
364 this.getTreeselect(); 364 this.getTreeselect();
365 - this.getConfigKey("sys.user.initPassword").then(response => { 365 + this.getConfigKey("sys.user.init-password").then(response => {
366 this.initPassword = response.msg; 366 this.initPassword = response.msg;
367 }); 367 });
368 }, 368 },
sql/ruoyi-vue-pro.sql
1 /* 1 /*
2 Navicat Premium Data Transfer 2 Navicat Premium Data Transfer
3 3
4 - Source Server : 127.0.0.1 4 + Source Server : local-mysql001
5 Source Server Type : MySQL 5 Source Server Type : MySQL
6 Source Server Version : 50718 6 Source Server Version : 50718
7 Source Host : localhost:3306 7 Source Host : localhost:3306
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 Target Server Version : 50718 11 Target Server Version : 50718
12 File Encoding : 65001 12 File Encoding : 65001
13 13
14 - Date: 21/03/2021 18:53:24 14 + Date: 18/04/2021 00:36:06
15 */ 15 */
16 16
17 SET NAMES utf8mb4; 17 SET NAMES utf8mb4;
@@ -43,7 +43,7 @@ CREATE TABLE `inf_api_access_log` ( @@ -43,7 +43,7 @@ CREATE TABLE `inf_api_access_log` (
43 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', 43 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
44 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤', 44 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
45 PRIMARY KEY (`id`) USING BTREE 45 PRIMARY KEY (`id`) USING BTREE
46 -) ENGINE=InnoDB AUTO_INCREMENT=1318 DEFAULT CHARSET=utf8mb4 COMMENT='API 访问日志表'; 46 +) ENGINE=InnoDB AUTO_INCREMENT=3750 DEFAULT CHARSET=utf8mb4 COMMENT='API 访问日志表';
47 47
48 -- ---------------------------- 48 -- ----------------------------
49 -- Records of inf_api_access_log 49 -- Records of inf_api_access_log
@@ -84,7 +84,7 @@ CREATE TABLE `inf_api_error_log` ( @@ -84,7 +84,7 @@ CREATE TABLE `inf_api_error_log` (
84 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', 84 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
85 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤', 85 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
86 PRIMARY KEY (`id`) USING BTREE 86 PRIMARY KEY (`id`) USING BTREE
87 -) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='系统异常日志'; 87 +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COMMENT='系统异常日志';
88 88
89 -- ---------------------------- 89 -- ----------------------------
90 -- Records of inf_api_error_log 90 -- Records of inf_api_error_log
@@ -201,7 +201,7 @@ CREATE TABLE `inf_job_log` ( @@ -201,7 +201,7 @@ CREATE TABLE `inf_job_log` (
201 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', 201 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
202 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤', 202 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
203 PRIMARY KEY (`id`) USING BTREE 203 PRIMARY KEY (`id`) USING BTREE
204 -) ENGINE=InnoDB AUTO_INCREMENT=627 DEFAULT CHARSET=utf8mb4 COMMENT='定时任务日志表'; 204 +) ENGINE=InnoDB AUTO_INCREMENT=2322 DEFAULT CHARSET=utf8mb4 COMMENT='定时任务日志表';
205 205
206 -- ---------------------------- 206 -- ----------------------------
207 -- Records of inf_job_log 207 -- Records of inf_job_log
@@ -264,7 +264,7 @@ CREATE TABLE `sys_dict_data` ( @@ -264,7 +264,7 @@ CREATE TABLE `sys_dict_data` (
264 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', 264 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
265 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤', 265 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
266 PRIMARY KEY (`id`) USING BTREE 266 PRIMARY KEY (`id`) USING BTREE
267 -) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8mb4 COMMENT='字典数æ®è¡¨'; 267 +) ENGINE=InnoDB AUTO_INCREMENT=78 DEFAULT CHARSET=utf8mb4 COMMENT='字典数æ®è¡¨';
268 268
269 -- ---------------------------- 269 -- ----------------------------
270 -- Records of sys_dict_data 270 -- Records of sys_dict_data
@@ -324,6 +324,19 @@ INSERT INTO `sys_dict_data` VALUES (61, 2, &#39;管ç†å‘˜&#39;, &#39;2&#39;, &#39;user_type&#39;, 0, NUL @@ -324,6 +324,19 @@ INSERT INTO `sys_dict_data` VALUES (61, 2, &#39;管ç†å‘˜&#39;, &#39;2&#39;, &#39;user_type&#39;, 0, NUL
324 INSERT INTO `sys_dict_data` VALUES (62, 0, '未处ç†', '0', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:19', '', '2021-02-26 08:11:23', b'0'); 324 INSERT INTO `sys_dict_data` VALUES (62, 0, '未处ç†', '0', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:19', '', '2021-02-26 08:11:23', b'0');
325 INSERT INTO `sys_dict_data` VALUES (63, 1, '已处ç†', '1', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:26', '', '2021-02-26 08:11:29', b'0'); 325 INSERT INTO `sys_dict_data` VALUES (63, 1, '已处ç†', '1', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:26', '', '2021-02-26 08:11:29', b'0');
326 INSERT INTO `sys_dict_data` VALUES (64, 2, '已忽略', '2', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:34', '', '2021-02-26 08:11:34', b'0'); 326 INSERT INTO `sys_dict_data` VALUES (64, 2, '已忽略', '2', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:34', '', '2021-02-26 08:11:34', b'0');
  327 +INSERT INTO `sys_dict_data` VALUES (65, 1, '云片', 'YUN_PIAN', 'sys_sms_channel_code', 0, NULL, '1', '2021-04-05 01:05:14', '1', '2021-04-13 00:20:13', b'0');
  328 +INSERT INTO `sys_dict_data` VALUES (66, 2, '阿里云', 'ALIYUN', 'sys_sms_channel_code', 0, NULL, '1', '2021-04-05 01:05:26', '1', '2021-04-13 00:20:16', b'0');
  329 +INSERT INTO `sys_dict_data` VALUES (67, 1, '验è¯ç ', '1', 'sys_sms_template_type', 0, NULL, '1', '2021-04-05 21:50:57', '1', '2021-04-05 21:50:57', b'0');
  330 +INSERT INTO `sys_dict_data` VALUES (68, 2, '通知', '2', 'sys_sms_template_type', 0, NULL, '1', '2021-04-05 21:51:08', '1', '2021-04-05 21:51:08', b'0');
  331 +INSERT INTO `sys_dict_data` VALUES (69, 0, 'è¥é”€', '3', 'sys_sms_template_type', 0, NULL, '1', '2021-04-05 21:51:15', '1', '2021-04-05 21:51:15', b'0');
  332 +INSERT INTO `sys_dict_data` VALUES (70, 0, 'åˆå§‹åŒ–', '0', 'sys_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:33', '1', '2021-04-11 09:30:18', b'0');
  333 +INSERT INTO `sys_dict_data` VALUES (71, 1, 'å‘逿ˆåŠŸ', '10', 'sys_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:43', '1', '2021-04-11 09:30:20', b'0');
  334 +INSERT INTO `sys_dict_data` VALUES (72, 2, 'å‘é€å¤±è´¥', '20', 'sys_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:49', '1', '2021-04-11 09:30:22', b'0');
  335 +INSERT INTO `sys_dict_data` VALUES (73, 3, 'ä¸å‘é€', '30', 'sys_sms_send_status', 0, NULL, '1', '2021-04-11 20:19:44', '1', '2021-04-11 09:30:23', b'0');
  336 +INSERT INTO `sys_dict_data` VALUES (74, 0, '等待结果', '0', 'sys_sms_receive_status', 0, NULL, '1', '2021-04-11 20:27:43', '1', '2021-04-17 23:05:19', b'0');
  337 +INSERT INTO `sys_dict_data` VALUES (75, 1, '接收æˆåŠŸ', '10', 'sys_sms_receive_status', 0, NULL, '1', '2021-04-11 20:29:25', '1', '2021-04-11 20:29:35', b'0');
  338 +INSERT INTO `sys_dict_data` VALUES (76, 2, '接收失败', '20', 'sys_sms_receive_status', 0, NULL, '1', '2021-04-11 20:29:31', '1', '2021-04-11 20:29:39', b'0');
  339 +INSERT INTO `sys_dict_data` VALUES (77, 0, '调试(钉钉)', 'DEBUG_DING_TALK', 'sys_sms_channel_code', 0, NULL, '1', '2021-04-13 00:20:37', '1', '2021-04-13 00:20:37', b'0');
327 COMMIT; 340 COMMIT;
328 341
329 -- ---------------------------- 342 -- ----------------------------
@@ -343,7 +356,7 @@ CREATE TABLE `sys_dict_type` ( @@ -343,7 +356,7 @@ CREATE TABLE `sys_dict_type` (
343 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤', 356 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
344 PRIMARY KEY (`id`) USING BTREE, 357 PRIMARY KEY (`id`) USING BTREE,
345 UNIQUE KEY `dict_type` (`type`) 358 UNIQUE KEY `dict_type` (`type`)
346 -) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8mb4 COMMENT='字典类型表'; 359 +) ENGINE=InnoDB AUTO_INCREMENT=115 DEFAULT CHARSET=utf8mb4 COMMENT='字典类型表';
347 360
348 -- ---------------------------- 361 -- ----------------------------
349 -- Records of sys_dict_type 362 -- Records of sys_dict_type
@@ -366,6 +379,10 @@ INSERT INTO `sys_dict_type` VALUES (107, &#39;定时任务状æ€&#39;, &#39;inf_job_status&#39;, @@ -366,6 +379,10 @@ INSERT INTO `sys_dict_type` VALUES (107, &#39;定时任务状æ€&#39;, &#39;inf_job_status&#39;,
366 INSERT INTO `sys_dict_type` VALUES (108, '定时任务日志状æ€', 'inf_job_log_status', 0, NULL, '', '2021-02-08 10:03:51', '', '2021-02-08 10:03:51', b'0'); 379 INSERT INTO `sys_dict_type` VALUES (108, '定时任务日志状æ€', 'inf_job_log_status', 0, NULL, '', '2021-02-08 10:03:51', '', '2021-02-08 10:03:51', b'0');
367 INSERT INTO `sys_dict_type` VALUES (109, '用户类型', 'user_type', 0, NULL, '', '2021-02-26 00:15:51', '', '2021-02-26 00:15:51', b'0'); 380 INSERT INTO `sys_dict_type` VALUES (109, '用户类型', 'user_type', 0, NULL, '', '2021-02-26 00:15:51', '', '2021-02-26 00:15:51', b'0');
368 INSERT INTO `sys_dict_type` VALUES (110, 'API 异常数æ®çš„处ç†çжæ€', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:01', '', '2021-02-26 07:07:01', b'0'); 381 INSERT INTO `sys_dict_type` VALUES (110, 'API 异常数æ®çš„处ç†çжæ€', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:01', '', '2021-02-26 07:07:01', b'0');
  382 +INSERT INTO `sys_dict_type` VALUES (111, '短信渠é“ç¼–ç ', 'sys_sms_channel_code', 0, NULL, '1', '2021-04-05 01:04:50', '1', '2021-04-05 01:04:50', b'0');
  383 +INSERT INTO `sys_dict_type` VALUES (112, '短信模æ¿çš„类型', 'sys_sms_template_type', 0, NULL, '1', '2021-04-05 21:50:43', '1', '2021-04-05 21:50:43', b'0');
  384 +INSERT INTO `sys_dict_type` VALUES (113, '短信å‘é€çжæ€', 'sys_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:03', '1', '2021-04-11 09:30:02', b'0');
  385 +INSERT INTO `sys_dict_type` VALUES (114, '短信接收状æ€', 'sys_sms_receive_status', 0, NULL, '1', '2021-04-11 20:27:14', '1', '2021-04-11 20:27:14', b'0');
369 COMMIT; 386 COMMIT;
370 387
371 -- ---------------------------- 388 -- ----------------------------
@@ -386,7 +403,7 @@ CREATE TABLE `sys_login_log` ( @@ -386,7 +403,7 @@ CREATE TABLE `sys_login_log` (
386 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', 403 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
387 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤', 404 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
388 PRIMARY KEY (`id`) USING BTREE 405 PRIMARY KEY (`id`) USING BTREE
389 -) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COMMENT='系统访问记录'; 406 +) ENGINE=InnoDB AUTO_INCREMENT=84 DEFAULT CHARSET=utf8mb4 COMMENT='系统访问记录';
390 407
391 -- ---------------------------- 408 -- ----------------------------
392 -- Records of sys_login_log 409 -- Records of sys_login_log
@@ -415,7 +432,7 @@ CREATE TABLE `sys_menu` ( @@ -415,7 +432,7 @@ CREATE TABLE `sys_menu` (
415 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', 432 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
416 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤', 433 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
417 PRIMARY KEY (`id`) USING BTREE 434 PRIMARY KEY (`id`) USING BTREE
418 -) ENGINE=InnoDB AUTO_INCREMENT=1093 DEFAULT CHARSET=utf8mb4 COMMENT='èœå•æƒé™è¡¨'; 435 +) ENGINE=InnoDB AUTO_INCREMENT=1110 DEFAULT CHARSET=utf8mb4 COMMENT='èœå•æƒé™è¡¨';
419 436
420 -- ---------------------------- 437 -- ----------------------------
421 -- Records of sys_menu 438 -- Records of sys_menu
@@ -530,6 +547,22 @@ INSERT INTO `sys_menu` VALUES (1089, &#39;日志查询&#39;, &#39;infra:api-error-log:query&#39; @@ -530,6 +547,22 @@ INSERT INTO `sys_menu` VALUES (1089, &#39;日志查询&#39;, &#39;infra:api-error-log:query&#39;
530 INSERT INTO `sys_menu` VALUES (1090, '文件管ç†', '', 2, 0, 2, 'file', 'upload', 'infra/file/index', 0, '', '2021-03-12 20:16:20', '1', '2021-03-13 11:07:05', b'0'); 547 INSERT INTO `sys_menu` VALUES (1090, '文件管ç†', '', 2, 0, 2, 'file', 'upload', 'infra/file/index', 0, '', '2021-03-12 20:16:20', '1', '2021-03-13 11:07:05', b'0');
531 INSERT INTO `sys_menu` VALUES (1091, '文件查询', 'infra:file:query', 3, 1, 1090, '', '', '', 0, '', '2021-03-12 20:16:20', '', '2021-03-12 20:16:20', b'0'); 548 INSERT INTO `sys_menu` VALUES (1091, '文件查询', 'infra:file:query', 3, 1, 1090, '', '', '', 0, '', '2021-03-12 20:16:20', '', '2021-03-12 20:16:20', b'0');
532 INSERT INTO `sys_menu` VALUES (1092, '文件删除', 'infra:file:delete', 3, 4, 1090, '', '', '', 0, '', '2021-03-12 20:16:20', '', '2021-03-12 20:16:20', b'0'); 549 INSERT INTO `sys_menu` VALUES (1092, '文件删除', 'infra:file:delete', 3, 4, 1090, '', '', '', 0, '', '2021-03-12 20:16:20', '', '2021-03-12 20:16:20', b'0');
  550 +INSERT INTO `sys_menu` VALUES (1093, '短信管ç†', '', 1, 11, 1, 'sms', 'validCode', NULL, 0, '1', '2021-04-05 01:10:16', '1', '2021-04-05 01:11:38', b'0');
  551 +INSERT INTO `sys_menu` VALUES (1094, '短信渠é“', '', 2, 0, 1093, 'sms-channel', 'phone', 'system/sms/smsChannel', 0, '', '2021-04-01 11:07:15', '1', '2021-04-09 23:44:07', b'0');
  552 +INSERT INTO `sys_menu` VALUES (1095, 'çŸ­ä¿¡æ¸ é“æŸ¥è¯¢', 'system:sms-channel:query', 3, 1, 1094, '', '', '', 0, '', '2021-04-01 11:07:15', '', '2021-04-01 11:07:15', b'0');
  553 +INSERT INTO `sys_menu` VALUES (1096, '短信渠é“创建', 'system:sms-channel:create', 3, 2, 1094, '', '', '', 0, '', '2021-04-01 11:07:15', '', '2021-04-01 11:07:15', b'0');
  554 +INSERT INTO `sys_menu` VALUES (1097, 'çŸ­ä¿¡æ¸ é“æ›´æ–°', 'system:sms-channel:update', 3, 3, 1094, '', '', '', 0, '', '2021-04-01 11:07:15', '', '2021-04-01 11:07:15', b'0');
  555 +INSERT INTO `sys_menu` VALUES (1098, '短信渠é“删除', 'system:sms-channel:delete', 3, 4, 1094, '', '', '', 0, '', '2021-04-01 11:07:15', '', '2021-04-01 11:07:15', b'0');
  556 +INSERT INTO `sys_menu` VALUES (1100, '短信模æ¿', '', 2, 1, 1093, 'sms-template', 'phone', 'system/sms/smsTemplate', 0, '', '2021-04-01 17:35:17', '1', '2021-04-11 19:34:21', b'0');
  557 +INSERT INTO `sys_menu` VALUES (1101, 'çŸ­ä¿¡æ¨¡æ¿æŸ¥è¯¢', 'system:sms-template:query', 3, 1, 1100, '', '', '', 0, '', '2021-04-01 17:35:17', '', '2021-04-01 17:35:17', b'0');
  558 +INSERT INTO `sys_menu` VALUES (1102, '短信模æ¿åˆ›å»º', 'system:sms-template:create', 3, 2, 1100, '', '', '', 0, '', '2021-04-01 17:35:17', '', '2021-04-01 17:35:17', b'0');
  559 +INSERT INTO `sys_menu` VALUES (1103, 'çŸ­ä¿¡æ¨¡æ¿æ›´æ–°', 'system:sms-template:update', 3, 3, 1100, '', '', '', 0, '', '2021-04-01 17:35:17', '', '2021-04-01 17:35:17', b'0');
  560 +INSERT INTO `sys_menu` VALUES (1104, '短信模æ¿åˆ é™¤', 'system:sms-template:delete', 3, 4, 1100, '', '', '', 0, '', '2021-04-01 17:35:17', '', '2021-04-01 17:35:17', b'0');
  561 +INSERT INTO `sys_menu` VALUES (1105, '短信模æ¿å¯¼å‡º', 'system:sms-template:export', 3, 5, 1100, '', '', '', 0, '', '2021-04-01 17:35:17', '', '2021-04-01 17:35:17', b'0');
  562 +INSERT INTO `sys_menu` VALUES (1106, 'å‘逿µ‹è¯•短信', 'system:sms-template:send-sms', 3, 6, 1100, '', '', '', 0, '1', '2021-04-11 00:26:40', '1', '2021-04-11 00:26:40', b'0');
  563 +INSERT INTO `sys_menu` VALUES (1107, '短信日志', '', 2, 2, 1093, 'sms-log', 'phone', 'system/sms/smsLog', 0, '', '2021-04-11 08:37:05', '1', '2021-04-11 19:34:25', b'0');
  564 +INSERT INTO `sys_menu` VALUES (1108, '短信日志查询', 'system:sms-log:query', 3, 1, 1107, '', '', '', 0, '', '2021-04-11 08:37:05', '', '2021-04-11 08:37:05', b'0');
  565 +INSERT INTO `sys_menu` VALUES (1109, '短信日志导出', 'system:sms-log:export', 3, 5, 1107, '', '', '', 0, '', '2021-04-11 08:37:05', '', '2021-04-11 08:37:05', b'0');
533 COMMIT; 566 COMMIT;
534 567
535 -- ---------------------------- 568 -- ----------------------------
@@ -589,7 +622,7 @@ CREATE TABLE `sys_operate_log` ( @@ -589,7 +622,7 @@ CREATE TABLE `sys_operate_log` (
589 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', 622 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
590 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤', 623 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
591 PRIMARY KEY (`id`) USING BTREE 624 PRIMARY KEY (`id`) USING BTREE
592 -) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8mb4 COMMENT='æ“作日志记录'; 625 +) ENGINE=InnoDB AUTO_INCREMENT=177 DEFAULT CHARSET=utf8mb4 COMMENT='æ“作日志记录';
593 626
594 -- ---------------------------- 627 -- ----------------------------
595 -- Records of sys_operate_log 628 -- Records of sys_operate_log
@@ -835,6 +868,116 @@ INSERT INTO `sys_role_menu` VALUES (238, 101, 1065, &#39;&#39;, &#39;2021-01-21 03:23:27&#39;, &#39; @@ -835,6 +868,116 @@ INSERT INTO `sys_role_menu` VALUES (238, 101, 1065, &#39;&#39;, &#39;2021-01-21 03:23:27&#39;, &#39;
835 COMMIT; 868 COMMIT;
836 869
837 -- ---------------------------- 870 -- ----------------------------
  871 +-- Table structure for sys_sms_channel
  872 +-- ----------------------------
  873 +DROP TABLE IF EXISTS `sys_sms_channel`;
  874 +CREATE TABLE `sys_sms_channel` (
  875 + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ç¼–å·',
  876 + `signature` varchar(10) NOT NULL COMMENT '短信签å',
  877 + `code` varchar(63) NOT NULL COMMENT '渠é“ç¼–ç ',
  878 + `status` tinyint(4) NOT NULL COMMENT 'å¼€å¯çжæ€',
  879 + `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  880 + `api_key` varchar(128) NOT NULL COMMENT '短信 API 的账å·',
  881 + `api_secret` varchar(128) DEFAULT NULL COMMENT '短信 API 的秘钥',
  882 + `callback_url` varchar(255) DEFAULT NULL COMMENT '短信å‘é€å›žè°ƒ URL',
  883 + `creator` varchar(64) DEFAULT '' COMMENT '创建者',
  884 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  885 + `updater` varchar(64) DEFAULT '' COMMENT '更新者',
  886 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
  887 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
  888 + PRIMARY KEY (`id`) USING BTREE
  889 +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='短信渠é“';
  890 +
  891 +-- ----------------------------
  892 +-- Records of sys_sms_channel
  893 +-- ----------------------------
  894 +BEGIN;
  895 +INSERT INTO `sys_sms_channel` VALUES (1, '芋é“', 'YUN_PIAN', 0, '呵呵呵哒', '1555a14277cb8a608cf45a9e6a80d510', NULL, 'http://java.nat300.top/api/system/sms/callback/sms/yunpian', '', '2021-03-31 06:12:20', '1', '2021-04-13 01:03:19', b'0');
  896 +INSERT INTO `sys_sms_channel` VALUES (2, 'Ballcat', 'ALIYUN', 0, '啦啦啦', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, '', '2021-03-31 11:53:10', '1', '2021-04-14 00:08:37', b'0');
  897 +INSERT INTO `sys_sms_channel` VALUES (3, '测试', 'YUN_PIAN', 0, '哈哈哈', '23132', NULL, 'http://www.baidu.com', '1', '2021-04-05 21:10:34', '1', '2021-04-11 16:21:58', b'1');
  898 +INSERT INTO `sys_sms_channel` VALUES (4, '测试渠é“', 'DEBUG_DING_TALK', 0, '123', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2021-04-13 00:23:14', '1', '2021-04-14 00:07:10', b'0');
  899 +COMMIT;
  900 +
  901 +-- ----------------------------
  902 +-- Table structure for sys_sms_log
  903 +-- ----------------------------
  904 +DROP TABLE IF EXISTS `sys_sms_log`;
  905 +CREATE TABLE `sys_sms_log` (
  906 + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ç¼–å·',
  907 + `channel_id` bigint(20) NOT NULL COMMENT '短信渠é“ç¼–å·',
  908 + `channel_code` varchar(63) NOT NULL COMMENT '短信渠é“ç¼–ç ',
  909 + `template_id` bigint(20) NOT NULL COMMENT '模æ¿ç¼–å·',
  910 + `template_code` varchar(63) NOT NULL COMMENT '模æ¿ç¼–ç ',
  911 + `template_type` tinyint(4) NOT NULL COMMENT '短信类型',
  912 + `template_content` varchar(255) NOT NULL COMMENT '短信内容',
  913 + `template_params` varchar(255) NOT NULL COMMENT 'çŸ­ä¿¡å‚æ•°',
  914 + `api_template_id` varchar(63) NOT NULL COMMENT '短信 API 的模æ¿ç¼–å·',
  915 + `mobile` varchar(11) NOT NULL COMMENT '手机å·',
  916 + `user_id` bigint(20) DEFAULT NULL COMMENT '用户编å·',
  917 + `user_type` tinyint(4) DEFAULT NULL COMMENT '用户类型',
  918 + `send_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'å‘é€çжæ€',
  919 + `send_time` datetime DEFAULT NULL COMMENT 'å‘逿—¶é—´',
  920 + `send_code` int(11) DEFAULT NULL COMMENT 'å‘é€ç»“果的编ç ',
  921 + `send_msg` varchar(255) DEFAULT NULL COMMENT 'å‘é€ç»“果的æç¤º',
  922 + `api_send_code` varchar(63) DEFAULT NULL COMMENT '短信 API å‘é€ç»“果的编ç ',
  923 + `api_send_msg` varchar(255) DEFAULT NULL COMMENT '短信 API å‘é€å¤±è´¥çš„æç¤º',
  924 + `api_request_id` varchar(255) DEFAULT NULL COMMENT '短信 API å‘é€è¿”回的唯一请求 ID',
  925 + `api_serial_no` varchar(255) DEFAULT NULL COMMENT '短信 API å‘é€è¿”回的åºå·',
  926 + `receive_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '接收状æ€',
  927 + `receive_time` datetime DEFAULT NULL COMMENT '接收时间',
  928 + `api_receive_code` varchar(63) DEFAULT NULL COMMENT 'API 接收结果的编ç ',
  929 + `api_receive_msg` varchar(255) DEFAULT NULL COMMENT 'API 接收结果的说明',
  930 + `creator` varchar(64) DEFAULT '' COMMENT '创建者',
  931 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  932 + `updater` varchar(64) DEFAULT '' COMMENT '更新者',
  933 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
  934 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
  935 + PRIMARY KEY (`id`) USING BTREE
  936 +) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8mb4 COMMENT='短信日志';
  937 +
  938 +-- ----------------------------
  939 +-- Records of sys_sms_log
  940 +-- ----------------------------
  941 +BEGIN;
  942 +COMMIT;
  943 +
  944 +-- ----------------------------
  945 +-- Table structure for sys_sms_template
  946 +-- ----------------------------
  947 +DROP TABLE IF EXISTS `sys_sms_template`;
  948 +CREATE TABLE `sys_sms_template` (
  949 + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ç¼–å·',
  950 + `type` tinyint(4) NOT NULL COMMENT '短信签å',
  951 + `status` tinyint(4) NOT NULL COMMENT 'å¼€å¯çжæ€',
  952 + `code` varchar(63) NOT NULL COMMENT '模æ¿ç¼–ç ',
  953 + `name` varchar(63) NOT NULL COMMENT '模æ¿åç§°',
  954 + `content` varchar(255) NOT NULL COMMENT '模æ¿å†…容',
  955 + `params` varchar(255) NOT NULL COMMENT '傿•°æ•°ç»„',
  956 + `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  957 + `api_template_id` varchar(63) NOT NULL COMMENT '短信 API 的模æ¿ç¼–å·',
  958 + `channel_id` bigint(20) NOT NULL COMMENT '短信渠é“ç¼–å·',
  959 + `channel_code` varchar(63) NOT NULL COMMENT '短信渠é“ç¼–ç ',
  960 + `creator` varchar(64) DEFAULT '' COMMENT '创建者',
  961 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  962 + `updater` varchar(64) DEFAULT '' COMMENT '更新者',
  963 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
  964 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
  965 + PRIMARY KEY (`id`) USING BTREE
  966 +) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COMMENT='短信模æ¿';
  967 +
  968 +-- ----------------------------
  969 +-- Records of sys_sms_template
  970 +-- ----------------------------
  971 +BEGIN;
  972 +INSERT INTO `sys_sms_template` VALUES (2, 1, 0, 'test_01', '测试验è¯ç çŸ­ä¿¡', '正在进行登录æ“作{operation},您的验è¯ç æ˜¯{code}', '[\"operation\",\"code\"]', NULL, '4383920', 1, 'YUN_PIAN', '', '2021-03-31 10:49:38', '1', '2021-04-10 01:22:00', b'0');
  973 +INSERT INTO `sys_sms_template` 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');
  974 +INSERT INTO `sys_sms_template` VALUES (4, 3, 0, 'test-ooxx', '测试模æ¿', 'biubiubiu', '[]', '1111', '110', 1, 'YUN_PIAN', '1', '2021-04-09 23:58:42', '1', '2021-04-02 07:47:12', b'1');
  975 +INSERT INTO `sys_sms_template` VALUES (5, 3, 0, 'test-ooxx', '测试模æ¿', 'biubiubiu', '[]', '1111', '110', 1, 'YUN_PIAN', '1', '2021-04-09 23:58:42', '1', '2021-04-02 08:32:22', b'1');
  976 +INSERT INTO `sys_sms_template` VALUES (6, 3, 0, 'test-01', '测试模æ¿', '哈哈哈 {name}', '[\"name\"]', 'f哈哈哈', '4383920', 1, 'YUN_PIAN', '1', '2021-04-10 01:07:21', '1', '2021-04-10 01:22:05', b'0');
  977 +INSERT INTO `sys_sms_template` VALUES (7, 3, 0, 'test-04', '测试下', 'è€é¸¡{name},牛逼{code}', '[\"name\",\"code\"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2021-04-13 00:29:53', '1', '2021-04-14 00:30:38', b'0');
  978 +COMMIT;
  979 +
  980 +-- ----------------------------
838 -- Table structure for sys_user 981 -- Table structure for sys_user
839 -- ---------------------------- 982 -- ----------------------------
840 DROP TABLE IF EXISTS `sys_user`; 983 DROP TABLE IF EXISTS `sys_user`;
@@ -865,8 +1008,8 @@ CREATE TABLE `sys_user` ( @@ -865,8 +1008,8 @@ CREATE TABLE `sys_user` (
865 -- Records of sys_user 1008 -- Records of sys_user
866 -- ---------------------------- 1009 -- ----------------------------
867 BEGIN; 1010 BEGIN;
868 -INSERT INTO `sys_user` VALUES (1, 'admin', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '芋é“', '管ç†å‘˜', 103, '[1]', 'aoteman@126.com', '15612345678', 1, 'http://127.0.0.1:8080/api/system/file/get/add5ec1891a7d97d2cc1d60847e16294.jpg', 0, '127.0.0.1', '2021-01-05 17:03:47', 'admin', '2021-01-05 17:03:47', '1', '2021-03-21 18:16:16', b'0');  
869 -INSERT INTO `sys_user` VALUES (2, 'ry', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', 'è‹¥ä¾', '测试员', 105, '[2]', 'ry@qq.com', '15666666666', 1, '', 0, '127.0.0.1', '2021-01-05 17:03:47', 'admin', '2021-01-05 17:03:47', '', '2021-01-05 17:03:47', b'0'); 1011 +INSERT INTO `sys_user` VALUES (1, 'admin', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', 'èŠ‹é“æºç ', '管ç†å‘˜', 103, '[1]', 'aoteman@126.com', '15612345678', 1, 'http://api-dashboard.yudao.iocoder.cn/api/infra/file/get/5e8609290e915c4fa8b08e67.jpg', 0, '127.0.0.1', '2021-01-05 17:03:47', 'admin', '2021-01-05 17:03:47', '1', '2021-04-05 02:16:10', b'0');
  1012 +INSERT INTO `sys_user` VALUES (2, 'ry', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', 'è‹¥ä¾', '测试员', 105, '[2]', 'ry@qq.com', '15666666666', 1, '', 0, '127.0.0.1', '2021-01-05 17:03:47', 'admin', '2021-01-05 17:03:47', '', '2021-04-01 04:50:36', b'1');
870 INSERT INTO `sys_user` VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋é“', 'ä¸è¦å“我', 100, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '', NULL, '', '2021-01-07 09:07:17', '1', '2021-03-14 22:35:17', b'0'); 1013 INSERT INTO `sys_user` VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋é“', 'ä¸è¦å“我', 100, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '', NULL, '', '2021-01-07 09:07:17', '1', '2021-03-14 22:35:17', b'0');
871 INSERT INTO `sys_user` VALUES (103, 'yuanma', '', 'æºç ', NULL, 100, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '', NULL, '', '2021-01-13 23:50:35', '', '2021-01-13 23:50:35', b'0'); 1014 INSERT INTO `sys_user` VALUES (103, 'yuanma', '', 'æºç ', NULL, 100, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '', NULL, '', '2021-01-13 23:50:35', '', '2021-01-13 23:50:35', b'0');
872 INSERT INTO `sys_user` VALUES (104, 'test', '$2a$10$.TOFpaIiI3PzEwkGrNq0Eu6Cc3rOqJMxTb1DqeSEM8StxaGPBRKoi', '测试å·', NULL, 100, '[]', '', '15601691200', 1, '', 0, '', NULL, '', '2021-01-21 02:13:53', '1', '2021-03-14 22:36:38', b'0'); 1015 INSERT INTO `sys_user` VALUES (104, 'test', '$2a$10$.TOFpaIiI3PzEwkGrNq0Eu6Cc3rOqJMxTb1DqeSEM8StxaGPBRKoi', '测试å·', NULL, 100, '[]', '', '15601691200', 1, '', 0, '', NULL, '', '2021-01-21 02:13:53', '1', '2021-03-14 22:36:38', b'0');
@@ -924,13 +1067,40 @@ CREATE TABLE `sys_user_session` ( @@ -924,13 +1067,40 @@ CREATE TABLE `sys_user_session` (
924 -- Records of sys_user_session 1067 -- Records of sys_user_session
925 -- ---------------------------- 1068 -- ----------------------------
926 BEGIN; 1069 BEGIN;
  1070 +INSERT INTO `sys_user_session` VALUES ('04c6624c7bf14b1ba1a01cb976a9d876', 1, '2021-04-05 21:40:12', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-05 20:21:09', NULL, '2021-04-01 12:25:35', b'1');
  1071 +INSERT INTO `sys_user_session` VALUES ('0e235ce5ae7342a09b372a00bd7d1b41', 1, '2021-04-05 01:43:22', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-05 00:51:03', NULL, '2021-04-01 04:18:06', b'1');
  1072 +INSERT INTO `sys_user_session` VALUES ('0e6943f8ca9b4215a014843eb489ccc7', 1, '2021-04-05 22:53:22', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-05 21:43:59', NULL, '2021-04-01 17:25:41', b'1');
  1073 +INSERT INTO `sys_user_session` VALUES ('12166cd28b4f448ea468d13c471dfc6e', 1, '2021-04-09 19:48:58', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-09 19:18:58', NULL, '2021-04-02 04:33:15', b'1');
  1074 +INSERT INTO `sys_user_session` VALUES ('134d908ae33146bd9b5291471c04f604', 1, '2021-04-10 00:29:28', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-09 23:10:26', NULL, '2021-04-02 08:08:17', b'1');
  1075 +INSERT INTO `sys_user_session` VALUES ('1407ce21e47947b9b8d93bff1b55c7d6', 1, '2021-04-07 01:09:11', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-07 00:07:43', NULL, '2021-04-01 18:10:44', b'1');
  1076 +INSERT INTO `sys_user_session` VALUES ('1477c38290ff4cee8887ebfe593faa02', 1, '2021-04-17 23:34:57', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-17 23:04:57', NULL, '2021-04-12 21:36:29', b'1');
  1077 +INSERT INTO `sys_user_session` VALUES ('3c75ea73e13b4857a18eb57ca2eea80f', 1, '2021-04-11 20:06:52', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 19:36:52', NULL, '2021-04-11 09:10:53', b'1');
  1078 +INSERT INTO `sys_user_session` VALUES ('40d532d8900c43b791266429a7911751', 1, '2021-04-05 22:11:34', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-05 21:41:34', NULL, '2021-04-01 12:28:20', b'1');
  1079 +INSERT INTO `sys_user_session` VALUES ('43676e85d0e04980b2a67181f8d9933b', 1, '2021-04-11 10:41:09', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 09:56:31', NULL, '2021-04-02 17:32:07', b'1');
927 INSERT INTO `sys_user_session` VALUES ('505b4e7d8b0d4b40aa23bf540da81234', 1, '2021-03-14 01:25:13', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-14 00:31:43', NULL, '2021-03-13 07:35:26', b'1'); 1080 INSERT INTO `sys_user_session` VALUES ('505b4e7d8b0d4b40aa23bf540da81234', 1, '2021-03-14 01:25:13', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-14 00:31:43', NULL, '2021-03-13 07:35:26', b'1');
  1081 +INSERT INTO `sys_user_session` VALUES ('56a92b99f7b642ccbb7508042a25cb0c', 1, '2021-04-11 21:16:33', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 20:14:54', NULL, '2021-04-11 10:08:20', b'1');
928 INSERT INTO `sys_user_session` VALUES ('5a7248bf87d14e7e9f0578b05969986c', 1, '2021-03-13 10:42:50', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-13 09:37:36', NULL, '2021-03-12 19:53:07', b'1'); 1082 INSERT INTO `sys_user_session` VALUES ('5a7248bf87d14e7e9f0578b05969986c', 1, '2021-03-13 10:42:50', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-13 09:37:36', NULL, '2021-03-12 19:53:07', b'1');
  1083 +INSERT INTO `sys_user_session` VALUES ('5c30d80eb72048daa1a24d3d4f01317b', 1, '2021-04-12 00:31:10', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 23:08:14', NULL, '2021-04-11 15:47:45', b'1');
  1084 +INSERT INTO `sys_user_session` VALUES ('5dca80a5c61541479a4dbb6e004c2e28', 1, '2021-04-14 00:57:25', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-13 23:38:30', NULL, '2021-04-12 17:33:48', b'1');
  1085 +INSERT INTO `sys_user_session` VALUES ('7324a76b029a49ee95bf54ceb4164ba9', 1, '2021-04-13 01:29:14', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-13 00:18:40', NULL, '2021-04-11 23:15:00', b'1');
  1086 +INSERT INTO `sys_user_session` VALUES ('749619894bc441bb9773902515f81e6a', 1, '2021-04-11 00:39:51', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 00:09:51', NULL, '2021-04-02 16:50:56', b'1');
  1087 +INSERT INTO `sys_user_session` VALUES ('7768ae62ad974fd989f5159649a4be82', 1, '2021-04-11 00:53:39', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-10 23:23:27', NULL, '2021-04-02 17:04:58', b'1');
  1088 +INSERT INTO `sys_user_session` VALUES ('79efcb8f64aa42af9f4b327fb383532f', 1, '2021-04-11 22:44:07', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 21:34:53', NULL, '2021-04-11 14:10:45', b'1');
  1089 +INSERT INTO `sys_user_session` VALUES ('87d5b95fdad9447189a95abf8a5152df', 1, '2021-04-17 23:01:18', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-17 22:31:18', NULL, '2021-04-12 21:03:27', b'1');
  1090 +INSERT INTO `sys_user_session` VALUES ('8b3eac5e4a104a4191c8070e03d553ea', 1, '2021-04-05 02:45:12', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-05 02:15:12', NULL, '2021-04-01 11:05:25', b'1');
929 INSERT INTO `sys_user_session` VALUES ('9ae27346d8b7491aad1385f51e8aa196', 1, '2021-03-13 14:02:12', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-13 10:43:06', NULL, '2021-03-13 06:40:35', b'1'); 1091 INSERT INTO `sys_user_session` VALUES ('9ae27346d8b7491aad1385f51e8aa196', 1, '2021-03-13 14:02:12', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-13 10:43:06', NULL, '2021-03-13 06:40:35', b'1');
  1092 +INSERT INTO `sys_user_session` VALUES ('a2fb443b31c049008975ff8ee5499db1', 1, '2021-04-11 09:42:09', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 09:12:09', NULL, '2021-04-02 17:16:00', b'1');
  1093 +INSERT INTO `sys_user_session` VALUES ('a71a74adf9d141e2849d2a411d558205', 1, '2021-04-17 18:24:44', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-17 17:54:44', NULL, '2021-04-12 17:54:50', b'1');
930 INSERT INTO `sys_user_session` VALUES ('ae9ee7452ee54e4b983d658188c15c4d', 1, '2021-03-14 21:32:57', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-14 20:25:00', NULL, '2021-03-13 15:19:10', b'1'); 1094 INSERT INTO `sys_user_session` VALUES ('ae9ee7452ee54e4b983d658188c15c4d', 1, '2021-03-14 21:32:57', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-14 20:25:00', NULL, '2021-03-13 15:19:10', b'1');
931 -INSERT INTO `sys_user_session` VALUES ('d0adf48f82914212b947e5ab04d9fb65', 1, '2021-03-21 19:16:28', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-03-21 18:13:37', NULL, '2021-03-21 18:46:28', b'0'); 1095 +INSERT INTO `sys_user_session` VALUES ('b727853eccea4c8589e006ffea985146', 1, '2021-04-12 01:36:00', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-12 01:06:00', NULL, '2021-04-11 19:40:07', b'1');
  1096 +INSERT INTO `sys_user_session` VALUES ('c095616db95044c5bed66a3f84519b8b', 1, '2021-04-11 19:59:33', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 19:29:33', NULL, '2021-04-11 09:04:19', b'1');
  1097 +INSERT INTO `sys_user_session` VALUES ('d0adf48f82914212b947e5ab04d9fb65', 1, '2021-03-21 19:16:28', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-03-21 18:13:37', NULL, '2021-03-15 05:53:20', b'1');
  1098 +INSERT INTO `sys_user_session` VALUES ('dfbce0af867547f4bb01ac6f2e583337', 1, '2021-04-11 17:06:15', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 16:36:15', NULL, '2021-04-11 08:24:03', b'1');
  1099 +INSERT INTO `sys_user_session` VALUES ('e5ecf10e40a5463b8f9b5b453cb1649b', 1, '2021-04-11 17:06:22', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 16:36:22', NULL, '2021-04-11 08:24:03', b'1');
  1100 +INSERT INTO `sys_user_session` VALUES ('e80c2400724042a2ab73732166cde8fc', 1, '2021-03-21 21:17:12', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-03-21 20:47:12', NULL, '2021-03-15 08:18:56', b'1');
932 INSERT INTO `sys_user_session` VALUES ('e8872f5192584440a548641b83c877ef', 1, '2021-03-21 18:36:01', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-03-21 17:51:48', NULL, '2021-03-15 03:54:20', b'1'); 1101 INSERT INTO `sys_user_session` VALUES ('e8872f5192584440a548641b83c877ef', 1, '2021-03-21 18:36:01', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-03-21 17:51:48', NULL, '2021-03-15 03:54:20', b'1');
933 INSERT INTO `sys_user_session` VALUES ('f1ab99b09b5a475795579ff99d60ac78', 1, '2021-03-14 23:04:31', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-14 21:12:44', NULL, '2021-03-15 03:32:38', b'1'); 1102 INSERT INTO `sys_user_session` VALUES ('f1ab99b09b5a475795579ff99d60ac78', 1, '2021-03-14 23:04:31', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-14 21:12:44', NULL, '2021-03-15 03:32:38', b'1');
  1103 +INSERT INTO `sys_user_session` VALUES ('f2a4182f62ea4559b9946a523928fac4', 1, '2021-04-10 01:45:57', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-10 00:55:38', NULL, '2021-04-02 14:52:48', b'1');
934 INSERT INTO `sys_user_session` VALUES ('f853b50d064340a581e9a49bba9411fc', 1, '2021-03-10 01:55:41', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-10 01:11:53', NULL, '2021-03-12 18:37:05', b'1'); 1104 INSERT INTO `sys_user_session` VALUES ('f853b50d064340a581e9a49bba9411fc', 1, '2021-03-10 01:55:41', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-10 01:11:53', NULL, '2021-03-12 18:37:05', b'1');
935 COMMIT; 1105 COMMIT;
936 1106
@@ -964,7 +1134,7 @@ CREATE TABLE `tool_codegen_column` ( @@ -964,7 +1134,7 @@ CREATE TABLE `tool_codegen_column` (
964 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', 1134 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
965 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤', 1135 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
966 PRIMARY KEY (`id`) USING BTREE 1136 PRIMARY KEY (`id`) USING BTREE
967 -) ENGINE=InnoDB AUTO_INCREMENT=389 DEFAULT CHARSET=utf8mb4 COMMENT='代ç ç”Ÿæˆè¡¨å­—段定义'; 1137 +) ENGINE=InnoDB AUTO_INCREMENT=447 DEFAULT CHARSET=utf8mb4 COMMENT='代ç ç”Ÿæˆè¡¨å­—段定义';
968 1138
969 -- ---------------------------- 1139 -- ----------------------------
970 -- Records of tool_codegen_column 1140 -- Records of tool_codegen_column
@@ -1126,6 +1296,64 @@ INSERT INTO `tool_codegen_column` VALUES (385, 33, &#39;create_time&#39;, &#39;datetime&#39;, &#39;å @@ -1126,6 +1296,64 @@ INSERT INTO `tool_codegen_column` VALUES (385, 33, &#39;create_time&#39;, &#39;datetime&#39;, &#39;å
1126 INSERT INTO `tool_codegen_column` VALUES (386, 33, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 6, 'String', 'updater', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0'); 1296 INSERT INTO `tool_codegen_column` VALUES (386, 33, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 6, 'String', 'updater', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0');
1127 INSERT INTO `tool_codegen_column` VALUES (387, 33, 'update_time', 'datetime', 'æ›´æ–°æ—¶é—´', b'0', b'0', '0', 7, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0'); 1297 INSERT INTO `tool_codegen_column` VALUES (387, 33, 'update_time', 'datetime', 'æ›´æ–°æ—¶é—´', b'0', b'0', '0', 7, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0');
1128 INSERT INTO `tool_codegen_column` VALUES (388, 33, 'deleted', 'bit(1)', '是å¦åˆ é™¤', b'0', b'0', '0', 8, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0'); 1298 INSERT INTO `tool_codegen_column` VALUES (388, 33, 'deleted', 'bit(1)', '是å¦åˆ é™¤', b'0', b'0', '0', 8, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0');
  1299 +INSERT INTO `tool_codegen_column` VALUES (389, 34, 'id', 'bigint(20)', 'ç¼–å·', b'0', b'1', '1', 1, 'Long', 'id', '', '1024', b'0', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1300 +INSERT INTO `tool_codegen_column` VALUES (390, 34, 'signature', 'varchar(8)', '短信签å', b'0', b'0', '0', 2, 'String', 'signature', '', 'èŠ‹é“æºç ', b'1', b'1', b'1', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1301 +INSERT INTO `tool_codegen_column` VALUES (391, 34, 'code', 'varchar(63)', '渠é“ç¼–ç ', b'0', b'0', '0', 3, 'String', 'code', 'sys_sms_channel_code', 'YUN_PIAN', b'1', b'0', b'0', '=', b'1', 'select', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1302 +INSERT INTO `tool_codegen_column` VALUES (392, 34, 'status', 'tinyint(4)', 'å¯ç”¨çжæ€', b'0', b'0', '0', 4, 'Integer', 'status', 'sys_common_status', '1', b'1', b'1', b'1', '=', b'1', 'radio', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1303 +INSERT INTO `tool_codegen_column` VALUES (393, 34, 'remark', 'varchar(255)', '备注', b'1', b'0', '0', 5, 'String', 'remark', '', '好åƒï¼', b'1', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1304 +INSERT INTO `tool_codegen_column` VALUES (394, 34, 'api_key', 'varchar(63)', '短信 API 的账å·', b'0', b'0', '0', 6, 'String', 'apiKey', '', 'yudao', b'1', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1305 +INSERT INTO `tool_codegen_column` VALUES (395, 34, 'api_secret', 'varchar(63)', '短信 API 的秘钥', b'1', b'0', '0', 7, 'String', 'apiSecret', '', 'yuanma', b'1', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1306 +INSERT INTO `tool_codegen_column` VALUES (396, 34, 'callback_url', 'varchar(255)', '短信å‘é€å›žè°ƒ URL', b'1', b'0', '0', 8, 'String', 'callbackUrl', '', 'http://www.iocoder.cn', b'1', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1307 +INSERT INTO `tool_codegen_column` VALUES (397, 34, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 9, 'String', 'creator', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1308 +INSERT INTO `tool_codegen_column` VALUES (398, 34, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 10, 'Date', 'createTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1309 +INSERT INTO `tool_codegen_column` VALUES (399, 34, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 11, 'String', 'updater', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1310 +INSERT INTO `tool_codegen_column` VALUES (400, 34, 'update_time', 'datetime', 'æ›´æ–°æ—¶é—´', b'0', b'0', '0', 12, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1311 +INSERT INTO `tool_codegen_column` VALUES (401, 34, 'deleted', 'bit(1)', '是å¦åˆ é™¤', b'0', b'0', '0', 13, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1312 +INSERT INTO `tool_codegen_column` VALUES (402, 35, 'id', 'bigint(20)', 'ç¼–å·', b'0', b'1', '1', 1, 'Long', 'id', '', '1024', b'0', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1313 +INSERT INTO `tool_codegen_column` VALUES (403, 35, 'type', 'tinyint(4)', '短信签å', b'0', b'0', '0', 2, 'Integer', 'type', 'sys_sms_template_type', '1', b'1', b'1', b'1', '=', b'1', 'select', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1314 +INSERT INTO `tool_codegen_column` VALUES (404, 35, 'status', 'tinyint(4)', 'å¼€å¯çжæ€', b'0', b'0', '0', 3, 'Integer', 'status', 'sys_common_status', '1', b'1', b'1', b'1', '=', b'1', 'radio', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1315 +INSERT INTO `tool_codegen_column` VALUES (405, 35, 'code', 'varchar(63)', '模æ¿ç¼–ç ', b'0', b'0', '0', 4, 'String', 'code', '', 'test_01', b'1', b'1', b'1', 'LIKE', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1316 +INSERT INTO `tool_codegen_column` VALUES (406, 35, 'name', 'varchar(63)', '模æ¿åç§°', b'0', b'0', '0', 5, 'String', 'name', '', 'yudao', b'1', b'1', b'0', 'LIKE', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1317 +INSERT INTO `tool_codegen_column` VALUES (407, 35, 'content', 'varchar(255)', '模æ¿å†…容', b'0', b'0', '0', 6, 'String', 'content', '', '你好,{name}。你长的太{like}啦ï¼', b'1', b'1', b'1', 'LIKE', b'1', 'editor', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1318 +INSERT INTO `tool_codegen_column` VALUES (408, 35, 'params', 'varchar(255)', '傿•°æ•°ç»„', b'0', b'0', '0', 7, 'String', 'params', '', 'name,code', b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1319 +INSERT INTO `tool_codegen_column` VALUES (409, 35, 'remark', 'varchar(255)', '备注', b'1', b'0', '0', 8, 'String', 'remark', '', '哈哈哈', b'1', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1320 +INSERT INTO `tool_codegen_column` VALUES (410, 35, 'api_template_id', 'varchar(63)', '短信 API 的模æ¿ç¼–å·', b'0', b'0', '0', 9, 'String', 'apiTemplateId', '', '4383920', b'1', b'1', b'1', 'LIKE', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1321 +INSERT INTO `tool_codegen_column` VALUES (411, 35, 'channel_id', 'bigint(20)', '短信渠é“ç¼–å·', b'0', b'0', '0', 10, 'Long', 'channelId', '', '10', b'1', b'1', b'1', '=', b'1', 'select', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1322 +INSERT INTO `tool_codegen_column` VALUES (412, 35, 'channel_code', 'varchar(63)', '短信渠é“ç¼–ç ', b'0', b'0', '0', 11, 'String', 'channelCode', 'sys_sms_channel_code', 'ALIYUN', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1323 +INSERT INTO `tool_codegen_column` VALUES (413, 35, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 12, 'String', 'creator', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1324 +INSERT INTO `tool_codegen_column` VALUES (414, 35, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 13, 'Date', 'createTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1325 +INSERT INTO `tool_codegen_column` VALUES (415, 35, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 14, 'String', 'updater', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1326 +INSERT INTO `tool_codegen_column` VALUES (416, 35, 'update_time', 'datetime', 'æ›´æ–°æ—¶é—´', b'0', b'0', '0', 15, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1327 +INSERT INTO `tool_codegen_column` VALUES (417, 35, 'deleted', 'bit(1)', '是å¦åˆ é™¤', b'0', b'0', '0', 16, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1328 +INSERT INTO `tool_codegen_column` VALUES (418, 36, 'id', 'bigint(20)', 'ç¼–å·', b'0', b'1', '1', 1, 'Long', 'id', '', '1024', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1329 +INSERT INTO `tool_codegen_column` VALUES (419, 36, 'channel_id', 'bigint(20)', '短信渠é“ç¼–å·', b'0', b'0', '0', 2, 'Long', 'channelId', '', '10', b'0', b'0', b'1', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1330 +INSERT INTO `tool_codegen_column` VALUES (420, 36, 'channel_code', 'varchar(63)', '短信渠é“ç¼–ç ', b'0', b'0', '0', 3, 'String', 'channelCode', '', 'ALIYUN', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1331 +INSERT INTO `tool_codegen_column` VALUES (421, 36, 'template_id', 'bigint(20)', '模æ¿ç¼–å·', b'0', b'0', '0', 4, 'Long', 'templateId', '', '20', b'0', b'0', b'1', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1332 +INSERT INTO `tool_codegen_column` VALUES (422, 36, 'template_code', 'varchar(63)', '模æ¿ç¼–ç ', b'0', b'0', '0', 5, 'String', 'templateCode', '', 'test-01', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1333 +INSERT INTO `tool_codegen_column` VALUES (423, 36, 'template_type', 'tinyint(4)', '短信类型', b'0', b'0', '0', 6, 'Integer', 'templateType', 'sys_sms_template_type', '1', b'0', b'0', b'0', '=', b'1', 'select', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1334 +INSERT INTO `tool_codegen_column` VALUES (424, 36, 'template_content', 'varchar(255)', '短信内容', b'0', b'0', '0', 7, 'String', 'templateContent', '', '你好,你的验è¯ç æ˜¯ 1024', b'0', b'0', b'0', '=', b'1', 'editor', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1335 +INSERT INTO `tool_codegen_column` VALUES (425, 36, 'template_params', 'varchar(255)', 'çŸ­ä¿¡å‚æ•°', b'0', b'0', '0', 8, 'String', 'templateParams', '', 'name,code', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1336 +INSERT INTO `tool_codegen_column` VALUES (426, 36, 'api_template_id', 'varchar(63)', '短信 API 的模æ¿ç¼–å·', b'0', b'0', '0', 9, 'String', 'apiTemplateId', '', 'SMS_207945135', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1337 +INSERT INTO `tool_codegen_column` VALUES (427, 36, 'mobile', 'varchar(11)', '手机å·', b'0', b'0', '0', 10, 'String', 'mobile', '', '15601691300', b'0', b'0', b'1', 'LIKE', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1338 +INSERT INTO `tool_codegen_column` VALUES (428, 36, 'user_id', 'bigint(20)', '用户编å·', b'1', b'0', '0', 11, 'Long', 'userId', '', '10', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1339 +INSERT INTO `tool_codegen_column` VALUES (429, 36, 'user_type', 'tinyint(4)', '用户类型', b'1', b'0', '0', 12, 'Integer', 'userType', 'user_type', '1', b'0', b'0', b'0', '=', b'1', 'select', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1340 +INSERT INTO `tool_codegen_column` VALUES (430, 36, 'send_status', 'tinyint(4)', 'å‘é€çжæ€', b'0', b'0', '0', 13, 'Integer', 'sendStatus', 'sys_sms_send_status', '1', b'0', b'0', b'1', '=', b'1', 'radio', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1341 +INSERT INTO `tool_codegen_column` VALUES (431, 36, 'send_time', 'datetime', 'å‘逿—¶é—´', b'1', b'0', '0', 14, 'Date', 'sendTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1342 +INSERT INTO `tool_codegen_column` VALUES (432, 36, 'send_code', 'int(11)', 'å‘é€ç»“果的编ç ', b'1', b'0', '0', 15, 'Integer', 'sendCode', '', '0', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1343 +INSERT INTO `tool_codegen_column` VALUES (433, 36, 'send_msg', 'varchar(255)', 'å‘é€ç»“果的æç¤º', b'1', b'0', '0', 16, 'String', 'sendMsg', '', 'æˆåŠŸ', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1344 +INSERT INTO `tool_codegen_column` VALUES (434, 36, 'api_send_code', 'varchar(63)', '短信 API å‘é€ç»“果的编ç ', b'1', b'0', '0', 17, 'String', 'apiSendCode', '', 'SUCCESS', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1345 +INSERT INTO `tool_codegen_column` VALUES (435, 36, 'api_send_msg', 'varchar(255)', '短信 API å‘é€å¤±è´¥çš„æç¤º', b'1', b'0', '0', 18, 'String', 'apiSendMsg', '', 'æˆåŠŸ', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1346 +INSERT INTO `tool_codegen_column` VALUES (436, 36, 'api_request_id', 'varchar(255)', '短信 API å‘é€è¿”回的唯一请求 ID', b'1', b'0', '0', 19, 'String', 'apiRequestId', '', '3837C6D3-B96F-428C-BBB2-86135D4B5B99', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1347 +INSERT INTO `tool_codegen_column` VALUES (437, 36, 'api_serial_no', 'varchar(255)', '短信 API å‘é€è¿”回的åºå·', b'1', b'0', '0', 20, 'String', 'apiSerialNo', '', '62923244790', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1348 +INSERT INTO `tool_codegen_column` VALUES (438, 36, 'receive_status', 'tinyint(4)', '接收状æ€', b'0', b'0', '0', 21, 'Integer', 'receiveStatus', 'sys_sms_receive_status', '0', b'0', b'0', b'1', '=', b'1', 'radio', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1349 +INSERT INTO `tool_codegen_column` VALUES (439, 36, 'receive_time', 'datetime', '接收时间', b'1', b'0', '0', 22, 'Date', 'receiveTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1350 +INSERT INTO `tool_codegen_column` VALUES (440, 36, 'api_receive_code', 'varchar(63)', 'API 接收结果的编ç ', b'1', b'0', '0', 23, 'String', 'apiReceiveCode', '', 'DELIVRD', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1351 +INSERT INTO `tool_codegen_column` VALUES (441, 36, 'api_receive_msg', 'varchar(255)', 'API 接收结果的说明', b'1', b'0', '0', 24, 'String', 'apiReceiveMsg', '', 'DELIVRD', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1352 +INSERT INTO `tool_codegen_column` VALUES (442, 36, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 25, 'String', 'creator', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1353 +INSERT INTO `tool_codegen_column` VALUES (443, 36, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 26, 'Date', 'createTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'1', 'datetime', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1354 +INSERT INTO `tool_codegen_column` VALUES (444, 36, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 27, 'String', 'updater', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1355 +INSERT INTO `tool_codegen_column` VALUES (445, 36, 'update_time', 'datetime', 'æ›´æ–°æ—¶é—´', b'0', b'0', '0', 28, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1356 +INSERT INTO `tool_codegen_column` VALUES (446, 36, 'deleted', 'bit(1)', '是å¦åˆ é™¤', b'0', b'0', '0', 29, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
1129 COMMIT; 1357 COMMIT;
1130 1358
1131 -- ---------------------------- 1359 -- ----------------------------
@@ -1151,7 +1379,7 @@ CREATE TABLE `tool_codegen_table` ( @@ -1151,7 +1379,7 @@ CREATE TABLE `tool_codegen_table` (
1151 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', 1379 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
1152 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤', 1380 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
1153 PRIMARY KEY (`id`) USING BTREE 1381 PRIMARY KEY (`id`) USING BTREE
1154 -) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8mb4 COMMENT='代ç ç”Ÿæˆè¡¨å®šä¹‰'; 1382 +) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8mb4 COMMENT='代ç ç”Ÿæˆè¡¨å®šä¹‰';
1155 1383
1156 -- ---------------------------- 1384 -- ----------------------------
1157 -- Records of tool_codegen_table 1385 -- Records of tool_codegen_table
@@ -1169,6 +1397,9 @@ INSERT INTO `tool_codegen_table` VALUES (28, 1, &#39;sys_dict_type&#39;, &#39;å­—å…¸ç±»åž‹è¡ @@ -1169,6 +1397,9 @@ INSERT INTO `tool_codegen_table` VALUES (28, 1, &#39;sys_dict_type&#39;, &#39;字典类型è¡
1169 INSERT INTO `tool_codegen_table` VALUES (29, 1, 'sys_dict_type', '字典类型表', NULL, 'system', 'dict', 'SysDictType', '字典类型', '芋艿', 1, NULL, '', '2021-03-06 03:52:57', '', '2021-03-06 04:03:52', b'0'); 1397 INSERT INTO `tool_codegen_table` VALUES (29, 1, 'sys_dict_type', '字典类型表', NULL, 'system', 'dict', 'SysDictType', '字典类型', '芋艿', 1, NULL, '', '2021-03-06 03:52:57', '', '2021-03-06 04:03:52', b'0');
1170 INSERT INTO `tool_codegen_table` VALUES (30, 1, 'sys_dict_data', '字典数æ®è¡¨', NULL, 'system', 'type', 'SysDictData', '字典数æ®', 'èŠ‹é“æºç ', 1, NULL, '', '2021-03-06 06:48:28', '', '2021-03-06 06:50:47', b'0'); 1398 INSERT INTO `tool_codegen_table` VALUES (30, 1, 'sys_dict_data', '字典数æ®è¡¨', NULL, 'system', 'type', 'SysDictData', '字典数æ®', 'èŠ‹é“æºç ', 1, NULL, '', '2021-03-06 06:48:28', '', '2021-03-06 06:50:47', b'0');
1171 INSERT INTO `tool_codegen_table` VALUES (33, 1, 'inf_file', '文件表', NULL, 'infra', 'file', 'InfFile', '文件', '芋艿', 1, 2, '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0'); 1399 INSERT INTO `tool_codegen_table` VALUES (33, 1, 'inf_file', '文件表', NULL, 'infra', 'file', 'InfFile', '文件', '芋艿', 1, 2, '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0');
  1400 +INSERT INTO `tool_codegen_table` VALUES (34, 1, 'sys_sms_channel', '短信渠é“', NULL, 'system', 'sms', 'SysSmsChannel', '短信渠é“', 'èŠ‹é“æºç ', 1, 1093, '1', '2021-04-03 13:39:06', '1', '2021-04-05 20:52:09', b'0');
  1401 +INSERT INTO `tool_codegen_table` VALUES (35, 1, 'sys_sms_template', '短信模æ¿', NULL, 'system', 'sms', 'SysSmsTemplate', '短信模æ¿', 'èŠ‹é“æºç ', 1, 1093, '1', '2021-04-03 13:58:55', '1', '2021-04-05 22:23:38', b'0');
  1402 +INSERT INTO `tool_codegen_table` VALUES (36, 1, 'sys_sms_log', '短信日志', NULL, 'system', 'sms', 'SysSmsLog', '短信日志', 'èŠ‹é“æºç ', 1, 1093, '1', '2021-04-11 01:12:57', '1', '2021-04-11 20:33:54', b'0');
1172 COMMIT; 1403 COMMIT;
1173 1404
1174 -- ---------------------------- 1405 -- ----------------------------
src/main/java/cn/iocoder/dashboard/common/core/KeyValue.java 0 → 100644
  1 +package cn.iocoder.dashboard.common.core;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Data;
  5 +import lombok.NoArgsConstructor;
  6 +
  7 +/**
  8 + * Key Value 的键值对
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +@Data
  13 +@NoArgsConstructor
  14 +@AllArgsConstructor
  15 +public class KeyValue<K, V> {
  16 +
  17 + private K key;
  18 + private V value;
  19 +
  20 +}
src/main/java/cn/iocoder/dashboard/common/enums/DefaultBitFieldEnum.java 0 → 100644
  1 +package cn.iocoder.dashboard.common.enums;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 通用状态枚举
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@Getter
  12 +@AllArgsConstructor
  13 +public enum DefaultBitFieldEnum {
  14 +
  15 + NO(0, "否"),
  16 + YES(1, "是");
  17 +
  18 + /**
  19 + * 状态值
  20 + */
  21 + private final Integer val;
  22 + /**
  23 + * 状态名
  24 + */
  25 + private final String name;
  26 +
  27 +}
src/main/java/cn/iocoder/dashboard/common/exception/ErrorCode.java
1 package cn.iocoder.dashboard.common.exception; 1 package cn.iocoder.dashboard.common.exception;
2 2
  3 +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
3 import cn.iocoder.dashboard.common.exception.enums.ServiceErrorCodeRange; 4 import cn.iocoder.dashboard.common.exception.enums.ServiceErrorCodeRange;
4 import lombok.Data; 5 import lombok.Data;
5 6
6 /** 7 /**
7 * 错误码对象 8 * 错误码对象
8 * 9 *
9 - * 全局错误码,占用 [0, 999],参见 {@link GlobalException} 10 + * 全局错误码,占用 [0, 999], 参见 {@link GlobalErrorCodeConstants}
10 * 业务异常错误码,占用 [1 000 000 000, +∞),参见 {@link ServiceErrorCodeRange} 11 * 业务异常错误码,占用 [1 000 000 000, +∞),参见 {@link ServiceErrorCodeRange}
11 * 12 *
12 * TODO 错误码设计成对象的原因,为未来的 i18 国际化做准备 13 * TODO 错误码设计成对象的原因,为未来的 i18 国际化做准备
@@ -21,11 +22,11 @@ public class ErrorCode { @@ -21,11 +22,11 @@ public class ErrorCode {
21 /** 22 /**
22 * 错误提示 23 * 错误提示
23 */ 24 */
24 - private final String message; 25 + private final String msg;
25 26
26 public ErrorCode(Integer code, String message) { 27 public ErrorCode(Integer code, String message) {
27 this.code = code; 28 this.code = code;
28 - this.message = message; 29 + this.msg = message;
29 } 30 }
30 31
31 } 32 }
src/main/java/cn/iocoder/dashboard/common/exception/GlobalException.java deleted
1 -package cn.iocoder.dashboard.common.exception;  
2 -  
3 -import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;  
4 -import lombok.Data;  
5 -import lombok.EqualsAndHashCode;  
6 -  
7 -/**  
8 - * 全局异常 Exception  
9 - */  
10 -@Data  
11 -@EqualsAndHashCode(callSuper = true)  
12 -public class GlobalException extends RuntimeException {  
13 -  
14 - /**  
15 - * 全局错误码  
16 - *  
17 - * @see GlobalErrorCodeConstants  
18 - */  
19 - private Integer code;  
20 - /**  
21 - * 错误提示  
22 - */  
23 - private String message;  
24 -  
25 - /**  
26 - * 空构造方法,避免反序列化问题  
27 - */  
28 - public GlobalException() {  
29 - }  
30 -  
31 - public GlobalException(ErrorCode errorCode) {  
32 - this.code = errorCode.getCode();  
33 - this.message = errorCode.getMessage();  
34 - }  
35 -  
36 - public GlobalException(Integer code, String message) {  
37 - this.code = code;  
38 - this.message = message;  
39 - }  
40 -  
41 -}  
src/main/java/cn/iocoder/dashboard/common/exception/ServiceException.java
@@ -30,7 +30,7 @@ public final class ServiceException extends RuntimeException { @@ -30,7 +30,7 @@ public final class ServiceException extends RuntimeException {
30 30
31 public ServiceException(ErrorCode errorCode) { 31 public ServiceException(ErrorCode errorCode) {
32 this.code = errorCode.getCode(); 32 this.code = errorCode.getCode();
33 - this.message = errorCode.getMessage(); 33 + this.message = errorCode.getMsg();
34 } 34 }
35 35
36 public ServiceException(Integer code, String message) { 36 public ServiceException(Integer code, String message) {
src/main/java/cn/iocoder/dashboard/common/exception/enums/GlobalErrorCodeConstants.java
@@ -32,6 +32,7 @@ public interface GlobalErrorCodeConstants { @@ -32,6 +32,7 @@ public interface GlobalErrorCodeConstants {
32 32
33 // ========== 自定义错误段 ========== 33 // ========== 自定义错误段 ==========
34 ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求 34 ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求
  35 + ErrorCode DEMO_DENY = new ErrorCode(901, "演示模式,禁止写操作");
35 36
36 ErrorCode UNKNOWN = new ErrorCode(999, "未知错误"); 37 ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
37 38
src/main/java/cn/iocoder/dashboard/common/exception/util/ServiceExceptionUtil.java
@@ -47,12 +47,12 @@ public class ServiceExceptionUtil { @@ -47,12 +47,12 @@ public class ServiceExceptionUtil {
47 // ========== 和 ServiceException 的集成 ========== 47 // ========== 和 ServiceException 的集成 ==========
48 48
49 public static ServiceException exception(ErrorCode errorCode) { 49 public static ServiceException exception(ErrorCode errorCode) {
50 - String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMessage()); 50 + String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMsg());
51 return exception0(errorCode.getCode(), messagePattern); 51 return exception0(errorCode.getCode(), messagePattern);
52 } 52 }
53 53
54 public static ServiceException exception(ErrorCode errorCode, Object... params) { 54 public static ServiceException exception(ErrorCode errorCode, Object... params) {
55 - String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMessage()); 55 + String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMsg());
56 return exception0(errorCode.getCode(), messagePattern, params); 56 return exception0(errorCode.getCode(), messagePattern, params);
57 } 57 }
58 58
src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java
1 package cn.iocoder.dashboard.common.pojo; 1 package cn.iocoder.dashboard.common.pojo;
2 2
3 import cn.iocoder.dashboard.common.exception.ErrorCode; 3 import cn.iocoder.dashboard.common.exception.ErrorCode;
4 -import cn.iocoder.dashboard.common.exception.GlobalException;  
5 import cn.iocoder.dashboard.common.exception.ServiceException; 4 import cn.iocoder.dashboard.common.exception.ServiceException;
6 import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants; 5 import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
7 import com.fasterxml.jackson.annotation.JsonIgnore; 6 import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -9,6 +8,7 @@ import lombok.Data; @@ -9,6 +8,7 @@ import lombok.Data;
9 import org.springframework.util.Assert; 8 import org.springframework.util.Assert;
10 9
11 import java.io.Serializable; 10 import java.io.Serializable;
  11 +import java.util.Objects;
12 12
13 /** 13 /**
14 * 通用返回 14 * 通用返回
@@ -16,7 +16,7 @@ import java.io.Serializable; @@ -16,7 +16,7 @@ import java.io.Serializable;
16 * @param <T> 数据泛型 16 * @param <T> 数据泛型
17 */ 17 */
18 @Data 18 @Data
19 -public final class CommonResult<T> implements Serializable { 19 +public class CommonResult<T> implements Serializable {
20 20
21 /** 21 /**
22 * 错误码 22 * 错误码
@@ -31,7 +31,7 @@ public final class CommonResult&lt;T&gt; implements Serializable { @@ -31,7 +31,7 @@ public final class CommonResult&lt;T&gt; implements Serializable {
31 /** 31 /**
32 * 错误提示,用户可阅读 32 * 错误提示,用户可阅读
33 * 33 *
34 - * @see ErrorCode#getMessage() () 34 + * @see ErrorCode#getMsg() ()
35 */ 35 */
36 private String msg; 36 private String msg;
37 37
@@ -57,7 +57,7 @@ public final class CommonResult&lt;T&gt; implements Serializable { @@ -57,7 +57,7 @@ public final class CommonResult&lt;T&gt; implements Serializable {
57 } 57 }
58 58
59 public static <T> CommonResult<T> error(ErrorCode errorCode) { 59 public static <T> CommonResult<T> error(ErrorCode errorCode) {
60 - return error(errorCode.getCode(), errorCode.getMessage()); 60 + return error(errorCode.getCode(), errorCode.getMsg());
61 } 61 }
62 62
63 public static <T> CommonResult<T> success(T data) { 63 public static <T> CommonResult<T> success(T data) {
@@ -68,9 +68,13 @@ public final class CommonResult&lt;T&gt; implements Serializable { @@ -68,9 +68,13 @@ public final class CommonResult&lt;T&gt; implements Serializable {
68 return result; 68 return result;
69 } 69 }
70 70
  71 + public static boolean isSuccess(Integer code) {
  72 + return Objects.equals(code, GlobalErrorCodeConstants.SUCCESS.getCode());
  73 + }
  74 +
71 @JsonIgnore // 避免 jackson 序列化 75 @JsonIgnore // 避免 jackson 序列化
72 public boolean isSuccess() { 76 public boolean isSuccess() {
73 - return GlobalErrorCodeConstants.SUCCESS.getCode().equals(code); 77 + return isSuccess(code);
74 } 78 }
75 79
76 @JsonIgnore // 避免 jackson 序列化 80 @JsonIgnore // 避免 jackson 序列化
@@ -81,16 +85,12 @@ public final class CommonResult&lt;T&gt; implements Serializable { @@ -81,16 +85,12 @@ public final class CommonResult&lt;T&gt; implements Serializable {
81 // ========= 和 Exception 异常体系集成 ========= 85 // ========= 和 Exception 异常体系集成 =========
82 86
83 /** 87 /**
84 - * 判断是否有异常。如果有,则抛出 {@link GlobalException} 或 {@link ServiceException} 异常 88 + * 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常
85 */ 89 */
86 - public void checkError() throws GlobalException, ServiceException { 90 + public void checkError() throws ServiceException {
87 if (isSuccess()) { 91 if (isSuccess()) {
88 return; 92 return;
89 } 93 }
90 - // 全局异常  
91 - if (GlobalErrorCodeConstants.isMatch(code)) {  
92 - throw new GlobalException(code, msg);  
93 - }  
94 // 业务异常 94 // 业务异常
95 throw new ServiceException(code, msg); 95 throw new ServiceException(code, msg);
96 } 96 }
@@ -99,8 +99,4 @@ public final class CommonResult&lt;T&gt; implements Serializable { @@ -99,8 +99,4 @@ public final class CommonResult&lt;T&gt; implements Serializable {
99 return error(serviceException.getCode(), serviceException.getMessage()); 99 return error(serviceException.getCode(), serviceException.getMessage());
100 } 100 }
101 101
102 - public static <T> CommonResult<T> error(GlobalException globalException) {  
103 - return error(globalException.getCode(), globalException.getMessage());  
104 - }  
105 -  
106 } 102 }
src/main/java/cn/iocoder/dashboard/framework/excel/core/convert/DictConvert.java
@@ -13,6 +13,11 @@ import com.alibaba.excel.metadata.GlobalConfiguration; @@ -13,6 +13,11 @@ import com.alibaba.excel.metadata.GlobalConfiguration;
13 import com.alibaba.excel.metadata.property.ExcelContentProperty; 13 import com.alibaba.excel.metadata.property.ExcelContentProperty;
14 import lombok.extern.slf4j.Slf4j; 14 import lombok.extern.slf4j.Slf4j;
15 15
  16 +/**
  17 + * Excel {@link SysDictDataDO} 数据字典转换器
  18 + *
  19 + * @author 芋道源码
  20 + */
16 @Slf4j 21 @Slf4j
17 public class DictConvert implements Converter<Object> { 22 public class DictConvert implements Converter<Object> {
18 23
src/main/java/cn/iocoder/dashboard/framework/excel/core/convert/JsonConvert.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.excel.core.convert;
  2 +
  3 +import cn.iocoder.dashboard.util.json.JsonUtils;
  4 +import com.alibaba.excel.converters.Converter;
  5 +import com.alibaba.excel.enums.CellDataTypeEnum;
  6 +import com.alibaba.excel.metadata.CellData;
  7 +import com.alibaba.excel.metadata.GlobalConfiguration;
  8 +import com.alibaba.excel.metadata.property.ExcelContentProperty;
  9 +
  10 +/**
  11 + * Excel Json 转换器
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +public class JsonConvert implements Converter<Object> {
  16 +
  17 + @Override
  18 + public Class<?> supportJavaTypeKey() {
  19 + throw new UnsupportedOperationException("暂不支持,也不需要");
  20 + }
  21 +
  22 + @Override
  23 + public CellDataTypeEnum supportExcelTypeKey() {
  24 + throw new UnsupportedOperationException("暂不支持,也不需要");
  25 + }
  26 +
  27 + @Override
  28 + public Object convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
  29 + throw new UnsupportedOperationException("暂不支持,也不需要");
  30 + }
  31 +
  32 + @Override
  33 + public CellData<String> convertToExcelData(Object value, ExcelContentProperty contentProperty,
  34 + GlobalConfiguration globalConfiguration) {
  35 + // 生成 Excel 小表格
  36 + return new CellData<>(JsonUtils.toJsonString(value));
  37 + }
  38 +
  39 +}
src/main/java/cn/iocoder/dashboard/framework/redis/config/RedisConfig.java
@@ -48,8 +48,8 @@ public class RedisConfig { @@ -48,8 +48,8 @@ public class RedisConfig {
48 * 创建 Redis Pub/Sub 广播消费的容器 48 * 创建 Redis Pub/Sub 广播消费的容器
49 */ 49 */
50 @Bean 50 @Bean
51 - public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory factory,  
52 - List<AbstractChannelMessageListener<?>> listeners) { 51 + public RedisMessageListenerContainer redisMessageListenerContainer(
  52 + RedisConnectionFactory factory, List<AbstractChannelMessageListener<?>> listeners) {
53 // 创建 RedisMessageListenerContainer 对象 53 // 创建 RedisMessageListenerContainer 对象
54 RedisMessageListenerContainer container = new RedisMessageListenerContainer(); 54 RedisMessageListenerContainer container = new RedisMessageListenerContainer();
55 // 设置 RedisConnection 工厂。 55 // 设置 RedisConnection 工厂。
@@ -69,8 +69,8 @@ public class RedisConfig { @@ -69,8 +69,8 @@ public class RedisConfig {
69 * Redis Stream 的 xreadgroup 命令:https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html 69 * Redis Stream 的 xreadgroup 命令:https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html
70 */ 70 */
71 @Bean(initMethod = "start", destroyMethod = "stop") 71 @Bean(initMethod = "start", destroyMethod = "stop")
72 - public StreamMessageListenerContainer<String, ObjectRecord<String, String>> redisStreamMessageListenerContainer(RedisTemplate<String, Object> redisTemplate,  
73 - List<AbstractStreamMessageListener<?>> listeners) { 72 + public StreamMessageListenerContainer<String, ObjectRecord<String, String>> redisStreamMessageListenerContainer(
  73 + RedisTemplate<String, Object> redisTemplate, List<AbstractStreamMessageListener<?>> listeners) {
74 // 第一步,创建 StreamMessageListenerContainer 容器 74 // 第一步,创建 StreamMessageListenerContainer 容器
75 // 创建 options 配置 75 // 创建 options 配置
76 StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, ObjectRecord<String, String>> containerOptions = 76 StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, ObjectRecord<String, String>> containerOptions =
src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java
@@ -128,13 +128,13 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @@ -128,13 +128,13 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
128 // 设置每个请求的权限 128 // 设置每个请求的权限
129 .authorizeRequests() 129 .authorizeRequests()
130 // 登陆的接口,可匿名访问 130 // 登陆的接口,可匿名访问
131 - .antMatchers(webProperties.getApiPrefix() + "/login").anonymous() 131 + .antMatchers(api("/login")).anonymous()
132 // 通用的接口,可匿名访问 132 // 通用的接口,可匿名访问
133 - .antMatchers( webProperties.getApiPrefix() + "/system/captcha/**").anonymous() 133 + .antMatchers(api("/system/captcha/**")).anonymous()
134 // 静态资源,可匿名访问 134 // 静态资源,可匿名访问
135 .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll() 135 .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
136 // 文件的获取接口,可匿名访问 136 // 文件的获取接口,可匿名访问
137 - .antMatchers(webProperties.getApiPrefix() + "/infra/file/get/**").anonymous() 137 + .antMatchers(api("/infra/file/get/**")).anonymous()
138 // Swagger 接口文档 138 // Swagger 接口文档
139 .antMatchers("/swagger-ui.html").anonymous() 139 .antMatchers("/swagger-ui.html").anonymous()
140 .antMatchers("/swagger-resources/**").anonymous() 140 .antMatchers("/swagger-resources/**").anonymous()
@@ -148,13 +148,19 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @@ -148,13 +148,19 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
148 .antMatchers("/actuator/**").anonymous() 148 .antMatchers("/actuator/**").anonymous()
149 // Druid 监控 149 // Druid 监控
150 .antMatchers("/druid/**").anonymous() 150 .antMatchers("/druid/**").anonymous()
  151 + // 短信回调 API
  152 + .antMatchers(api("/system/sms/callback/**")).anonymous()
151 // 除上面外的所有请求全部需要鉴权认证 153 // 除上面外的所有请求全部需要鉴权认证
152 .anyRequest().authenticated() 154 .anyRequest().authenticated()
153 .and() 155 .and()
154 .headers().frameOptions().disable(); 156 .headers().frameOptions().disable();
155 - httpSecurity.logout().logoutUrl(webProperties.getApiPrefix() + "/logout").logoutSuccessHandler(logoutSuccessHandler); 157 + httpSecurity.logout().logoutUrl(api("/logout")).logoutSuccessHandler(logoutSuccessHandler);
156 // 添加 JWT Filter 158 // 添加 JWT Filter
157 httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); 159 httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
158 } 160 }
159 161
  162 + private String api(String url) {
  163 + return webProperties.getApiPrefix() + url;
  164 + }
  165 +
160 } 166 }
src/main/java/cn/iocoder/dashboard/framework/sms/config/SmsConfiguration.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.config;
  2 +
  3 +import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
  4 +import cn.iocoder.dashboard.framework.sms.core.client.impl.SmsClientFactoryImpl;
  5 +import org.springframework.context.annotation.Bean;
  6 +import org.springframework.context.annotation.Configuration;
  7 +
  8 +/**
  9 + * 短信配置类
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Configuration
  14 +public class SmsConfiguration {
  15 +
  16 + @Bean
  17 + public SmsClientFactory smsClientFactory() {
  18 + return new SmsClientFactoryImpl();
  19 + }
  20 +
  21 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client;
  2 +
  3 +import cn.iocoder.dashboard.common.core.KeyValue;
  4 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
  5 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
  6 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO;
  7 +
  8 +import java.util.List;
  9 +
  10 +/**
  11 + * 短信客户端接口
  12 + *
  13 + * @author zzf
  14 + * @date 2021/1/25 14:14
  15 + */
  16 +public interface SmsClient {
  17 +
  18 + /**
  19 + * 获得渠道编号
  20 + *
  21 + * @return 渠道编号
  22 + */
  23 + Long getId();
  24 +
  25 + /**
  26 + * 发送消息
  27 + *
  28 + * @param logId 日志编号
  29 + * @param mobile 手机号
  30 + * @param apiTemplateId 短信 API 的模板编号
  31 + * @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序
  32 + * @return 短信发送结果
  33 + */
  34 + SmsCommonResult<SmsSendRespDTO> sendSms(Long logId, String mobile, String apiTemplateId,
  35 + List<KeyValue<String, Object>> templateParams);
  36 +
  37 + /**
  38 + * 解析接收短信的接收结果
  39 + *
  40 + * @param text 结果
  41 + * @return 结果内容
  42 + * @throws Throwable 当解析 text 发生异常时,则会抛出异常
  43 + */
  44 + List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable;
  45 +
  46 + /**
  47 + * 查询指定的短信模板
  48 + *
  49 + * @param apiTemplateId 短信 API 的模板编号
  50 + * @return 短信模板
  51 + */
  52 + SmsCommonResult<SmsTemplateRespDTO> getSmsTemplate(String apiTemplateId);
  53 +
  54 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client;
  2 +
  3 +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
  4 +
  5 +/**
  6 + * 短信客户端工厂接口
  7 + *
  8 + * @author zzf
  9 + * @date 2021/1/28 14:01
  10 + */
  11 +public interface SmsClientFactory {
  12 +
  13 + /**
  14 + * 获得短信 Client
  15 + *
  16 + * @param channelId 渠道编号
  17 + * @return 短信 Client
  18 + */
  19 + SmsClient getSmsClient(Long channelId);
  20 +
  21 + /**
  22 + * 获得短信 Client
  23 + *
  24 + * @param channelCode 渠道编码
  25 + * @return 短信 Client
  26 + */
  27 + SmsClient getSmsClient(String channelCode);
  28 +
  29 + /**
  30 + * 创建短信 Client
  31 + *
  32 + * @param properties 配置对象
  33 + */
  34 + void createOrUpdateSmsClient(SmsChannelProperties properties);
  35 +
  36 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCodeMapping.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client;
  2 +
  3 +import cn.iocoder.dashboard.common.exception.ErrorCode;
  4 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
  5 +
  6 +import java.util.function.Function;
  7 +
  8 +/**
  9 + * 将 API 的错误码,转换为通用的错误码
  10 + *
  11 + * @see SmsCommonResult
  12 + * @see SmsFrameworkErrorCodeConstants
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +public interface SmsCodeMapping extends Function<String, ErrorCode> {
  17 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCommonResult.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client;
  2 +
  3 +import cn.hutool.core.exceptions.ExceptionUtil;
  4 +import cn.hutool.core.lang.Assert;
  5 +import cn.iocoder.dashboard.common.exception.ErrorCode;
  6 +import cn.iocoder.dashboard.common.pojo.CommonResult;
  7 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
  8 +import lombok.Data;
  9 +import lombok.EqualsAndHashCode;
  10 +import lombok.ToString;
  11 +
  12 +/**
  13 + * 短信的 CommonResult 拓展类
  14 + *
  15 + * 考虑到不同的平台,返回的 code 和 msg 是不同的,所以统一额外返回 {@link #apiCode} 和 {@link #apiMsg} 字段
  16 + *
  17 + * 另外,一些短信平台(例如说阿里云、腾讯云)会返回一个请求编号,用于排查请求失败的问题,我们设置到 {@link #apiRequestId} 字段
  18 + *
  19 + * @author 芋道源码
  20 + */
  21 +@Data
  22 +@EqualsAndHashCode(callSuper = true)
  23 +@ToString(callSuper = true)
  24 +public class SmsCommonResult<T> extends CommonResult<T> {
  25 +
  26 + /**
  27 + * API 返回错误码
  28 + *
  29 + * 由于第三方的错误码可能是字符串,所以使用 String 类型
  30 + */
  31 + private String apiCode;
  32 + /**
  33 + * API 返回提示
  34 + */
  35 + private String apiMsg;
  36 +
  37 + /**
  38 + * API 请求编号
  39 + */
  40 + private String apiRequestId;
  41 +
  42 + private SmsCommonResult() {
  43 + }
  44 +
  45 + public static <T> SmsCommonResult<T> build(String apiCode, String apiMsg, String apiRequestId,
  46 + T data, SmsCodeMapping codeMapping) {
  47 + Assert.notNull(codeMapping, "参数 codeMapping 不能为空");
  48 + SmsCommonResult<T> result = new SmsCommonResult<T>().setApiCode(apiCode).setApiMsg(apiMsg).setApiRequestId(apiRequestId);
  49 + result.setData(data);
  50 + // 翻译错误码
  51 + if (codeMapping != null) {
  52 + ErrorCode errorCode = codeMapping.apply(apiCode);
  53 + if (errorCode == null) {
  54 + errorCode = SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
  55 + }
  56 + result.setCode(errorCode.getCode()).setMsg(errorCode.getMsg());
  57 + }
  58 + return result;
  59 + }
  60 +
  61 + public static <T> SmsCommonResult<T> error(Throwable ex) {
  62 + SmsCommonResult<T> result = new SmsCommonResult<>();
  63 + result.setCode(SmsFrameworkErrorCodeConstants.EXCEPTION.getCode());
  64 + result.setMsg(ExceptionUtil.getRootCauseMessage(ex));
  65 + return result;
  66 + }
  67 +
  68 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.util.Date;
  6 +
  7 +/**
  8 + * 消息接收 Response DTO
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +@Data
  13 +public class SmsReceiveRespDTO {
  14 +
  15 + /**
  16 + * 是否接收成功
  17 + */
  18 + private Boolean success;
  19 + /**
  20 + * API 接收结果的编码
  21 + */
  22 + private String errorCode;
  23 + /**
  24 + * API 接收结果的说明
  25 + */
  26 + private String errorMsg;
  27 +
  28 + /**
  29 + * 手机号
  30 + */
  31 + private String mobile;
  32 + /**
  33 + * 用户接收时间
  34 + */
  35 + private Date receiveTime;
  36 +
  37 + /**
  38 + * 短信 API 发送返回的序号
  39 + */
  40 + private String serialNo;
  41 + /**
  42 + * 短信日志编号
  43 + *
  44 + * 对应 SysSmsLogDO 的编号
  45 + */
  46 + private Long logId;
  47 +
  48 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +/**
  6 + * 短信发送 Response DTO
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +@Data
  11 +public class SmsSendRespDTO {
  12 +
  13 + /**
  14 + * 短信 API 发送返回的序号
  15 + */
  16 + private String serialNo;
  17 +
  18 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsTemplateRespDTO.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.dto;
  2 +
  3 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
  4 +import lombok.Data;
  5 +
  6 +/**
  7 + * 短信模板 Response DTO
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@Data
  12 +public class SmsTemplateRespDTO {
  13 +
  14 + /**
  15 + * 模板编号
  16 + */
  17 + private String id;
  18 + /**
  19 + * 短信内容
  20 + */
  21 + private String content;
  22 + /**
  23 + * 审核状态
  24 + *
  25 + * 枚举 {@link SmsTemplateAuditStatusEnum}
  26 + */
  27 + private Integer auditStatus;
  28 + /**
  29 + * 审核未通过的理由
  30 + */
  31 + private String auditReason;
  32 +
  33 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl;
  2 +
  3 +import cn.iocoder.dashboard.common.core.KeyValue;
  4 +import cn.iocoder.dashboard.framework.sms.core.client.SmsClient;
  5 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping;
  6 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
  7 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
  8 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
  9 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO;
  10 +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
  11 +import lombok.extern.slf4j.Slf4j;
  12 +
  13 +import java.util.List;
  14 +
  15 +/**
  16 + * 短信客户端抽象类
  17 + *
  18 + * @author zzf
  19 + * @date 2021/2/1 9:28
  20 + */
  21 +@Slf4j
  22 +public abstract class AbstractSmsClient implements SmsClient {
  23 +
  24 + /**
  25 + * 短信渠道配置
  26 + */
  27 + protected volatile SmsChannelProperties properties;
  28 + /**
  29 + * 错误码枚举类
  30 + */
  31 + protected final SmsCodeMapping codeMapping;
  32 +
  33 + /**
  34 + * 短信客户端有参构造函数
  35 + *
  36 + * @param properties 短信配置
  37 + */
  38 + public AbstractSmsClient(SmsChannelProperties properties, SmsCodeMapping codeMapping) {
  39 + this.properties = properties;
  40 + this.codeMapping = codeMapping;
  41 + }
  42 +
  43 + /**
  44 + * 初始化
  45 + */
  46 + public final void init() {
  47 + doInit();
  48 + log.info("[init][配置({}) 初始化完成]", properties);
  49 + }
  50 +
  51 + public final void refresh(SmsChannelProperties properties) {
  52 + // 判断是否更新
  53 + if (properties.equals(this.properties)) {
  54 + return;
  55 + }
  56 + log.info("[refresh][配置({})发生变化,重新初始化]", properties);
  57 + this.properties = properties;
  58 + // 初始化
  59 + this.init();
  60 + }
  61 +
  62 + /**
  63 + * 自定义初始化
  64 + */
  65 + protected abstract void doInit();
  66 +
  67 + @Override
  68 + public Long getId() {
  69 + return properties.getId();
  70 + }
  71 +
  72 + @Override
  73 + public final SmsCommonResult<SmsSendRespDTO> sendSms(Long logId, String mobile,
  74 + String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
  75 + // 执行短信发送
  76 + SmsCommonResult<SmsSendRespDTO> result;
  77 + try {
  78 + result = doSendSms(logId, mobile, apiTemplateId, templateParams);
  79 + } catch (Throwable ex) {
  80 + // 打印异常日志
  81 + log.error("[sendSms][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]",
  82 + logId, mobile, apiTemplateId, templateParams, ex);
  83 + // 封装返回
  84 + return SmsCommonResult.error(ex);
  85 + }
  86 + return result;
  87 + }
  88 +
  89 + protected abstract SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
  90 + String apiTemplateId, List<KeyValue<String, Object>> templateParams)
  91 + throws Throwable;
  92 +
  93 + @Override
  94 + public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable {
  95 + try {
  96 + return doParseSmsReceiveStatus(text);
  97 + } catch (Throwable ex) {
  98 + log.error("[parseSmsReceiveStatus][text({}) 解析发生异常]", text, ex);
  99 + throw ex;
  100 + }
  101 + }
  102 +
  103 + protected abstract List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable;
  104 +
  105 + @Override
  106 + public SmsCommonResult<SmsTemplateRespDTO> getSmsTemplate(String apiTemplateId) {
  107 + // 执行短信发送
  108 + SmsCommonResult<SmsTemplateRespDTO> result;
  109 + try {
  110 + result = doGetSmsTemplate(apiTemplateId);
  111 + } catch (Throwable ex) {
  112 + // 打印异常日志
  113 + log.error("[getSmsTemplate][获得短信模板({}) 发生异常]", apiTemplateId, ex);
  114 + // 封装返回
  115 + return SmsCommonResult.error(ex);
  116 + }
  117 + return result;
  118 + }
  119 +
  120 + protected abstract SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) throws Throwable;
  121 +
  122 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl;
  2 +
  3 +import cn.iocoder.dashboard.framework.sms.core.client.SmsClient;
  4 +import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
  5 +import cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun.AliyunSmsClient;
  6 +import cn.iocoder.dashboard.framework.sms.core.client.impl.debug.DebugDingTalkSmsClient;
  7 +import cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian.YunpianSmsClient;
  8 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
  9 +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
  10 +import lombok.extern.slf4j.Slf4j;
  11 +import org.springframework.util.Assert;
  12 +import org.springframework.validation.annotation.Validated;
  13 +
  14 +import java.util.Arrays;
  15 +import java.util.concurrent.ConcurrentHashMap;
  16 +import java.util.concurrent.ConcurrentMap;
  17 +
  18 +/**
  19 + * 短信客户端工厂接口
  20 + *
  21 + * @author zzf
  22 + */
  23 +@Validated
  24 +@Slf4j
  25 +public class SmsClientFactoryImpl implements SmsClientFactory {
  26 +
  27 + /**
  28 + * 短信客户端 Map
  29 + * key:渠道编号,使用 {@link SmsChannelProperties#getId()}
  30 + */
  31 + private final ConcurrentMap<Long, AbstractSmsClient> channelIdClients = new ConcurrentHashMap<>();
  32 +
  33 + /**
  34 + * 短信客户端 Map
  35 + * key:渠道编码,使用 {@link SmsChannelProperties#getCode()} ()}
  36 + *
  37 + * 注意,一些场景下,需要获得某个渠道类型的客户端,所以需要使用它。
  38 + * 例如说,解析短信接收结果,是相对通用的,不需要使用某个渠道编号的 {@link #channelIdClients}
  39 + */
  40 + private final ConcurrentMap<String, AbstractSmsClient> channelCodeClients = new ConcurrentHashMap<>();
  41 +
  42 + public SmsClientFactoryImpl() {
  43 + // 初始化 channelCodeClients 集合
  44 + Arrays.stream(SmsChannelEnum.values()).forEach(channel -> {
  45 + // 创建一个空的 SmsChannelProperties 对象
  46 + SmsChannelProperties properties = new SmsChannelProperties().setCode(channel.getCode())
  47 + .setApiKey("default").setApiSecret("default");
  48 + // 创建 Sms 客户端
  49 + AbstractSmsClient smsClient = createSmsClient(properties);
  50 + channelCodeClients.put(channel.getCode(), smsClient);
  51 + });
  52 + }
  53 +
  54 + @Override
  55 + public SmsClient getSmsClient(Long channelId) {
  56 + return channelIdClients.get(channelId);
  57 + }
  58 +
  59 + @Override
  60 + public SmsClient getSmsClient(String channelCode) {
  61 + return channelCodeClients.get(channelCode);
  62 + }
  63 +
  64 + @Override
  65 + public void createOrUpdateSmsClient(SmsChannelProperties properties) {
  66 + AbstractSmsClient client = channelIdClients.get(properties.getId());
  67 + if (client == null) {
  68 + client = this.createSmsClient(properties);
  69 + client.init();
  70 + channelIdClients.put(client.getId(), client);
  71 + } else {
  72 + client.refresh(properties);
  73 + }
  74 + }
  75 +
  76 + private AbstractSmsClient createSmsClient(SmsChannelProperties properties) {
  77 + SmsChannelEnum channelEnum = SmsChannelEnum.getByCode(properties.getCode());
  78 + Assert.notNull(channelEnum, String.format("渠道类型(%s) 为空", channelEnum));
  79 + // 创建客户端
  80 + switch (channelEnum) {
  81 + case ALIYUN: return new AliyunSmsClient(properties);
  82 + case YUN_PIAN: return new YunpianSmsClient(properties);
  83 + case DEBUG_DING_TALK: return new DebugDingTalkSmsClient(properties);
  84 + }
  85 + // 创建失败,错误日志 + 抛出异常
  86 + log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties);
  87 + throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", properties));
  88 + }
  89 +
  90 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun;
  2 +
  3 +import cn.hutool.core.lang.Assert;
  4 +import cn.hutool.core.util.ReflectUtil;
  5 +import cn.hutool.core.util.StrUtil;
  6 +import cn.iocoder.dashboard.common.core.KeyValue;
  7 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
  8 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
  9 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
  10 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO;
  11 +import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient;
  12 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
  13 +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
  14 +import cn.iocoder.dashboard.util.collection.MapUtils;
  15 +import cn.iocoder.dashboard.util.json.JsonUtils;
  16 +import com.aliyuncs.AcsRequest;
  17 +import com.aliyuncs.AcsResponse;
  18 +import com.aliyuncs.DefaultAcsClient;
  19 +import com.aliyuncs.IAcsClient;
  20 +import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest;
  21 +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
  22 +import com.aliyuncs.exceptions.ClientException;
  23 +import com.aliyuncs.profile.DefaultProfile;
  24 +import com.aliyuncs.profile.IClientProfile;
  25 +import com.fasterxml.jackson.annotation.JsonFormat;
  26 +import com.fasterxml.jackson.annotation.JsonProperty;
  27 +import com.google.common.annotations.VisibleForTesting;
  28 +import lombok.Data;
  29 +import lombok.extern.slf4j.Slf4j;
  30 +
  31 +import java.util.Date;
  32 +import java.util.List;
  33 +import java.util.Objects;
  34 +import java.util.function.Function;
  35 +import java.util.stream.Collectors;
  36 +
  37 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  38 +import static cn.iocoder.dashboard.util.date.DateUtils.TIME_ZONE_DEFAULT;
  39 +
  40 +/**
  41 + * 阿里短信客户端的实现类
  42 + *
  43 + * @author zzf
  44 + * @date 2021/1/25 14:17
  45 + */
  46 +@Slf4j
  47 +public class AliyunSmsClient extends AbstractSmsClient {
  48 +
  49 + /**
  50 + * REGION, 使用杭州
  51 + */
  52 + private static final String ENDPOINT = "cn-hangzhou";
  53 +
  54 + /**
  55 + * 阿里云客户端
  56 + */
  57 + private volatile IAcsClient client;
  58 +
  59 + public AliyunSmsClient(SmsChannelProperties properties) {
  60 + super(properties, new AliyunSmsCodeMapping());
  61 + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
  62 + Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
  63 + }
  64 +
  65 + @Override
  66 + protected void doInit() {
  67 + IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, properties.getApiKey(), properties.getApiSecret());
  68 + client = new DefaultAcsClient(profile);
  69 + }
  70 +
  71 + @Override
  72 + protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
  73 + String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
  74 + // 构建参数
  75 + SendSmsRequest request = new SendSmsRequest();
  76 + request.setPhoneNumbers(mobile);
  77 + request.setSignName(properties.getSignature());
  78 + request.setTemplateCode(apiTemplateId);
  79 + request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams)));
  80 + request.setOutId(String.valueOf(sendLogId));
  81 + // 执行请求
  82 + return invoke(request, response -> new SmsSendRespDTO().setSerialNo(response.getBizId()));
  83 + }
  84 +
  85 + @Override
  86 + protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
  87 + List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class);
  88 + return statuses.stream().map(status -> {
  89 + SmsReceiveRespDTO resp = new SmsReceiveRespDTO();
  90 + resp.setSuccess(status.getSuccess());
  91 + resp.setErrorCode(status.getErrCode()).setErrorMsg(status.getErrMsg());
  92 + resp.setMobile(status.getPhoneNumber()).setReceiveTime(status.getReportTime());
  93 + resp.setSerialNo(status.getBizId()).setLogId(Long.valueOf(status.getOutId()));
  94 + return resp;
  95 + }).collect(Collectors.toList());
  96 + }
  97 +
  98 + @Override
  99 + protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) {
  100 + // 构建参数
  101 + QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();
  102 + request.setTemplateCode(apiTemplateId);
  103 + // 执行请求
  104 + return invoke(request, response -> {
  105 + SmsTemplateRespDTO data = new SmsTemplateRespDTO();
  106 + data.setId(response.getTemplateCode()).setContent(response.getTemplateContent());
  107 + data.setAuditStatus(convertSmsTemplateAuditStatus(response.getTemplateStatus())).setAuditReason(response.getReason());
  108 + return data;
  109 + });
  110 + }
  111 +
  112 + @VisibleForTesting
  113 + Integer convertSmsTemplateAuditStatus(Integer templateStatus) {
  114 + switch (templateStatus) {
  115 + case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
  116 + case 1: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
  117 + case 2: return SmsTemplateAuditStatusEnum.FAIL.getStatus();
  118 + default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus));
  119 + }
  120 + }
  121 +
  122 + @VisibleForTesting
  123 + <T extends AcsResponse, R> SmsCommonResult<R> invoke(AcsRequest<T> request, Function<T, R> responseConsumer) {
  124 + try {
  125 + // 执行发送. 由于阿里云 sms 短信没有统一的 Response,但是有统一的 code、message、requestId 属性,所以只好反射
  126 + T sendResult = client.getAcsResponse(request);
  127 + String code = (String) ReflectUtil.getFieldValue(sendResult, "code");
  128 + String message = (String) ReflectUtil.getFieldValue(sendResult, "message");
  129 + String requestId = (String) ReflectUtil.getFieldValue(sendResult, "requestId");
  130 + // 解析结果
  131 + R data = null;
  132 + if (Objects.equals(code, "OK")) { // 请求成功的情况下
  133 + data = responseConsumer.apply(sendResult);
  134 + }
  135 + // 拼接结果
  136 + return SmsCommonResult.build(code, message, requestId, data, codeMapping);
  137 + } catch (ClientException ex) {
  138 + return SmsCommonResult.build(ex.getErrCode(), formatResultMsg(ex), ex.getRequestId(), null, codeMapping);
  139 + }
  140 + }
  141 +
  142 + private static String formatResultMsg(ClientException ex) {
  143 + if (StrUtil.isEmpty(ex.getErrorDescription())) {
  144 + return ex.getErrMsg();
  145 + }
  146 + return ex.getErrMsg() + " => " + ex.getErrorDescription();
  147 + }
  148 +
  149 + /**
  150 + * 短信接收状态
  151 + *
  152 + * 参见 https://help.aliyun.com/document_detail/101867.html 文档
  153 + *
  154 + * @author 芋道源码
  155 + */
  156 + @Data
  157 + public static class SmsReceiveStatus {
  158 +
  159 + /**
  160 + * 手机号
  161 + */
  162 + @JsonProperty("phone_number")
  163 + private String phoneNumber;
  164 + /**
  165 + * 发送时间
  166 + */
  167 + @JsonProperty("send_time")
  168 + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
  169 + private Date sendTime;
  170 + /**
  171 + * 状态报告时间
  172 + */
  173 + @JsonProperty("report_time")
  174 + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
  175 + private Date reportTime;
  176 + /**
  177 + * 是否接收成功
  178 + */
  179 + private Boolean success;
  180 + /**
  181 + * 状态报告说明
  182 + */
  183 + @JsonProperty("err_msg")
  184 + private String errMsg;
  185 + /**
  186 + * 状态报告编码
  187 + */
  188 + @JsonProperty("err_code")
  189 + private String errCode;
  190 + /**
  191 + * 发送序列号
  192 + */
  193 + @JsonProperty("biz_id")
  194 + private String bizId;
  195 + /**
  196 + * 用户序列号
  197 + *
  198 + * 这里我们传递的是 SysSmsLogDO 的日志编号
  199 + */
  200 + @JsonProperty("out_id")
  201 + private String outId;
  202 + /**
  203 + * 短信长度,例如说 1、2、3
  204 + *
  205 + * 140 字节算一条短信,短信长度超过 140 字节时会拆分成多条短信发送
  206 + */
  207 + @JsonProperty("sms_size")
  208 + private Integer smsSize;
  209 +
  210 + }
  211 +
  212 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun;
  2 +
  3 +import cn.iocoder.dashboard.common.exception.ErrorCode;
  4 +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
  5 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping;
  6 +
  7 +import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.*;
  8 +
  9 +/**
  10 + * 阿里云的 SmsCodeMapping 实现类
  11 + *
  12 + * 参见 https://help.aliyun.com/document_detail/101346.htm 文档
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +public class AliyunSmsCodeMapping implements SmsCodeMapping {
  17 +
  18 + @Override
  19 + public ErrorCode apply(String apiCode) {
  20 + switch (apiCode) {
  21 + case "OK": return GlobalErrorCodeConstants.SUCCESS;
  22 + case "isv.ACCOUNT_NOT_EXISTS":
  23 + case "isv.ACCOUNT_ABNORMAL":
  24 + case "MissingAccessKeyId": return SMS_ACCOUNT_INVALID;
  25 + case "isp.RAM_PERMISSION_DENY": return SMS_PERMISSION_DENY;
  26 + case "isv.INVALID_JSON_PARAM":
  27 + case "isv.INVALID_PARAMETERS": return SMS_API_PARAM_ERROR;
  28 + case "isv.BUSINESS_LIMIT_CONTROL": return SMS_SEND_BUSINESS_LIMIT_CONTROL;
  29 + case "isv.DAY_LIMIT_CONTROL": return SMS_SEND_DAY_LIMIT_CONTROL;
  30 + case "isv.SMS_CONTENT_ILLEGAL": return SMS_SEND_CONTENT_INVALID;
  31 + case "isv.SMS_TEMPLATE_ILLEGAL": return SMS_TEMPLATE_INVALID;
  32 + case "isv.SMS_SIGNATURE_ILLEGAL":
  33 + case "isv.SIGN_NAME_ILLEGAL":
  34 + case "isv.SMS_SIGN_ILLEGAL": return SMS_SIGN_INVALID;
  35 + case "isv.AMOUNT_NOT_ENOUGH":
  36 + case "isv.OUT_OF_SERVICE": return SMS_ACCOUNT_MONEY_NOT_ENOUGH;
  37 + case "isv.MOBILE_NUMBER_ILLEGAL": return SMS_MOBILE_INVALID;
  38 + case "isv.TEMPLATE_MISSING_PARAMETERS": return SMS_TEMPLATE_PARAM_ERROR;
  39 + }
  40 + return SMS_UNKNOWN;
  41 + }
  42 +
  43 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/debug/DebugDingTalkCodeMapping.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl.debug;
  2 +
  3 +import cn.iocoder.dashboard.common.exception.ErrorCode;
  4 +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
  5 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping;
  6 +
  7 +import java.util.Objects;
  8 +
  9 +import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
  10 +
  11 +/**
  12 + * 钉钉的 SmsCodeMapping 实现类
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +public class DebugDingTalkCodeMapping implements SmsCodeMapping {
  17 +
  18 + @Override
  19 + public ErrorCode apply(String apiCode) {
  20 + return Objects.equals(apiCode, "0") ? GlobalErrorCodeConstants.SUCCESS : SMS_UNKNOWN;
  21 + }
  22 +
  23 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/debug/DebugDingTalkSmsClient.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl.debug;
  2 +
  3 +import cn.hutool.core.codec.Base64;
  4 +import cn.hutool.core.lang.Assert;
  5 +import cn.hutool.core.map.MapUtil;
  6 +import cn.hutool.core.util.StrUtil;
  7 +import cn.hutool.crypto.digest.DigestUtil;
  8 +import cn.hutool.crypto.digest.HmacAlgorithm;
  9 +import cn.hutool.http.HttpUtil;
  10 +import cn.iocoder.dashboard.common.core.KeyValue;
  11 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
  12 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
  13 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
  14 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO;
  15 +import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient;
  16 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
  17 +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
  18 +import cn.iocoder.dashboard.util.collection.MapUtils;
  19 +import cn.iocoder.dashboard.util.json.JsonUtils;
  20 +
  21 +import java.util.HashMap;
  22 +import java.util.List;
  23 +import java.util.Map;
  24 +
  25 +/**
  26 + * 基于钉钉 WebHook 实现的调试的短信客户端实现类
  27 + *
  28 + * 考虑到省钱,我们使用钉钉 WebHook 模拟发送短信,方便调试。
  29 + *
  30 + * @author 芋道源码
  31 + */
  32 +public class DebugDingTalkSmsClient extends AbstractSmsClient {
  33 +
  34 + public DebugDingTalkSmsClient(SmsChannelProperties properties) {
  35 + super(properties, new DebugDingTalkCodeMapping());
  36 + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
  37 + Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
  38 + }
  39 +
  40 + @Override
  41 + protected void doInit() {
  42 + }
  43 +
  44 + @Override
  45 + protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
  46 + String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
  47 + // 构建请求
  48 + String url = buildUrl("robot/send");
  49 + Map<String, Object> params = new HashMap<>();
  50 + params.put("msgtype", "text");
  51 + String content = String.format("【模拟短信】\n手机号:%s\n短信日志编号:%d\n模板参数:%s",
  52 + mobile, sendLogId, MapUtils.convertMap(templateParams));
  53 + params.put("text", MapUtil.builder().put("content", content).build());
  54 + // 执行请求
  55 + String responseText = HttpUtil.post(url, JsonUtils.toJsonString(params));
  56 + // 解析结果
  57 + Map<?, ?> responseObj = JsonUtils.parseObject(responseText, Map.class);
  58 + return SmsCommonResult.build(MapUtil.getStr(responseObj, "errcode"), MapUtil.getStr(responseObj, "errorMsg"),
  59 + null, new SmsSendRespDTO().setSerialNo(StrUtil.uuid()), codeMapping);
  60 + }
  61 +
  62 + /**
  63 + * 构建请求地址
  64 + *
  65 + * 参见 https://developers.dingtalk.com/document/app/custom-robot-access/title-nfv-794-g71 文档
  66 + *
  67 + * @param path 请求路径
  68 + * @return 请求地址
  69 + */
  70 + @SuppressWarnings("SameParameterValue")
  71 + private String buildUrl(String path) {
  72 + // 生成 timestamp
  73 + long timestamp = System.currentTimeMillis();
  74 + // 生成 sign
  75 + String secret = properties.getApiSecret();
  76 + String stringToSign = timestamp + "\n" + secret;
  77 + byte[] signData = DigestUtil.hmac(HmacAlgorithm.HmacSHA256, StrUtil.bytes(secret)).digest(stringToSign);
  78 + String sign = Base64.encode(signData);
  79 + // 构建最终 URL
  80 + return String.format("https://oapi.dingtalk.com/%s?access_token=%s&timestamp=%d&sign=%s",
  81 + path, properties.getApiKey(), timestamp, sign);
  82 + }
  83 +
  84 + @Override
  85 + protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
  86 + throw new UnsupportedOperationException("模拟短信客户端,暂时无需解析回调");
  87 + }
  88 +
  89 + @Override
  90 + protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) {
  91 + SmsTemplateRespDTO data = new SmsTemplateRespDTO().setId(apiTemplateId).setContent("")
  92 + .setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason("");
  93 + return SmsCommonResult.build("0", "success", null, data, codeMapping);
  94 + }
  95 +
  96 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.lang.Assert;
  5 +import cn.hutool.core.util.StrUtil;
  6 +import cn.hutool.core.util.URLUtil;
  7 +import cn.iocoder.dashboard.common.core.KeyValue;
  8 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
  9 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
  10 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
  11 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO;
  12 +import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient;
  13 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
  14 +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
  15 +import cn.iocoder.dashboard.util.json.JsonUtils;
  16 +import com.fasterxml.jackson.annotation.JsonFormat;
  17 +import com.fasterxml.jackson.annotation.JsonProperty;
  18 +import com.google.common.annotations.VisibleForTesting;
  19 +import com.yunpian.sdk.YunpianClient;
  20 +import com.yunpian.sdk.constant.YunpianConstant;
  21 +import com.yunpian.sdk.model.Result;
  22 +import com.yunpian.sdk.model.Template;
  23 +import lombok.Data;
  24 +import lombok.extern.slf4j.Slf4j;
  25 +
  26 +import java.util.*;
  27 +import java.util.function.Function;
  28 +import java.util.function.Supplier;
  29 +import java.util.stream.Collectors;
  30 +
  31 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  32 +import static cn.iocoder.dashboard.util.date.DateUtils.TIME_ZONE_DEFAULT;
  33 +
  34 +/**
  35 + * 云片短信客户端的实现类
  36 + *
  37 + * @author zzf
  38 + * @date 9:48 2021/3/5
  39 + */
  40 +@Slf4j
  41 +public class YunpianSmsClient extends AbstractSmsClient {
  42 +
  43 + /**
  44 + * 云信短信客户端
  45 + */
  46 + private volatile YunpianClient client;
  47 +
  48 + public YunpianSmsClient(SmsChannelProperties properties) {
  49 + super(properties, new YunpianSmsCodeMapping());
  50 + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
  51 + }
  52 +
  53 + @Override
  54 + public void doInit() {
  55 + YunpianClient oldClient = client;
  56 + // 初始化新的客户端
  57 + YunpianClient newClient = new YunpianClient(properties.getApiKey());
  58 + newClient.init();
  59 + this.client = newClient;
  60 + // 销毁老的客户端
  61 + if (oldClient != null) {
  62 + oldClient.close();
  63 + }
  64 + }
  65 +
  66 + @Override
  67 + protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
  68 + String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
  69 + return invoke(() -> {
  70 + Map<String, String> request = new HashMap<>();
  71 + request.put(YunpianConstant.MOBILE, mobile);
  72 + request.put(YunpianConstant.TPL_ID, apiTemplateId);
  73 + request.put(YunpianConstant.TPL_VALUE, formatTplValue(templateParams));
  74 + request.put(YunpianConstant.UID, String.valueOf(sendLogId));
  75 + request.put(YunpianConstant.CALLBACK_URL, properties.getCallbackUrl());
  76 + return client.sms().tpl_single_send(request);
  77 + }, response -> new SmsSendRespDTO().setSerialNo(String.valueOf(response.getSid())));
  78 + }
  79 +
  80 + private static String formatTplValue(List<KeyValue<String, Object>> templateParams) {
  81 + if (CollUtil.isEmpty(templateParams)) {
  82 + return "";
  83 + }
  84 + // 参考 https://www.yunpian.com/official/document/sms/zh_cn/introduction_demos_encode_sample 格式化
  85 + StringJoiner joiner = new StringJoiner("&");
  86 + templateParams.forEach(param -> joiner.add(String.format("#%s#=%s", param.getKey(), URLUtil.encode(String.valueOf(param.getValue())))));
  87 + return joiner.toString();
  88 + }
  89 +
  90 + @Override
  91 + protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
  92 + List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class);
  93 + return statuses.stream().map(status -> {
  94 + SmsReceiveRespDTO resp = new SmsReceiveRespDTO();
  95 + resp.setSuccess(Objects.equals(status.getReportStatus(), "SUCCESS"));
  96 + resp.setErrorCode(status.getErrorMsg()).setErrorMsg(status.getErrorDetail());
  97 + resp.setMobile(status.getMobile()).setReceiveTime(status.getUserReceiveTime());
  98 + resp.setSerialNo(String.valueOf(status.getSid())).setLogId(status.getUid());
  99 + return resp;
  100 + }).collect(Collectors.toList());
  101 + }
  102 +
  103 + @Override
  104 + protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) throws Throwable {
  105 + return invoke(() -> {
  106 + Map<String, String> request = new HashMap<>();
  107 + request.put(YunpianConstant.APIKEY, properties.getApiKey());
  108 + request.put(YunpianConstant.TPL_ID, apiTemplateId);
  109 + return client.tpl().get(request);
  110 + }, response -> {
  111 + Template template = response.get(0);
  112 + return new SmsTemplateRespDTO().setId(String.valueOf(template.getTpl_id())).setContent(template.getTpl_content())
  113 + .setAuditStatus(convertSmsTemplateAuditStatus(template.getCheck_status())).setAuditReason(template.getReason());
  114 + });
  115 + }
  116 +
  117 + @VisibleForTesting
  118 + Integer convertSmsTemplateAuditStatus(String checkStatus) {
  119 + switch (checkStatus) {
  120 + case "CHECKING": return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
  121 + case "SUCCESS": return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
  122 + case "FAIL": return SmsTemplateAuditStatusEnum.FAIL.getStatus();
  123 + default: throw new IllegalArgumentException(String.format("未知审核状态(%s)", checkStatus));
  124 + }
  125 + }
  126 +
  127 + @VisibleForTesting
  128 + <T, R> SmsCommonResult<R> invoke(Supplier<Result<T>> requestConsumer, Function<T, R> responseConsumer) throws Throwable {
  129 + // 执行请求
  130 + Result<T> result = requestConsumer.get();
  131 + if (result.getThrowable() != null) {
  132 + throw result.getThrowable();
  133 + }
  134 + // 解析结果
  135 + R data = null;
  136 + if (result.getData() != null) {
  137 + data = responseConsumer.apply(result.getData());
  138 + }
  139 + // 拼接结果
  140 + return SmsCommonResult.build(String.valueOf(result.getCode()), formatResultMsg(result), null, data, codeMapping);
  141 + }
  142 +
  143 + private static String formatResultMsg(Result<?> sendResult) {
  144 + if (StrUtil.isEmpty(sendResult.getDetail())) {
  145 + return sendResult.getMsg();
  146 + }
  147 + return sendResult.getMsg() + " => " + sendResult.getDetail();
  148 + }
  149 +
  150 + /**
  151 + * 短信接收状态
  152 + *
  153 + * 参见 https://www.yunpian.com/official/document/sms/zh_cn/domestic_push_report 文档
  154 + *
  155 + * @author 芋道源码
  156 + */
  157 + @Data
  158 + public static class SmsReceiveStatus {
  159 +
  160 + /**
  161 + * 接收状态
  162 + *
  163 + * 目前仅有 SUCCESS / FAIL,所以使用 Boolean 接收
  164 + */
  165 + @JsonProperty("report_status")
  166 + private String reportStatus;
  167 + /**
  168 + * 接收手机号
  169 + */
  170 + private String mobile;
  171 + /**
  172 + * 运营商返回的代码,如:"DB:0103"
  173 + *
  174 + * 由于不同运营商信息不同,此字段仅供参考;
  175 + */
  176 + @JsonProperty("error_msg")
  177 + private String errorMsg;
  178 + /**
  179 + * 运营商反馈代码的中文解释
  180 + *
  181 + * 默认不推送此字段,如需推送,请联系客服
  182 + */
  183 + @JsonProperty("error_detail")
  184 + private String errorDetail;
  185 + /**
  186 + * 短信编号
  187 + */
  188 + private Long sid;
  189 + /**
  190 + * 用户自定义 id
  191 + *
  192 + * 这里我们传递的是 SysSmsLogDO 的日志编号
  193 + */
  194 + private Long uid;
  195 + /**
  196 + * 用户接收时间
  197 + */
  198 + @JsonProperty("user_receive_time")
  199 + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
  200 + private Date userReceiveTime;
  201 +
  202 + }
  203 +
  204 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian;
  2 +
  3 +import cn.iocoder.dashboard.common.exception.ErrorCode;
  4 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping;
  5 +
  6 +import static cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants.SUCCESS;
  7 +import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.*;
  8 +import static com.yunpian.sdk.constant.Code.*;
  9 +
  10 +/**
  11 + * 云片的 SmsCodeMapping 实现类
  12 + *
  13 + * 参见 https://www.yunpian.com/official/document/sms/zh_CN/returnvalue_common 文档
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +public class YunpianSmsCodeMapping implements SmsCodeMapping {
  18 +
  19 + @Override
  20 + public ErrorCode apply(String apiCode) {
  21 + int code = Integer.parseInt(apiCode);
  22 + switch (code) {
  23 + case OK: return SUCCESS;
  24 + case ARGUMENT_MISSING: return SMS_API_PARAM_ERROR;
  25 + case BAD_ARGUMENT_FORMAT: return SMS_TEMPLATE_PARAM_ERROR;
  26 + case TPL_NOT_FOUND:
  27 + case TPL_NOT_VALID: return SMS_TEMPLATE_INVALID;
  28 + case MONEY_NOT_ENOUGH: return SMS_ACCOUNT_MONEY_NOT_ENOUGH;
  29 + case BLACK_WORD: return SMS_SEND_CONTENT_INVALID;
  30 + case DUP_IN_SHORT_TIME:
  31 + case TOO_MANY_TIME_IN_5:
  32 + case DAY_LIMIT_PER_MOBILE:
  33 + case HOUR_LIMIT_PER_MOBILE: return SMS_SEND_BUSINESS_LIMIT_CONTROL;
  34 + case BLACK_PHONE_FILTER: return SMS_MOBILE_BLACK;
  35 + case SIGN_NOT_MATCH:
  36 + case BAD_SIGN_FORMAT:
  37 + case SIGN_NOT_VALID: return SMS_SIGN_INVALID;
  38 + case BAD_API_KEY: return SMS_ACCOUNT_INVALID;
  39 + case API_NOT_ALLOWED: return SMS_PERMISSION_DENY;
  40 + case IP_NOT_ALLOWED: return SMS_IP_DENY;
  41 + }
  42 + return SMS_UNKNOWN;
  43 + }
  44 +
  45 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.enums;
  2 +
  3 +import cn.hutool.core.util.ArrayUtil;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +/**
  8 + * 短信渠道枚举
  9 + *
  10 + * @author zzf
  11 + * @date 2021/1/25 10:56
  12 + */
  13 +@Getter
  14 +@AllArgsConstructor
  15 +public enum SmsChannelEnum {
  16 +
  17 + DEBUG_DING_TALK("DEBUG_DING_TALK", "调试(钉钉)"),
  18 + YUN_PIAN("YUN_PIAN", "云片"),
  19 + ALIYUN("ALIYUN", "阿里云"),
  20 +// TENCENT("TENCENT", "腾讯云"),
  21 +// HUA_WEI("HUA_WEI", "华为云"),
  22 + ;
  23 +
  24 + /**
  25 + * 编码
  26 + */
  27 + private final String code;
  28 + /**
  29 + * 名字
  30 + */
  31 + private final String name;
  32 +
  33 + public static SmsChannelEnum getByCode(String code) {
  34 + return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values());
  35 + }
  36 +
  37 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.enums;
  2 +
  3 +import cn.iocoder.dashboard.common.exception.ErrorCode;
  4 +
  5 +/**
  6 + * 短信框架的错误码枚举
  7 + *
  8 + * 短信框架,使用 2-001-000-000 段
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +public interface SmsFrameworkErrorCodeConstants {
  13 +
  14 + ErrorCode SMS_UNKNOWN = new ErrorCode(2001000000, "未知错误,需要解析");
  15 +
  16 + // ========== 权限 / 限流等相关 2001000100 ==========
  17 +
  18 + ErrorCode SMS_PERMISSION_DENY = new ErrorCode(2001000100, "没有发送短信的权限");
  19 + // 云片:可以配置 IP 白名单,只有在白名单中才可以发送短信
  20 + ErrorCode SMS_IP_DENY = new ErrorCode(2001000100, "IP 不允许发送短信");
  21 +
  22 + // 阿里云:将短信发送频率限制在正常的业务限流范围内。默认短信验证码:使用同一签名,对同一个手机号验证码,支持 1 条 / 分钟,5 条 / 小时,累计 10 条 / 天。
  23 + ErrorCode SMS_SEND_BUSINESS_LIMIT_CONTROL = new ErrorCode(2001000102, "指定手机的发送限流");
  24 + // 阿里云:已经达到您在控制台设置的短信日发送量限额值。在国内消息设置 > 安全设置,修改发送总量阈值。
  25 + ErrorCode SMS_SEND_DAY_LIMIT_CONTROL = new ErrorCode(2001000103, "每天的发送限流");
  26 +
  27 + ErrorCode SMS_SEND_CONTENT_INVALID = new ErrorCode(2001000104, "短信内容有敏感词");
  28 +
  29 + // ========== 模板相关 2001000200 ==========
  30 + ErrorCode SMS_TEMPLATE_INVALID = new ErrorCode(2001000200, "短信模板不合法"); // 包括短信模板不存在
  31 + ErrorCode SMS_TEMPLATE_PARAM_ERROR = new ErrorCode(2001000201, "模板参数不正确");
  32 +
  33 + // ========== 签名相关 2001000300 ==========
  34 + ErrorCode SMS_SIGN_INVALID = new ErrorCode(2001000300, "短信签名不可用");
  35 +
  36 + // ========== 账户相关 2001000400 ==========
  37 + ErrorCode SMS_ACCOUNT_MONEY_NOT_ENOUGH = new ErrorCode(2001000400, "账户余额不足");
  38 + ErrorCode SMS_ACCOUNT_INVALID = new ErrorCode(2001000401, "apiKey 不存在");
  39 +
  40 + // ========== 其它相关 2001000900 开头 ==========
  41 + ErrorCode SMS_API_PARAM_ERROR = new ErrorCode(2001000900, "请求参数缺失");
  42 + ErrorCode SMS_MOBILE_INVALID = new ErrorCode(2001000901, "手机格式不正确");
  43 + ErrorCode SMS_MOBILE_BLACK = new ErrorCode(2001000902, "手机号在黑名单中");
  44 +
  45 + ErrorCode EXCEPTION = new ErrorCode(2001000999, "调用异常");
  46 +
  47 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.enums;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 短信模板的审核状态枚举
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@AllArgsConstructor
  12 +@Getter
  13 +public enum SmsTemplateAuditStatusEnum {
  14 +
  15 + CHECKING(1),
  16 + SUCCESS(2),
  17 + FAIL(3);
  18 +
  19 + private final Integer status;
  20 +
  21 +}
src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperties.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.property;
  2 +
  3 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
  4 +import lombok.Data;
  5 +import org.springframework.validation.annotation.Validated;
  6 +
  7 +import javax.validation.constraints.NotEmpty;
  8 +import javax.validation.constraints.NotNull;
  9 +
  10 +/**
  11 + * 短信渠道配置类
  12 + *
  13 + * @author zzf
  14 + * @date 2021/1/25 17:01
  15 + */
  16 +@Data
  17 +@Validated
  18 +public class SmsChannelProperties {
  19 +
  20 + /**
  21 + * 渠道编号
  22 + */
  23 + @NotNull(message = "短信渠道 ID 不能为空")
  24 + private Long id;
  25 + /**
  26 + * 短信签名
  27 + */
  28 + @NotEmpty(message = "短信签名不能为空")
  29 + private String signature;
  30 + /**
  31 + * 渠道编码
  32 + *
  33 + * 枚举 {@link SmsChannelEnum}
  34 + */
  35 + @NotEmpty(message = "渠道编码不能为空")
  36 + private String code;
  37 + /**
  38 + * 短信 API 的账号
  39 + */
  40 + @NotEmpty(message = "短信 API 的账号不能为空")
  41 + private String apiKey;
  42 + /**
  43 + * 短信 API 的秘钥
  44 + */
  45 + @NotEmpty(message = "短信 API 的秘钥不能为空")
  46 + private String apiSecret;
  47 + /**
  48 + * 短信发送回调 URL
  49 + */
  50 + private String callbackUrl;
  51 +
  52 +}
src/main/java/cn/iocoder/dashboard/framework/web/config/WebConfiguration.java
@@ -2,7 +2,9 @@ package cn.iocoder.dashboard.framework.web.config; @@ -2,7 +2,9 @@ package cn.iocoder.dashboard.framework.web.config;
2 2
3 import cn.iocoder.dashboard.framework.web.core.enums.FilterOrderEnum; 3 import cn.iocoder.dashboard.framework.web.core.enums.FilterOrderEnum;
4 import cn.iocoder.dashboard.framework.web.core.filter.CacheRequestBodyFilter; 4 import cn.iocoder.dashboard.framework.web.core.filter.CacheRequestBodyFilter;
  5 +import cn.iocoder.dashboard.framework.web.core.filter.DemoFilter;
5 import cn.iocoder.dashboard.framework.web.core.filter.XssFilter; 6 import cn.iocoder.dashboard.framework.web.core.filter.XssFilter;
  7 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
6 import org.springframework.boot.context.properties.EnableConfigurationProperties; 8 import org.springframework.boot.context.properties.EnableConfigurationProperties;
7 import org.springframework.boot.web.servlet.FilterRegistrationBean; 9 import org.springframework.boot.web.servlet.FilterRegistrationBean;
8 import org.springframework.context.annotation.Bean; 10 import org.springframework.context.annotation.Bean;
@@ -68,6 +70,15 @@ public class WebConfiguration implements WebMvcConfigurer { @@ -68,6 +70,15 @@ public class WebConfiguration implements WebMvcConfigurer {
68 return createFilterBean(new XssFilter(properties, pathMatcher), FilterOrderEnum.XSS_FILTER); 70 return createFilterBean(new XssFilter(properties, pathMatcher), FilterOrderEnum.XSS_FILTER);
69 } 71 }
70 72
  73 + /**
  74 + * 创建 DemoFilter Bean,演示模式
  75 + */
  76 + @Bean
  77 + @ConditionalOnProperty(value = "yudao.demo", havingValue = "true")
  78 + public FilterRegistrationBean<DemoFilter> demoFilter() {
  79 + return createFilterBean(new DemoFilter(), FilterOrderEnum.DEMO_FILTER);
  80 + }
  81 +
71 private static <T extends Filter> FilterRegistrationBean<T> createFilterBean(T filter, Integer order) { 82 private static <T extends Filter> FilterRegistrationBean<T> createFilterBean(T filter, Integer order) {
72 FilterRegistrationBean<T> bean = new FilterRegistrationBean<>(filter); 83 FilterRegistrationBean<T> bean = new FilterRegistrationBean<>(filter);
73 bean.setOrder(order); 84 bean.setOrder(order);
src/main/java/cn/iocoder/dashboard/framework/web/core/enums/FilterOrderEnum.java
@@ -9,6 +9,7 @@ public interface FilterOrderEnum { @@ -9,6 +9,7 @@ public interface FilterOrderEnum {
9 9
10 int CORS_FILTER = Integer.MIN_VALUE; 10 int CORS_FILTER = Integer.MIN_VALUE;
11 11
  12 +
12 int REQUEST_BODY_CACHE_FILTER = Integer.MIN_VALUE + 500; 13 int REQUEST_BODY_CACHE_FILTER = Integer.MIN_VALUE + 500;
13 14
14 // OrderedRequestContextFilter 默认为 -105,用于国际化上下文等等 15 // OrderedRequestContextFilter 默认为 -105,用于国际化上下文等等
@@ -19,4 +20,6 @@ public interface FilterOrderEnum { @@ -19,4 +20,6 @@ public interface FilterOrderEnum {
19 20
20 // Spring Security Filter 默认为 -100,可见 SecurityProperties 配置属性类 21 // Spring Security Filter 默认为 -100,可见 SecurityProperties 配置属性类
21 22
  23 + int DEMO_FILTER = Integer.MAX_VALUE;
  24 +
22 } 25 }
src/main/java/cn/iocoder/dashboard/framework/web/core/filter/DemoFilter.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.web.core.filter;
  2 +
  3 +import cn.hutool.core.util.StrUtil;
  4 +import cn.iocoder.dashboard.common.pojo.CommonResult;
  5 +import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils;
  6 +import cn.iocoder.dashboard.util.servlet.ServletUtils;
  7 +import org.springframework.web.filter.OncePerRequestFilter;
  8 +
  9 +import javax.servlet.FilterChain;
  10 +import javax.servlet.http.HttpServletRequest;
  11 +import javax.servlet.http.HttpServletResponse;
  12 +
  13 +import static cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants.DEMO_DENY;
  14 +
  15 +/**
  16 + * 演示 Filter,禁止用户发起写操作,避免影响测试数据
  17 + *
  18 + * @author 芋道源码
  19 + */
  20 +public class DemoFilter extends OncePerRequestFilter {
  21 +
  22 + @Override
  23 + protected boolean shouldNotFilter(HttpServletRequest request) {
  24 + String method = request.getMethod();
  25 + return !StrUtil.equalsAnyIgnoreCase(method, "POST", "PUT", "DELETE") // 写操作时,不进行过滤率
  26 + || SecurityFrameworkUtils.getLoginUser() == null; // 非登陆用户时,不进行过滤
  27 + }
  28 +
  29 + @Override
  30 + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
  31 + // 直接返回 DEMO_DENY 的结果。即,请求不继续
  32 + ServletUtils.writeJSON(response, CommonResult.error(DEMO_DENY));
  33 + }
  34 +
  35 +}
src/main/java/cn/iocoder/dashboard/framework/web/core/handler/GlobalExceptionHandler.java
@@ -3,7 +3,6 @@ package cn.iocoder.dashboard.framework.web.core.handler; @@ -3,7 +3,6 @@ package cn.iocoder.dashboard.framework.web.core.handler;
3 import cn.hutool.core.exceptions.ExceptionUtil; 3 import cn.hutool.core.exceptions.ExceptionUtil;
4 import cn.hutool.core.map.MapUtil; 4 import cn.hutool.core.map.MapUtil;
5 import cn.hutool.extra.servlet.ServletUtil; 5 import cn.hutool.extra.servlet.ServletUtil;
6 -import cn.iocoder.dashboard.common.exception.GlobalException;  
7 import cn.iocoder.dashboard.common.exception.ServiceException; 6 import cn.iocoder.dashboard.common.exception.ServiceException;
8 import cn.iocoder.dashboard.common.pojo.CommonResult; 7 import cn.iocoder.dashboard.common.pojo.CommonResult;
9 import cn.iocoder.dashboard.framework.logger.apilog.core.service.ApiErrorLogFrameworkService; 8 import cn.iocoder.dashboard.framework.logger.apilog.core.service.ApiErrorLogFrameworkService;
@@ -96,9 +95,6 @@ public class GlobalExceptionHandler { @@ -96,9 +95,6 @@ public class GlobalExceptionHandler {
96 if (ex instanceof AccessDeniedException) { 95 if (ex instanceof AccessDeniedException) {
97 return accessDeniedExceptionHandler(request, (AccessDeniedException) ex); 96 return accessDeniedExceptionHandler(request, (AccessDeniedException) ex);
98 } 97 }
99 - if (ex instanceof GlobalException) {  
100 - return globalExceptionHandler(request, (GlobalException) ex);  
101 - }  
102 return defaultExceptionHandler(request, ex); 98 return defaultExceptionHandler(request, ex);
103 } 99 }
104 100
@@ -223,25 +219,6 @@ public class GlobalExceptionHandler { @@ -223,25 +219,6 @@ public class GlobalExceptionHandler {
223 } 219 }
224 220
225 /** 221 /**
226 - * 处理全局异常 ServiceException  
227 - *  
228 - * 例如说,Dubbo 请求超时,调用的 Dubbo 服务系统异常  
229 - */  
230 - @ExceptionHandler(value = GlobalException.class)  
231 - public CommonResult<?> globalExceptionHandler(HttpServletRequest req, GlobalException ex) {  
232 - // 系统异常时,才打印异常日志  
233 - if (INTERNAL_SERVER_ERROR.getCode().equals(ex.getCode())) {  
234 - // 插入异常日志  
235 - this.createExceptionLog(req, ex);  
236 - // 普通全局异常,打印 info 日志即可  
237 - } else {  
238 - log.info("[globalExceptionHandler]", ex);  
239 - }  
240 - // 返回 ERROR CommonResult  
241 - return CommonResult.error(ex);  
242 - }  
243 -  
244 - /**  
245 * 处理系统异常,兜底处理所有的一切 222 * 处理系统异常,兜底处理所有的一切
246 */ 223 */
247 @ExceptionHandler(value = Exception.class) 224 @ExceptionHandler(value = Exception.class)
@@ -250,7 +227,7 @@ public class GlobalExceptionHandler { @@ -250,7 +227,7 @@ public class GlobalExceptionHandler {
250 // 插入异常日志 227 // 插入异常日志
251 this.createExceptionLog(req, ex); 228 this.createExceptionLog(req, ex);
252 // 返回 ERROR CommonResult 229 // 返回 ERROR CommonResult
253 - return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMessage()); 230 + return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg());
254 } 231 }
255 232
256 private void createExceptionLog(HttpServletRequest req, Throwable e) { 233 private void createExceptionLog(HttpServletRequest req, Throwable e) {
src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/SysDictDataController.java
@@ -61,7 +61,7 @@ public class SysDictDataController { @@ -61,7 +61,7 @@ public class SysDictDataController {
61 @GetMapping("/list-all-simple") 61 @GetMapping("/list-all-simple")
62 @ApiOperation(value = "获得全部字典数据列表", notes = "一般用于管理后台缓存字典数据在本地") 62 @ApiOperation(value = "获得全部字典数据列表", notes = "一般用于管理后台缓存字典数据在本地")
63 // 无需添加权限认证,因为前端全局都需要 63 // 无需添加权限认证,因为前端全局都需要
64 - public CommonResult<List<SysDictDataSimpleVO>> getSimpleDictDatas() { 64 + public CommonResult<List<SysDictDataSimpleRespVO>> getSimpleDictDatas() {
65 List<SysDictDataDO> list = dictDataService.getDictDatas(); 65 List<SysDictDataDO> list = dictDataService.getDictDatas();
66 return success(SysDictDataConvert.INSTANCE.convertList(list)); 66 return success(SysDictDataConvert.INSTANCE.convertList(list));
67 } 67 }
src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/SysDictTypeController.java
@@ -41,7 +41,7 @@ public class SysDictTypeController { @@ -41,7 +41,7 @@ public class SysDictTypeController {
41 return success(dictTypeId); 41 return success(dictTypeId);
42 } 42 }
43 43
44 - @PostMapping("update") 44 + @PutMapping("/update")
45 @ApiOperation("修改字典类型") 45 @ApiOperation("修改字典类型")
46 @PreAuthorize("@ss.hasPermission('system:dict:update')") 46 @PreAuthorize("@ss.hasPermission('system:dict:update')")
47 public CommonResult<Boolean> updateDictType(@Valid @RequestBody SysDictTypeUpdateReqVO reqVO) { 47 public CommonResult<Boolean> updateDictType(@Valid @RequestBody SysDictTypeUpdateReqVO reqVO) {
src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/vo/data/SysDictDataSimpleVO.java renamed to src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/vo/data/SysDictDataSimpleRespVO.java
@@ -4,9 +4,9 @@ import io.swagger.annotations.ApiModel; @@ -4,9 +4,9 @@ import io.swagger.annotations.ApiModel;
4 import io.swagger.annotations.ApiModelProperty; 4 import io.swagger.annotations.ApiModelProperty;
5 import lombok.Data; 5 import lombok.Data;
6 6
7 -@ApiModel("数据字典精简 VO") 7 +@ApiModel("数据字典精简 Response VO")
8 @Data 8 @Data
9 -public class SysDictDataSimpleVO { 9 +public class SysDictDataSimpleRespVO {
10 10
11 @ApiModelProperty(value = "字典类型", required = true, example = "gender") 11 @ApiModelProperty(value = "字典类型", required = true, example = "gender")
12 private String dictType; 12 private String dictType;
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms;
  2 +
  3 +import cn.hutool.core.util.URLUtil;
  4 +import cn.hutool.extra.servlet.ServletUtil;
  5 +import cn.iocoder.dashboard.common.pojo.CommonResult;
  6 +import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
  7 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
  8 +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService;
  9 +import io.swagger.annotations.Api;
  10 +import io.swagger.annotations.ApiImplicitParam;
  11 +import io.swagger.annotations.ApiOperation;
  12 +import org.springframework.web.bind.annotation.PostMapping;
  13 +import org.springframework.web.bind.annotation.RequestMapping;
  14 +import org.springframework.web.bind.annotation.RequestParam;
  15 +import org.springframework.web.bind.annotation.RestController;
  16 +
  17 +import javax.annotation.Resource;
  18 +import javax.servlet.http.HttpServletRequest;
  19 +
  20 +import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
  21 +
  22 +@Api(tags = "短信回调")
  23 +@RestController
  24 +@RequestMapping("/system/sms/callback")
  25 +public class SmsCallbackController {
  26 +
  27 + @Resource
  28 + private SysSmsService smsService;
  29 +
  30 + @PostMapping("/sms/yunpian")
  31 + @ApiOperation(value = "云片短信的回调", notes = "参见 https://www.yunpian.com/official/document/sms/zh_cn/domestic_push_report 文档")
  32 + @ApiImplicitParam(name = "sms_status", value = "发送状态", required = true, example = "[{具体内容}]", dataTypeClass = Long.class)
  33 + @OperateLog(enable = false)
  34 + public String receiveYunpianSmsStatus(@RequestParam("sms_status") String smsStatus) throws Throwable {
  35 + String text = URLUtil.decode(smsStatus); // decode 解码参数,因为它被 encode
  36 + smsService.receiveSmsStatus(SmsChannelEnum.YUN_PIAN.getCode(), text);
  37 + return "SUCCESS"; // 约定返回 SUCCESS 为成功
  38 + }
  39 +
  40 + @PostMapping("/sms/aliyun")
  41 + @ApiOperation(value = "阿里云短信的回调", notes = "参见 https://help.aliyun.com/document_detail/120998.html 文档")
  42 + @OperateLog(enable = false)
  43 + public CommonResult<Boolean> receiveAliyunSmsStatus(HttpServletRequest request) throws Throwable {
  44 + String text = ServletUtil.getBody(request);
  45 + smsService.receiveSmsStatus(SmsChannelEnum.ALIYUN.getCode(), text);
  46 + return success(true);
  47 + }
  48 +
  49 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SysSmsChannelController.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.CommonResult;
  4 +import cn.iocoder.dashboard.common.pojo.PageResult;
  5 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.*;
  6 +import cn.iocoder.dashboard.modules.system.convert.sms.SysSmsChannelConvert;
  7 +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
  8 +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
  9 +import io.swagger.annotations.Api;
  10 +import io.swagger.annotations.ApiImplicitParam;
  11 +import io.swagger.annotations.ApiOperation;
  12 +import org.springframework.security.access.prepost.PreAuthorize;
  13 +import org.springframework.web.bind.annotation.*;
  14 +
  15 +import javax.annotation.Resource;
  16 +import javax.validation.Valid;
  17 +import java.util.Comparator;
  18 +import java.util.List;
  19 +
  20 +import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
  21 +
  22 +@Api(tags = "短信渠道")
  23 +@RestController
  24 +@RequestMapping("system/sms-channel")
  25 +public class SysSmsChannelController {
  26 +
  27 + @Resource
  28 + private SysSmsChannelService smsChannelService;
  29 +
  30 + @PostMapping("/create")
  31 + @ApiOperation("创建短信渠道")
  32 + @PreAuthorize("@ss.hasPermission('system:sms-channel:create')")
  33 + public CommonResult<Long> createSmsChannel(@Valid @RequestBody SysSmsChannelCreateReqVO createReqVO) {
  34 + return success(smsChannelService.createSmsChannel(createReqVO));
  35 + }
  36 +
  37 + @PutMapping("/update")
  38 + @ApiOperation("更新短信渠道")
  39 + @PreAuthorize("@ss.hasPermission('system:sms-channel:update')")
  40 + public CommonResult<Boolean> updateSmsChannel(@Valid @RequestBody SysSmsChannelUpdateReqVO updateReqVO) {
  41 + smsChannelService.updateSmsChannel(updateReqVO);
  42 + return success(true);
  43 + }
  44 +
  45 + @DeleteMapping("/delete")
  46 + @ApiOperation("删除短信渠道")
  47 + @ApiImplicitParam(name = "id", value = "编号", required = true)
  48 + @PreAuthorize("@ss.hasPermission('system:sms-channel:delete')")
  49 + public CommonResult<Boolean> deleteSmsChannel(@RequestParam("id") Long id) {
  50 + smsChannelService.deleteSmsChannel(id);
  51 + return success(true);
  52 + }
  53 +
  54 + @GetMapping("/get")
  55 + @ApiOperation("获得短信渠道")
  56 + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
  57 + @PreAuthorize("@ss.hasPermission('system:sms-channel:query')")
  58 + public CommonResult<SysSmsChannelRespVO> getSmsChannel(@RequestParam("id") Long id) {
  59 + SysSmsChannelDO smsChannel = smsChannelService.getSmsChannel(id);
  60 + return success(SysSmsChannelConvert.INSTANCE.convert(smsChannel));
  61 + }
  62 +
  63 + @GetMapping("/page")
  64 + @ApiOperation("获得短信渠道分页")
  65 + @PreAuthorize("@ss.hasPermission('system:sms-channel:query')")
  66 + public CommonResult<PageResult<SysSmsChannelRespVO>> getSmsChannelPage(@Valid SysSmsChannelPageReqVO pageVO) {
  67 + PageResult<SysSmsChannelDO> pageResult = smsChannelService.getSmsChannelPage(pageVO);
  68 + return success(SysSmsChannelConvert.INSTANCE.convertPage(pageResult));
  69 + }
  70 +
  71 + @GetMapping("/list-all-simple")
  72 + @ApiOperation(value = "获得短信渠道精简列表", notes = "包含被禁用的短信渠道")
  73 + public CommonResult<List<SysSmsChannelSimpleRespVO>> getSimpleSmsChannels() {
  74 + List<SysSmsChannelDO> list = smsChannelService.getSmsChannelList();
  75 + // 排序后,返回给前端
  76 + list.sort(Comparator.comparing(SysSmsChannelDO::getId));
  77 + return success(SysSmsChannelConvert.INSTANCE.convertList03(list));
  78 + }
  79 +
  80 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SysSmsLogController.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.CommonResult;
  4 +import cn.iocoder.dashboard.common.pojo.PageResult;
  5 +import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils;
  6 +import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
  7 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogExcelVO;
  8 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogExportReqVO;
  9 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogPageReqVO;
  10 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogRespVO;
  11 +import cn.iocoder.dashboard.modules.system.convert.sms.SysSmsLogConvert;
  12 +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO;
  13 +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsLogService;
  14 +import io.swagger.annotations.Api;
  15 +import io.swagger.annotations.ApiOperation;
  16 +import org.springframework.security.access.prepost.PreAuthorize;
  17 +import org.springframework.validation.annotation.Validated;
  18 +import org.springframework.web.bind.annotation.GetMapping;
  19 +import org.springframework.web.bind.annotation.RequestMapping;
  20 +import org.springframework.web.bind.annotation.RestController;
  21 +
  22 +import javax.annotation.Resource;
  23 +import javax.servlet.http.HttpServletResponse;
  24 +import javax.validation.Valid;
  25 +import java.io.IOException;
  26 +import java.util.List;
  27 +
  28 +import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
  29 +import static cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum.EXPORT;
  30 +
  31 +@Api(tags = "短信日志")
  32 +@RestController
  33 +@RequestMapping("/system/sms-log")
  34 +@Validated
  35 +public class SysSmsLogController {
  36 +
  37 + @Resource
  38 + private SysSmsLogService smsLogService;
  39 +
  40 + @GetMapping("/page")
  41 + @ApiOperation("获得短信日志分页")
  42 + @PreAuthorize("@ss.hasPermission('system:sms-log:query')")
  43 + public CommonResult<PageResult<SysSmsLogRespVO>> getSmsLogPage(@Valid SysSmsLogPageReqVO pageVO) {
  44 + PageResult<SysSmsLogDO> pageResult = smsLogService.getSmsLogPage(pageVO);
  45 + return success(SysSmsLogConvert.INSTANCE.convertPage(pageResult));
  46 + }
  47 +
  48 + @GetMapping("/export-excel")
  49 + @ApiOperation("导出短信日志 Excel")
  50 + @PreAuthorize("@ss.hasPermission('system:sms-log:export')")
  51 + @OperateLog(type = EXPORT)
  52 + public void exportSmsLogExcel(@Valid SysSmsLogExportReqVO exportReqVO,
  53 + HttpServletResponse response) throws IOException {
  54 + List<SysSmsLogDO> list = smsLogService.getSmsLogList(exportReqVO);
  55 + // 导出 Excel
  56 + List<SysSmsLogExcelVO> datas = SysSmsLogConvert.INSTANCE.convertList02(list);
  57 + ExcelUtils.write(response, "短信日志.xls", "数据", SysSmsLogExcelVO.class, datas);
  58 + }
  59 +
  60 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SysSmsTemplateController.http 0 → 100644
  1 +### 请求 /menu/list 接口 => 成功
  2 +POST {{baseUrl}}/system/sms-template/send-sms
  3 +Authorization: Bearer {{token}}
  4 +Content-Type: application/json
  5 +
  6 +{
  7 + "code": "test_01",
  8 + "params": {
  9 + "key01": "value01",
  10 + "key02": "value02"
  11 + }
  12 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SysSmsTemplateController.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.CommonResult;
  4 +import cn.iocoder.dashboard.common.pojo.PageResult;
  5 +import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils;
  6 +import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
  7 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.*;
  8 +import cn.iocoder.dashboard.modules.system.convert.sms.SysSmsTemplateConvert;
  9 +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
  10 +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService;
  11 +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService;
  12 +import io.swagger.annotations.Api;
  13 +import io.swagger.annotations.ApiImplicitParam;
  14 +import io.swagger.annotations.ApiOperation;
  15 +import org.springframework.security.access.prepost.PreAuthorize;
  16 +import org.springframework.web.bind.annotation.*;
  17 +
  18 +import javax.annotation.Resource;
  19 +import javax.servlet.http.HttpServletResponse;
  20 +import javax.validation.Valid;
  21 +import java.io.IOException;
  22 +import java.util.List;
  23 +
  24 +import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
  25 +import static cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum.EXPORT;
  26 +
  27 +@Api("短信模板")
  28 +@RestController
  29 +@RequestMapping("/system/sms-template")
  30 +public class SysSmsTemplateController {
  31 +
  32 + @Resource
  33 + private SysSmsTemplateService smsTemplateService;
  34 + @Resource
  35 + private SysSmsService smsService;
  36 +
  37 + @PostMapping("/create")
  38 + @ApiOperation("创建短信模板")
  39 + @PreAuthorize("@ss.hasPermission('system:sms-template:create')")
  40 + public CommonResult<Long> createSmsTemplate(@Valid @RequestBody SysSmsTemplateCreateReqVO createReqVO) {
  41 + return success(smsTemplateService.createSmsTemplate(createReqVO));
  42 + }
  43 +
  44 + @PutMapping("/update")
  45 + @ApiOperation("更新短信模板")
  46 + @PreAuthorize("@ss.hasPermission('system:sms-template:update')")
  47 + public CommonResult<Boolean> updateSmsTemplate(@Valid @RequestBody SysSmsTemplateUpdateReqVO updateReqVO) {
  48 + smsTemplateService.updateSmsTemplate(updateReqVO);
  49 + return success(true);
  50 + }
  51 +
  52 + @DeleteMapping("/delete")
  53 + @ApiOperation("删除短信模板")
  54 + @ApiImplicitParam(name = "id", value = "编号", required = true)
  55 + @PreAuthorize("@ss.hasPermission('system:sms-template:delete')")
  56 + public CommonResult<Boolean> deleteSmsTemplate(@RequestParam("id") Long id) {
  57 + smsTemplateService.deleteSmsTemplate(id);
  58 + return success(true);
  59 + }
  60 +
  61 + @GetMapping("/get")
  62 + @ApiOperation("获得短信模板")
  63 + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
  64 + @PreAuthorize("@ss.hasPermission('system:sms-template:query')")
  65 + public CommonResult<SysSmsTemplateRespVO> getSmsTemplate(@RequestParam("id") Long id) {
  66 + SysSmsTemplateDO smsTemplate = smsTemplateService.getSmsTemplate(id);
  67 + return success(SysSmsTemplateConvert.INSTANCE.convert(smsTemplate));
  68 + }
  69 +
  70 + @GetMapping("/page")
  71 + @ApiOperation("获得短信模板分页")
  72 + @PreAuthorize("@ss.hasPermission('system:sms-template:query')")
  73 + public CommonResult<PageResult<SysSmsTemplateRespVO>> getSmsTemplatePage(@Valid SysSmsTemplatePageReqVO pageVO) {
  74 + PageResult<SysSmsTemplateDO> pageResult = smsTemplateService.getSmsTemplatePage(pageVO);
  75 + return success(SysSmsTemplateConvert.INSTANCE.convertPage(pageResult));
  76 + }
  77 +
  78 + @GetMapping("/export-excel")
  79 + @ApiOperation("导出短信模板 Excel")
  80 + @PreAuthorize("@ss.hasPermission('system:sms-template:export')")
  81 + @OperateLog(type = EXPORT)
  82 + public void exportSmsTemplateExcel(@Valid SysSmsTemplateExportReqVO exportReqVO,
  83 + HttpServletResponse response) throws IOException {
  84 + List<SysSmsTemplateDO> list = smsTemplateService.getSmsTemplateList(exportReqVO);
  85 + // 导出 Excel
  86 + List<SysSmsTemplateExcelVO> datas = SysSmsTemplateConvert.INSTANCE.convertList02(list);
  87 + ExcelUtils.write(response, "短信模板.xls", "数据", SysSmsTemplateExcelVO.class, datas);
  88 + }
  89 +
  90 + @PostMapping("/send-sms")
  91 + @ApiOperation("发送短信")
  92 + @PreAuthorize("@ss.hasPermission('system:sms-template:send-sms')")
  93 + public CommonResult<Long> sendSms(@Valid @RequestBody SysSmsTemplateSendReqVO sendReqVO) {
  94 + return success(smsService.sendSingleSms(sendReqVO.getMobile(), null, null,
  95 + sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
  96 + }
  97 +
  98 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelBaseVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel;
  2 +
  3 +import io.swagger.annotations.ApiModelProperty;
  4 +import lombok.Data;
  5 +import org.hibernate.validator.constraints.URL;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +/**
  10 +* 短信渠道 Base VO,提供给添加、修改、详细的子 VO 使用
  11 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  12 +*/
  13 +@Data
  14 +public class SysSmsChannelBaseVO {
  15 +
  16 + @ApiModelProperty(value = "短信签名", required = true, example = "芋道源码")
  17 + @NotNull(message = "短信签名不能为空")
  18 + private String signature;
  19 +
  20 + @ApiModelProperty(value = "启用状态", required = true, example = "1")
  21 + @NotNull(message = "启用状态不能为空")
  22 + private Integer status;
  23 +
  24 + @ApiModelProperty(value = "备注", example = "好吃!")
  25 + private String remark;
  26 +
  27 + @ApiModelProperty(value = "短信 API 的账号", required = true, example = "yudao")
  28 + @NotNull(message = "短信 API 的账号不能为空")
  29 + private String apiKey;
  30 +
  31 + @ApiModelProperty(value = "短信 API 的秘钥", example = "yuanma")
  32 + private String apiSecret;
  33 +
  34 + @ApiModelProperty(value = "短信发送回调 URL", example = "http://www.iocoder.cn")
  35 + @URL(message = "回调 URL 格式不正确")
  36 + private String callbackUrl;
  37 +
  38 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelCreateReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import javax.validation.constraints.NotNull;
  10 +
  11 +@ApiModel("短信渠道创建 Request VO")
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +@ToString(callSuper = true)
  15 +public class SysSmsChannelCreateReqVO extends SysSmsChannelBaseVO {
  16 +
  17 + @ApiModelProperty(value = "渠道编码", required = true, example = "YUN_PIAN", notes = "参见 SmsChannelEnum 枚举类")
  18 + @NotNull(message = "渠道编码不能为空")
  19 + private String code;
  20 +
  21 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelPageReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageParam;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +import org.springframework.format.annotation.DateTimeFormat;
  10 +
  11 +import java.util.Date;
  12 +
  13 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  14 +
  15 +@ApiModel("短信渠道分页 Request VO")
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
  19 +public class SysSmsChannelPageReqVO extends PageParam {
  20 +
  21 + @ApiModelProperty(value = "任务状态", example = "1")
  22 + private Integer status;
  23 +
  24 + @ApiModelProperty(value = "短信签名", example = "芋道源码", notes = "模糊匹配")
  25 + private String signature;
  26 +
  27 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  28 + @ApiModelProperty(value = "开始创建时间")
  29 + private Date beginCreateTime;
  30 +
  31 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  32 + @ApiModelProperty(value = "结束创建时间")
  33 + private Date endCreateTime;
  34 +
  35 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelRespVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import java.util.Date;
  10 +
  11 +@ApiModel("短信渠道 Response VO")
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +@ToString(callSuper = true)
  15 +public class SysSmsChannelRespVO extends SysSmsChannelBaseVO {
  16 +
  17 + @ApiModelProperty(value = "编号", required = true, example = "1024")
  18 + private Long id;
  19 +
  20 + @ApiModelProperty(value = "渠道编码", required = true, example = "YUN_PIAN", notes = "参见 SmsChannelEnum 枚举类")
  21 + private String code;
  22 +
  23 + @ApiModelProperty(value = "创建时间", required = true)
  24 + private Date createTime;
  25 +
  26 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelSimpleRespVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +@ApiModel("短信渠道精简 Response VO")
  10 +@Data
  11 +public class SysSmsChannelSimpleRespVO {
  12 +
  13 + @ApiModelProperty(value = "编号", required = true, example = "1024")
  14 + @NotNull(message = "编号不能为空")
  15 + private Long id;
  16 +
  17 + @ApiModelProperty(value = "短信签名", required = true, example = "芋道源码")
  18 + @NotNull(message = "短信签名不能为空")
  19 + private String signature;
  20 +
  21 + @ApiModelProperty(value = "渠道编码", required = true, example = "YUN_PIAN", notes = "参见 SmsChannelEnum 枚举类")
  22 + private String code;
  23 +
  24 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelUpdateReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import javax.validation.constraints.NotNull;
  10 +
  11 +@ApiModel("短信渠道更新 Request VO")
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +@ToString(callSuper = true)
  15 +public class SysSmsChannelUpdateReqVO extends SysSmsChannelBaseVO {
  16 +
  17 + @ApiModelProperty(value = "编号", required = true, example = "1024")
  18 + @NotNull(message = "编号不能为空")
  19 + private Long id;
  20 +
  21 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/log/SysSmsLogExcelVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.log;
  2 +
  3 +import cn.iocoder.dashboard.framework.excel.core.annotations.DictFormat;
  4 +import cn.iocoder.dashboard.framework.excel.core.convert.DictConvert;
  5 +import cn.iocoder.dashboard.framework.excel.core.convert.JsonConvert;
  6 +import com.alibaba.excel.annotation.ExcelProperty;
  7 +import lombok.Data;
  8 +
  9 +import java.util.Date;
  10 +import java.util.Map;
  11 +
  12 +import static cn.iocoder.dashboard.modules.system.enums.dict.SysDictTypeEnum.*;
  13 +
  14 +/**
  15 + * 短信日志 Excel VO
  16 + *
  17 + * @author 芋道源码
  18 + */
  19 +@Data
  20 +public class SysSmsLogExcelVO {
  21 +
  22 + @ExcelProperty("编号")
  23 + private Long id;
  24 +
  25 + @ExcelProperty("短信渠道编号")
  26 + private Long channelId;
  27 +
  28 + @ExcelProperty("短信渠道编码")
  29 + private String channelCode;
  30 +
  31 + @ExcelProperty("模板编号")
  32 + private Long templateId;
  33 +
  34 + @ExcelProperty("模板编码")
  35 + private String templateCode;
  36 +
  37 + @ExcelProperty(value = "短信类型", converter = DictConvert.class)
  38 + @DictFormat(SYS_SMS_TEMPLATE_TYPE)
  39 + private Integer templateType;
  40 +
  41 + @ExcelProperty("短信内容")
  42 + private String templateContent;
  43 +
  44 + @ExcelProperty(value = "短信参数", converter = JsonConvert.class)
  45 + private Map<String, Object> templateParams;
  46 +
  47 + @ExcelProperty("短信 API 的模板编号")
  48 + private String apiTemplateId;
  49 +
  50 + @ExcelProperty("手机号")
  51 + private String mobile;
  52 +
  53 + @ExcelProperty("用户编号")
  54 + private Long userId;
  55 +
  56 + @ExcelProperty(value = "用户类型", converter = DictConvert.class)
  57 + @DictFormat(USER_TYPE)
  58 + private Integer userType;
  59 +
  60 + @ExcelProperty(value = "发送状态", converter = DictConvert.class)
  61 + @DictFormat(SYS_SMS_SEND_STATUS)
  62 + private Integer sendStatus;
  63 +
  64 + @ExcelProperty("发送时间")
  65 + private Date sendTime;
  66 +
  67 + @ExcelProperty("发送结果的编码")
  68 + private Integer sendCode;
  69 +
  70 + @ExcelProperty("发送结果的提示")
  71 + private String sendMsg;
  72 +
  73 + @ExcelProperty("短信 API 发送结果的编码")
  74 + private String apiSendCode;
  75 +
  76 + @ExcelProperty("短信 API 发送失败的提示")
  77 + private String apiSendMsg;
  78 +
  79 + @ExcelProperty("短信 API 发送返回的唯一请求 ID")
  80 + private String apiRequestId;
  81 +
  82 + @ExcelProperty("短信 API 发送返回的序号")
  83 + private String apiSerialNo;
  84 +
  85 + @ExcelProperty(value = "接收状态", converter = DictConvert.class)
  86 + @DictFormat(SYS_SMS_RECEIVE_STATUS)
  87 + private Integer receiveStatus;
  88 +
  89 + @ExcelProperty("接收时间")
  90 + private Date receiveTime;
  91 +
  92 + @ExcelProperty("API 接收结果的编码")
  93 + private String apiReceiveCode;
  94 +
  95 + @ExcelProperty("API 接收结果的说明")
  96 + private String apiReceiveMsg;
  97 +
  98 + @ExcelProperty("创建时间")
  99 + private Date createTime;
  100 +
  101 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/log/SysSmsLogExportReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.log;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +
  8 +import java.util.Date;
  9 +
  10 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@ApiModel(value = "短信日志 Excel 导出 Request VO", description = "参数和 SysSmsLogPageReqVO 是一致的")
  13 +@Data
  14 +public class SysSmsLogExportReqVO {
  15 +
  16 + @ApiModelProperty(value = "短信渠道编号", example = "10")
  17 + private Long channelId;
  18 +
  19 + @ApiModelProperty(value = "模板编号", example = "20")
  20 + private Long templateId;
  21 +
  22 + @ApiModelProperty(value = "手机号", example = "15601691300")
  23 + private String mobile;
  24 +
  25 + @ApiModelProperty(value = "发送状态", example = "1")
  26 + private Integer sendStatus;
  27 +
  28 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  29 + @ApiModelProperty(value = "开始发送时间")
  30 + private Date beginSendTime;
  31 +
  32 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  33 + @ApiModelProperty(value = "结束发送时间")
  34 + private Date endSendTime;
  35 +
  36 + @ApiModelProperty(value = "接收状态", example = "0")
  37 + private Integer receiveStatus;
  38 +
  39 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  40 + @ApiModelProperty(value = "开始接收时间")
  41 + private Date beginReceiveTime;
  42 +
  43 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  44 + @ApiModelProperty(value = "结束接收时间")
  45 + private Date endReceiveTime;
  46 +
  47 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/log/SysSmsLogPageReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.log;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageParam;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +import org.springframework.format.annotation.DateTimeFormat;
  10 +
  11 +import java.util.Date;
  12 +
  13 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  14 +
  15 +@ApiModel("短信日志分页 Request VO")
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
  19 +public class SysSmsLogPageReqVO extends PageParam {
  20 +
  21 + @ApiModelProperty(value = "短信渠道编号", example = "10")
  22 + private Long channelId;
  23 +
  24 + @ApiModelProperty(value = "模板编号", example = "20")
  25 + private Long templateId;
  26 +
  27 + @ApiModelProperty(value = "手机号", example = "15601691300")
  28 + private String mobile;
  29 +
  30 + @ApiModelProperty(value = "发送状态", example = "1", notes = "参见 SysSmsSendStatusEnum 枚举类")
  31 + private Integer sendStatus;
  32 +
  33 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  34 + @ApiModelProperty(value = "开始发送时间")
  35 + private Date beginSendTime;
  36 +
  37 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  38 + @ApiModelProperty(value = "结束发送时间")
  39 + private Date endSendTime;
  40 +
  41 + @ApiModelProperty(value = "接收状态", example = "0", notes = "参见 SysSmsReceiveStatusEnum 枚举类")
  42 + private Integer receiveStatus;
  43 +
  44 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  45 + @ApiModelProperty(value = "开始接收时间")
  46 + private Date beginReceiveTime;
  47 +
  48 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  49 + @ApiModelProperty(value = "结束接收时间")
  50 + private Date endReceiveTime;
  51 +
  52 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/log/SysSmsLogRespVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.log;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +import java.util.Date;
  8 +import java.util.Map;
  9 +
  10 +@ApiModel("短信日志 Response VO")
  11 +@Data
  12 +public class SysSmsLogRespVO {
  13 +
  14 + @ApiModelProperty(value = "编号", required = true, example = "1024")
  15 + private Long id;
  16 +
  17 + @ApiModelProperty(value = "短信渠道编号", required = true, example = "10")
  18 + private Long channelId;
  19 +
  20 + @ApiModelProperty(value = "短信渠道编码", required = true, example = "ALIYUN")
  21 + private String channelCode;
  22 +
  23 + @ApiModelProperty(value = "模板编号", required = true, example = "20")
  24 + private Long templateId;
  25 +
  26 + @ApiModelProperty(value = "模板编码", required = true, example = "test-01")
  27 + private String templateCode;
  28 +
  29 + @ApiModelProperty(value = "短信类型", required = true, example = "1")
  30 + private Integer templateType;
  31 +
  32 + @ApiModelProperty(value = "短信内容", required = true, example = "你好,你的验证码是 1024")
  33 + private String templateContent;
  34 +
  35 + @ApiModelProperty(value = "短信参数", required = true, example = "name,code")
  36 + private Map<String, Object> templateParams;
  37 +
  38 + @ApiModelProperty(value = "短信 API 的模板编号", required = true, example = "SMS_207945135")
  39 + private String apiTemplateId;
  40 +
  41 + @ApiModelProperty(value = "手机号", required = true, example = "15601691300")
  42 + private String mobile;
  43 +
  44 + @ApiModelProperty(value = "用户编号", example = "10")
  45 + private Long userId;
  46 +
  47 + @ApiModelProperty(value = "用户类型", example = "1")
  48 + private Integer userType;
  49 +
  50 + @ApiModelProperty(value = "发送状态", required = true, example = "1")
  51 + private Integer sendStatus;
  52 +
  53 + @ApiModelProperty(value = "发送时间")
  54 + private Date sendTime;
  55 +
  56 + @ApiModelProperty(value = "发送结果的编码", example = "0")
  57 + private Integer sendCode;
  58 +
  59 + @ApiModelProperty(value = "发送结果的提示", example = "成功")
  60 + private String sendMsg;
  61 +
  62 + @ApiModelProperty(value = "短信 API 发送结果的编码", example = "SUCCESS")
  63 + private String apiSendCode;
  64 +
  65 + @ApiModelProperty(value = "短信 API 发送失败的提示", example = "成功")
  66 + private String apiSendMsg;
  67 +
  68 + @ApiModelProperty(value = "短信 API 发送返回的唯一请求 ID", example = "3837C6D3-B96F-428C-BBB2-86135D4B5B99")
  69 + private String apiRequestId;
  70 +
  71 + @ApiModelProperty(value = "短信 API 发送返回的序号", example = "62923244790")
  72 + private String apiSerialNo;
  73 +
  74 + @ApiModelProperty(value = "接收状态", required = true, example = "0")
  75 + private Integer receiveStatus;
  76 +
  77 + @ApiModelProperty(value = "接收时间")
  78 + private Date receiveTime;
  79 +
  80 + @ApiModelProperty(value = "API 接收结果的编码", example = "DELIVRD")
  81 + private String apiReceiveCode;
  82 +
  83 + @ApiModelProperty(value = "API 接收结果的说明", example = "用户接收成功")
  84 + private String apiReceiveMsg;
  85 +
  86 + @ApiModelProperty(value = "创建时间", required = true)
  87 + private Date createTime;
  88 +
  89 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateBaseVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.template;
  2 +
  3 +import io.swagger.annotations.ApiModelProperty;
  4 +import lombok.Data;
  5 +
  6 +import javax.validation.constraints.NotNull;
  7 +
  8 +/**
  9 +* 短信模板 Base VO,提供给添加、修改、详细的子 VO 使用
  10 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  11 +*/
  12 +@Data
  13 +public class SysSmsTemplateBaseVO {
  14 +
  15 + @ApiModelProperty(value = "短信类型", required = true, example = "1", notes = "参见 SysSmsTemplateTypeEnum 枚举类")
  16 + @NotNull(message = "短信类型不能为空")
  17 + private Integer type;
  18 +
  19 + @ApiModelProperty(value = "开启状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举类")
  20 + @NotNull(message = "开启状态不能为空")
  21 + private Integer status;
  22 +
  23 + @ApiModelProperty(value = "模板编码", required = true, example = "test_01")
  24 + @NotNull(message = "模板编码不能为空")
  25 + private String code;
  26 +
  27 + @ApiModelProperty(value = "模板名称", required = true, example = "yudao")
  28 + @NotNull(message = "模板名称不能为空")
  29 + private String name;
  30 +
  31 + @ApiModelProperty(value = "模板内容", required = true, example = "你好,{name}。你长的太{like}啦!")
  32 + @NotNull(message = "模板内容不能为空")
  33 + private String content;
  34 +
  35 + @ApiModelProperty(value = "备注", example = "哈哈哈")
  36 + private String remark;
  37 +
  38 + @ApiModelProperty(value = "短信 API 的模板编号", required = true, example = "4383920")
  39 + @NotNull(message = "短信 API 的模板编号不能为空")
  40 + private String apiTemplateId;
  41 +
  42 + @ApiModelProperty(value = "短信渠道编号", required = true, example = "10")
  43 + @NotNull(message = "短信渠道编号不能为空")
  44 + private Long channelId;
  45 +
  46 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateCreateReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.template;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +@ApiModel("短信模板创建 Request VO")
  9 +@Data
  10 +@EqualsAndHashCode(callSuper = true)
  11 +@ToString(callSuper = true)
  12 +public class SysSmsTemplateCreateReqVO extends SysSmsTemplateBaseVO {
  13 +
  14 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateExcelVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.template;
  2 +
  3 +import cn.iocoder.dashboard.framework.excel.core.annotations.DictFormat;
  4 +import cn.iocoder.dashboard.framework.excel.core.convert.DictConvert;
  5 +import com.alibaba.excel.annotation.ExcelProperty;
  6 +import lombok.Data;
  7 +
  8 +import java.util.Date;
  9 +
  10 +import static cn.iocoder.dashboard.modules.system.enums.dict.SysDictTypeEnum.*;
  11 +
  12 +/**
  13 + * 短信模板 Excel VO
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Data
  18 +public class SysSmsTemplateExcelVO {
  19 +
  20 + @ExcelProperty("编号")
  21 + private Long id;
  22 +
  23 + @ExcelProperty(value = "短信签名", converter = DictConvert.class)
  24 + @DictFormat(SYS_SMS_TEMPLATE_TYPE)
  25 + private Integer type;
  26 +
  27 + @ExcelProperty(value = "开启状态", converter = DictConvert.class)
  28 + @DictFormat(SYS_COMMON_STATUS)
  29 + private Integer status;
  30 +
  31 + @ExcelProperty("模板编码")
  32 + private String code;
  33 +
  34 + @ExcelProperty("模板名称")
  35 + private String name;
  36 +
  37 + @ExcelProperty("模板内容")
  38 + private String content;
  39 +
  40 + @ExcelProperty("备注")
  41 + private String remark;
  42 +
  43 + @ExcelProperty("短信 API 的模板编号")
  44 + private String apiTemplateId;
  45 +
  46 + @ExcelProperty("短信渠道编号")
  47 + private Long channelId;
  48 +
  49 + @ExcelProperty(value = "短信渠道编码", converter = DictConvert.class)
  50 + @DictFormat(SYS_SMS_CHANNEL_CODE)
  51 + private String channelCode;
  52 +
  53 + @ExcelProperty("创建时间")
  54 + private Date createTime;
  55 +
  56 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateExportReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.template;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +
  8 +import java.util.Date;
  9 +
  10 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@ApiModel(value = "短信模板 Excel 导出 Request VO", description = "参数和 SysSmsTemplatePageReqVO 是一致的")
  13 +@Data
  14 +public class SysSmsTemplateExportReqVO {
  15 +
  16 + @ApiModelProperty(value = "短信签名", example = "1")
  17 + private Integer type;
  18 +
  19 + @ApiModelProperty(value = "开启状态", example = "1")
  20 + private Integer status;
  21 +
  22 + @ApiModelProperty(value = "模板编码", example = "test_01", notes = "模糊匹配")
  23 + private String code;
  24 +
  25 + @ApiModelProperty(value = "模板内容", example = "你好,{name}。你长的太{like}啦!", notes = "模糊匹配")
  26 + private String content;
  27 +
  28 + @ApiModelProperty(value = "短信 API 的模板编号", example = "4383920", notes = "模糊匹配")
  29 + private String apiTemplateId;
  30 +
  31 + @ApiModelProperty(value = "短信渠道编号", example = "10")
  32 + private Long channelId;
  33 +
  34 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  35 + @ApiModelProperty(value = "开始创建时间")
  36 + private Date beginCreateTime;
  37 +
  38 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  39 + @ApiModelProperty(value = "结束创建时间")
  40 + private Date endCreateTime;
  41 +
  42 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplatePageReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.template;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageParam;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +import org.springframework.format.annotation.DateTimeFormat;
  10 +
  11 +import java.util.Date;
  12 +
  13 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  14 +
  15 +@ApiModel("短信模板分页 Request VO")
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
  19 +public class SysSmsTemplatePageReqVO extends PageParam {
  20 +
  21 + @ApiModelProperty(value = "短信签名", example = "1")
  22 + private Integer type;
  23 +
  24 + @ApiModelProperty(value = "开启状态", example = "1")
  25 + private Integer status;
  26 +
  27 + @ApiModelProperty(value = "模板编码", example = "test_01", notes = "模糊匹配")
  28 + private String code;
  29 +
  30 + @ApiModelProperty(value = "模板内容", example = "你好,{name}。你长的太{like}啦!", notes = "模糊匹配")
  31 + private String content;
  32 +
  33 + @ApiModelProperty(value = "短信 API 的模板编号", example = "4383920", notes = "模糊匹配")
  34 + private String apiTemplateId;
  35 +
  36 + @ApiModelProperty(value = "短信渠道编号", example = "10")
  37 + private Long channelId;
  38 +
  39 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  40 + @ApiModelProperty(value = "开始创建时间")
  41 + private Date beginCreateTime;
  42 +
  43 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  44 + @ApiModelProperty(value = "结束创建时间")
  45 + private Date endCreateTime;
  46 +
  47 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateRespVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.template;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import java.util.Date;
  10 +import java.util.List;
  11 +
  12 +@ApiModel("短信模板 Response VO")
  13 +@Data
  14 +@EqualsAndHashCode(callSuper = true)
  15 +@ToString(callSuper = true)
  16 +public class SysSmsTemplateRespVO extends SysSmsTemplateBaseVO {
  17 +
  18 + @ApiModelProperty(value = "编号", required = true, example = "1024")
  19 + private Long id;
  20 +
  21 + @ApiModelProperty(value = "短信渠道编码", required = true, example = "ALIYUN")
  22 + private String channelCode;
  23 +
  24 + @ApiModelProperty(value = "参数数组", example = "name,code")
  25 + private List<String> params;
  26 +
  27 + @ApiModelProperty(value = "创建时间", required = true)
  28 + private Date createTime;
  29 +
  30 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateSendReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.template;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +import java.util.Map;
  9 +
  10 +@ApiModel("短信模板的发送 Request VO")
  11 +@Data
  12 +public class SysSmsTemplateSendReqVO {
  13 +
  14 + @ApiModelProperty(value = "手机号", required = true, example = "15601691300")
  15 + @NotNull(message = "手机号不能为空")
  16 + private String mobile;
  17 +
  18 + @ApiModelProperty(value = "模板编码", required = true, example = "test_01")
  19 + @NotNull(message = "模板编码不能为空")
  20 + private String templateCode;
  21 +
  22 + @ApiModelProperty(value = "模板参数")
  23 + private Map<String, Object> templateParams;
  24 +
  25 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateUpdateReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.sms.vo.template;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import javax.validation.constraints.NotNull;
  10 +
  11 +@ApiModel("短信模板更新 Request VO")
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +@ToString(callSuper = true)
  15 +public class SysSmsTemplateUpdateReqVO extends SysSmsTemplateBaseVO {
  16 +
  17 + @ApiModelProperty(value = "编号", required = true, example = "1024")
  18 + @NotNull(message = "编号不能为空")
  19 + private Long id;
  20 +
  21 +}
src/main/java/cn/iocoder/dashboard/modules/system/controller/user/SysUserController.java
@@ -149,9 +149,9 @@ public class SysUserController { @@ -149,9 +149,9 @@ public class SysUserController {
149 // 手动创建导出 demo 149 // 手动创建导出 demo
150 List<SysUserImportExcelVO> list = Arrays.asList( 150 List<SysUserImportExcelVO> list = Arrays.asList(
151 SysUserImportExcelVO.builder().username("yudao").deptId(1L).email("yudao@iocoder.cn").mobile("15601691300") 151 SysUserImportExcelVO.builder().username("yudao").deptId(1L).email("yudao@iocoder.cn").mobile("15601691300")
152 - .nickname("芋道").status(CommonStatusEnum.ENABLE.getStatus()).sex(SysSexEnum.MALE.getSEX()).build(), 152 + .nickname("芋道").status(CommonStatusEnum.ENABLE.getStatus()).sex(SysSexEnum.MALE.getSex()).build(),
153 SysUserImportExcelVO.builder().username("yuanma").deptId(2L).email("yuanma@iocoder.cn").mobile("15601701300") 153 SysUserImportExcelVO.builder().username("yuanma").deptId(2L).email("yuanma@iocoder.cn").mobile("15601701300")
154 - .nickname("源码").status(CommonStatusEnum.DISABLE.getStatus()).sex(SysSexEnum.FEMALE.getSEX()).build() 154 + .nickname("源码").status(CommonStatusEnum.DISABLE.getStatus()).sex(SysSexEnum.FEMALE.getSex()).build()
155 ); 155 );
156 156
157 // 输出 157 // 输出
src/main/java/cn/iocoder/dashboard/modules/system/controller/user/vo/profile/SysUserProfileUpdateReqVO.java
@@ -3,9 +3,9 @@ package cn.iocoder.dashboard.modules.system.controller.user.vo.profile; @@ -3,9 +3,9 @@ package cn.iocoder.dashboard.modules.system.controller.user.vo.profile;
3 import io.swagger.annotations.ApiModel; 3 import io.swagger.annotations.ApiModel;
4 import io.swagger.annotations.ApiModelProperty; 4 import io.swagger.annotations.ApiModelProperty;
5 import lombok.Data; 5 import lombok.Data;
  6 +import org.hibernate.validator.constraints.Length;
6 7
7 import javax.validation.constraints.Email; 8 import javax.validation.constraints.Email;
8 -import javax.validation.constraints.Pattern;  
9 import javax.validation.constraints.Size; 9 import javax.validation.constraints.Size;
10 10
11 @ApiModel("用户个人信息更新 Request VO") 11 @ApiModel("用户个人信息更新 Request VO")
@@ -22,7 +22,7 @@ public class SysUserProfileUpdateReqVO { @@ -22,7 +22,7 @@ public class SysUserProfileUpdateReqVO {
22 private String email; 22 private String email;
23 23
24 @ApiModelProperty(value = "手机号码", example = "15601691300") 24 @ApiModelProperty(value = "手机号码", example = "15601691300")
25 - @Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$",message = "手机号码格式错误") 25 + @Length(min = 11, max = 11, message = "手机号长度必须 11 位")
26 private String mobile; 26 private String mobile;
27 27
28 @ApiModelProperty(value = "用户性别", example = "1", notes = "参见 SysSexEnum 枚举类") 28 @ApiModelProperty(value = "用户性别", example = "1", notes = "参见 SysSexEnum 枚举类")
src/main/java/cn/iocoder/dashboard/modules/system/controller/user/vo/user/SysUserBaseVO.java
@@ -2,10 +2,10 @@ package cn.iocoder.dashboard.modules.system.controller.user.vo.user; @@ -2,10 +2,10 @@ package cn.iocoder.dashboard.modules.system.controller.user.vo.user;
2 2
3 import io.swagger.annotations.ApiModelProperty; 3 import io.swagger.annotations.ApiModelProperty;
4 import lombok.Data; 4 import lombok.Data;
  5 +import org.hibernate.validator.constraints.Length;
5 6
6 import javax.validation.constraints.Email; 7 import javax.validation.constraints.Email;
7 import javax.validation.constraints.NotBlank; 8 import javax.validation.constraints.NotBlank;
8 -import javax.validation.constraints.Pattern;  
9 import javax.validation.constraints.Size; 9 import javax.validation.constraints.Size;
10 import java.util.Set; 10 import java.util.Set;
11 11
@@ -40,7 +40,7 @@ public class SysUserBaseVO { @@ -40,7 +40,7 @@ public class SysUserBaseVO {
40 private String email; 40 private String email;
41 41
42 @ApiModelProperty(value = "手机号码", example = "15601691300") 42 @ApiModelProperty(value = "手机号码", example = "15601691300")
43 - @Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$",message = "手机号码格式错误") 43 + @Length(min = 11, max = 11, message = "手机号长度必须 11 位")
44 private String mobile; 44 private String mobile;
45 45
46 @ApiModelProperty(value = "用户性别", example = "1", notes = "参见 SysSexEnum 枚举类") 46 @ApiModelProperty(value = "用户性别", example = "1", notes = "参见 SysSexEnum 枚举类")
src/main/java/cn/iocoder/dashboard/modules/system/convert/dict/SysDictDataConvert.java
@@ -13,7 +13,7 @@ public interface SysDictDataConvert { @@ -13,7 +13,7 @@ public interface SysDictDataConvert {
13 13
14 SysDictDataConvert INSTANCE = Mappers.getMapper(SysDictDataConvert.class); 14 SysDictDataConvert INSTANCE = Mappers.getMapper(SysDictDataConvert.class);
15 15
16 - List<SysDictDataSimpleVO> convertList(List<SysDictDataDO> list); 16 + List<SysDictDataSimpleRespVO> convertList(List<SysDictDataDO> list);
17 17
18 SysDictDataRespVO convert(SysDictDataDO bean); 18 SysDictDataRespVO convert(SysDictDataDO bean);
19 19
src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsChannelConvert.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.convert.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageResult;
  4 +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
  5 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelCreateReqVO;
  6 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelRespVO;
  7 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelSimpleRespVO;
  8 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelUpdateReqVO;
  9 +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
  10 +import org.mapstruct.Mapper;
  11 +import org.mapstruct.factory.Mappers;
  12 +
  13 +import java.util.List;
  14 +
  15 +/**
  16 + * 短信渠道 Convert
  17 + *
  18 + * @author 芋道源码
  19 + */
  20 +@Mapper
  21 +public interface SysSmsChannelConvert {
  22 +
  23 + SysSmsChannelConvert INSTANCE = Mappers.getMapper(SysSmsChannelConvert.class);
  24 +
  25 + SysSmsChannelDO convert(SysSmsChannelCreateReqVO bean);
  26 +
  27 + SysSmsChannelDO convert(SysSmsChannelUpdateReqVO bean);
  28 +
  29 + SysSmsChannelRespVO convert(SysSmsChannelDO bean);
  30 +
  31 + List<SysSmsChannelRespVO> convertList(List<SysSmsChannelDO> list);
  32 +
  33 + PageResult<SysSmsChannelRespVO> convertPage(PageResult<SysSmsChannelDO> page);
  34 +
  35 + List<SmsChannelProperties> convertList02(List<SysSmsChannelDO> list);
  36 +
  37 + List<SysSmsChannelSimpleRespVO> convertList03(List<SysSmsChannelDO> list);
  38 +
  39 +}
src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsLogConvert.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.convert.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageResult;
  4 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogExcelVO;
  5 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogRespVO;
  6 +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO;
  7 +import org.mapstruct.Mapper;
  8 +import org.mapstruct.factory.Mappers;
  9 +
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * 短信日志 Convert
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface SysSmsLogConvert {
  19 +
  20 + SysSmsLogConvert INSTANCE = Mappers.getMapper(SysSmsLogConvert.class);
  21 +
  22 + SysSmsLogRespVO convert(SysSmsLogDO bean);
  23 +
  24 + List<SysSmsLogRespVO> convertList(List<SysSmsLogDO> list);
  25 +
  26 + PageResult<SysSmsLogRespVO> convertPage(PageResult<SysSmsLogDO> page);
  27 +
  28 + List<SysSmsLogExcelVO> convertList02(List<SysSmsLogDO> list);
  29 +
  30 +}
src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsTemplateConvert.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.convert.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageResult;
  4 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO;
  5 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExcelVO;
  6 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateRespVO;
  7 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateUpdateReqVO;
  8 +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
  9 +import org.mapstruct.Mapper;
  10 +import org.mapstruct.factory.Mappers;
  11 +
  12 +import java.util.List;
  13 +
  14 +@Mapper
  15 +public interface SysSmsTemplateConvert {
  16 +
  17 + SysSmsTemplateConvert INSTANCE = Mappers.getMapper(SysSmsTemplateConvert.class);
  18 +
  19 + SysSmsTemplateDO convert(SysSmsTemplateCreateReqVO bean);
  20 +
  21 + SysSmsTemplateDO convert(SysSmsTemplateUpdateReqVO bean);
  22 +
  23 + SysSmsTemplateRespVO convert(SysSmsTemplateDO bean);
  24 +
  25 + List<SysSmsTemplateRespVO> convertList(List<SysSmsTemplateDO> list);
  26 +
  27 + PageResult<SysSmsTemplateRespVO> convertPage(PageResult<SysSmsTemplateDO> page);
  28 +
  29 + List<SysSmsTemplateExcelVO> convertList02(List<SysSmsTemplateDO> list);
  30 +
  31 +}
src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.dal.dataobject.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
  5 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
  6 +import com.baomidou.mybatisplus.annotation.TableName;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import lombok.ToString;
  10 +
  11 +/**
  12 + * 短信渠道 DO
  13 + *
  14 + * @author zzf
  15 + * @since 2021-01-25
  16 + */
  17 +@TableName(value = "sys_sms_channel", autoResultMap = true)
  18 +@Data
  19 +@EqualsAndHashCode(callSuper = true)
  20 +@ToString(callSuper = true)
  21 +public class SysSmsChannelDO extends BaseDO {
  22 +
  23 + /**
  24 + * 渠道编号
  25 + */
  26 + private Long id;
  27 + /**
  28 + * 短信签名
  29 + */
  30 + private String signature;
  31 + /**
  32 + * 渠道编码
  33 + *
  34 + * 枚举 {@link SmsChannelEnum}
  35 + */
  36 + private String code;
  37 + /**
  38 + * 启用状态
  39 + *
  40 + * 枚举 {@link CommonStatusEnum}
  41 + */
  42 + private Integer status;
  43 + /**
  44 + * 备注
  45 + */
  46 + private String remark;
  47 + /**
  48 + * 短信 API 的账号
  49 + */
  50 + private String apiKey;
  51 + /**
  52 + * 短信 API 的秘钥
  53 + */
  54 + private String apiSecret;
  55 + /**
  56 + * 短信发送回调 URL
  57 + */
  58 + private String callbackUrl;
  59 +
  60 +}
src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsLogDO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.dal.dataobject.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.enums.UserTypeEnum;
  4 +import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
  5 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
  6 +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsReceiveStatusEnum;
  7 +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum;
  8 +import com.baomidou.mybatisplus.annotation.TableField;
  9 +import com.baomidou.mybatisplus.annotation.TableName;
  10 +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
  11 +import lombok.*;
  12 +
  13 +import java.util.Date;
  14 +import java.util.Map;
  15 +
  16 +/**
  17 + * 短信日志 DO
  18 + *
  19 + * @author zzf
  20 + * @since 2021-01-25
  21 + */
  22 +@TableName(value = "sys_sms_log", autoResultMap = true)
  23 +@Data
  24 +@EqualsAndHashCode(callSuper = true)
  25 +@ToString(callSuper = true)
  26 +@Builder
  27 +@AllArgsConstructor
  28 +@NoArgsConstructor
  29 +public class SysSmsLogDO extends BaseDO {
  30 +
  31 + /**
  32 + * 自增编号
  33 + */
  34 + private Long id;
  35 +
  36 + // ========= 渠道相关字段 =========
  37 +
  38 + /**
  39 + * 短信渠道编号
  40 + *
  41 + * 关联 {@link SysSmsChannelDO#getId()}
  42 + */
  43 + private Long channelId;
  44 + /**
  45 + * 短信渠道编码
  46 + *
  47 + * 冗余 {@link SysSmsChannelDO#getCode()}
  48 + */
  49 + private String channelCode;
  50 +
  51 + // ========= 模板相关字段 =========
  52 +
  53 + /**
  54 + * 模板编号
  55 + *
  56 + * 关联 {@link SysSmsTemplateDO#getId()}
  57 + */
  58 + private Long templateId;
  59 + /**
  60 + * 模板编码
  61 + *
  62 + * 冗余 {@link SysSmsTemplateDO#getCode()}
  63 + */
  64 + private String templateCode;
  65 + /**
  66 + * 短信类型
  67 + *
  68 + * 冗余 {@link SysSmsTemplateDO#getType()}
  69 + */
  70 + private Integer templateType;
  71 + /**
  72 + * 基于 {@link SysSmsTemplateDO#getContent()} 格式化后的内容
  73 + */
  74 + private String templateContent;
  75 + /**
  76 + * 基于 {@link SysSmsTemplateDO#getParams()} 输入后的参数
  77 + */
  78 + @TableField(typeHandler = JacksonTypeHandler.class)
  79 + private Map<String, Object> templateParams;
  80 + /**
  81 + * 短信 API 的模板编号
  82 + *
  83 + * 冗余 {@link SysSmsTemplateDO#getApiTemplateId()}
  84 + */
  85 + private String apiTemplateId;
  86 +
  87 + // ========= 手机相关字段 =========
  88 +
  89 + /**
  90 + * 手机号
  91 + */
  92 + private String mobile;
  93 + /**
  94 + * 用户编号
  95 + */
  96 + private Long userId;
  97 + /**
  98 + * 用户类型
  99 + *
  100 + * 枚举 {@link UserTypeEnum}
  101 + */
  102 + private Integer userType;
  103 +
  104 + // ========= 发送相关字段 =========
  105 +
  106 + /**
  107 + * 发送状态
  108 + *
  109 + * 枚举 {@link SysSmsSendStatusEnum}
  110 + */
  111 + private Integer sendStatus;
  112 + /**
  113 + * 发送时间
  114 + */
  115 + private Date sendTime;
  116 + /**
  117 + * 发送结果的编码
  118 + *
  119 + * 枚举 {@link SmsFrameworkErrorCodeConstants}
  120 + */
  121 + private Integer sendCode;
  122 + /**
  123 + * 发送结果的提示
  124 + *
  125 + * 一般情况下,使用 {@link SmsFrameworkErrorCodeConstants}
  126 + * 异常情况下,通过格式化 Exception 的提示存储
  127 + */
  128 + private String sendMsg;
  129 + /**
  130 + * 短信 API 发送结果的编码
  131 + *
  132 + * 由于第三方的错误码可能是字符串,所以使用 String 类型
  133 + */
  134 + private String apiSendCode;
  135 + /**
  136 + * 短信 API 发送失败的提示
  137 + */
  138 + private String apiSendMsg;
  139 + /**
  140 + * 短信 API 发送返回的唯一请求 ID
  141 + *
  142 + * 用于和短信 API 进行定位于排错
  143 + */
  144 + private String apiRequestId;
  145 + /**
  146 + * 短信 API 发送返回的序号
  147 + *
  148 + * 用于和短信 API 平台的发送记录关联
  149 + */
  150 + private String apiSerialNo;
  151 +
  152 + // ========= 接收相关字段 =========
  153 +
  154 + /**
  155 + * 接收状态
  156 + *
  157 + * 枚举 {@link SysSmsReceiveStatusEnum}
  158 + */
  159 + private Integer receiveStatus;
  160 + /**
  161 + * 接收时间
  162 + */
  163 + private Date receiveTime;
  164 + /**
  165 + * 短信 API 接收结果的编码
  166 + */
  167 + private String apiReceiveCode;
  168 + /**
  169 + * 短信 API 接收结果的提示
  170 + */
  171 + private String apiReceiveMsg;
  172 +
  173 +}
src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.dal.dataobject.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
  5 +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsTemplateTypeEnum;
  6 +import com.baomidou.mybatisplus.annotation.TableField;
  7 +import com.baomidou.mybatisplus.annotation.TableName;
  8 +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
  9 +import lombok.Data;
  10 +import lombok.EqualsAndHashCode;
  11 +import lombok.ToString;
  12 +
  13 +import java.util.List;
  14 +
  15 +/**
  16 + * 短信模板 DO
  17 + *
  18 + * @author zzf
  19 + * @since 2021-01-25
  20 + */
  21 +@TableName(value = "sys_sms_template", autoResultMap = true)
  22 +@Data
  23 +@EqualsAndHashCode(callSuper = true)
  24 +@ToString(callSuper = true)
  25 +public class SysSmsTemplateDO extends BaseDO {
  26 +
  27 + /**
  28 + * 自增编号
  29 + */
  30 + private Long id;
  31 +
  32 + // ========= 模板相关字段 =========
  33 +
  34 + /**
  35 + * 短信类型
  36 + *
  37 + * 枚举 {@link SysSmsTemplateTypeEnum}
  38 + */
  39 + private Integer type;
  40 + /**
  41 + * 启用状态
  42 + *
  43 + * 枚举 {@link CommonStatusEnum}
  44 + */
  45 + private Integer status;
  46 + /**
  47 + * 模板编码,保证唯一
  48 + */
  49 + private String code;
  50 + /**
  51 + * 模板名称
  52 + */
  53 + private String name;
  54 + /**
  55 + * 模板内容
  56 + *
  57 + * 内容的参数,使用 {} 包括,例如说 {name}
  58 + */
  59 + private String content;
  60 + /**
  61 + * 参数数组(自动根据内容生成)
  62 + */
  63 + @TableField(typeHandler = JacksonTypeHandler.class)
  64 + private List<String> params;
  65 + /**
  66 + * 备注
  67 + */
  68 + private String remark;
  69 + /**
  70 + * 短信 API 的模板编号
  71 + */
  72 + private String apiTemplateId;
  73 +
  74 + // ========= 渠道相关字段 =========
  75 +
  76 + /**
  77 + * 短信渠道编号
  78 + *
  79 + * 关联 {@link SysSmsChannelDO#getId()}
  80 + */
  81 + private Long channelId;
  82 + /**
  83 + * 短信渠道编码
  84 + *
  85 + * 冗余 {@link SysSmsChannelDO#getCode()}
  86 + */
  87 + private String channelCode;
  88 +
  89 +}
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsChannelMapper.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.dal.mysql.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageResult;
  4 +import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX;
  6 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO;
  7 +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
  8 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +import org.apache.ibatis.annotations.Select;
  11 +
  12 +import java.util.Date;
  13 +import java.util.List;
  14 +
  15 +@Mapper
  16 +public interface SysSmsChannelMapper extends BaseMapperX<SysSmsChannelDO> {
  17 +
  18 + default PageResult<SysSmsChannelDO> selectPage(SysSmsChannelPageReqVO reqVO) {
  19 + return selectPage(reqVO, new QueryWrapperX<SysSmsChannelDO>()
  20 + .likeIfPresent("signature", reqVO.getSignature())
  21 + .eqIfPresent("status", reqVO.getStatus())
  22 + .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
  23 + .orderByDesc("id"));
  24 + }
  25 +
  26 + @Select("SELECT id FROM sys_sms_channel WHERE update_time > #{maxUpdateTime} LIMIT 1")
  27 + Long selectExistsByUpdateTimeAfter(Date maxUpdateTime);
  28 +
  29 +}
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsLogMapper.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.dal.mysql.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageResult;
  4 +import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX;
  6 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogExportReqVO;
  7 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogPageReqVO;
  8 +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +
  11 +import java.util.List;
  12 +
  13 +@Mapper
  14 +public interface SysSmsLogMapper extends BaseMapperX<SysSmsLogDO> {
  15 +
  16 + default PageResult<SysSmsLogDO> selectPage(SysSmsLogPageReqVO reqVO) {
  17 + return selectPage(reqVO, new QueryWrapperX<SysSmsLogDO>()
  18 + .eqIfPresent("channel_id", reqVO.getChannelId())
  19 + .eqIfPresent("template_id", reqVO.getTemplateId())
  20 + .likeIfPresent("mobile", reqVO.getMobile())
  21 + .eqIfPresent("send_status", reqVO.getSendStatus())
  22 + .betweenIfPresent("send_time", reqVO.getBeginSendTime(), reqVO.getEndSendTime())
  23 + .eqIfPresent("receive_status", reqVO.getReceiveStatus())
  24 + .betweenIfPresent("receive_time", reqVO.getBeginReceiveTime(), reqVO.getEndReceiveTime())
  25 + .orderByDesc("id"));
  26 + }
  27 +
  28 + default List<SysSmsLogDO> selectList(SysSmsLogExportReqVO reqVO) {
  29 + return selectList(new QueryWrapperX<SysSmsLogDO>()
  30 + .eqIfPresent("channel_id", reqVO.getChannelId())
  31 + .eqIfPresent("template_id", reqVO.getTemplateId())
  32 + .likeIfPresent("mobile", reqVO.getMobile())
  33 + .eqIfPresent("send_status", reqVO.getSendStatus())
  34 + .betweenIfPresent("send_time", reqVO.getBeginSendTime(), reqVO.getEndSendTime())
  35 + .eqIfPresent("receive_status", reqVO.getReceiveStatus())
  36 + .betweenIfPresent("receive_time", reqVO.getBeginReceiveTime(), reqVO.getEndReceiveTime())
  37 + .orderByDesc("id"));
  38 + }
  39 +
  40 +}
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsTemplateMapper.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.dal.mysql.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageResult;
  4 +import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX;
  6 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExportReqVO;
  7 +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplatePageReqVO;
  8 +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +import org.apache.ibatis.annotations.Select;
  11 +
  12 +import java.util.Date;
  13 +import java.util.List;
  14 +
  15 +@Mapper
  16 +public interface SysSmsTemplateMapper extends BaseMapperX<SysSmsTemplateDO> {
  17 +
  18 + default SysSmsTemplateDO selectByCode(String code) {
  19 + return selectOne("code", code);
  20 + }
  21 +
  22 + default PageResult<SysSmsTemplateDO> selectPage(SysSmsTemplatePageReqVO reqVO) {
  23 + return selectPage(reqVO, new QueryWrapperX<SysSmsTemplateDO>()
  24 + .eqIfPresent("type", reqVO.getType())
  25 + .eqIfPresent("status", reqVO.getStatus())
  26 + .likeIfPresent("code", reqVO.getCode())
  27 + .likeIfPresent("content", reqVO.getContent())
  28 + .likeIfPresent("api_template_id", reqVO.getApiTemplateId())
  29 + .eqIfPresent("channel_id", reqVO.getChannelId())
  30 + .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
  31 + .orderByDesc("id"));
  32 + }
  33 +
  34 + default List<SysSmsTemplateDO> selectList(SysSmsTemplateExportReqVO reqVO) {
  35 + return selectList(new QueryWrapperX<SysSmsTemplateDO>()
  36 + .eqIfPresent("type", reqVO.getType())
  37 + .eqIfPresent("status", reqVO.getStatus())
  38 + .likeIfPresent("code", reqVO.getCode())
  39 + .likeIfPresent("content", reqVO.getContent())
  40 + .likeIfPresent("api_template_id", reqVO.getApiTemplateId())
  41 + .eqIfPresent("channel_id", reqVO.getChannelId())
  42 + .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
  43 + .orderByDesc("id"));
  44 + }
  45 +
  46 + default Integer selectCountByChannelId(Long channelId) {
  47 + return selectCount("channel_id", channelId);
  48 + }
  49 +
  50 + @Select("SELECT id FROM sys_sms_template WHERE update_time > #{maxUpdateTime} LIMIT 1")
  51 + Long selectExistsByUpdateTimeAfter(Date maxUpdateTime);
  52 +
  53 +}
src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/RedisKeyConstants.java 0 → 100644
src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java
@@ -78,4 +78,18 @@ public interface SysErrorCodeConstants { @@ -78,4 +78,18 @@ public interface SysErrorCodeConstants {
78 ErrorCode FILE_UPLOAD_FAILED = new ErrorCode(1002009002, "文件上传失败"); 78 ErrorCode FILE_UPLOAD_FAILED = new ErrorCode(1002009002, "文件上传失败");
79 ErrorCode FILE_IS_EMPTY= new ErrorCode(1002009003, "文件为空"); 79 ErrorCode FILE_IS_EMPTY= new ErrorCode(1002009003, "文件为空");
80 80
  81 + // ========== 短信渠道 1002011000 ==========
  82 + ErrorCode SMS_CHANNEL_NOT_EXISTS = new ErrorCode(1002011000, "短信渠道不存在");
  83 + ErrorCode SMS_CHANNEL_DISABLE = new ErrorCode(1002011001, "短信渠道不处于开启状态,不允许选择");
  84 + ErrorCode SMS_CHANNEL_HAS_CHILDREN = new ErrorCode(1002011002, "无法删除,该短信渠道还有短信模板");
  85 +
  86 + // ========== 短信模板 1002011000 ==========
  87 + ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1002011000, "短信模板不存在");
  88 + ErrorCode SMS_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1002011001, "已经存在编码为【{}】的短信模板");
  89 +
  90 + // ========== 短信发送 1002012000 ==========
  91 + ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1002012000, "手机号不存在");
  92 + ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1002012001, "模板参数({})缺失");
  93 +
  94 +
81 } 95 }
src/main/java/cn/iocoder/dashboard/modules/system/enums/common/SysSexEnum.java
@@ -3,6 +3,11 @@ package cn.iocoder.dashboard.modules.system.enums.common; @@ -3,6 +3,11 @@ package cn.iocoder.dashboard.modules.system.enums.common;
3 import lombok.AllArgsConstructor; 3 import lombok.AllArgsConstructor;
4 import lombok.Getter; 4 import lombok.Getter;
5 5
  6 +/**
  7 + * 性别的枚举值
  8 + *
  9 + * @author 芋道源码
  10 + */
6 @Getter 11 @Getter
7 @AllArgsConstructor 12 @AllArgsConstructor
8 public enum SysSexEnum { 13 public enum SysSexEnum {
@@ -10,6 +15,9 @@ public enum SysSexEnum { @@ -10,6 +15,9 @@ public enum SysSexEnum {
10 MALE(1), // 男 15 MALE(1), // 男
11 FEMALE(2); // 女 16 FEMALE(2); // 女
12 17
13 - private final Integer SEX; 18 + /**
  19 + * 性别
  20 + */
  21 + private final Integer sex;
14 22
15 } 23 }
src/main/java/cn/iocoder/dashboard/modules/system/enums/dict/SysDictTypeEnum.java
@@ -18,6 +18,10 @@ public enum SysDictTypeEnum { @@ -18,6 +18,10 @@ public enum SysDictTypeEnum {
18 SYS_LOGIN_RESULT("sys_login_result"), // 登陆结果 18 SYS_LOGIN_RESULT("sys_login_result"), // 登陆结果
19 SYS_CONFIG_TYPE("sys_config_type"), // 参数配置类型 19 SYS_CONFIG_TYPE("sys_config_type"), // 参数配置类型
20 SYS_BOOLEAN_STRING("sys_boolean_string"), // Boolean 是否类型 20 SYS_BOOLEAN_STRING("sys_boolean_string"), // Boolean 是否类型
  21 + SYS_SMS_CHANNEL_CODE("sys_sms_channel_code"), // 短信渠道编码
  22 + SYS_SMS_TEMPLATE_TYPE("sys_sms_template_type"), // 短信模板类型
  23 + SYS_SMS_SEND_STATUS("sys_sms_send_status"), // 短信发送状态
  24 + SYS_SMS_RECEIVE_STATUS("sys_sms_receive_status"), // 短信接收状态
21 25
22 INF_REDIS_TIMEOUT_TYPE("inf_redis_timeout_type"), // Redis 超时类型 26 INF_REDIS_TIMEOUT_TYPE("inf_redis_timeout_type"), // Redis 超时类型
23 INF_JOB_STATUS("inf_job_status"), // 定时任务状态的枚举 27 INF_JOB_STATUS("inf_job_status"), // 定时任务状态的枚举
src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsReceiveStatusEnum.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.enums.sms;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 短信的接收状态枚举
  8 + *
  9 + * @author 芋道源码
  10 + * @date 2021/2/1 13:39
  11 + */
  12 +@Getter
  13 +@AllArgsConstructor
  14 +public enum SysSmsReceiveStatusEnum {
  15 +
  16 + INIT(0), // 初始化
  17 + SUCCESS(10), // 接收成功
  18 + FAILURE(20), // 接收失败
  19 + ;
  20 +
  21 + private final int status;
  22 +
  23 +}
src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendStatusEnum.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.enums.sms;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 短信的发送状态枚举
  8 + *
  9 + * @author zzf
  10 + * @date 2021/2/1 13:39
  11 + */
  12 +@Getter
  13 +@AllArgsConstructor
  14 +public enum SysSmsSendStatusEnum {
  15 +
  16 + INIT(0), // 初始化
  17 + SUCCESS(10), // 发送成功
  18 + FAILURE(20), // 发送失败
  19 + IGNORE(30), // 忽略,即不发送
  20 + ;
  21 +
  22 + private final int status;
  23 +
  24 +}
src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsTemplateTypeEnum.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.enums.sms;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 短信的模板类型枚举
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@Getter
  12 +@AllArgsConstructor
  13 +public enum SysSmsTemplateTypeEnum {
  14 +
  15 + VERIFICATION_CODE(1), // 验证码
  16 + NOTICE(2), // 通知
  17 + PROMOTION(3), // 营销
  18 + ;
  19 +
  20 + /**
  21 + * 类型
  22 + */
  23 + private final int type;
  24 +
  25 +}
src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SysSmsChannelRefreshConsumer.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.mq.consumer.sms;
  2 +
  3 +import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener;
  4 +import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsChannelRefreshMessage;
  5 +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
  6 +import lombok.extern.slf4j.Slf4j;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +import javax.annotation.Resource;
  10 +
  11 +/**
  12 + * 针对 {@link SysSmsChannelRefreshMessage} 的消费者
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Component
  17 +@Slf4j
  18 +public class SysSmsChannelRefreshConsumer extends AbstractChannelMessageListener<SysSmsChannelRefreshMessage> {
  19 +
  20 + @Resource
  21 + private SysSmsChannelService smsChannelService;
  22 +
  23 + @Override
  24 + public void onMessage(SysSmsChannelRefreshMessage message) {
  25 + log.info("[onMessage][收到 SmsChannel 刷新消息]");
  26 + smsChannelService.initSmsClients();
  27 + }
  28 +
  29 +}
src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SysSmsSendConsumer.java
@@ -2,16 +2,29 @@ package cn.iocoder.dashboard.modules.system.mq.consumer.sms; @@ -2,16 +2,29 @@ package cn.iocoder.dashboard.modules.system.mq.consumer.sms;
2 2
3 import cn.iocoder.dashboard.framework.redis.core.stream.AbstractStreamMessageListener; 3 import cn.iocoder.dashboard.framework.redis.core.stream.AbstractStreamMessageListener;
4 import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; 4 import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage;
  5 +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService;
5 import lombok.extern.slf4j.Slf4j; 6 import lombok.extern.slf4j.Slf4j;
6 import org.springframework.stereotype.Component; 7 import org.springframework.stereotype.Component;
7 8
  9 +import javax.annotation.Resource;
  10 +
  11 +/**
  12 + * 针对 {@link SysSmsSendMessage} 的消费者
  13 + *
  14 + * @author zzf
  15 + * @date 2021/3/9 16:35
  16 + */
8 @Component 17 @Component
9 @Slf4j 18 @Slf4j
10 public class SysSmsSendConsumer extends AbstractStreamMessageListener<SysSmsSendMessage> { 19 public class SysSmsSendConsumer extends AbstractStreamMessageListener<SysSmsSendMessage> {
11 20
  21 + @Resource
  22 + private SysSmsService smsService;
  23 +
12 @Override 24 @Override
13 public void onMessage(SysSmsSendMessage message) { 25 public void onMessage(SysSmsSendMessage message) {
14 log.info("[onMessage][消息内容({})]", message); 26 log.info("[onMessage][消息内容({})]", message);
  27 + smsService.doSendSms(message);
15 } 28 }
16 29
17 } 30 }
src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SysSmsTemplateRefreshConsumer.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.mq.consumer.sms;
  2 +
  3 +import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener;
  4 +import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsTemplateRefreshMessage;
  5 +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService;
  6 +import lombok.extern.slf4j.Slf4j;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +import javax.annotation.Resource;
  10 +
  11 +/**
  12 + * 针对 {@link SysSmsTemplateRefreshMessage} 的消费者
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Component
  17 +@Slf4j
  18 +public class SysSmsTemplateRefreshConsumer extends AbstractChannelMessageListener<SysSmsTemplateRefreshMessage> {
  19 +
  20 + @Resource
  21 + private SysSmsTemplateService smsTemplateService;
  22 +
  23 + @Override
  24 + public void onMessage(SysSmsTemplateRefreshMessage message) {
  25 + log.info("[onMessage][收到 SmsTemplate 刷新消息]");
  26 + smsTemplateService.initLocalCache();
  27 + }
  28 +
  29 +}