Commit 1e402d80632067d8d4a57710bf5c0e6838f298b3

Authored by YunaiV
1 parent ab41c966

mp:增加【自动回复】的前端实现

yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpAutoReplyController.java
... ... @@ -8,11 +8,13 @@ import cn.iocoder.yudao.module.mp.convert.message.MpAutoReplyConvert;
8 8 import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO;
9 9 import cn.iocoder.yudao.module.mp.service.message.MpAutoReplyService;
10 10 import io.swagger.annotations.Api;
  11 +import io.swagger.annotations.ApiImplicitParam;
11 12 import io.swagger.annotations.ApiOperation;
12 13 import org.springframework.security.access.prepost.PreAuthorize;
13 14 import org.springframework.validation.annotation.Validated;
14 15 import org.springframework.web.bind.annotation.GetMapping;
15 16 import org.springframework.web.bind.annotation.RequestMapping;
  17 +import org.springframework.web.bind.annotation.RequestParam;
16 18 import org.springframework.web.bind.annotation.RestController;
17 19  
18 20 import javax.annotation.Resource;
... ... @@ -37,4 +39,13 @@ public class MpAutoReplyController {
37 39 return success(MpAutoReplyConvert.INSTANCE.convertPage(pageResult));
38 40 }
39 41  
  42 + @GetMapping("/get")
  43 + @ApiOperation("获得公众号自动回复")
  44 + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024")
  45 + @PreAuthorize("@ss.hasPermission('mp:auto-reply:query')")
  46 + public CommonResult<MpAutoReplyRespVO> getAutoReply(@RequestParam("id") Long id) {
  47 + MpAutoReplyDO autoReply = mpAutoReplyService.getAutoReply(id);
  48 + return success(MpAutoReplyConvert.INSTANCE.convert(autoReply));
  49 + }
  50 +
