Commit e62495f65076dde537b559b6b39a1fc9eaa0eedd
Merge branch 'master' of https://gitee.com/zhijiantianya/ruoyi-vue-pro
Showing
141 changed files
with
8690 additions
and
185 deletions
Too many changes.
To preserve performance only 100 of 141 files are displayed.
pom.xml
| ... | ... | @@ -46,6 +46,7 @@ |
| 46 | 46 | <easyexcel.verion>2.2.7</easyexcel.verion> |
| 47 | 47 | <velocity.version>2.2</velocity.version> |
| 48 | 48 | <screw.version>1.0.5</screw.version> |
| 49 | + <!-- 三方云服务相关 --> | |
| 49 | 50 | </properties> |
| 50 | 51 | |
| 51 | 52 | <!-- 依赖声明 --> |
| ... | ... | @@ -271,6 +272,27 @@ |
| 271 | 272 | <version>${screw.version}</version> |
| 272 | 273 | </dependency> |
| 273 | 274 | |
| 275 | + <!-- 三方云服务相关 --> | |
| 276 | + | |
| 277 | + <!-- SMS SDK begin --> | |
| 278 | + <dependency> | |
| 279 | + <groupId>com.yunpian.sdk</groupId> | |
| 280 | + <artifactId>yunpian-java-sdk</artifactId> | |
| 281 | + <version>1.2.7</version> | |
| 282 | + </dependency> | |
| 283 | + | |
| 284 | + <dependency> | |
| 285 | + <groupId>com.aliyun</groupId> | |
| 286 | + <artifactId>aliyun-java-sdk-core</artifactId> | |
| 287 | + <version>4.5.18</version> | |
| 288 | + </dependency> | |
| 289 | + <dependency> | |
| 290 | + <groupId>com.aliyun</groupId> | |
| 291 | + <artifactId>aliyun-java-sdk-dysmsapi</artifactId> | |
| 292 | + <version>2.1.0</version> | |
| 293 | + </dependency> | |
| 294 | + <!-- SMS SDK end --> | |
| 295 | + | |
| 274 | 296 | </dependencies> |
| 275 | 297 | |
| 276 | 298 | ... | ... |
ruoyi-ui/.env.demo1024
0 → 100644
ruoyi-ui/package.json
| ... | ... | @@ -8,6 +8,7 @@ |
| 8 | 8 | "dev": "vue-cli-service serve", |
| 9 | 9 | "build:prod": "vue-cli-service build", |
| 10 | 10 | "build:stage": "vue-cli-service build --mode staging", |
| 11 | + "build:demo1024": "vue-cli-service build --mode demo1024", | |
| 11 | 12 | "preview": "node build/index.js --preview", |
| 12 | 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 | 17 | SYS_OPERATE_TYPE: 'sys_operate_type', |
| 18 | 18 | SYS_LOGIN_RESULT: 'sys_login_result', |
| 19 | 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 | 25 | INF_REDIS_TIMEOUT_TYPE: 'inf_redis_timeout_type', |
| 22 | 26 | INF_JOB_STATUS: 'inf_job_status', | ... | ... |
ruoyi-ui/src/views/system/operatelog/index.vue
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> | ... | ... |
sql/ruoyi-vue-pro.sql
| 1 | 1 | /* |
| 2 | 2 | Navicat Premium Data Transfer |
| 3 | 3 | |
| 4 | - Source Server : 127.0.0.1 | |
| 4 | + Source Server : local-mysql001 | |
| 5 | 5 | Source Server Type : MySQL |
| 6 | 6 | Source Server Version : 50718 |
| 7 | 7 | Source Host : localhost:3306 |
| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | Target Server Version : 50718 |
| 12 | 12 | File Encoding : 65001 |
| 13 | 13 | |
| 14 | - Date: 21/03/2021 18:53:24 | |
| 14 | + Date: 05/04/2021 23:51:38 | |
| 15 | 15 | */ |
| 16 | 16 | |
| 17 | 17 | SET NAMES utf8mb4; |
| ... | ... | @@ -43,7 +43,7 @@ CREATE TABLE `inf_api_access_log` ( |
| 43 | 43 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', |
| 44 | 44 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ 除', |
| 45 | 45 | PRIMARY KEY (`id`) USING BTREE |
| 46 | -) ENGINE=InnoDB AUTO_INCREMENT=1318 DEFAULT CHARSET=utf8mb4 COMMENT='API 访问日志表'; | |
| 46 | +) ENGINE=InnoDB AUTO_INCREMENT=1909 DEFAULT CHARSET=utf8mb4 COMMENT='API 访问日志表'; | |
| 47 | 47 | |
| 48 | 48 | -- ---------------------------- |
| 49 | 49 | -- Records of inf_api_access_log |
| ... | ... | @@ -84,7 +84,7 @@ CREATE TABLE `inf_api_error_log` ( |
| 84 | 84 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', |
| 85 | 85 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ 除', |
| 86 | 86 | PRIMARY KEY (`id`) USING BTREE |
| 87 | -) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='系统异常日志'; | |
| 87 | +) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COMMENT='系统异常日志'; | |
| 88 | 88 | |
| 89 | 89 | -- ---------------------------- |
| 90 | 90 | -- Records of inf_api_error_log |
| ... | ... | @@ -201,7 +201,7 @@ CREATE TABLE `inf_job_log` ( |
| 201 | 201 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', |
| 202 | 202 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ 除', |
| 203 | 203 | PRIMARY KEY (`id`) USING BTREE |
| 204 | -) ENGINE=InnoDB AUTO_INCREMENT=627 DEFAULT CHARSET=utf8mb4 COMMENT='定时任务日志表'; | |
| 204 | +) ENGINE=InnoDB AUTO_INCREMENT=1035 DEFAULT CHARSET=utf8mb4 COMMENT='定时任务日志表'; | |
| 205 | 205 | |
| 206 | 206 | -- ---------------------------- |
| 207 | 207 | -- Records of inf_job_log |
| ... | ... | @@ -264,7 +264,7 @@ CREATE TABLE `sys_dict_data` ( |
| 264 | 264 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', |
| 265 | 265 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ 除', |
| 266 | 266 | PRIMARY KEY (`id`) USING BTREE |
| 267 | -) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8mb4 COMMENT='å—典数æ®è¡¨'; | |
| 267 | +) ENGINE=InnoDB AUTO_INCREMENT=70 DEFAULT CHARSET=utf8mb4 COMMENT='å—典数æ®è¡¨'; | |
| 268 | 268 | |
| 269 | 269 | -- ---------------------------- |
| 270 | 270 | -- Records of sys_dict_data |
| ... | ... | @@ -324,6 +324,11 @@ INSERT INTO `sys_dict_data` VALUES (61, 2, '管ç†å‘˜', '2', 'user_type', 0, NUL |
| 324 | 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 | 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 | 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, 0, '云片', 'YUN_PIAN', 'sys_sms_channel_code', 0, NULL, '1', '2021-04-05 01:05:14', '1', '2021-04-05 01:05:14', b'0'); | |
| 328 | +INSERT INTO `sys_dict_data` VALUES (66, 0, '阿里云', 'ALIYUN', 'sys_sms_channel_code', 0, NULL, '1', '2021-04-05 01:05:26', '1', '2021-04-05 01:05:26', 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'); | |
| 327 | 332 | COMMIT; |
| 328 | 333 | |
| 329 | 334 | -- ---------------------------- |
| ... | ... | @@ -343,7 +348,7 @@ CREATE TABLE `sys_dict_type` ( |
| 343 | 348 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ 除', |
| 344 | 349 | PRIMARY KEY (`id`) USING BTREE, |
| 345 | 350 | UNIQUE KEY `dict_type` (`type`) |
| 346 | -) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8mb4 COMMENT='å—典类型表'; | |
| 351 | +) ENGINE=InnoDB AUTO_INCREMENT=113 DEFAULT CHARSET=utf8mb4 COMMENT='å—典类型表'; | |
| 347 | 352 | |
| 348 | 353 | -- ---------------------------- |
| 349 | 354 | -- Records of sys_dict_type |
| ... | ... | @@ -366,6 +371,8 @@ INSERT INTO `sys_dict_type` VALUES (107, '定时任务状æ€', 'inf_job_status', |
| 366 | 371 | 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 | 372 | 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 | 373 | 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'); |
| 374 | +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'); | |
| 375 | +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'); | |
| 369 | 376 | COMMIT; |
| 370 | 377 | |
| 371 | 378 | -- ---------------------------- |
| ... | ... | @@ -386,7 +393,7 @@ CREATE TABLE `sys_login_log` ( |
| 386 | 393 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', |
| 387 | 394 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ 除', |
| 388 | 395 | PRIMARY KEY (`id`) USING BTREE |
| 389 | -) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COMMENT='系统访问记录'; | |
| 396 | +) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8mb4 COMMENT='系统访问记录'; | |
| 390 | 397 | |
| 391 | 398 | -- ---------------------------- |
| 392 | 399 | -- Records of sys_login_log |
| ... | ... | @@ -415,7 +422,7 @@ CREATE TABLE `sys_menu` ( |
| 415 | 422 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', |
| 416 | 423 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ 除', |
| 417 | 424 | PRIMARY KEY (`id`) USING BTREE |
| 418 | -) ENGINE=InnoDB AUTO_INCREMENT=1093 DEFAULT CHARSET=utf8mb4 COMMENT='èœå•æƒé™è¡¨'; | |
| 425 | +) ENGINE=InnoDB AUTO_INCREMENT=1100 DEFAULT CHARSET=utf8mb4 COMMENT='èœå•æƒé™è¡¨'; | |
| 419 | 426 | |
| 420 | 427 | -- ---------------------------- |
| 421 | 428 | -- Records of sys_menu |
| ... | ... | @@ -530,6 +537,12 @@ INSERT INTO `sys_menu` VALUES (1089, '日志查询', 'infra:api-error-log:query' |
| 530 | 537 | 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 | 538 | 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 | 539 | 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'); |
| 540 | +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'); | |
| 541 | +INSERT INTO `sys_menu` VALUES (1094, 'çŸä¿¡æ¸ é“', '', 2, 0, 1093, 'sms-channel', '', 'system/sms/smsChannel', 0, '', '2021-04-01 11:07:15', '1', '2021-04-05 20:32:53', b'0'); | |
| 542 | +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'); | |
| 543 | +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'); | |
| 544 | +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'); | |
| 545 | +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'); | |
| 533 | 546 | COMMIT; |
| 534 | 547 | |
| 535 | 548 | -- ---------------------------- |
| ... | ... | @@ -589,7 +602,7 @@ CREATE TABLE `sys_operate_log` ( |
| 589 | 602 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', |
| 590 | 603 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ 除', |
| 591 | 604 | PRIMARY KEY (`id`) USING BTREE |
| 592 | -) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8mb4 COMMENT='æ“作日志记录'; | |
| 605 | +) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8mb4 COMMENT='æ“作日志记录'; | |
| 593 | 606 | |
| 594 | 607 | -- ---------------------------- |
| 595 | 608 | -- Records of sys_operate_log |
| ... | ... | @@ -835,6 +848,118 @@ INSERT INTO `sys_role_menu` VALUES (238, 101, 1065, '', '2021-01-21 03:23:27', ' |
| 835 | 848 | COMMIT; |
| 836 | 849 | |
| 837 | 850 | -- ---------------------------- |
| 851 | +-- Table structure for sys_sms_channel | |
| 852 | +-- ---------------------------- | |
| 853 | +DROP TABLE IF EXISTS `sys_sms_channel`; | |
| 854 | +CREATE TABLE `sys_sms_channel` ( | |
| 855 | + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ç¼–å·', | |
| 856 | + `signature` varchar(10) NOT NULL COMMENT 'çŸä¿¡ç¾å', | |
| 857 | + `code` varchar(63) NOT NULL COMMENT 'æ¸ é“ç¼–ç ', | |
| 858 | + `status` tinyint(4) NOT NULL COMMENT 'å¼€å¯çжæ€', | |
| 859 | + `remark` varchar(255) DEFAULT NULL COMMENT '备注', | |
| 860 | + `api_key` varchar(63) NOT NULL COMMENT 'çŸä¿¡ API 的账å·', | |
| 861 | + `api_secret` varchar(63) DEFAULT NULL COMMENT 'çŸä¿¡ API 的秘钥', | |
| 862 | + `callback_url` varchar(255) DEFAULT NULL COMMENT 'çŸä¿¡å‘é€å›žè°ƒ URL', | |
| 863 | + `creator` varchar(64) DEFAULT '' COMMENT '创建者', | |
| 864 | + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', | |
| 865 | + `updater` varchar(64) DEFAULT '' COMMENT '更新者', | |
| 866 | + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', | |
| 867 | + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ 除', | |
| 868 | + PRIMARY KEY (`id`) USING BTREE | |
| 869 | +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='çŸä¿¡æ¸ é“'; | |
| 870 | + | |
| 871 | +-- ---------------------------- | |
| 872 | +-- Records of sys_sms_channel | |
| 873 | +-- ---------------------------- | |
| 874 | +BEGIN; | |
| 875 | +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-05 21:02:38', b'0'); | |
| 876 | +INSERT INTO `sys_sms_channel` VALUES (2, 'Ballcat', 'ALIYUN', 0, '啦啦啦', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, '', '2021-03-31 11:53:10', '1', '2021-04-05 21:02:44', b'0'); | |
| 877 | +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-05 21:10:34', b'0'); | |
| 878 | +COMMIT; | |
| 879 | + | |
| 880 | +-- ---------------------------- | |
| 881 | +-- Table structure for sys_sms_log | |
| 882 | +-- ---------------------------- | |
| 883 | +DROP TABLE IF EXISTS `sys_sms_log`; | |
| 884 | +CREATE TABLE `sys_sms_log` ( | |
| 885 | + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ç¼–å·', | |
| 886 | + `channel_id` bigint(20) NOT NULL COMMENT 'çŸä¿¡æ¸ é“ç¼–å·', | |
| 887 | + `channel_code` varchar(63) NOT NULL COMMENT 'çŸä¿¡æ¸ é“ç¼–ç ', | |
| 888 | + `template_id` bigint(20) NOT NULL COMMENT '模æ¿ç¼–å·', | |
| 889 | + `template_code` varchar(63) NOT NULL COMMENT '模æ¿ç¼–ç ', | |
| 890 | + `template_type` tinyint(4) NOT NULL COMMENT 'çŸä¿¡ç±»åž‹', | |
| 891 | + `template_content` varchar(255) NOT NULL COMMENT 'çŸä¿¡å†…容', | |
| 892 | + `template_params` varchar(255) NOT NULL COMMENT 'çŸä¿¡å‚æ•°', | |
| 893 | + `api_template_id` varchar(63) NOT NULL COMMENT 'çŸä¿¡ API 的模æ¿ç¼–å·', | |
| 894 | + `mobile` varchar(11) NOT NULL COMMENT '手机å·', | |
| 895 | + `user_id` bigint(20) DEFAULT '0' COMMENT '用户编å·', | |
| 896 | + `user_type` tinyint(4) DEFAULT '0' COMMENT '用户类型', | |
| 897 | + `send_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'å‘é€çжæ€', | |
| 898 | + `send_time` datetime DEFAULT NULL COMMENT 'å‘逿—¶é—´', | |
| 899 | + `send_code` int(11) DEFAULT NULL COMMENT 'å‘é€ç»“果的编ç ', | |
| 900 | + `send_msg` varchar(255) DEFAULT NULL COMMENT 'å‘é€ç»“果的æç¤º', | |
| 901 | + `api_send_code` varchar(63) DEFAULT NULL COMMENT 'çŸä¿¡ API å‘é€ç»“果的编ç ', | |
| 902 | + `api_send_msg` varchar(255) DEFAULT NULL COMMENT 'çŸä¿¡ API å‘é€å¤±è´¥çš„æç¤º', | |
| 903 | + `api_request_id` varchar(255) DEFAULT NULL COMMENT 'çŸä¿¡ API å‘é€è¿”回的唯一请求 ID', | |
| 904 | + `api_serial_no` varchar(255) DEFAULT NULL COMMENT 'çŸä¿¡ API å‘é€è¿”回的åºå·', | |
| 905 | + `receive_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '接收状æ€', | |
| 906 | + `receive_time` datetime DEFAULT NULL COMMENT '接收时间', | |
| 907 | + `api_receive_code` varchar(63) DEFAULT NULL COMMENT 'API 接收结果的编ç ', | |
| 908 | + `api_receive_msg` varchar(255) DEFAULT NULL COMMENT 'API 接收结果的说明', | |
| 909 | + `creator` varchar(64) DEFAULT '' COMMENT '创建者', | |
| 910 | + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', | |
| 911 | + `updater` varchar(64) DEFAULT '' COMMENT '更新者', | |
| 912 | + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', | |
| 913 | + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ 除', | |
| 914 | + PRIMARY KEY (`id`) USING BTREE | |
| 915 | +) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4 COMMENT='çŸä¿¡moan'; | |
| 916 | + | |
| 917 | +-- ---------------------------- | |
| 918 | +-- Records of sys_sms_log | |
| 919 | +-- ---------------------------- | |
| 920 | +BEGIN; | |
| 921 | +INSERT INTO `sys_sms_log` VALUES (15, 1, 'YUN_PIAN', 2, 'test_01', 1, 'æ£åœ¨è¿›è¡Œç™»å½•æ“作登陆,您的验è¯ç 是1234', '{\"code\":\"1234\",\"operation\":\"登陆\"}', '4383920', '15601691399', 1, 2, 10, '2021-04-04 23:24:13', 0, 'æˆåŠŸ', '0', 'å‘逿ˆåŠŸ', NULL, '62922707786', 10, '2021-04-04 23:24:26', 'DELIVRD', 'DELIVRD', NULL, '2021-04-04 23:23:29', NULL, '2021-04-04 23:25:17', b'0'); | |
| 922 | +INSERT INTO `sys_sms_log` VALUES (16, 2, 'ALIYUN', 3, 'test_02', 1, '您的验è¯ç 1234,该验è¯ç 5分钟内有效,请勿泄æ¼äºŽä»–人ï¼', '{\"code\":\"1234\"}', 'SMS_207945135', '15601691399', 1, 2, 20, '2021-04-05 00:08:39', 999, '未知错误,需è¦è§£æž', 'SDK.InvalidAccessKeySecret', 'SDK.InvalidAccessKeySecret : Specified Access Key Secret is not valid.\r\nRequestId : 2EA9C6A5-579F-4D21-B7D3-0AD3BA4F7741', '2EA9C6A5-579F-4D21-B7D3-0AD3BA4F7741', NULL, 0, NULL, NULL, NULL, NULL, '2021-04-05 00:08:39', NULL, '2021-04-05 00:08:39', b'0'); | |
| 923 | +INSERT INTO `sys_sms_log` VALUES (17, 2, 'ALIYUN', 3, 'test_02', 1, '您的验è¯ç 1234,该验è¯ç 5分钟内有效,请勿泄æ¼äºŽä»–人ï¼', '{\"code\":\"1234\"}', 'SMS_207945135', '15601691399', 1, 2, 20, '2021-04-05 00:09:43', 999, '未知错误,需è¦è§£æž', 'SDK.InvalidAccessKeySecret', 'SDK.InvalidAccessKeySecret : Specified Access Key Secret is not valid.\r\nRequestId : BF766164-9C03-44FD-B6D3-ADA74118E432', 'BF766164-9C03-44FD-B6D3-ADA74118E432', NULL, 0, NULL, NULL, NULL, NULL, '2021-04-05 00:09:43', NULL, '2021-04-05 00:09:43', b'0'); | |
| 924 | +INSERT INTO `sys_sms_log` VALUES (18, 2, 'ALIYUN', 3, 'test_02', 1, '您的验è¯ç 1234,该验è¯ç 5分钟内有效,请勿泄æ¼äºŽä»–人ï¼', '{\"code\":\"1234\"}', 'SMS_207945135', '15601691399', 1, 2, 20, '2021-04-05 00:11:13', 999, '未知错误,需è¦è§£æž', 'SDK.InvalidAccessKeySecret', 'SDK.InvalidAccessKeySecret : Specified Access Key Secret is not valid.\r\nRequestId : 2D7C0ABC-7538-45B4-BFEF-B610D591CE3D', '2D7C0ABC-7538-45B4-BFEF-B610D591CE3D', NULL, 0, NULL, NULL, NULL, NULL, '2021-04-05 00:11:12', NULL, '2021-04-05 00:11:13', b'0'); | |
| 925 | +INSERT INTO `sys_sms_log` VALUES (19, 2, 'ALIYUN', 3, 'test_02', 1, '您的验è¯ç 1234,该验è¯ç 5分钟内有效,请勿泄æ¼äºŽä»–人ï¼', '{\"code\":\"1234\"}', 'SMS_207945135', '15601691399', 1, 2, 20, '2021-04-05 00:12:21', 999, '未知错误,需è¦è§£æž', 'SDK.InvalidAccessKeySecret', 'SDK.InvalidAccessKeySecret : Specified Access Key Secret is not valid.\r\nRequestId : 0A86DC5C-2985-474F-B076-748C9F2C5D3F', '0A86DC5C-2985-474F-B076-748C9F2C5D3F', NULL, 0, NULL, NULL, NULL, NULL, '2021-04-05 00:12:01', NULL, '2021-04-05 00:12:21', b'0'); | |
| 926 | +INSERT INTO `sys_sms_log` VALUES (20, 1, 'YUN_PIAN', 2, 'test_01', 1, 'æ£åœ¨è¿›è¡Œç™»å½•æ“作登陆,您的验è¯ç 是1234', '{\"code\":\"1234\",\"operation\":\"登陆\"}', '4383920', '15601691399', 1, 2, 10, '2021-04-05 00:14:36', 0, 'æˆåŠŸ', '0', 'å‘逿ˆåŠŸ', NULL, '62923244790', 0, NULL, NULL, NULL, NULL, '2021-04-05 00:13:42', NULL, '2021-04-05 00:14:36', b'0'); | |
| 927 | +INSERT INTO `sys_sms_log` VALUES (21, 2, 'ALIYUN', 3, 'test_02', 1, '您的验è¯ç 1234,该验è¯ç 5分钟内有效,请勿泄æ¼äºŽä»–人ï¼', '{\"code\":\"1234\"}', 'SMS_207945135', '15601691399', 1, 2, 20, '2021-04-05 00:19:43', 999, '未知错误,需è¦è§£æž', 'SDK.InvalidAccessKeySecret', 'SDK.InvalidAccessKeySecret : Specified Access Key Secret is not valid.\r\nRequestId : 3837C6D3-B96F-428C-BBB2-86135D4B5B99', '3837C6D3-B96F-428C-BBB2-86135D4B5B99', NULL, 0, NULL, NULL, NULL, NULL, '2021-04-05 00:15:06', NULL, '2021-04-05 00:19:44', b'0'); | |
| 928 | +COMMIT; | |
| 929 | + | |
| 930 | +-- ---------------------------- | |
| 931 | +-- Table structure for sys_sms_template | |
| 932 | +-- ---------------------------- | |
| 933 | +DROP TABLE IF EXISTS `sys_sms_template`; | |
| 934 | +CREATE TABLE `sys_sms_template` ( | |
| 935 | + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ç¼–å·', | |
| 936 | + `type` tinyint(4) NOT NULL COMMENT 'çŸä¿¡ç¾å', | |
| 937 | + `status` tinyint(4) NOT NULL COMMENT 'å¼€å¯çжæ€', | |
| 938 | + `code` varchar(63) NOT NULL COMMENT '模æ¿ç¼–ç ', | |
| 939 | + `name` varchar(63) NOT NULL COMMENT '模æ¿åç§°', | |
| 940 | + `content` varchar(255) NOT NULL COMMENT '模æ¿å†…容', | |
| 941 | + `params` varchar(255) NOT NULL COMMENT '傿•°æ•°ç»„', | |
| 942 | + `remark` varchar(255) DEFAULT NULL COMMENT '备注', | |
| 943 | + `api_template_id` varchar(63) NOT NULL COMMENT 'çŸä¿¡ API 的模æ¿ç¼–å·', | |
| 944 | + `channel_id` bigint(20) NOT NULL COMMENT 'çŸä¿¡æ¸ é“ç¼–å·', | |
| 945 | + `channel_code` varchar(63) NOT NULL COMMENT 'çŸä¿¡æ¸ é“ç¼–ç ', | |
| 946 | + `creator` varchar(64) DEFAULT '' COMMENT '创建者', | |
| 947 | + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', | |
| 948 | + `updater` varchar(64) DEFAULT '' COMMENT '更新者', | |
| 949 | + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', | |
| 950 | + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ 除', | |
| 951 | + PRIMARY KEY (`id`) USING BTREE | |
| 952 | +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='çŸä¿¡æ¨¡æ¿'; | |
| 953 | + | |
| 954 | +-- ---------------------------- | |
| 955 | +-- Records of sys_sms_template | |
| 956 | +-- ---------------------------- | |
| 957 | +BEGIN; | |
| 958 | +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', '', '2021-03-31 12:01:38', b'0'); | |
| 959 | +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', '', '2021-03-31 11:56:30', b'0'); | |
| 960 | +COMMIT; | |
| 961 | + | |
| 962 | +-- ---------------------------- | |
| 838 | 963 | -- Table structure for sys_user |
| 839 | 964 | -- ---------------------------- |
| 840 | 965 | DROP TABLE IF EXISTS `sys_user`; |
| ... | ... | @@ -865,8 +990,8 @@ CREATE TABLE `sys_user` ( |
| 865 | 990 | -- Records of sys_user |
| 866 | 991 | -- ---------------------------- |
| 867 | 992 | 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'); | |
| 993 | +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'); | |
| 994 | +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 | 995 | 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 | 996 | 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 | 997 | 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,11 +1049,17 @@ CREATE TABLE `sys_user_session` ( |
| 924 | 1049 | -- Records of sys_user_session |
| 925 | 1050 | -- ---------------------------- |
| 926 | 1051 | BEGIN; |
| 1052 | +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'); | |
| 1053 | +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'); | |
| 1054 | +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-05 22:23:22', b'0'); | |
| 1055 | +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'); | |
| 927 | 1056 | 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'); |
| 928 | 1057 | 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'); |
| 1058 | +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 | 1059 | 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'); |
| 930 | 1060 | 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'); | |
| 1061 | +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'); | |
| 1062 | +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 | 1063 | 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 | 1064 | 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'); |
| 934 | 1065 | 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'); |
| ... | ... | @@ -964,7 +1095,7 @@ CREATE TABLE `tool_codegen_column` ( |
| 964 | 1095 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', |
| 965 | 1096 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ 除', |
| 966 | 1097 | PRIMARY KEY (`id`) USING BTREE |
| 967 | -) ENGINE=InnoDB AUTO_INCREMENT=389 DEFAULT CHARSET=utf8mb4 COMMENT='代ç 生æˆè¡¨å—段定义'; | |
| 1098 | +) ENGINE=InnoDB AUTO_INCREMENT=418 DEFAULT CHARSET=utf8mb4 COMMENT='代ç 生æˆè¡¨å—段定义'; | |
| 968 | 1099 | |
| 969 | 1100 | -- ---------------------------- |
| 970 | 1101 | -- Records of tool_codegen_column |
| ... | ... | @@ -1126,6 +1257,35 @@ INSERT INTO `tool_codegen_column` VALUES (385, 33, 'create_time', 'datetime', 'å |
| 1126 | 1257 | 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 | 1258 | 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 | 1259 | 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'); |
| 1260 | +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'); | |
| 1261 | +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'); | |
| 1262 | +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'); | |
| 1263 | +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'); | |
| 1264 | +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'); | |
| 1265 | +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'); | |
| 1266 | +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'); | |
| 1267 | +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'); | |
| 1268 | +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'); | |
| 1269 | +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'); | |
| 1270 | +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'); | |
| 1271 | +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'); | |
| 1272 | +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'); | |
| 1273 | +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'); | |
| 1274 | +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'); | |
| 1275 | +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'); | |
| 1276 | +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'); | |
| 1277 | +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'); | |
| 1278 | +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'); | |
| 1279 | +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'); | |
| 1280 | +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'); | |
| 1281 | +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'); | |
| 1282 | +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'); | |
| 1283 | +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'); | |
| 1284 | +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'); | |
| 1285 | +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'); | |
| 1286 | +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'); | |
| 1287 | +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'); | |
| 1288 | +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'); | |
| 1129 | 1289 | COMMIT; |
| 1130 | 1290 | |
| 1131 | 1291 | -- ---------------------------- |
| ... | ... | @@ -1151,7 +1311,7 @@ CREATE TABLE `tool_codegen_table` ( |
| 1151 | 1311 | `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´', |
| 1152 | 1312 | `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ 除', |
| 1153 | 1313 | PRIMARY KEY (`id`) USING BTREE |
| 1154 | -) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8mb4 COMMENT='代ç 生æˆè¡¨å®šä¹‰'; | |
| 1314 | +) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COMMENT='代ç 生æˆè¡¨å®šä¹‰'; | |
| 1155 | 1315 | |
| 1156 | 1316 | -- ---------------------------- |
| 1157 | 1317 | -- Records of tool_codegen_table |
| ... | ... | @@ -1169,6 +1329,8 @@ INSERT INTO `tool_codegen_table` VALUES (28, 1, 'sys_dict_type', 'å—å…¸ç±»åž‹è¡ |
| 1169 | 1329 | 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 | 1330 | 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 | 1331 | 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'); |
| 1332 | +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'); | |
| 1333 | +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'); | |
| 1172 | 1334 | COMMIT; |
| 1173 | 1335 | |
| 1174 | 1336 | -- ---------------------------- | ... | ... |
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 | 1 | package cn.iocoder.dashboard.common.exception; |
| 2 | 2 | |
| 3 | +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants; | |
| 3 | 4 | import cn.iocoder.dashboard.common.exception.enums.ServiceErrorCodeRange; |
| 4 | 5 | import lombok.Data; |
| 5 | 6 | |
| 6 | 7 | /** |
| 7 | 8 | * 错误码对象 |
| 8 | 9 | * |
| 9 | - * 全局错误码,占用 [0, 999],参见 {@link GlobalException} | |
| 10 | + * 全局错误码,占用 [0, 999], 参见 {@link GlobalErrorCodeConstants} | |
| 10 | 11 | * 业务异常错误码,占用 [1 000 000 000, +∞),参见 {@link ServiceErrorCodeRange} |
| 11 | 12 | * |
| 12 | 13 | * TODO 错误码设计成对象的原因,为未来的 i18 国际化做准备 |
| ... | ... | @@ -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 | 27 | public ErrorCode(Integer code, String message) { |
| 27 | 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 | 30 | |
| 31 | 31 | public ServiceException(ErrorCode errorCode) { |
| 32 | 32 | this.code = errorCode.getCode(); |
| 33 | - this.message = errorCode.getMessage(); | |
| 33 | + this.message = errorCode.getMsg(); | |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | 36 | public ServiceException(Integer code, String message) { | ... | ... |
src/main/java/cn/iocoder/dashboard/common/exception/util/ServiceExceptionUtil.java
| ... | ... | @@ -47,12 +47,12 @@ public class ServiceExceptionUtil { |
| 47 | 47 | // ========== 和 ServiceException 的集成 ========== |
| 48 | 48 | |
| 49 | 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 | 51 | return exception0(errorCode.getCode(), messagePattern); |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | 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 | 56 | return exception0(errorCode.getCode(), messagePattern, params); |
| 57 | 57 | } |
| 58 | 58 | ... | ... |
src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java
| 1 | 1 | package cn.iocoder.dashboard.common.pojo; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.dashboard.common.exception.ErrorCode; |
| 4 | -import cn.iocoder.dashboard.common.exception.GlobalException; | |
| 5 | 4 | import cn.iocoder.dashboard.common.exception.ServiceException; |
| 6 | 5 | import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants; |
| 7 | 6 | import com.fasterxml.jackson.annotation.JsonIgnore; |
| ... | ... | @@ -9,6 +8,7 @@ import lombok.Data; |
| 9 | 8 | import org.springframework.util.Assert; |
| 10 | 9 | |
| 11 | 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 | 16 | * @param <T> 数据泛型 |
| 17 | 17 | */ |
| 18 | 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<T> implements Serializable { |
| 31 | 31 | /** |
| 32 | 32 | * 错误提示,用户可阅读 |
| 33 | 33 | * |
| 34 | - * @see ErrorCode#getMessage() () | |
| 34 | + * @see ErrorCode#getMsg() () | |
| 35 | 35 | */ |
| 36 | 36 | private String msg; |
| 37 | 37 | |
| ... | ... | @@ -57,7 +57,7 @@ public final class CommonResult<T> implements Serializable { |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | 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 | 63 | public static <T> CommonResult<T> success(T data) { |
| ... | ... | @@ -68,9 +68,13 @@ public final class CommonResult<T> implements Serializable { |
| 68 | 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 | 75 | @JsonIgnore // 避免 jackson 序列化 |
| 72 | 76 | public boolean isSuccess() { |
| 73 | - return GlobalErrorCodeConstants.SUCCESS.getCode().equals(code); | |
| 77 | + return isSuccess(code); | |
| 74 | 78 | } |
| 75 | 79 | |
| 76 | 80 | @JsonIgnore // 避免 jackson 序列化 |
| ... | ... | @@ -81,16 +85,12 @@ public final class CommonResult<T> implements Serializable { |
| 81 | 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 | 91 | if (isSuccess()) { |
| 88 | 92 | return; |
| 89 | 93 | } |
| 90 | - // 全局异常 | |
| 91 | - if (GlobalErrorCodeConstants.isMatch(code)) { | |
| 92 | - throw new GlobalException(code, msg); | |
| 93 | - } | |
| 94 | 94 | // 业务异常 |
| 95 | 95 | throw new ServiceException(code, msg); |
| 96 | 96 | } |
| ... | ... | @@ -99,8 +99,4 @@ public final class CommonResult<T> implements Serializable { |
| 99 | 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 | 13 | import com.alibaba.excel.metadata.property.ExcelContentProperty; |
| 14 | 14 | import lombok.extern.slf4j.Slf4j; |
| 15 | 15 | |
| 16 | +/** | |
| 17 | + * Excel {@link SysDictDataDO} 数据字典转换器 | |
| 18 | + * | |
| 19 | + * @author 芋道源码 | |
| 20 | + */ | |
| 16 | 21 | @Slf4j |
| 17 | 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 | 48 | * 创建 Redis Pub/Sub 广播消费的容器 |
| 49 | 49 | */ |
| 50 | 50 | @Bean |
| 51 | - public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory factory, | |
| 52 | - List<AbstractChannelMessageListener<?>> listeners) { | |
| 51 | + public RedisMessageListenerContainer redisMessageListenerContainer( | |
| 52 | + RedisConnectionFactory factory, List<AbstractChannelMessageListener<?>> listeners) { | |
| 53 | 53 | // 创建 RedisMessageListenerContainer 对象 |
| 54 | 54 | RedisMessageListenerContainer container = new RedisMessageListenerContainer(); |
| 55 | 55 | // 设置 RedisConnection 工厂。 |
| ... | ... | @@ -69,8 +69,8 @@ public class RedisConfig { |
| 69 | 69 | * Redis Stream 的 xreadgroup 命令:https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html |
| 70 | 70 | */ |
| 71 | 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 | 74 | // 第一步,创建 StreamMessageListenerContainer 容器 |
| 75 | 75 | // 创建 options 配置 |
| 76 | 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 | 128 | // 设置每个请求的权限 |
| 129 | 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 | 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 | 138 | // Swagger 接口文档 |
| 139 | 139 | .antMatchers("/swagger-ui.html").anonymous() |
| 140 | 140 | .antMatchers("/swagger-resources/**").anonymous() |
| ... | ... | @@ -148,13 +148,19 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { |
| 148 | 148 | .antMatchers("/actuator/**").anonymous() |
| 149 | 149 | // Druid 监控 |
| 150 | 150 | .antMatchers("/druid/**").anonymous() |
| 151 | + // 短信回调 API | |
| 152 | + .antMatchers(api("/system/sms/callback/**")).anonymous() | |
| 151 | 153 | // 除上面外的所有请求全部需要鉴权认证 |
| 152 | 154 | .anyRequest().authenticated() |
| 153 | 155 | .and() |
| 154 | 156 | .headers().frameOptions().disable(); |
| 155 | - httpSecurity.logout().logoutUrl(webProperties.getApiPrefix() + "/logout").logoutSuccessHandler(logoutSuccessHandler); | |
| 157 | + httpSecurity.logout().logoutUrl(api("/logout")).logoutSuccessHandler(logoutSuccessHandler); | |
| 156 | 158 | // 添加 JWT Filter |
| 157 | 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
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×tamp=%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/core/handler/GlobalExceptionHandler.java
| ... | ... | @@ -3,7 +3,6 @@ package cn.iocoder.dashboard.framework.web.core.handler; |
| 3 | 3 | import cn.hutool.core.exceptions.ExceptionUtil; |
| 4 | 4 | import cn.hutool.core.map.MapUtil; |
| 5 | 5 | import cn.hutool.extra.servlet.ServletUtil; |
| 6 | -import cn.iocoder.dashboard.common.exception.GlobalException; | |
| 7 | 6 | import cn.iocoder.dashboard.common.exception.ServiceException; |
| 8 | 7 | import cn.iocoder.dashboard.common.pojo.CommonResult; |
| 9 | 8 | import cn.iocoder.dashboard.framework.logger.apilog.core.service.ApiErrorLogFrameworkService; |
| ... | ... | @@ -96,9 +95,6 @@ public class GlobalExceptionHandler { |
| 96 | 95 | if (ex instanceof AccessDeniedException) { |
| 97 | 96 | return accessDeniedExceptionHandler(request, (AccessDeniedException) ex); |
| 98 | 97 | } |
| 99 | - if (ex instanceof GlobalException) { | |
| 100 | - return globalExceptionHandler(request, (GlobalException) ex); | |
| 101 | - } | |
| 102 | 98 | return defaultExceptionHandler(request, ex); |
| 103 | 99 | } |
| 104 | 100 | |
| ... | ... | @@ -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 | 224 | @ExceptionHandler(value = Exception.class) |
| ... | ... | @@ -250,7 +227,7 @@ public class GlobalExceptionHandler { |
| 250 | 227 | // 插入异常日志 |
| 251 | 228 | this.createExceptionLog(req, ex); |
| 252 | 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 | 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 | 61 | @GetMapping("/list-all-simple") |
| 62 | 62 | @ApiOperation(value = "获得全部字典数据列表", notes = "一般用于管理后台缓存字典数据在本地") |
| 63 | 63 | // 无需添加权限认证,因为前端全局都需要 |
| 64 | - public CommonResult<List<SysDictDataSimpleVO>> getSimpleDictDatas() { | |
| 64 | + public CommonResult<List<SysDictDataSimpleRespVO>> getSimpleDictDatas() { | |
| 65 | 65 | List<SysDictDataDO> list = dictDataService.getDictDatas(); |
| 66 | 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 | 41 | return success(dictTypeId); |
| 42 | 42 | } |
| 43 | 43 | |
| 44 | - @PostMapping("update") | |
| 44 | + @PutMapping("/update") | |
| 45 | 45 | @ApiOperation("修改字典类型") |
| 46 | 46 | @PreAuthorize("@ss.hasPermission('system:dict:update')") |
| 47 | 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 | 4 | import io.swagger.annotations.ApiModelProperty; |
| 5 | 5 | import lombok.Data; |
| 6 | 6 | |
| 7 | -@ApiModel("数据字典精简 VO") | |
| 7 | +@ApiModel("数据字典精简 Response VO") | |
| 8 | 8 | @Data |
| 9 | -public class SysDictDataSimpleVO { | |
| 9 | +public class SysDictDataSimpleRespVO { | |
| 10 | 10 | |
| 11 | 11 | @ApiModelProperty(value = "字典类型", required = true, example = "gender") |
| 12 | 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
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/convert/dict/SysDictDataConvert.java
| ... | ... | @@ -13,7 +13,7 @@ public interface SysDictDataConvert { |
| 13 | 13 | |
| 14 | 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 | 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
| ... | ... | @@ -30,8 +30,8 @@ public interface SysErrorCodeConstants { |
| 30 | 30 | |
| 31 | 31 | // ========== 角色模块 1002003000 ========== |
| 32 | 32 | ErrorCode ROLE_NOT_EXISTS = new ErrorCode(1002003000, "角色不存在"); |
| 33 | - ErrorCode ROLE_NAME_DUPLICATE = new ErrorCode(1002003001, "已经存在名为【{}}】的角色"); | |
| 34 | - ErrorCode ROLE_CODE_DUPLICATE = new ErrorCode(1002003002, "已经存在编码为【{}}】的角色"); | |
| 33 | + ErrorCode ROLE_NAME_DUPLICATE = new ErrorCode(1002003001, "已经存在名为【{}】的角色"); | |
| 34 | + ErrorCode ROLE_CODE_DUPLICATE = new ErrorCode(1002003002, "已经存在编码为【{}】的角色"); | |
| 35 | 35 | ErrorCode ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE = new ErrorCode(1002003004, "不能操作类型为系统内置的角色"); |
| 36 | 36 | |
| 37 | 37 | // ========== 用户模块 1002004000 ========== |
| ... | ... | @@ -78,4 +78,18 @@ public interface SysErrorCodeConstants { |
| 78 | 78 | ErrorCode FILE_UPLOAD_FAILED = new ErrorCode(1002009002, "文件上传失败"); |
| 79 | 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/dict/SysDictTypeEnum.java
| ... | ... | @@ -18,6 +18,10 @@ public enum SysDictTypeEnum { |
| 18 | 18 | SYS_LOGIN_RESULT("sys_login_result"), // 登陆结果 |
| 19 | 19 | SYS_CONFIG_TYPE("sys_config_type"), // 参数配置类型 |
| 20 | 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 | 26 | INF_REDIS_TIMEOUT_TYPE("inf_redis_timeout_type"), // Redis 超时类型 |
| 23 | 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 | 2 | |
| 3 | 3 | import cn.iocoder.dashboard.framework.redis.core.stream.AbstractStreamMessageListener; |
| 4 | 4 | import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; |
| 5 | +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; | |
| 5 | 6 | import lombok.extern.slf4j.Slf4j; |
| 6 | 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 | 17 | @Component |
| 9 | 18 | @Slf4j |
| 10 | 19 | public class SysSmsSendConsumer extends AbstractStreamMessageListener<SysSmsSendMessage> { |
| 11 | 20 | |
| 21 | + @Resource | |
| 22 | + private SysSmsService smsService; | |
| 23 | + | |
| 12 | 24 | @Override |
| 13 | 25 | public void onMessage(SysSmsSendMessage message) { |
| 14 | 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 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SysSmsChannelRefreshMessage.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.system.mq.message.sms; | |
| 2 | + | |
| 3 | +import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * 短信渠道的数据刷新 Message | |
| 8 | + */ | |
| 9 | +@Data | |
| 10 | +public class SysSmsChannelRefreshMessage implements ChannelMessage { | |
| 11 | + | |
| 12 | + @Override | |
| 13 | + public String getChannel() { | |
| 14 | + return "system.sms-channel.refresh"; | |
| 15 | + } | |
| 16 | + | |
| 17 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SysSmsSendMessage.java
| 1 | 1 | package cn.iocoder.dashboard.modules.system.mq.message.sms; |
| 2 | 2 | |
| 3 | +import cn.iocoder.dashboard.common.core.KeyValue; | |
| 3 | 4 | import cn.iocoder.dashboard.framework.redis.core.stream.StreamMessage; |
| 4 | 5 | import lombok.Data; |
| 5 | 6 | |
| 6 | 7 | import javax.validation.constraints.NotNull; |
| 7 | -import java.util.Map; | |
| 8 | +import java.util.List; | |
| 8 | 9 | |
| 9 | 10 | /** |
| 10 | 11 | * 短信发送消息 |
| ... | ... | @@ -15,28 +16,29 @@ import java.util.Map; |
| 15 | 16 | public class SysSmsSendMessage implements StreamMessage { |
| 16 | 17 | |
| 17 | 18 | /** |
| 19 | + * 短信日志编号 | |
| 20 | + */ | |
| 21 | + @NotNull(message = "短信日志编号不能为空") | |
| 22 | + private Long logId; | |
| 23 | + /** | |
| 18 | 24 | * 手机号 |
| 19 | 25 | */ |
| 20 | 26 | @NotNull(message = "手机号不能为空") |
| 21 | 27 | private String mobile; |
| 22 | 28 | /** |
| 23 | - * 短信模板编号 | |
| 29 | + * 短信渠道编号 | |
| 24 | 30 | */ |
| 25 | - @NotNull(message = "短信模板编号不能为空") | |
| 26 | - private String templateCode; | |
| 31 | + @NotNull(message = "短信渠道编号不能为空") | |
| 32 | + private Long channelId; | |
| 27 | 33 | /** |
| 28 | - * 短信模板参数 | |
| 34 | + * 短信 API 的模板编号 | |
| 29 | 35 | */ |
| 30 | - private Map<String, Object> templateParams; | |
| 31 | - | |
| 36 | + @NotNull(message = "短信 API 的模板编号不能为空") | |
| 37 | + private String apiTemplateId; | |
| 32 | 38 | /** |
| 33 | - * 用户编号,允许空 | |
| 34 | - */ | |
| 35 | - private Integer userId; | |
| 36 | - /** | |
| 37 | - * 用户类型,允许空 | |
| 39 | + * 短信模板参数 | |
| 38 | 40 | */ |
| 39 | - private Integer userType; | |
| 41 | + private List<KeyValue<String, Object>> templateParams; | |
| 40 | 42 | |
| 41 | 43 | @Override |
| 42 | 44 | public String getStreamKey() { | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SysSmsTemplateRefreshMessage.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.system.mq.message.sms; | |
| 2 | + | |
| 3 | +import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * 短信模板的数据刷新 Message | |
| 8 | + */ | |
| 9 | +@Data | |
| 10 | +public class SysSmsTemplateRefreshMessage implements ChannelMessage { | |
| 11 | + | |
| 12 | + @Override | |
| 13 | + public String getChannel() { | |
| 14 | + return "system.sms-template.refresh"; | |
| 15 | + } | |
| 16 | + | |
| 17 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysRoleProducer.java
src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SysSmsProducer.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.system.mq.producer.sms; | |
| 2 | + | |
| 3 | +import cn.iocoder.dashboard.common.core.KeyValue; | |
| 4 | +import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; | |
| 5 | +import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsChannelRefreshMessage; | |
| 6 | +import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; | |
| 7 | +import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsTemplateRefreshMessage; | |
| 8 | +import lombok.extern.slf4j.Slf4j; | |
| 9 | +import org.springframework.data.redis.core.StringRedisTemplate; | |
| 10 | +import org.springframework.stereotype.Component; | |
| 11 | + | |
| 12 | +import javax.annotation.Resource; | |
| 13 | +import java.util.List; | |
| 14 | + | |
| 15 | +/** | |
| 16 | + * Sms 短信相关消息的 Producer | |
| 17 | + * | |
| 18 | + * @author zzf | |
| 19 | + * @date 2021/3/9 16:35 | |
| 20 | + */ | |
| 21 | +@Slf4j | |
| 22 | +@Component | |
| 23 | +public class SysSmsProducer { | |
| 24 | + | |
| 25 | + @Resource | |
| 26 | + private StringRedisTemplate stringRedisTemplate; | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * 发送 {@link SysSmsSendMessage} 消息 | |
| 30 | + * | |
| 31 | + * @param logId 短信日志编号 | |
| 32 | + * @param mobile 手机号 | |
| 33 | + * @param channelId 渠道编号 | |
| 34 | + * @param apiTemplateId 短信模板编号 | |
| 35 | + * @param templateParams 短信模板参数 | |
| 36 | + */ | |
| 37 | + public void sendSmsSendMessage(Long logId, String mobile, | |
| 38 | + Long channelId, String apiTemplateId, List<KeyValue<String, Object>> templateParams) { | |
| 39 | + SysSmsSendMessage message = new SysSmsSendMessage().setLogId(logId).setMobile(mobile); | |
| 40 | + message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams); | |
| 41 | + RedisMessageUtils.sendStreamMessage(stringRedisTemplate, message); | |
| 42 | + } | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * 发送 {@link SysSmsChannelRefreshMessage} 消息 | |
| 46 | + */ | |
| 47 | + public void sendSmsChannelRefreshMessage() { | |
| 48 | + SysSmsChannelRefreshMessage message = new SysSmsChannelRefreshMessage(); | |
| 49 | + RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message); | |
| 50 | + } | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * 发送 {@link SysSmsTemplateRefreshMessage} 消息 | |
| 54 | + */ | |
| 55 | + public void sendSmsTemplateRefreshMessage() { | |
| 56 | + SysSmsTemplateRefreshMessage message = new SysSmsTemplateRefreshMessage(); | |
| 57 | + RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message); | |
| 58 | + } | |
| 59 | + | |
| 60 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/SysPermissionService.java
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java
| ... | ... | @@ -15,6 +15,7 @@ import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysMenuProduce |
| 15 | 15 | import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; |
| 16 | 16 | import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; |
| 17 | 17 | import cn.iocoder.dashboard.util.collection.CollectionUtils; |
| 18 | +import com.google.common.annotations.VisibleForTesting; | |
| 18 | 19 | import com.google.common.collect.ImmutableMap; |
| 19 | 20 | import com.google.common.collect.ImmutableMultimap; |
| 20 | 21 | import com.google.common.collect.Multimap; |
| ... | ... | @@ -168,10 +169,6 @@ public class SysMenuServiceImpl implements SysMenuService { |
| 168 | 169 | */ |
| 169 | 170 | @Transactional(rollbackFor = Exception.class) |
| 170 | 171 | public void deleteMenu(Long menuId) { |
| 171 | - // 校验更新的菜单是否存在 | |
| 172 | - if (menuMapper.selectById(menuId) == null) { | |
| 173 | - throw ServiceExceptionUtil.exception(MENU_NOT_EXISTS); | |
| 174 | - } | |
| 175 | 172 | // 校验是否还有子菜单 |
| 176 | 173 | if (menuMapper.selectCountByParentId(menuId) > 0) { |
| 177 | 174 | throw ServiceExceptionUtil.exception(MENU_EXISTS_CHILDREN); |
| ... | ... | @@ -250,7 +247,8 @@ public class SysMenuServiceImpl implements SysMenuService { |
| 250 | 247 | * @param parentId 父菜单编号 |
| 251 | 248 | * @param childId 当前菜单编号 |
| 252 | 249 | */ |
| 253 | - private void checkParentResource(Long parentId, Long childId) { | |
| 250 | + @VisibleForTesting | |
| 251 | + public void checkParentResource(Long parentId, Long childId) { | |
| 254 | 252 | if (parentId == null || MenuIdEnum.ROOT.getId().equals(parentId)) { |
| 255 | 253 | return; |
| 256 | 254 | } |
| ... | ... | @@ -279,7 +277,8 @@ public class SysMenuServiceImpl implements SysMenuService { |
| 279 | 277 | * @param parentId 父菜单编号 |
| 280 | 278 | * @param id 菜单编号 |
| 281 | 279 | */ |
| 282 | - private void checkResource(Long parentId, String name, Long id) { | |
| 280 | + @VisibleForTesting | |
| 281 | + public void checkResource(Long parentId, String name, Long id) { | |
| 283 | 282 | SysMenuDO menu = menuMapper.selectByParentIdAndName(parentId, name); |
| 284 | 283 | if (menu == null) { |
| 285 | 284 | return; | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java
| ... | ... | @@ -3,7 +3,6 @@ package cn.iocoder.dashboard.modules.system.service.permission.impl; |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.collection.CollectionUtil; |
| 5 | 5 | import cn.hutool.core.util.ArrayUtil; |
| 6 | -import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; | |
| 7 | 6 | import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils; |
| 8 | 7 | import cn.iocoder.dashboard.modules.system.dal.mysql.permission.SysRoleMenuMapper; |
| 9 | 8 | import cn.iocoder.dashboard.modules.system.dal.mysql.permission.SysUserRoleMapper; | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java
| ... | ... | @@ -18,6 +18,7 @@ import cn.iocoder.dashboard.modules.system.enums.permission.SysRoleTypeEnum; |
| 18 | 18 | import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysRoleProducer; |
| 19 | 19 | import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; |
| 20 | 20 | import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; |
| 21 | +import com.google.common.annotations.VisibleForTesting; | |
| 21 | 22 | import com.google.common.collect.ImmutableMap; |
| 22 | 23 | import lombok.extern.slf4j.Slf4j; |
| 23 | 24 | import org.springframework.lang.Nullable; |
| ... | ... | @@ -58,7 +59,7 @@ public class SysRoleServiceImpl implements SysRoleService { |
| 58 | 59 | */ |
| 59 | 60 | private volatile Map<Long, SysRoleDO> roleCache; |
| 60 | 61 | /** |
| 61 | - * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新 | |
| 62 | + * 缓存角色的最大更新时间,用于后续的增量轮询,判断是否有更新 | |
| 62 | 63 | */ |
| 63 | 64 | private volatile Date maxUpdateTime; |
| 64 | 65 | |
| ... | ... | @@ -77,7 +78,7 @@ public class SysRoleServiceImpl implements SysRoleService { |
| 77 | 78 | @Override |
| 78 | 79 | @PostConstruct |
| 79 | 80 | public void initLocalCache() { |
| 80 | - // 获取菜单列表,如果有更新 | |
| 81 | + // 获取角色列表,如果有更新 | |
| 81 | 82 | List<SysRoleDO> roleList = this.loadRoleIfUpdate(maxUpdateTime); |
| 82 | 83 | if (CollUtil.isEmpty(roleList)) { |
| 83 | 84 | return; |
| ... | ... | @@ -98,23 +99,23 @@ public class SysRoleServiceImpl implements SysRoleService { |
| 98 | 99 | } |
| 99 | 100 | |
| 100 | 101 | /** |
| 101 | - * 如果菜单发生变化,从数据库中获取最新的全量菜单。 | |
| 102 | + * 如果角色发生变化,从数据库中获取最新的全量角色。 | |
| 102 | 103 | * 如果未发生变化,则返回空 |
| 103 | 104 | * |
| 104 | - * @param maxUpdateTime 当前菜单的最大更新时间 | |
| 105 | - * @return 菜单列表 | |
| 105 | + * @param maxUpdateTime 当前角色的最大更新时间 | |
| 106 | + * @return 角色列表 | |
| 106 | 107 | */ |
| 107 | 108 | private List<SysRoleDO> loadRoleIfUpdate(Date maxUpdateTime) { |
| 108 | 109 | // 第一步,判断是否要更新。 |
| 109 | 110 | if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 |
| 110 | - log.info("[loadRoleIfUpdate][首次加载全量菜单]"); | |
| 111 | - } else { // 判断数据库中是否有更新的菜单 | |
| 111 | + log.info("[loadRoleIfUpdate][首次加载全量角色]"); | |
| 112 | + } else { // 判断数据库中是否有更新的角色 | |
| 112 | 113 | if (!roleMapper.selectExistsByUpdateTimeAfter(maxUpdateTime)) { |
| 113 | 114 | return null; |
| 114 | 115 | } |
| 115 | - log.info("[loadRoleIfUpdate][增量加载全量菜单]"); | |
| 116 | + log.info("[loadRoleIfUpdate][增量加载全量角色]"); | |
| 116 | 117 | } |
| 117 | - // 第二步,如果有更新,则从数据库加载所有菜单 | |
| 118 | + // 第二步,如果有更新,则从数据库加载所有角色 | |
| 118 | 119 | return roleMapper.selectList(); |
| 119 | 120 | } |
| 120 | 121 | |
| ... | ... | @@ -245,7 +246,8 @@ public class SysRoleServiceImpl implements SysRoleService { |
| 245 | 246 | * @param code 角色额编码 |
| 246 | 247 | * @param id 角色编号 |
| 247 | 248 | */ |
| 248 | - private void checkDuplicateRole(String name, String code, Long id) { | |
| 249 | + @VisibleForTesting | |
| 250 | + public void checkDuplicateRole(String name, String code, Long id) { | |
| 249 | 251 | // 1. 该 name 名字被其它角色所使用 |
| 250 | 252 | SysRoleDO role = roleMapper.selectByName(name); |
| 251 | 253 | if (role != null && !role.getId().equals(id)) { |
| ... | ... | @@ -258,7 +260,7 @@ public class SysRoleServiceImpl implements SysRoleService { |
| 258 | 260 | // 该 code 编码被其它角色所使用 |
| 259 | 261 | role = roleMapper.selectByCode(code); |
| 260 | 262 | if (role != null && !role.getId().equals(id)) { |
| 261 | - throw ServiceExceptionUtil.exception(ROLE_CODE_DUPLICATE, name); | |
| 263 | + throw ServiceExceptionUtil.exception(ROLE_CODE_DUPLICATE, code); | |
| 262 | 264 | } |
| 263 | 265 | } |
| 264 | 266 | |
| ... | ... | @@ -267,7 +269,8 @@ public class SysRoleServiceImpl implements SysRoleService { |
| 267 | 269 | * |
| 268 | 270 | * @param id 角色编号 |
| 269 | 271 | */ |
| 270 | - private void checkUpdateRole(Long id) { | |
| 272 | + @VisibleForTesting | |
| 273 | + public void checkUpdateRole(Long id) { | |
| 271 | 274 | SysRoleDO roleDO = roleMapper.selectById(id); |
| 272 | 275 | if (roleDO == null) { |
| 273 | 276 | throw ServiceExceptionUtil.exception(ROLE_NOT_EXISTS); | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.system.service.sms; | |
| 2 | + | |
| 3 | +import cn.iocoder.dashboard.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelCreateReqVO; | |
| 5 | +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO; | |
| 6 | +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelUpdateReqVO; | |
| 7 | +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; | |
| 8 | + | |
| 9 | +import javax.validation.Valid; | |
| 10 | +import java.util.Collection; | |
| 11 | +import java.util.List; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * 短信渠道Service接口 | |
| 15 | + * | |
| 16 | + * @author zzf | |
| 17 | + * @date 2021/1/25 9:24 | |
| 18 | + */ | |
| 19 | +public interface SysSmsChannelService { | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * 初始化短信客户端 | |
| 23 | + */ | |
| 24 | + void initSmsClients(); | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * 创建短信渠道 | |
| 28 | + * | |
| 29 | + * @param createReqVO 创建信息 | |
| 30 | + * @return 编号 | |
| 31 | + */ | |
| 32 | + Long createSmsChannel(@Valid SysSmsChannelCreateReqVO createReqVO); | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * 更新短信渠道 | |
| 36 | + * | |
| 37 | + * @param updateReqVO 更新信息 | |
| 38 | + */ | |
| 39 | + void updateSmsChannel(@Valid SysSmsChannelUpdateReqVO updateReqVO); | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * 删除短信渠道 | |
| 43 | + * | |
| 44 | + * @param id 编号 | |
| 45 | + */ | |
| 46 | + void deleteSmsChannel(Long id); | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * 获得短信渠道 | |
| 50 | + * | |
| 51 | + * @param id 编号 | |
| 52 | + * @return 短信渠道 | |
| 53 | + */ | |
| 54 | + SysSmsChannelDO getSmsChannel(Long id); | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * 获得短信渠道列表 | |
| 58 | + * | |
| 59 | + * @param ids 编号 | |
| 60 | + * @return 短信渠道列表 | |
| 61 | + */ | |
| 62 | + List<SysSmsChannelDO> getSmsChannelList(Collection<Long> ids); | |
| 63 | + | |
| 64 | + /** | |
| 65 | + * 获得所有短信渠道列表 | |
| 66 | + * | |
| 67 | + * @return 短信渠道列表 | |
| 68 | + */ | |
| 69 | + List<SysSmsChannelDO> getSmsChannelList(); | |
| 70 | + | |
| 71 | + /** | |
| 72 | + * 获得短信渠道分页 | |
| 73 | + * | |
| 74 | + * @param pageReqVO 分页查询 | |
| 75 | + * @return 短信渠道分页 | |
| 76 | + */ | |
| 77 | + PageResult<SysSmsChannelDO> getSmsChannelPage(SysSmsChannelPageReqVO pageReqVO); | |
| 78 | + | |
| 79 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.system.service.sms; | |
| 2 | + | |
| 3 | +import cn.iocoder.dashboard.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogExportReqVO; | |
| 5 | +import cn.iocoder.dashboard.modules.system.controller.sms.vo.log.SysSmsLogPageReqVO; | |
| 6 | +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO; | |
| 7 | +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; | |
| 8 | + | |
| 9 | +import java.util.Date; | |
| 10 | +import java.util.List; | |
| 11 | +import java.util.Map; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * 短信日志 Service 实现类 | |
| 15 | + * | |
| 16 | + * @author zzf | |
| 17 | + * @date 13:48 2021/3/2 | |
| 18 | + */ | |
| 19 | +public interface SysSmsLogService { | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * 创建短信日志 | |
| 23 | + * | |
| 24 | + * @param mobile 手机号 | |
| 25 | + * @param userId 用户编号 | |
| 26 | + * @param userType 用户类型 | |
| 27 | + * @param isSend 是否发送 | |
| 28 | + * @param template 短信模板 | |
| 29 | + * @param templateContent 短信内容 | |
| 30 | + * @param templateParams 短信参数 | |
| 31 | + * @return 发送日志编号 | |
| 32 | + */ | |
| 33 | + Long createSmsLog(String mobile, Long userId, Integer userType, Boolean isSend, | |
| 34 | + SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams); | |
| 35 | + | |
| 36 | + /** | |
| 37 | + * 更新日志的发送结果 | |
| 38 | + * | |
| 39 | + * @param id 日志编号 | |
| 40 | + * @param sendCode 发送结果的编码 | |
| 41 | + * @param sendMsg 发送结果的提示 | |
| 42 | + * @param apiSendCode 短信 API 发送结果的编码 | |
| 43 | + * @param apiSendMsg 短信 API 发送失败的提示 | |
| 44 | + * @param apiRequestId 短信 API 发送返回的唯一请求 ID | |
| 45 | + * @param apiSerialNo 短信 API 发送返回的序号 | |
| 46 | + */ | |
| 47 | + void updateSmsSendResult(Long id, Integer sendCode, String sendMsg, | |
| 48 | + String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo); | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * 更新日志的接收结果 | |
| 52 | + * | |
| 53 | + * @param id 日志编号 | |
| 54 | + * @param success 是否接收成功 | |
| 55 | + * @param receiveTime 用户接收时间 | |
| 56 | + * @param apiReceiveCode API 接收结果的编码 | |
| 57 | + * @param apiReceiveMsg API 接收结果的说明 | |
| 58 | + */ | |
| 59 | + void updateSmsReceiveResult(Long id, Boolean success, Date receiveTime, String apiReceiveCode, String apiReceiveMsg); | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * 获得短信日志分页 | |
| 63 | + * | |
| 64 | + * @param pageReqVO 分页查询 | |
| 65 | + * @return 短信日志分页 | |
| 66 | + */ | |
| 67 | + PageResult<SysSmsLogDO> getSmsLogPage(SysSmsLogPageReqVO pageReqVO); | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * 获得短信日志列表, 用于 Excel 导出 | |
| 71 | + * | |
| 72 | + * @param exportReqVO 查询条件 | |
| 73 | + * @return 短信日志列表 | |
| 74 | + */ | |
| 75 | + List<SysSmsLogDO> getSmsLogList(SysSmsLogExportReqVO exportReqVO); | |
| 76 | + | |
| 77 | +} | ... | ... |