Browse Source

feat: 客服异常预警 - 新建&编辑预警 - 前端页面&交互逻辑

zhengxy 2 years ago
parent
commit
272594f7fd

+ 0 - 175
project/src/components/customerAlerts/dialog/earlyWarnDialog.vue

@@ -1,175 +0,0 @@
1
-<template>
2
-  <el-dialog
3
-    :visible.sync="dialogVisible"
4
-    :before-close="handleCancel"
5
-    class="bind-dialog"
6
-    :title="title"
7
-    width="450px"
8
-    :close-on-click-modal="false"
9
-  >
10
-    <div class="form-wrap" v-loading="loading">
11
-      <div class="form-item">
12
-        <span class="lable required">ADQ账号</span>
13
-        <el-select v-model="form.account_id" size="small" placeholder="请选择ADQ账号" clearable filterable multiple>
14
-          <el-option v-for="item in adqOptions" :key="item.account_id" :label="item.account_id" :value="item.account_id" />
15
-        </el-select>
16
-      </div>
17
-      <!-- <div class="form-tips">可传空,此时会将原来设置的投放账号置空</div> -->
18
-    </div>
19
-    <div slot="footer" class="dialog-footer">
20
-      <el-button size="mini" @click="handleCancel">取 消</el-button>
21
-      <el-button size="mini" type="primary" @click="handleConfirm">确 定</el-button>
22
-    </div>
23
-  </el-dialog>
24
-</template>
25
-
26
-<script>
27
-export default {
28
-  name: "bindAdqDialog",
29
-  props: {
30
-    // 控制弹框是否显示
31
-    dialogVisible: {
32
-      type: Boolean,
33
-      default: () => false
34
-    },
35
-    // 公众号信息
36
-    mpAccountInfo: {
37
-      type: Object,
38
-      default: () => ({})
39
-    },
40
-  },
41
-  data() {
42
-    return {
43
-      loading: false,
44
-      adqOptions: [], // ADQ投放账号选项
45
-      form: {
46
-        app_id: '',
47
-        account_id: [],
48
-      }
49
-    }
50
-  },
51
-  computed: {
52
-    title() {
53
-      return `${this.mpAccountInfo.account_name ? this.mpAccountInfo.account_name + '-' : ''}绑定ADQ账号`
54
-    },
55
-  },
56
-  watch: {
57
-    dialogVisible(isShow) {
58
-      if (isShow) {
59
-        // 获取ADQ账号选项列表
60
-        this.handleGetAdqOptions()
61
-        // 获取表单数据
62
-        this.handleGetFormData()
63
-      }
64
-    },
65
-  },
66
-  methods: {
67
-    // 获取ADQ账号选项列表
68
-    async handleGetAdqOptions() {
69
-      const { data: res = {} } = await this.$axios.get(this.URL.BASEURL + this.URL.dataBoardHS_adqAccountList, {
70
-        params: {
71
-          is_select: 1
72
-        }
73
-      })
74
-      if (res && res.errno == 0) {
75
-        this.adqOptions = res.rst
76
-      } else if (res.errno != 4002) {
77
-        this.$message.warning(res.err)
78
-      }
79
-    },
80
-    async handleConfirm() {
81
-      try {
82
-        // 表单校验
83
-        await this.handleFormValidate()
84
-        const url = `${this.URL.BASEURL}${this.URL.dataBoardHS_bindAdq}`
85
-        const params = {
86
-          app_id: this.form.app_id,
87
-          account_id: this.form.account_id.join(','),
88
-        }
89
-        this.loading = true
90
-        const { data: res = {} } = await this.$axios.post(url, params)
91
-        if (res && res.errno == 0) {
92
-          this.$message.success('操作成功')
93
-          this.handleClearFormData()
94
-          this.$emit('confirm')
95
-        } else if (res.errno != 4002) {
96
-          this.$message.warning(res.err || '操作失败')
97
-        }
98
-      } catch (error) {
99
-        console.log('error => ', error)
100
-      } finally {
101
-        this.loading = false
102
-      }
103
-    },
104
-    handleCancel() {
105
-      this.handleClearFormData()
106
-      this.$emit('cancel')
107
-    },
108
-    // 执行表单校验
109
-    handleFormValidate() {
110
-      return new Promise((resolve, reject) => {
111
-        if (!this.form.account_id || !this.form.account_id.length) {
112
-          this.$message.warning('请选择ADQ账号')
113
-          reject('表单校验未通过')
114
-        } else {
115
-          resolve('表单校验通过')
116
-        }
117
-      })
118
-    },
119
-    // 获取表单数据
120
-    handleGetFormData() {
121
-      const { wechat_account_id = '', account_id = '' } = this.mpAccountInfo
122
-      this.form.app_id = wechat_account_id || ''
123
-      this.form.account_id = (account_id && Array.isArray(account_id)) ? account_id : []
124
-    },
125
-    // 清空弹框表单数据
126
-    handleClearFormData() {
127
-      this.form.app_id = ''
128
-      this.form.account_id = []
129
-    },
130
-  },
131
-};
132
-</script>
133
-
134
-<style lang="scss" scoped>
135
-.bind-dialog {
136
-  .form-wrap {
137
-    padding: 0 10px;
138
-    .form-item {
139
-      display: flex;
140
-      align-items: center;
141
-      margin-top: 16px;
142
-      &:first-child {
143
-        margin-top: 0;
144
-      }
145
-      .lable {
146
-        width: 80px;
147
-        font-weight: 500;
148
-        flex-shrink: 0;
149
-
150
-        &.required {
151
-          position: relative;
152
-          &::before {
153
-            position: absolute;
154
-            left: -8px;
155
-            top: 0;
156
-            content: "*";
157
-            color: #f56c6c;
158
-          }
159
-        }
160
-      }
161
-      .el-select {
162
-        width: 100%;
163
-      }
164
-    }
165
-    .form-tips {
166
-      margin: 5px 0 0 80px;
167
-      font-size: 13px;
168
-      color: #999;
169
-    }
170
-  }
171
-  .dialog-footer {
172
-    text-align: center;
173
-  }
174
-}
175
-</style>