40 51 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyBaseVO.java
... ... @@ -30,7 +30,7 @@ public class MpAutoReplyBaseVO {
30 30  
31 31 @ApiModelProperty(value = "请求的关键字", example = "关键字", notes = "当 type 为 MpAutoReplyTypeEnum#KEYWORD 时,必填")
32 32 private String requestKeyword;
33   - @ApiModelProperty(value = "请求的关键字", example = "关键字", notes = "当 type 为 MpAutoReplyTypeEnum#KEYWORD 时,必填")
  33 + @ApiModelProperty(value = "请求的匹配方式", example = "1", notes = "当 type 为 MpAutoReplyTypeEnum#KEYWORD 时,必填")
34 34 private Integer requestMatch;
35 35  
36 36 @ApiModelProperty(value = "请求的消息类型", example = "text", notes = "当 type 为 MpAutoReplyTypeEnum#MESSAGE 时,必填")
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyRespVO.java
... ... @@ -6,6 +6,8 @@ import lombok.Data;
6 6 import lombok.EqualsAndHashCode;
7 7 import lombok.ToString;
8 8  
  9 +import java.util.Date;
  10 +
9 11 @ApiModel("管理后台 - 公众号自动回复 Response VO")
10 12 @Data
11 13 @EqualsAndHashCode(callSuper = true)
... ... @@ -20,4 +22,7 @@ public class MpAutoReplyRespVO extends MpAutoReplyBaseVO {
20 22 @ApiModelProperty(value = "微信公众号 appid", required = true, example = "wx1234567890")
21 23 private String appId;
22 24  
  25 + @ApiModelProperty(value = "创建时间", required = true)
  26 + private Date createTime;
  27 +
23 28 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/message/MpAutoReplyConvert.java
... ... @@ -27,4 +27,6 @@ public interface MpAutoReplyConvert {
27 27  
28 28 PageResult<MpAutoReplyRespVO> convertPage(PageResult<MpAutoReplyDO> page);
29 29  
  30 + MpAutoReplyRespVO convert(MpAutoReplyDO bean);
  31 +
30 32 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyService.java
... ... @@ -22,6 +22,14 @@ public interface MpAutoReplyService {
22 22 PageResult<MpAutoReplyDO> getAutoReplyPage(MpMessagePageReqVO pageVO);
23 23  
24 24 /**
  25 + * 获得公众号自动回复
  26 + *
  27 + * @param id 编号
  28 + * @return 自动回复
  29 + */
  30 + MpAutoReplyDO getAutoReply(Long id);
  31 +
  32 + /**
25 33 * 当收到消息时,自动回复
26 34 *
27 35 * @param appId 微信公众号 appId
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyServiceImpl.java
... ... @@ -45,6 +45,11 @@ public class MpAutoReplyServiceImpl implements MpAutoReplyService {
45 45 }
46 46  
47 47 @Override
  48 + public MpAutoReplyDO getAutoReply(Long id) {
  49 + return mpAutoReplyMapper.selectById(id);
  50 + }
  51 +
  52 + @Override
48 53 public WxMpXmlOutMessage replyForMessage(String appId, WxMpXmlMessage wxMessage) {
49 54 // 第一步,匹配自动回复
50 55 List<MpAutoReplyDO> replies = null;
... ...
yudao-ui-admin/src/api/mp/autoReply.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 创建公众号的自动回复
  4 +export function createAutoReply(data) {
  5 + return request({
  6 + url: '/mp/auto-reply/create',
  7 + method: 'post',
  8 + data: data
  9 + })
  10 +}
  11 +
  12 +// 更新公众号的自动回复
  13 +export function updateAutoReply(data) {
  14 + return request({
  15 + url: '/mp/auto-reply/update',
  16 + method: 'put',
  17 + data: data
  18 + })
  19 +}
  20 +
  21 +// 删除公众号的自动回复
  22 +export function deleteAutoReply(id) {
  23 + return request({
  24 + url: '/mp/auto-reply/delete?id=' + id,
  25 + method: 'delete'
  26 + })
  27 +}
  28 +
  29 +// 获得公众号的自动回复
  30 +export function getAutoReply(id) {
  31 + return request({
  32 + url: '/mp/auto-reply/get?id=' + id,
  33 + method: 'get'
  34 + })
  35 +}
  36 +
  37 +// 获得公众号的自动回复分页
  38 +export function getAutoReplyPage(query) {
  39 + return request({
  40 + url: '/mp/auto-reply/page',
  41 + method: 'get',
  42 + params: query
  43 + })
  44 +}
... ...
yudao-ui-admin/src/utils/dict.js
... ... @@ -58,6 +58,9 @@ export const DICT_TYPE = {
58 58 PAY_REFUND_ORDER_STATUS: 'pay_refund_order_status', // 退款订单状态
59 59 PAY_REFUND_ORDER_TYPE: 'pay_refund_order_type', // 退款订单类别
60 60  
  61 + // ========== MP 模块 ==========
  62 + MP_AUTO_REPLY_REQUEST_MATCH: 'mp_auto_reply_request_match', // 自动回复请求匹配类型
  63 +
61 64 // ========== MALL - PRODUCT 模块 ==========
62 65 PRODUCT_SPU_STATUS: 'product_spu_status', // 商品 SPU 状态
63 66  
... ...
yudao-ui-admin/src/views/mp/autoReply/index.vue
... ... @@ -22,6 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 22 SOFTWARE.
23 23 芋道源码:
24 24 ① 移除 avue 框架,使用 element-ui 重写
  25 + ② 重写代码,保持和现有项目保持一致
25 26 -->
26 27 <template>
27 28 <div class="app-container">
... ... @@ -44,10 +45,10 @@ SOFTWARE.
44 45 <el-row :gutter="10" class="mb8">
45 46 <el-col :span="1.5">
46 47 <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
47   - v-hasPermi="['mp:auto-reply:create']" v-if="list.length <= 0">新增
  48 + v-hasPermi="['mp:auto-reply:create']" v-if="type !== '1' || list.length <= 0">新增
48 49 </el-button>
49 50 </el-col>
50   - <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  51 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
51 52 </el-row>
52 53 <!-- 列表 -->
53 54 <el-tab-pane name="1">
... ... @@ -97,7 +98,11 @@ SOFTWARE.
97 98 <span slot="label"><i class="el-icon-news"></i> 关键词回复</span>
98 99 <el-table v-loading="loading" :data="list">
99 100 <el-table-column label="关键词" align="center" prop="requestKeyword"/>
100   - <el-table-column label="匹配类型" align="center" prop="requestMatch"/>
  101 + <el-table-column label="匹配类型" align="center" prop="requestMatch">
  102 + <template v-slot="scope">
  103 + <dict-tag :type="DICT_TYPE.MP_AUTO_REPLY_REQUEST_MATCH" :value="scope.row.requestMatch"/>
  104 + </template>
  105 + </el-table-column>
101 106 <el-table-column label="回复消息类型" align="center" prop="responseMessageType"/>
102 107 <el-table-column label="创建时间" align="center" prop="createTime" width="180">
103 108 <template slot-scope="scope">
... ... @@ -118,39 +123,31 @@ SOFTWARE.
118 123 </el-tab-pane>
119 124 </el-tabs>
120 125  
121   - <el-dialog :title="handleType === 'add' ? '新增回复消息' : '修改回复消息'" :visible.sync="dialog1Visible" width="50%">
122   - <el-form label-width="100px">
123   - <el-form-item label="请求消息类型" v-if="type == '2'">
124   - <el-select v-model="objData.reqType" placeholder="请选择">
125   - <el-option
126   - v-for="item in dictData.get('wx_req_type')"
127   - :key="item.value"
128   - :label="item.label"
129   - :value="item.value"
130   - :disabled="item.disabled"
131   - v-if="item.value !== 'event'">
  126 + <!-- 添加或修改自动回复的对话框 -->
  127 + <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
  128 + <el-form ref="form" :model="form" :rules="rules" label-width="80px">
  129 + <el-form-item label="消息类型" prop="requestMessageType" v-if="type === '2'">
  130 + <el-select v-model="form.requestMessageType" placeholder="请选择">
  131 + <el-option v-for="item in dictData.get('wx_req_type')" :key="item.value" :label="item.label"
  132 + :value="item.value" :disabled="item.disabled" v-if="item.value !== 'event'">
132 133 </el-option>
133 134 </el-select>
134 135 </el-form-item>
135   - <el-form-item label="匹配类型" v-if="type === '3'">
136   - <el-select v-model="objData.repMate" placeholder="请选择" style="width: 100px">
137   - <el-option
138   - v-for="item in dictData.get('wx_rep_mate')"
139   - :key="item.value"
140   - :label="item.label"
141   - :value="item.value">
142   - </el-option>
  136 + <el-form-item label="匹配类型" prop="requestMatch" v-if="type === '3'">
  137 + <el-select v-model="form.requestMatch" placeholder="请选择匹配类型" clearable size="small">
  138 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.MP_AUTO_REPLY_REQUEST_MATCH)"
  139 + :key="dict.value" :label="dict.label" :value="parseInt(dict.value)"/>
143 140 </el-select>
144 141 </el-form-item>
145   - <el-form-item label="关键词" v-if="type === '3'">
146   - <el-input placeholder="请输入内容" v-model="objData.reqKey" clearable> </el-input>
  142 + <el-form-item label="关键词" prop="requestKeyword" v-if="type === '3'">
  143 + <el-input v-model="form.requestKeyword" placeholder="请输入内容" clearable />
147 144 </el-form-item>
148 145 <el-form-item label="回复消息">
149   - <WxReplySelect :objData="objData" v-if="hackResetWxReplySelect"></WxReplySelect>
  146 + <wx-reply-select :objData="objData" v-if="hackResetWxReplySelect" />
150 147 </el-form-item>
151 148 </el-form>
152 149 <span slot="footer" class="dialog-footer">
153   - <el-button @click="dialog1Visible = false">取 消</el-button>
  150 + <el-button @click="cancel">取 消</el-button>
154 151 <el-button type="primary" @click="handleSubmit">确 定</el-button>
155 152 </span>
156 153 </el-dialog>
... ... @@ -158,11 +155,9 @@ SOFTWARE.
158 155 </template>
159 156  
160 157 <script>
161   -// import { getPage, getObj, addObj, putObj, delObj } from '@/api/wxmp/wxautoreply'
162   -// import { tableOption1, tableOption2, tableOption3 } from '@/const/crud/wxmp/wxautoreply'
163 158 import WxReplySelect from '@/views/mp/components/wx-reply/main.vue'
164 159 import { getSimpleAccounts } from "@/api/mp/account";
165   -import { getTagPage } from "@/api/mp/tag";
  160 +import { createAutoReply, deleteAutoReply, getAutoReply, getAutoReplyPage, updateAutoReply } from "@/api/mp/autoReply";
166 161  
167 162 export default {
168 163 name: 'mpAutoReply',
... ... @@ -188,13 +183,24 @@ export default {
188 183 accountId: undefined,
189 184 },
190 185  
191   - dialog1Visible:false,
192   - objData:{
193   - repType : 'text'
  186 + // 弹出层标题
  187 + title: "",
  188 + // 是否显示弹出层
  189 + open: false,
  190 + // 表单参数
  191 + form: {},
  192 + // 回复消息
  193 + objData: {
  194 + type : 'text'
194 195 },
195   - handleType: null,
  196 + // 表单校验
  197 + rules: {
  198 + requestKeyword: [{ required: true, message: "请求的关键字不能为空", trigger: "blur" }],
  199 + requestMatch: [{ required: true, message: "请求的关键字的匹配不能为空", trigger: "blur" }],
  200 + },
  201 + hackResetWxReplySelect: false, // 重置 WxReplySelect 组件,解决无法清除的问题
  202 +
196 203 dictData: new Map(),
197   - hackResetWxReplySelect: false,
198 204  
199 205 // 公众号账号列表
200 206 accounts: []
... ... @@ -211,14 +217,7 @@ export default {
211 217 this.getList();
212 218 })
213 219  
214   - // this.getPage(this.page)
215   - this.dictData.set('wx_rep_mate',[{
216   - value: '1',
217   - label: '全匹配'
218   - },{
219   - value: '2',
220   - label: '半匹配'
221   - }])
  220 + // TODO 芋艿:字典数据,一起搞
222 221 this.dictData.set('wx_req_type',[{
223 222 value: 'text',
224 223 label: '文本'
... ... @@ -250,15 +249,18 @@ export default {
250 249 getList() {
251 250 // 如果没有选中公众号账号,则进行提示。
252 251 if (!this.queryParams.accountId) {
253   - this.$message.error('未选中公众号,无法查询标签')
  252 + this.$message.error('未选中公众号,无法查询自动回复')
254 253 return false
255 254 }
256 255  
257 256 this.loading = false
258 257 // 处理查询参数
259   - let params = {...this.queryParams}
  258 + let params = {
  259 + ...this.queryParams,
  260 + type: this.type
  261 + }
260 262 // 执行查询
261   - getTagPage(params).then(response => {
  263 + getAutoReplyPage(params).then(response => {
262 264 this.list = response.data.list
263 265 this.total = response.data.total
264 266 this.loading = false
... ... @@ -278,75 +280,122 @@ export default {
278 280 }
279 281 this.handleQuery()
280 282 },
  283 + handleClick(tab, event) {
  284 + this.type = tab.name
  285 + this.handleQuery()
  286 + },
281 287  
  288 + /** 新增按钮操作 */
282 289 handleAdd(){
283   - this.hackResetWxReplySelect = false//销毁组件
284   - this.$nextTick(() => {
285   - this.hackResetWxReplySelect = true//重建组件
286   - })
287   - this.handleType = 'add'
288   - this.dialog1Visible = true
  290 + this.reset();
  291 + this.resetEditor();
  292 + // 打开表单,并设置初始化
  293 + this.open = true
  294 + this.title = '新增自动回复';
289 295 this.objData = {
290   - repType : 'text'
  296 + type : 'text'
291 297 }
292 298 },
293   - handleEdit(row){
294   - this.hackResetWxReplySelect = false//销毁组件
295   - this.$nextTick(() => {
296   - this.hackResetWxReplySelect = true//重建组件
  299 + /** 修改按钮操作 */
  300 + handleUpdate(row) {
  301 + this.reset();
  302 + this.resetEditor();
  303 + const id = row.id;
  304 + getAutoReply(id).then(response => {
  305 + // 设置属性
  306 + this.form = {...response.data}
  307 + this.$delete(this.form, 'responseMessageType');
  308 + this.$delete(this.form, 'responseContent');
  309 + this.$delete(this.form, 'responseMediaId');
  310 + this.$delete(this.form, 'responseMediaUrl');
  311 + this.$delete(this.form, 'responseDescription');
  312 + this.$delete(this.form, 'responseArticles');
  313 + this.objData = {
  314 + type: response.data.responseMessageType,
  315 + accountId: this.queryParams.accountId,
  316 + content: response.data.responseContent,
  317 + mediaId: response.data.responseMediaId,
  318 + url: response.data.responseMediaUrl,
  319 + title: response.data.responseTitle,
  320 + description: response.data.responseDescription,
  321 + thumbMediaId: response.data.responseThumbMediaId,
  322 + thumbMediaUrl: response.data.responseThumbMediaUrl,
  323 + articles: response.data.responseArticles,
  324 + musicUrl: response.data.responseMusicUrl,
  325 + hqMusicUrl: response.data.responseHqMusicUrl,
  326 + }
  327 +
  328 + // 打开表单
  329 + this.open = true
  330 + this.title = '修改自动回复';
297 331 })
298   - this.handleType = 'edit'
299   - this.dialog1Visible = true
300   - this.objData = Object.assign({}, row)
301 332 },
302   - handleClick(tab, event){
303   - this.tableData = []
304   - this.page.currentPage = 1
305   - this.type = tab.name
306   - this.getPage(this.page)
  333 + handleSubmit() {
  334 + this.$refs["form"].validate(valid => {
  335 + if (!valid) {
  336 + return;
  337 + }
  338 + // 处理回复消息
  339 + const form = {...this.form};
  340 + form.responseMessageType = this.objData.type;
  341 + form.responseContent = this.objData.content;
  342 + form.responseMediaId = this.objData.mediaId;
  343 + form.responseMediaUrl = this.objData.url;
  344 + form.responseTitle = this.objData.title;
  345 + form.responseDescription = this.objData.description;
  346 + form.responseThumbMediaId = this.objData.thumbMediaId;
  347 + form.responseThumbMediaUrl = this.objData.thumbMediaUrl;
  348 + form.responseArticles = this.objData.articles;
  349 + form.responseMusicUrl = this.objData.musicUrl;
  350 + form.responseHqMusicUrl = this.objData.hqMusicUrl;
  351 +
  352 + if (this.form.id !== undefined) {
  353 + updateAutoReply(form).then(response => {
  354 + this.$modal.msgSuccess("修改成功");
  355 + this.open = false;
  356 + this.getList();
  357 + });
  358 + } else {
  359 + createAutoReply(form).then(response => {
  360 + this.$modal.msgSuccess("新增成功");
  361 + this.open = false;
  362 + this.getList();
  363 + });
  364 + }
  365 + });
307 366 },
308   - handleDel: function(row, index) {
309   - var _this = this
310   - this.$confirm('是否确认删除此数据', '提示', {
311   - confirmButtonText: '确定',
312   - cancelButtonText: '取消',
313   - type: 'warning'
314   - }).then(function() {
315   - return delObj(row.id)
316   - }).then(data => {
317   - _this.$message({
318   - showClose: true,
319   - message: '删除成功',
320   - type: 'success'
321   - })
322   - this.getPage(this.page)
323   - }).catch(function(err) { })
  367 + // 表单重置
  368 + reset() {
  369 + this.form = {
  370 + id: undefined,
  371 + accountId: this.queryParams.accountId,
  372 + type: this.type,
  373 + requestKeyword: undefined,
  374 + requestMatch: this.type === '3' ? 1 : undefined,
  375 + requestMessageType: undefined,
  376 + };
  377 + this.resetForm("form");
324 378 },
325   - handleSubmit(row){
326   - if(this.handleType === 'add'){
327   - addObj(Object.assign({
328   - type:this.type
329   - }, this.objData)).then(data => {
330   - this.$message({
331   - showClose: true,
332   - message: '添加成功',
333   - type: 'success'
334   - })
335   - this.getPage(this.page)
336   - this.dialog1Visible = false
337   - })
338   - }
339   - if(this.handleType === 'edit'){
340   - putObj(this.objData).then(data => {
341   - this.$message({
342   - showClose: true,
343   - message: '修改成功',
344   - type: 'success'
345   - })
346   - this.getPage(this.page)
347   - this.dialog1Visible = false
348   - })
349   - }
  379 + // 取消按钮
  380 + cancel() {
  381 + this.open = false;
  382 + this.reset();
  383 + },
  384 + // 表单 Editor 重置
  385 + resetEditor() {
  386 + this.hackResetWxReplySelect = false // 销毁组件
  387 + this.$nextTick(() => {
  388 + this.hackResetWxReplySelect = true // 重建组件
  389 + })
  390 + },
  391 + handleDelete: function(row) {
  392 + const ids = row.id;
  393 + this.$modal.confirm('是否确认删除此数据?').then(function() {
  394 + return deleteAutoReply(ids);
  395 + }).then(() => {
  396 + this.getList();
  397 + this.$modal.msgSuccess("删除成功");
  398 + }).catch(() => {});
350 399 },
351 400 }
352 401 }
... ...