com-template.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. <style>
  2. .com-template .dialog {
  3. height: 500px;
  4. overflow: auto;
  5. }
  6. .com-template .el-tabs__header {
  7. padding: 0 20px;
  8. height: 56px;
  9. line-height: 56px;
  10. background-color: #fff;
  11. margin-bottom: 10px;
  12. }
  13. .com-template .export-btn {
  14. position: absolute;
  15. top: 10px;
  16. right: 10px;
  17. z-index: 2;
  18. }
  19. .com-template .form-body {
  20. padding: 20px 0;
  21. background-color: #fff;
  22. margin-bottom: 10px;
  23. }
  24. .com-template .form-button {
  25. margin: 0;
  26. }
  27. .com-template .form-button .el-form-item__content {
  28. margin-left: 0 !important;
  29. }
  30. .com-template .button-item {
  31. padding: 9px 25px;
  32. }
  33. </style>
  34. <template id="com-template">
  35. <div class="com-template" v-cloak>
  36. <el-card style="border:0" v-loading="cardLoading" shadow="never"
  37. body-style="background-color: #f3f3f3;padding: 0 0;position: relative;">
  38. <el-form size="small" class="export-btn" :inline="true">
  39. <el-form-item>
  40. <template v-if="showOneKey">
  41. <el-button type="primary" size="small"
  42. @click="getTemplate">一键添加模板消息
  43. </el-button>
  44. </template>
  45. </el-form-item>
  46. </el-form>
  47. <el-form @submit.native.prevent size="small" label-width="300px">
  48. <el-tabs v-model="activeName" @tab-click="handleClick">
  49. <el-tab-pane v-for="(item, index) in list" v-if="item.list.length > 0" :key="index" :label="item.name" :name="item.key">
  50. <el-row class="form-body">
  51. <div style="margin: 0 20px 20px;background-color: #F4F4F5;padding: 10px 15px;color: #909399;display: inline-block;font-size: 15px">
  52. 温馨提示:获取前请先确认您已获得模板消息的实用权限,并且模板消息中没有任何数据。获取后请不要到小程序后台
  53. 删除相应的模板消息,否则会影响模板消息正常使用。
  54. </div>
  55. <slot name="after_remind"></slot>
  56. <el-col :span="24">
  57. <template v-if="item.list.length">
  58. <el-form-item v-for="(tpl, index) in item.list" :key="index" :label="tpl.name">
  59. <el-input style="width: 30%" v-model.trim="tpl[tpl.tpl_name]"></el-input>
  60. <el-button size="small" @click="openDialog(tpl.img_url)">查看模板消息示例</el-button>
  61. <el-button size="small" @click="test(tpl[tpl.tpl_name])" v-if="false">发送测试</el-button>
  62. </el-form-item>
  63. </template>
  64. </el-col>
  65. </el-row>
  66. </el-tab-pane>
  67. </el-tabs>
  68. <el-card shadow="never" style="margin-bottom: 20px;" v-if="false">
  69. <div slot="header">
  70. <span>测试用户配置(最多选择三个)</span>
  71. </div>
  72. <div>
  73. <el-tag v-for="(item, index) in selectUsers"
  74. style="margin: 0 5px"
  75. :key="index"
  76. closable
  77. @close="deleteUser(index)">
  78. {{item.nickname}}
  79. </el-tag>
  80. <el-button v-if="selectUsers.length < 3" size="small" type="primary" @click="getUsers">添加用户
  81. </el-button>
  82. </div>
  83. </el-card>
  84. <el-button class="button-item" :loading="btnLoading" type="primary" @click="store" size="small">保存
  85. </el-button>
  86. <el-button class="button-item" :loading="btnLoading" type="primary" @click="testQrcode" size="small">生成测试二维码
  87. </el-button>
  88. </el-form>
  89. <el-dialog title="模板消息格式" :visible.sync="dialogVisible">
  90. <div class="dialog">
  91. <img style="width: 100%;" :src="dialogImgUrl">
  92. </div>
  93. </el-dialog>
  94. <el-dialog title="用户列表" :visible.sync="dialogUsersVisible">
  95. <template>
  96. <el-input style="width: 260px;margin-bottom: 20px;" size="small"
  97. v-model="ruleForm.keyword"
  98. clearable
  99. @clear="getUsers"
  100. @keyup.enter.native="getUsers"
  101. placeholder="输入用户ID、昵称搜索">
  102. <template slot="append">
  103. <el-button @click="getUsers">搜索</el-button>
  104. </template>
  105. </el-input>
  106. <el-table
  107. v-loading="tableLoading"
  108. ref="multipleTable"
  109. :data="users"
  110. tooltip-effect="dark"
  111. style="width: 100%"
  112. @selection-change="handleSelectionChange">
  113. <el-table-column
  114. type="selection"
  115. width="60">
  116. </el-table-column>
  117. <el-table-column
  118. prop="id"
  119. label="ID"
  120. width="80">
  121. </el-table-column>
  122. <el-table-column
  123. prop="nickname"
  124. label="昵称"
  125. width="120">
  126. </el-table-column>
  127. <el-table-column
  128. label="FormId"
  129. prop="oneFormId.form_id">
  130. </el-table-column>
  131. </el-table>
  132. </template>
  133. <div style="text-align: right;margin-top: 20px;">
  134. <el-button :loading="btnLoading" type="primary" @click="selectUserSubmit" size="small">添加
  135. </el-button>
  136. </div>
  137. </el-dialog>
  138. <el-dialog title="发送模板消息" :visible.sync="progressVisible">
  139. <div style="margin: 10px 0;">
  140. 总数{{selectUsers.length}}条,失败{{progressErrorCount}}条。
  141. </div>
  142. <el-progress :text-inside="true" :stroke-width="18" :percentage="progressCount"></el-progress>
  143. <div style="text-align: right;margin-top: 20px;">
  144. <el-button type="success" :loading="progressBtnLoading" @click="sendConfirm" size="small">确定
  145. </el-button>
  146. </div>
  147. <div style="margin-top: 20px;" v-for="(item,index) in progressErrors" :key="index">
  148. 用户: {{item.nickname}}(ID:{{item.id}}):{{item.value}}
  149. </div>
  150. </el-dialog>
  151. <el-dialog title="模板消息测试二维码" :visible.sync="templateVisible">
  152. <div style="text-align: center">
  153. <div style="margin-bottom: 10px">温馨提示:请先保存好模板消息之后在进行测试!</div>
  154. <div v-if="qrcode">
  155. <img :src="qrcode" alt="" width="430px" height="430px">
  156. </div>
  157. <div v-loading="!qrcode"></div>
  158. </div>
  159. </el-dialog>
  160. </el-card>
  161. </div>
  162. </template>
  163. <script>
  164. Vue.component('com-template', {
  165. template: '#com-template',
  166. props: {
  167. url: String, // 获取信息的地址
  168. submitUrl: String, // 表单提交的地址
  169. addUrl: String, // 一键添加的地址
  170. oneKey: { //是否显示一键获取模板消息
  171. type: Boolean,
  172. default: true
  173. },
  174. },
  175. data() {
  176. return {
  177. list: [],
  178. activeName: 'store',
  179. btnLoading: false,
  180. cardLoading: false,
  181. dialogVisible: false,
  182. dialogImgUrl: '',
  183. users: [],
  184. dialogUsersVisible: false,
  185. ruleForm: {},
  186. tableLoading: false,
  187. waitSelectUsers: [],
  188. selectUsers: [],
  189. progressVisible: false,
  190. progressErrors: [],
  191. progressCount: 0,
  192. progressErrorCount: 0, //发送失败数
  193. progressSendCount: 0, //发送总条数
  194. progressBtnLoading: false,
  195. platform: '',
  196. showOneKey:'',
  197. templateVisible: false,
  198. qrcode: '',
  199. };
  200. },
  201. methods: {
  202. test(tpl_id) {
  203. let self = this;
  204. if (self.selectUsers.length == 0) {
  205. self.$message.warning('请先添加测试用户');
  206. return;
  207. }
  208. self.progressBtnLoading = true;
  209. self.progressVisible = true;
  210. let count = 100;
  211. let usersCount = self.selectUsers.length;
  212. let progressItem = (count / usersCount).toFixed(0);
  213. self.selectUsers.forEach(function (item, index) {
  214. request({
  215. params: {
  216. r: 'mall/template-msg/test-send'
  217. },
  218. method: 'post',
  219. data: {
  220. tpl_id: tpl_id,
  221. user_id: item.id,
  222. }
  223. }).then(e => {
  224. self.progressBtnLoading = false;
  225. self.progressSendCount += 1;// 发送总数
  226. if (e.data.code == 0) {
  227. self.progressCount = self.progressCount + parseInt(progressItem);
  228. if (e.data.data.template_record && e.data.data.template_record.status === 0) {
  229. self.progressErrors.push({
  230. id: item.id,
  231. nickname: item.nickname,
  232. value: e.data.data.template_record.error
  233. });
  234. self.progressErrorCount += 1; //发送失败总数
  235. }
  236. } else {
  237. self.$message.error(e.data.msg);
  238. }
  239. if (self.progressSendCount == usersCount) {
  240. self.progressCount = 100;
  241. }
  242. }).catch(e => {
  243. });
  244. });
  245. },
  246. // 发送完成确认
  247. sendConfirm() {
  248. this.btnLoading = true;
  249. window.location.reload();
  250. },
  251. store() {
  252. let self = this;
  253. self.btnLoading = true;
  254. request({
  255. params: {
  256. r: this.submitUrl
  257. },
  258. method: 'post',
  259. data: {
  260. list: self.list,
  261. }
  262. }).then(e => {
  263. self.btnLoading = false;
  264. if (e.data.code == 0) {
  265. self.$message.success(e.data.msg);
  266. } else {
  267. self.$message.error(e.data.msg);
  268. }
  269. }).catch(e => {
  270. self.$message.error(e.data.msg);
  271. self.btnLoading = false;
  272. });
  273. },
  274. getDetail() {
  275. let self = this;
  276. self.cardLoading = true;
  277. request({
  278. params: {
  279. r: this.url,
  280. },
  281. method: 'get',
  282. }).then(e => {
  283. self.cardLoading = false;
  284. if (e.data.code == 0) {
  285. self.list = e.data.data.list;
  286. if (self.list.length > 0) {
  287. self.activeName = self.list[0].key
  288. }
  289. } else {
  290. self.$message.error(e.data.msg);
  291. }
  292. }).catch(e => {
  293. console.log(e);
  294. });
  295. }
  296. ,
  297. handleClick(tab, event) {
  298. if (['mpwx','bdapp','aliapp','ttapp'].indexOf(tab.name) >= 0) {
  299. if (['mpwx','bdapp'].indexOf(tab.name) >= 0) {
  300. this.showOneKey = true;
  301. } else {
  302. this.showOneKey = false;
  303. }
  304. this.platform = tab.name;
  305. this.getTestUser();
  306. } else {
  307. this.showOneKey = this.oneKey;
  308. }
  309. },
  310. openDialog(imgUrl) {
  311. this.dialogVisible = true;
  312. this.dialogImgUrl = imgUrl;
  313. },
  314. getTemplate() {
  315. request({
  316. params: {
  317. r: this.addUrl,
  318. add: true,
  319. platform:this.platform,
  320. },
  321. method: 'get',
  322. }).then(e => {
  323. if (e.data.code == 0) {
  324. this.list = e.data.data.list;
  325. } else {
  326. this.$message.error(e.data.msg);
  327. }
  328. }).catch(e => {
  329. console.log(e);
  330. });
  331. },
  332. getUsers() {
  333. let self = this;
  334. self.dialogUsersVisible = true;
  335. self.tableLoading = true;
  336. request({
  337. params: {
  338. r: 'mall/template-msg/users',
  339. is_all: 0,
  340. keyword: self.ruleForm.keyword,
  341. platform: this.platform
  342. },
  343. method: 'get',
  344. }).then(e => {
  345. self.tableLoading = false;
  346. if (e.data.code == 0) {
  347. self.users = e.data.data.users;
  348. self.isChecked();
  349. } else {
  350. self.$message.error(e.data.msg);
  351. }
  352. }).catch(e => {
  353. self.$message.error(e.data.msg);
  354. });
  355. },
  356. // 多选
  357. handleSelectionChange(val) {
  358. var self = this;
  359. self.waitSelectUsers = val;
  360. },
  361. selectUserSubmit() {
  362. let self = this;
  363. self.btnLoading = true;
  364. self.waitSelectUsers.forEach(function (item, index) {
  365. if (self.selectUsers.length > 0) {
  366. try {
  367. // 循环查询、如果是重复用户则不添加
  368. self.selectUsers.forEach(function (item2, index2) {
  369. if (item2.id == item.id) {
  370. throw new Error('finish')
  371. }
  372. });
  373. if (self.selectUsers.length < 3) {
  374. self.selectUsers.push(item)
  375. }
  376. } catch (e) {
  377. if (e.message != 'finish') throw e;
  378. }
  379. } else {
  380. if (self.selectUsers.length < 3) {
  381. self.selectUsers.push(item)
  382. }
  383. }
  384. });
  385. self.saveTestUser();
  386. },
  387. deleteUser(index) {
  388. this.selectUsers.splice(index, 1)
  389. this.saveTestUser();
  390. },
  391. saveTestUser() {
  392. request({
  393. params: {
  394. r: 'plugin/mpwx/mall/template-msg/add-test-user',
  395. },
  396. method: 'post',
  397. data: {
  398. user: this.selectUsers,
  399. platform: this.platform,
  400. }
  401. }).then(e => {
  402. this.dialogUsersVisible = false;
  403. this.btnLoading = false;
  404. if (e.data.code == 0) {
  405. } else {
  406. this.$message.error(e.data.msg);
  407. }
  408. }).catch(e => {
  409. console.log(e);
  410. });
  411. },
  412. getTestUser() {
  413. request({
  414. params: {
  415. r: 'plugin/mpwx/mall/template-msg/test-user',
  416. platform: this.platform,
  417. },
  418. method: 'get',
  419. }).then(e => {
  420. if (e.data.code == 0) {
  421. this.selectUsers = e.data.data.users;
  422. } else {
  423. this.$message.error(e.data.msg);
  424. }
  425. }).catch(e => {
  426. console.log(e);
  427. });
  428. },
  429. isChecked() {
  430. let self = this;
  431. self.users.forEach(function (item, index) {
  432. self.selectUsers.forEach(function (item2, index2) {
  433. if (item.id === item2.id) {
  434. self.$nextTick(() => {
  435. self.$refs.multipleTable.toggleRowSelection(self.users[index], true);
  436. });
  437. }
  438. })
  439. })
  440. },
  441. getPlatform() {
  442. let vars = getQuery('r').split("/");
  443. let p = vars[1];
  444. this.showOneKey = this.oneKey;
  445. if (['wxapp','bdapp','aliapp','ttapp'].indexOf(p) >= 0) {
  446. this.platform = p;
  447. } else {
  448. this.platform = 'wxapp';
  449. }
  450. },
  451. testQrcode() {
  452. this.templateVisible = true;
  453. if (this.qrcode) {
  454. return ;
  455. }
  456. this.$request({
  457. params: {
  458. r: 'plugin/mpwx/template-msg/qrcode',
  459. platform: this.platform,
  460. },
  461. method: 'get',
  462. }).then(e => {
  463. if (e.data.code == 0) {
  464. this.qrcode = e.data.data
  465. } else {
  466. this.$message.error(e.data.msg);
  467. }
  468. }).catch(e => {
  469. console.log(e);
  470. });
  471. }
  472. },
  473. mounted: function () {
  474. this.getPlatform();
  475. this.getDetail();
  476. this.getTestUser();
  477. },
  478. });
  479. </script>