+ 358 - 0
project/src/components/customerAlerts/dialog/warnDialog.vue

@@ -0,0 +1,358 @@
1
+<template>
2
+  <el-dialog
3
+    :visible.sync="dialogVisible"
4
+    :before-close="handleCancel"
5
+    class="warn-dialog"
6
+    :title="title"
7
+    width="560px"
8
+    :close-on-click-modal="false"
9
+  >
10
+    <div class="form-wrap" v-loading="loading">
11
+      <!-- 预警客服 -->
12
+      <div class="form-item">
13
+        <span class="lable required">预警客服:</span>
14
+          <customerServiceCorp
15
+            title=""
16
+            :icon_arrow_bg="false"
17
+            width="410px"
18
+            style="margin:0;"
19
+            :afferent_users="form.afferent_djuser_list"
20
+            @customerDefine="onChangeDjuserList"
21
+          />
22
+      </div>
23
+      <!-- 预警人员类型 -->
24
+      <div class="form-item">
25
+        <span class="lable required">预警人员:</span>
26
+        <el-radio-group v-model="form.type" style="margin-top: 3px;">
27
+          <el-radio :label="1">预警人</el-radio>
28
+          <el-radio :label="2">预警组</el-radio>
29
+        </el-radio-group>
30
+      </div>
31
+      <!-- 预警人 (渲染条件 form.type == 1) -->
32
+      <div v-if="form.type == 1" class="form-item">
33
+        <span class="lable"></span>
34
+        <el-select v-model="form.warnUserList" size="small" placeholder="请选择预警人" clearable filterable multiple>
35
+          <el-option v-for="item in warnUserOptions" :key="item.id" :label="item.name" :value="item.id" />
36
+        </el-select>
37
+      </div>
38
+      <!-- 预警组 (渲染条件 form.type === 2) -->
39
+      <div v-if="form.type == 2" class="form-item">
40
+        <span class="lable"></span>
41
+        <el-select v-model="form.warnGroupList" size="small" placeholder="请选择预警组" clearable filterable multiple>
42
+          <el-option v-for="item in warnGroupOptions" :key="item.id" :label="item.name" :value="item.id" />
43
+        </el-select>
44
+      </div>
45
+      <!-- 预警规则 -->
46
+      <div class="form-item flex-align-start">
47
+        <span class="lable required">预警规则:</span>
48
+        <div class="rules-wrap">
49
+          <div v-for="(item, idx) in form.rules" :key="idx" class="rules-item">
50
+            <el-input v-model.trim="item.minute" size="mini" placeholder="请输入" maxlength="3" clearable />
51
+            <span class="text">分钟内,添加人数</span>
52
+            <el-select v-model="item.contrast" size="mini">
53
+              <el-option v-for="contrast in contrastOptions" :key="contrast.value" :label="contrast.label" :value="contrast.value" />
54
+            </el-select>
55
+            <el-input v-model.trim="item.personCount" size="mini" placeholder="请输入" maxlength="5" clearable />
56
+            <span class="text">人</span>
57
+            <i v-if="idx > 0" class="el-icon-error" @click="onClickDelRules(idx)" />
58
+          </div>
59
+          <div class="add-wrap" @click="onClickAddRules">
60
+            <i class="el-icon-plus" />
61
+            <span>添加规则</span>
62
+          </div>
63
+        </div>
64
+      </div>
65
+    </div>
66
+    <div slot="footer" class="dialog-footer">
67
+      <el-button size="mini" @click="handleCancel">取 消</el-button>
68
+      <el-button size="mini" type="primary" @click="handleConfirm">确 定</el-button>
69
+    </div>
70
+  </el-dialog>
71
+</template>
72
+
73
+<script>
74
+import customerServiceCorp from '@/components/assembly/screen/customerServiceCorp.vue'
75
+
76
+const contrastOptions = [
77
+  { label: '低于', value: 1 },
78
+  { label: '高于', value: 2 },
79
+]
80
+
81
+export default {
82
+  name: "warnDialog",
83
+  components: {
84
+    customerServiceCorp,
85
+  },
86
+  props: {
87
+    // 控制弹框是否显示
88
+    dialogVisible: {
89
+      type: Boolean,
90
+      default: () => false
91
+    },
92
+    // 规则ID
93
+    ruleId: {
94
+      type: [String, Number],
95
+      default: () => ''
96
+    },
97
+  },
98
+  data() {
99
+    return {
100
+      loading: false,
101
+      contrastOptions: Object.freeze(contrastOptions),
102
+      warnUserOptions: [], // 预警人选项
103
+      warnGroupOptions: [], // 预警组选项
104
+      form: {
105
+        afferent_djuser_list: [], // 预警客服 [{ user_id: 888, corpid: 666 }]
106
+        djuser_list: [], // 预警客服
107
+        type: 1, // 预警人员类型 1预警人 2预警组
108
+        warnUserList: [], // 预警人
109
+        warnGroupList: [], // 预警组
110
+        rules: [ // 预警规则
111
+          {
112
+            minute: '',
113
+            contrast: 1,
114
+            personCount: '',
115
+          }
116
+        ]
117
+      }
118
+    }
119
+  },
120
+  computed: {
121
+    isEdit() {
122
+      return !!this.ruleId
123
+    },
124
+    title() {
125
+      return `${this.isEdit ? '编辑' : '新建'}预警`
126
+    },
127
+  },
128
+  watch: {
129
+    dialogVisible(isShow) {
130
+      if (isShow) {
131
+        // 获取"预警人"选项
132
+        this.handleGetWarnUserOptions()
133
+        // 获取"预警组"选项
134
+        this.handleGetWarnGroupOptions()
135
+        // 获取表单数据
136
+        this.handleGetFormData()
137
+      }
138
+    },
139
+  },
140
+  methods: {
141
+    // 获取"预警人"选项列表
142
+    async handleGetWarnUserOptions () {
143
+      try {
144
+        const { data: res = {} } = await this.$axios.get(this.URL.BASEURL + this.URL.warn_userList, {
145
+          params: {
146
+            sys_group_id: this.$cookie.getCookie('isSuperManage') == 1 ? sessionStorage.getItem('company_session_defaultCorp_level_1').toString() : '',
147
+            page: 1,
148
+            page_size: 500
149
+          }
150
+        })
151
+        if (res && res.errno == 0) {
152
+          this.warnUserOptions = res.rst.data
153
+        } else if (res.errno != 4002) {
154
+          this.warnUserOptions = []
155
+          this.$message.warning(res.err)
156
+        }
157
+      } catch (error) {
158
+        this.warnUserOptions = []
159
+        console.log('error => ', error)
160
+      }
161
+    },
162
+    // 获取"预警组"选项列表
163
+    async handleGetWarnGroupOptions () {
164
+      try {
165
+        const { data: res = {} } = await this.$axios.get(this.URL.BASEURL + this.URL.warn_userList, {
166
+          params: {
167
+            sys_group_id: this.$cookie.getCookie('isSuperManage') == 1 ? sessionStorage.getItem('company_session_defaultCorp_level_1').toString() : '',
168
+            page: 1,
169
+            page_size: 500
170
+          }
171
+        })
172
+        if (res && res.errno == 0) {
173
+          this.warnGroupOptions = res.rst.data
174
+        } else if (res.errno != 4002) {
175
+          this.warnGroupOptions = []
176
+          this.$message.warning(res.err)
177
+        }
178
+      } catch (error) {
179
+        this.warnGroupOptions = []
180
+        console.log('error => ', error)
181
+      }
182
+    },
183
+    async handleConfirm() {
184
+      try {
185
+        // 表单校验
186
+        await this.handleFormValidate()
187
+        const url = `${this.URL.BASEURL}${this.URL.dataBoardHS_bindAdq}`
188
+        const params = {}
189
+        this.loading = true
190
+        const { data: res = {} } = await this.$axios.post(url, params)
191
+        if (res && res.errno == 0) {
192
+          this.$message.success('操作成功')
193
+          this.handleClearFormData()
194
+          this.$emit('confirm')
195
+        } else if (res.errno != 4002) {
196
+          this.$message.warning(res.err || '操作失败')
197
+        }
198
+      } catch (error) {
199
+        console.log('error => ', error)
200
+      } finally {
201
+        this.loading = false
202
+      }
203
+    },
204
+    handleCancel() {
205
+      this.handleClearFormData()
206
+      this.$emit('cancel')
207
+    },
208
+    // 执行表单校验
209
+    handleFormValidate() {
210
+      return new Promise((resolve, reject) => {
211
+        // mock
212
+        console.log('form => ', JSON.parse(JSON.stringify(this.form)))
213
+        reject('表单校验未通过')
214
+        return
215
+        // mock
216
+
217
+        if (!this.form.xxxList || !this.form.xxxList.length) {
218
+          this.$message.warning('请选择ADQ账号')
219
+          reject('表单校验未通过')
220
+        } else {
221
+          resolve('表单校验通过')
222
+        }
223
+      })
224
+    },
225
+    // 获取表单数据
226
+    handleGetFormData() {
227
+      this.handleClearFormData()
228
+      if (this.isEdit) { // 编辑 => 获取规则详情 => 回显表单数据
229
+        this.handleGetRuleDetail()
230
+      }
231
+    },
232
+    // 获取规则详情
233
+    handleGetRuleDetail() {
234
+      console.log('handleGetRuleDetail => ruleId ', this.ruleId)
235
+    },
236
+    // 清空弹框表单数据
237
+    handleClearFormData() {
238
+      this.form.afferent_djuser_list = []
239
+      this.form.djuser_list = []
240
+      this.form.type = 1
241
+      this.form.warnUserList = []
242
+      this.form.warnGroupList = []
243
+      this.form.rules = [
244
+        {
245
+          minute: '',
246
+          contrast: 1,
247
+          personCount: '',
248
+        }
249
+      ]
250
+    },
251
+    // 监听点击“添加规则”
252
+    onClickAddRules() {
253
+      this.form.rules.push({
254
+        minute: '',
255
+        contrast: 1,
256
+        personCount: '',
257
+      })
258
+    },
259
+    // 监听点击“删除规则”
260
+    onClickDelRules(idx) {
261
+      this.form.rules.splice(idx, 1)
262
+    },
263
+    // 监听“客服”
264
+    onChangeDjuserList(val) {
265
+      console.log('onChangeDjuserList => val ', val)
266
+      this.form.djuser_list = val
267
+    },
268
+  },
269
+};
270
+</script>
271
+
272
+<style lang="scss" scoped>
273
+.warn-dialog {
274
+  /deep/ .el-dialog__body {
275
+    max-height: 380px;
276
+    overflow-y: auto;
277
+  }
278
+  .form-wrap {
279
+    padding-right: 20px;
280
+    .form-item {
281
+      display: flex;
282
+      align-items: center;
283
+      margin-top: 20px;
284
+      &.flex-align-start {
285
+        align-items: flex-start;
286
+      }
287
+      &:first-child {
288
+        margin-top: 0;
289
+      }
290
+      .lable {
291
+        width: 80px;
292
+        font-weight: 500;
293
+        flex-shrink: 0;
294
+        text-align: right;
295
+        margin-right: 10px;
296
+
297
+        &.required {
298
+          &::before {
299
+            position: relative;
300
+            right: 2px;
301
+            content: "*";
302
+            color: #f56c6c;
303
+          }
304
+        }
305
+      }
306
+      .el-select {
307
+        width: 100%;
308
+      }
309
+      .rules-wrap {
310
+        background-color: #F2F2F2;
311
+        padding: 14px;
312
+        flex: 1;
313
+        .rules-item {
314
+          display: flex;
315
+          align-items: center;
316
+          flex-shrink: 0;
317
+          margin-bottom: 10px;
318
+          .el-input {
319
+            width: 70px;
320
+            margin-right: 6px;
321
+            /deep/ .el-input__inner {
322
+              padding: 0 24px 0 8px;
323
+            }
324
+          }
325
+          .el-select {
326
+            width: 70px;
327
+            margin-right: 6px;
328
+          }
329
+          .text {
330
+            margin-right: 6px;
331
+            font-size: 13px;
332
+          }
333
+          .el-icon-error {
334
+            color: #F56C6C;
335
+            font-size: 14px;
336
+            cursor: pointer;
337
+          }
338
+        }
339
+        .add-wrap {
340
+          margin-top: 16px;
341
+          display: flex;
342
+          align-items: center;
343
+          color: #00B38A;
344
+          font-size: 13px;
345
+          cursor: pointer;
346
+          i {
347
+            font-weight: 600;
348
+            margin-right: 2px;
349
+          }
350
+        }
351
+      }
352
+    }
353
+  }
354
+  .dialog-footer {
355
+    text-align: center;
356
+  }
357
+}
358
+</style>

+ 45 - 5
project/src/components/customerAlerts/index.vue

@@ -1,7 +1,7 @@
1 1
 <template>
2 2
   <div v-loading="loading" class="customerAlerts-wrap">
3 3
     <div class="screenBox">
4
-      <el-button type="primary" size="mini">新建预警</el-button>
4
+      <el-button type="primary" size="mini" @click="onClickCreateWarnBtn">新建预警</el-button>
5 5
     </div>
6 6
     <el-table :height="height" :data="list" tooltip-effect="dark" style="width: 100%;margin-top:10px">
7 7
       <el-table-column label="预警客服" prop="name" min-width="200" align="center" fixed="left" />
@@ -14,7 +14,7 @@
14 14
             <span v-if="true" class="btn c-FF604D">禁用</span>
15 15
             <span v-else class="btn c-007AFF">启用</span>
16 16
           </template>
17
-          <span class="btn c-00b38a">编辑</span>
17
+          <span class="btn c-00b38a" @click="onClickEditWarnBtn(row.group_id)">编辑</span>
18 18
         </template>
19 19
       </el-table-column>
20 20
     </el-table>
@@ -22,12 +22,26 @@
22 22
       <el-pagination background :current-page="pagination.page" @current-change="handleCurrentChange" layout="prev, pager, next" :page-count="Number(pagination.pages)">
23 23
       </el-pagination>
24 24
     </div>
25
+
26
+    <!-- S 新建预警/编辑预警 -->
27
+    <warnDialog
28
+      :dialogVisible="warnDialogVisible"
29
+      :ruleId="currentWarnRuleId"
30
+      @confirm="onConfirmWarnDialog"
31
+      @cancel="onCancelWarnDialog"
32
+    />
33
+    <!-- E 新建预警/编辑预警 -->
25 34
   </div>
26 35
 </template>
36
+
27 37
 <script>
38
+import warnDialog from './dialog/warnDialog.vue'
39
+
28 40
 export default {
29 41
   name: 'customerAlerts',
30
-  components: {},
42
+  components: {
43
+    warnDialog,
44
+  },
31 45
   data () {
32 46
     return {
33 47
       height: '',
@@ -42,6 +56,9 @@ export default {
42 56
         keyword: '',
43 57
       },
44 58
       list: [],
59
+
60
+      warnDialogVisible: false, // 控制是否显示“新建预警”、“编辑预警”弹框
61
+      currentWarnRuleId: '', // 当前预警规则id
45 62
     }
46 63
   },
47 64
   created () {
@@ -83,9 +100,32 @@ export default {
83 100
       this.pagination.page = currentPage
84 101
       this.handleGetList()
85 102
     },
86
-  }
103
+
104
+    // S 新建预警、编辑预警
105
+    // 监听点击“新建预警”
106
+    onClickCreateWarnBtn() {
107
+      this.currentWarnRuleId = ''
108
+      this.warnDialogVisible = true
109
+    },
110
+    // 监听点击“编辑预警”
111
+    onClickEditWarnBtn(id) {
112
+      this.currentWarnRuleId = id
113
+      this.warnDialogVisible = true
114
+    },
115
+    // 监听新建预警 => 确定
116
+    onConfirmWarnDialog() {
117
+      this.warnDialogVisible = false
118
+      this.handleGetList()
119
+    },
120
+    // 监听新建预警 => 取消
121
+    onCancelWarnDialog() {
122
+      this.warnDialogVisible = false
123
+    },
124
+    // E 新建预警、编辑预警
125
+  },
87 126
 }
88 127
 </script>
128
+
89 129
 <style lang="scss" scoped>
90 130
 .customerAlerts-wrap {
91 131
   .screenBox {
@@ -100,4 +140,4 @@ export default {
100 140
     }
101 141
   }
102 142
 }
103
-</style>
143
+</style>