|
|
@@ -15,7 +15,8 @@
|
|
15
|
15
|
<div class="mb-4">
|
|
16
|
16
|
<div class="relative">
|
|
17
|
17
|
<input type="text" v-model="searchQuery" placeholder="搜索模型"
|
|
18
|
|
- class="w-full pl-10 pr-4 py-2 text-sm border rounded-lg focus:outline-none focus:border-blue-500" @keydown.enter="doSearch"/>
|
|
|
18
|
+ class="w-full pl-10 pr-4 py-2 text-sm border rounded-lg focus:outline-none focus:border-blue-500"
|
|
|
19
|
+ @keydown.enter="doSearch" />
|
|
19
|
20
|
<el-icon class="absolute left-3 top-2.5 text-gray-400" style="position: absolute;">
|
|
20
|
21
|
<Search />
|
|
21
|
22
|
</el-icon>
|
|
|
@@ -23,11 +24,11 @@
|
|
23
|
24
|
</div>
|
|
24
|
25
|
<div v-if="modelList.length" class="h-[calc(100vh-180px)] overflow-y-auto" ref="cardListRef" @scroll="doScroll">
|
|
25
|
26
|
<div v-for="(model, index) in modelList" :key="index" :class="[
|
|
26
|
|
- 'p-3 mb-2 rounded-lg cursor-pointer relative group',
|
|
27
|
|
- selectedModel === index
|
|
28
|
|
- ? 'bg-blue-50 border border-blue-500'
|
|
29
|
|
- : 'hover:bg-gray-50',
|
|
30
|
|
- ]" @click="selectModel(index)">
|
|
|
27
|
+ 'p-3 mb-2 rounded-lg cursor-pointer relative group',
|
|
|
28
|
+ selectedModel === index
|
|
|
29
|
+ ? 'bg-blue-50 border border-blue-500'
|
|
|
30
|
+ : 'hover:bg-gray-50',
|
|
|
31
|
+ ]" @click="selectModel(index)">
|
|
31
|
32
|
<div class="text-sm font-medium">{{ model.ruleName }}</div>
|
|
32
|
33
|
<div class="text-xs text-gray-500 mt-1">
|
|
33
|
34
|
最后更新: {{ model.updatedAt }}
|
|
|
@@ -40,7 +41,7 @@
|
|
40
|
41
|
</el-icon>
|
|
41
|
42
|
<template #dropdown>
|
|
42
|
43
|
<el-dropdown-menu>
|
|
43
|
|
- <el-dropdown-item style="color: red;">删除</el-dropdown-item>
|
|
|
44
|
+ <el-dropdown-item style="color: red;" @click="deleteModel(model)">删除</el-dropdown-item>
|
|
44
|
45
|
<!-- <el-dropdown-item>The Action 2st</el-dropdown-item>
|
|
45
|
46
|
<el-dropdown-item>The Action 3st</el-dropdown-item> -->
|
|
46
|
47
|
</el-dropdown-menu>
|
|
|
@@ -56,47 +57,58 @@
|
|
56
|
57
|
<!-- 右侧添加条件抽屉 -->
|
|
57
|
58
|
<div class="flex-1 overflow-hidden">
|
|
58
|
59
|
<el-drawer v-model="showConditionDrawer" title="添加条件" size="40%">
|
|
59
|
|
- <el-form :model="conditionForm" label-width="100px">
|
|
60
|
|
- <el-form-item label="条件分类">
|
|
|
60
|
+ <el-form :model="conditionForm" :rules="formRules" label-width="100px" ref="conditionFormRef">
|
|
|
61
|
+ <el-form-item label="条件分类" prop="type">
|
|
61
|
62
|
<el-select v-model="conditionForm.type" placeholder="请选择条件分类">
|
|
62
|
|
- <el-option label="基础检测" value="基础检测" />
|
|
63
|
|
- <el-option label="通话质量检测" value="通话质量检测" />
|
|
|
63
|
+ <el-option v-for="item in conditionTypes" :key="item.name" :label="item.name" :value="item.name" />
|
|
64
|
64
|
</el-select>
|
|
65
|
65
|
</el-form-item>
|
|
66
|
|
- <el-form-item label="条件名称">
|
|
|
66
|
+ <el-form-item label="条件名称" prop="name">
|
|
67
|
67
|
<el-select v-model="conditionForm.name" placeholder="请选择条件名称">
|
|
68
|
|
- <el-option label="开场白" value="开场白" />
|
|
69
|
|
- <el-option label="结束语" value="结束语" />
|
|
70
|
|
- <el-option label="音量" value="音量" />
|
|
|
68
|
+ <el-option v-for="item in conditionOptions" :key="item" :label="item" :value="item" />
|
|
71
|
69
|
</el-select>
|
|
72
|
70
|
</el-form-item>
|
|
73
|
|
- <el-form-item label="开场白">
|
|
74
|
|
- <div v-for="(greeting, index) in conditionForm.greetings" :key="index" class="mb-2">
|
|
75
|
|
- <div class="flex items-center">
|
|
76
|
|
- <el-input v-model="conditionForm.greetings[index]" :placeholder="`请输入开场白${index + 1}`" class="flex-1" style="width: 500px;"/>
|
|
77
|
|
- <el-button type="danger" @click="removeGreeting(index)" :icon="Delete" circle class="ml-2" />
|
|
78
|
|
- <el-button v-if="index === conditionForm.greetings.length - 1" @click="addGreeting" :icon="Plus" circle class="ml-2" />
|
|
79
|
|
- </div>
|
|
80
|
|
- </div>
|
|
81
|
|
- <!-- <el-button type="primary" @click="addGreeting">添加开场白</el-button> -->
|
|
|
71
|
+
|
|
|
72
|
+ <el-form-item label="关键词" prop="keywords">
|
|
|
73
|
+ <el-select v-model="conditionForm.keywords" multiple filterable placeholder="请选择关键词"
|
|
|
74
|
+ style="width: 500px;">
|
|
|
75
|
+ <el-option v-for="item in keywordOptions" :key="item.id" :label="item.term" :value="item.id" />
|
|
|
76
|
+ </el-select>
|
|
82
|
77
|
</el-form-item>
|
|
83
|
|
- <el-form-item label="分值">
|
|
|
78
|
+ <el-form-item label="分值" prop="score">
|
|
84
|
79
|
<div class="flex items-center">
|
|
85
|
|
- <el-slider v-model="conditionForm.score" :max="100" class="flex-1 mr-4" style="width: 400px;"/>
|
|
|
80
|
+ <el-slider v-model="conditionForm.score" :max="100" class="flex-1 mr-4" style="width: 400px;" />
|
|
86
|
81
|
<el-input-number v-model="conditionForm.score" :min="0" :max="100" />
|
|
87
|
82
|
</div>
|
|
88
|
83
|
</el-form-item>
|
|
89
|
|
- <el-form-item label="加减类型">
|
|
|
84
|
+ <el-form-item label="加减类型" prop="operation">
|
|
90
|
85
|
<el-select v-model="conditionForm.operation" placeholder="请选择加减类型">
|
|
91
|
|
- <el-option label="加分项" value="加分项" />
|
|
92
|
|
- <el-option label="减分项" value="减分项" />
|
|
|
86
|
+ <el-option label="加分项" value="0" />
|
|
|
87
|
+ <el-option label="减分项" value="1" />
|
|
93
|
88
|
</el-select>
|
|
94
|
89
|
</el-form-item>
|
|
|
90
|
+ <el-form-item label="加减分频次" prop="frequency">
|
|
|
91
|
+ <el-input v-model="conditionForm.frequency" style="max-width: 600px" placeholder="请输入数字,0表示仅一次">
|
|
|
92
|
+ <template #prepend>每出现</template>
|
|
|
93
|
+ <template #append>
|
|
|
94
|
+ {{ `${conditionForm.operation === '1' ? '减' : '加'}${conditionForm.score || 0}分`
|
|
|
95
|
+ }}
|
|
|
96
|
+ </template>
|
|
|
97
|
+ </el-input>
|
|
|
98
|
+ </el-form-item>
|
|
|
99
|
+ <el-form-item v-if="conditionForm.name === '音量'" label="正常音量">
|
|
|
100
|
+ <el-slider v-model="conditionForm.volumeRange" range :min="100" :max="500" style="width: 400px;"
|
|
|
101
|
+ :marks="volumeMarks" />
|
|
|
102
|
+ </el-form-item>
|
|
|
103
|
+ <el-form-item v-if="conditionForm.name === '语速'" label="正常语速">
|
|
|
104
|
+ <el-slider v-model="conditionForm.speedRange" range :min="100" :max="500" style="width: 400px;"
|
|
|
105
|
+ :marks="speedMarks" />
|
|
|
106
|
+ </el-form-item>
|
|
95
|
107
|
<el-form-item label="是否预警">
|
|
96
|
108
|
<el-switch v-model="conditionForm.warning" />
|
|
97
|
109
|
</el-form-item>
|
|
98
|
110
|
<el-form-item label="是否致命">
|
|
99
|
|
- <el-switch v-model="conditionForm.warning" />
|
|
|
111
|
+ <el-switch v-model="conditionForm.fatal" />
|
|
100
|
112
|
</el-form-item>
|
|
101
|
113
|
</el-form>
|
|
102
|
114
|
<div class="flex justify-end mt-4">
|
|
|
@@ -104,11 +116,11 @@
|
|
104
|
116
|
<el-button type="primary" @click="saveCondition">保存</el-button>
|
|
105
|
117
|
</div>
|
|
106
|
118
|
</el-drawer>
|
|
107
|
|
- <div class="bg-white rounded-lg shadow-sm p-6 h-full overflow-y-auto">
|
|
|
119
|
+ <div v-if="selectedModel >= 0" class="bg-white rounded-lg shadow-sm p-6 h-full overflow-y-auto">
|
|
108
|
120
|
<!-- 操作按钮 -->
|
|
109
|
121
|
<div class="absolute mt-6 right-8">
|
|
110
|
|
- <el-button @click="cancel">取消</el-button>
|
|
111
|
|
- <el-button type="primary" @click="save">保存</el-button>
|
|
|
122
|
+ <!-- <el-button @click="cancel">取消</el-button> -->
|
|
|
123
|
+ <el-button type="primary" @click="submit">保存</el-button>
|
|
112
|
124
|
</div>
|
|
113
|
125
|
<!-- 基本信息 -->
|
|
114
|
126
|
<div class="mb-6">
|
|
|
@@ -118,20 +130,21 @@
|
|
118
|
130
|
</div>
|
|
119
|
131
|
<div class="flex items-center gap-6 mb-4">
|
|
120
|
132
|
<div class="flex-1">
|
|
121
|
|
- <label class="block text-sm mb-2">模型名称</label>
|
|
122
|
|
- <el-input v-model="currentModel.ruleName" placeholder="请输入模型名称" />
|
|
|
133
|
+ <label class="block text-sm mb-2"><span class="text-red-500">*</span>模型名称</label>
|
|
|
134
|
+ <el-input v-model="currentModel.ruleName" placeholder="请输入模型名称" clearable @blur="changeRuleName"/>
|
|
123
|
135
|
</div>
|
|
124
|
136
|
<div class="flex-1">
|
|
125
|
|
- <label class="block text-sm mb-2">规则时效</label>
|
|
|
137
|
+ <label class="block text-sm mb-2"><span class="text-red-500">*</span>规则时效</label>
|
|
126
|
138
|
<el-date-picker v-model="currentModel.effectiveDate" type="daterange" range-separator="至"
|
|
127
|
|
- start-placeholder="开始日期" end-placeholder="结束日期" class="w-full" />
|
|
|
139
|
+ start-placeholder="开始日期" end-placeholder="结束日期" class="w-full" clearable/>
|
|
128
|
140
|
</div>
|
|
129
|
141
|
</div>
|
|
130
|
142
|
</div>
|
|
|
143
|
+
|
|
131
|
144
|
<!-- 模型条件 -->
|
|
132
|
145
|
<div>
|
|
133
|
146
|
<div class="flex items-center justify-between mb-4">
|
|
134
|
|
- <h2 class="text-lg font-medium">模型条件</h2>
|
|
|
147
|
+ <h2 class="text-lg font-medium"><span class="text-red-500">*</span>模型条件</h2>
|
|
135
|
148
|
<el-button type="primary" @click="addCondition">
|
|
136
|
149
|
<el-icon class="mr-1">
|
|
137
|
150
|
<Plus />
|
|
|
@@ -141,24 +154,51 @@
|
|
141
|
154
|
<el-table :data="currentModel.conditions" stripe>
|
|
142
|
155
|
<el-table-column prop="type" label="条件分类" width="140" />
|
|
143
|
156
|
<el-table-column prop="name" label="条件名称" />
|
|
144
|
|
- <el-table-column prop="operation" label="加减分项" width="140" />
|
|
145
|
|
- <el-table-column prop="warning" label="是否预警" width="140" />
|
|
146
|
|
- <el-table-column prop="fatal" label="是否致命" width="140" />
|
|
147
|
|
- <el-table-column prop="frequency" label="加减分频次" width="140" />
|
|
|
157
|
+ <el-table-column prop="operation" label="加减分项" width="140">
|
|
|
158
|
+ <template #default="{ row }">
|
|
|
159
|
+ <span :class="row.operation? 'text-red-500' : 'text-gray-500'">
|
|
|
160
|
+ {{ row.operation? '减分项' : '加分项' }}
|
|
|
161
|
+ </span>
|
|
|
162
|
+ </template>
|
|
|
163
|
+ </el-table-column>
|
|
|
164
|
+ <el-table-column prop="warning" label="是否预警" width="140">
|
|
|
165
|
+ <template #default="{ row }">
|
|
|
166
|
+ <span :class="row.warning ? 'text-red-500' : 'text-gray-500'">
|
|
|
167
|
+ {{ row.warning ? '预警' : '非预警' }}
|
|
|
168
|
+ </span>
|
|
|
169
|
+ </template>
|
|
|
170
|
+ </el-table-column>
|
|
|
171
|
+ <el-table-column prop="fatal" label="是否致命" width="140">
|
|
|
172
|
+ <template #default="{ row }">
|
|
|
173
|
+ <span :class="row.fatal ? 'text-red-500' : 'text-gray-500'">
|
|
|
174
|
+ {{ row.f ? '致命' : '非致命' }}
|
|
|
175
|
+ </span>
|
|
|
176
|
+ </template>
|
|
|
177
|
+ </el-table-column>
|
|
|
178
|
+ <el-table-column prop="frequency" label="加减分频次" width="140">
|
|
|
179
|
+ <template #default="{ row }">
|
|
|
180
|
+ <span>
|
|
|
181
|
+ {{ row.frequency ? `每出现${row.frequency}次${row.operation === '1' ? '减' : '加'}${row.score || 0}分` :
|
|
|
182
|
+ `出现多次仅${row.operation === '1' ? '减' : '加'}${row.score || 0}分`
|
|
|
183
|
+ }}
|
|
|
184
|
+ </span>
|
|
|
185
|
+ </template>
|
|
|
186
|
+ </el-table-column>
|
|
148
|
187
|
<el-table-column prop="score" label="分值" width="100" />
|
|
149
|
188
|
<el-table-column label="操作" fixed="right" width="120">
|
|
150
|
|
- <template #default="{ row }">
|
|
|
189
|
+ <template #default="{ row, $index }">
|
|
151
|
190
|
<el-button type="primary" :icon="Edit" circle class="mr-2" @click="editCondition(row)" />
|
|
152
|
|
- <el-button type="danger" :icon="Delete" circle @click="deleteCondition(row)" />
|
|
|
191
|
+ <el-button type="danger" :icon="Delete" circle @click="deleteCondition($index, row)" />
|
|
153
|
192
|
</template>
|
|
154
|
193
|
</el-table-column>
|
|
155
|
194
|
</el-table>
|
|
156
|
|
- <!-- <div class="mt-4 text-sm text-gray-500">
|
|
157
|
|
- <span>共 {{ currentModel.conditions.length }} 条</span>
|
|
158
|
|
- </div> -->
|
|
159
|
195
|
</div>
|
|
160
|
196
|
|
|
161
|
|
-
|
|
|
197
|
+
|
|
|
198
|
+ </div>
|
|
|
199
|
+
|
|
|
200
|
+ <div v-else class="h-[calc(100vh-180px)]">
|
|
|
201
|
+ <el-empty :image-size="200" description="请选择模型"/>
|
|
162
|
202
|
</div>
|
|
163
|
203
|
|
|
164
|
204
|
</div>
|
|
|
@@ -166,17 +206,24 @@
|
|
166
|
206
|
</div>
|
|
167
|
207
|
</template>
|
|
168
|
208
|
<script lang="ts" setup name="RuleModel">
|
|
169
|
|
-import { ref, onMounted } from 'vue';
|
|
|
209
|
+import { ref, onMounted, watch, nextTick } from 'vue';
|
|
170
|
210
|
import { Edit, Delete, Search, Plus, MoreFilled } from '@element-plus/icons-vue';
|
|
171
|
211
|
import moment from 'moment';
|
|
172
|
212
|
import { createPageData, getPageListData, editPageData, deletePageData } from '@/api/main/system/system';
|
|
|
213
|
+import { ElMessage, ElMessageBox } from 'element-plus';
|
|
173
|
214
|
|
|
174
|
215
|
const searchQuery = ref('');
|
|
175
|
|
-const selectedModel = ref(0);
|
|
|
216
|
+const selectedModel = ref(-1);
|
|
176
|
217
|
const currentPage = ref(1);
|
|
177
|
218
|
const pageSize = 10;
|
|
178
|
219
|
const cardListRef = ref(null);
|
|
179
|
220
|
const modelList: any = ref([]);
|
|
|
221
|
+const volumeMarks = {
|
|
|
222
|
+ 260: '标准',
|
|
|
223
|
+}
|
|
|
224
|
+const speedMarks = {
|
|
|
225
|
+ 260: '标准',
|
|
|
226
|
+}
|
|
180
|
227
|
const currentModel: any = ref({
|
|
181
|
228
|
id: 0,
|
|
182
|
229
|
ruleName: '',
|
|
|
@@ -185,8 +232,48 @@ const currentModel: any = ref({
|
|
185
|
232
|
conditions: [],
|
|
186
|
233
|
});
|
|
187
|
234
|
const selectModel = (index: number) => {
|
|
|
235
|
+ if (!modelList.value?.length) return;
|
|
188
|
236
|
selectedModel.value = index;
|
|
|
237
|
+ currentModel.value = modelList.value[index];
|
|
|
238
|
+ currentModel.value.conditions = [];
|
|
|
239
|
+ if (currentModel.value.startTime && currentModel.value.endTime) {
|
|
|
240
|
+ currentModel.value.effectiveDate = [
|
|
|
241
|
+ moment(currentModel.value.startTime),
|
|
|
242
|
+ moment(currentModel.value.endTime)
|
|
|
243
|
+ ];
|
|
|
244
|
+ }
|
|
|
245
|
+
|
|
|
246
|
+ getCases();
|
|
189
|
247
|
};
|
|
|
248
|
+
|
|
|
249
|
+// 获取条件
|
|
|
250
|
+const getCases = async () => {
|
|
|
251
|
+ if (selectedModel.value < 0) return;
|
|
|
252
|
+ // 获取模型案例逻辑
|
|
|
253
|
+ const res = await getPageListData(`/quality/scoringCriteria`, {
|
|
|
254
|
+ rulesId: currentModel.value.id,
|
|
|
255
|
+ });
|
|
|
256
|
+ if (res?.data?.length) {
|
|
|
257
|
+ console.log('模型案例', res.data)
|
|
|
258
|
+ currentModel.value.conditions = res.data.map((item: any) => {
|
|
|
259
|
+ return {
|
|
|
260
|
+ id: item.id,
|
|
|
261
|
+ rulesId: item.rulesId,
|
|
|
262
|
+ type: item.conditionCategory,
|
|
|
263
|
+ name: item.conditionName,
|
|
|
264
|
+ score: item.score,
|
|
|
265
|
+ frequency: item.frequency,
|
|
|
266
|
+ keywords: item.content,
|
|
|
267
|
+ operation: item.scoreType + '',
|
|
|
268
|
+ warning: item.isAlert === 1,
|
|
|
269
|
+ fatal: item.isCritical === 1,
|
|
|
270
|
+ speedRange: [item.minValue, item.maxValue],
|
|
|
271
|
+ volumeRange: [item.minValue, item.maxValue],
|
|
|
272
|
+ }
|
|
|
273
|
+ });
|
|
|
274
|
+ }
|
|
|
275
|
+}
|
|
|
276
|
+
|
|
190
|
277
|
const showConditionDrawer = ref(false);
|
|
191
|
278
|
|
|
192
|
279
|
const addGreeting = () => {
|
|
|
@@ -197,33 +284,76 @@ const removeGreeting = (index: number) => {
|
|
197
|
284
|
conditionForm.value.greetings.splice(index, 1);
|
|
198
|
285
|
};
|
|
199
|
286
|
|
|
200
|
|
-const getModelCases = async () => {
|
|
|
287
|
+const getModelCases = async (name = '') => {
|
|
|
288
|
+ if (conditionTypes.value?.length) return;
|
|
201
|
289
|
// 获取模型案例逻辑
|
|
202
|
290
|
const res = await getPageListData(`/quality/qcresult/getInspectionRulesType`, {});
|
|
203
|
291
|
if (res?.data?.length) {
|
|
204
|
292
|
console.log('模型案例', res.data)
|
|
|
293
|
+ conditionTypes.value = res.data;
|
|
|
294
|
+ if (conditionTypes.value.length) {
|
|
|
295
|
+ const selectedType = conditionTypes.value.find(item => name ? item.name === res.data[0].name : item.name === name);
|
|
|
296
|
+ conditionOptions.value = selectedType ? selectedType.Condition : [];
|
|
|
297
|
+ }
|
|
|
298
|
+
|
|
|
299
|
+ }
|
|
|
300
|
+
|
|
|
301
|
+}
|
|
|
302
|
+
|
|
|
303
|
+const getWords = async () => {
|
|
|
304
|
+ if (keywordOptions.value?.length) return;
|
|
|
305
|
+ // 获取模型案例逻辑
|
|
|
306
|
+ const res = await getPageListData(`/quality/searchLexicon`, {
|
|
|
307
|
+ type: 1,
|
|
|
308
|
+ });
|
|
|
309
|
+ if (res?.data?.length) {
|
|
|
310
|
+ keywordOptions.value = res.data;
|
|
205
|
311
|
}
|
|
206
|
|
-
|
|
207
|
312
|
}
|
|
208
|
313
|
|
|
209
|
|
-const conditionForm: any = ref({});
|
|
|
314
|
+const conditionFormRef = ref();
|
|
|
315
|
+const formRules = {
|
|
|
316
|
+ type: [{ required: true, message: '请选择条件分类', trigger: 'change' }],
|
|
|
317
|
+ name: [{ required: true, message: '请选择条件名称', trigger: 'change' }],
|
|
|
318
|
+ keywords: [{ required: true, message: '请选择关键词', trigger: 'change' }],
|
|
|
319
|
+ score: [{ required: true, message: '请设置分值', trigger: 'change' }],
|
|
|
320
|
+ operation: [{ required: true, message: '请选择加减类型', trigger: 'change' }]
|
|
|
321
|
+};
|
|
|
322
|
+const conditionForm: any = ref({
|
|
|
323
|
+ volumeRange: [250, 300],
|
|
|
324
|
+});
|
|
210
|
325
|
|
|
211
|
326
|
const addCondition = async () => {
|
|
|
327
|
+ getModelCases();
|
|
|
328
|
+ getWords();
|
|
212
|
329
|
showConditionDrawer.value = true;
|
|
213
|
|
-
|
|
214
|
|
- // 获取可用条件列表
|
|
215
|
|
- await getModelCases();
|
|
216
|
330
|
conditionForm.value = {
|
|
217
|
331
|
type: '',
|
|
218
|
332
|
name: '',
|
|
219
|
|
- greetings: [''] as string[],
|
|
220
|
333
|
score: 0,
|
|
221
|
|
- operation: '',
|
|
222
|
|
- warning: false
|
|
|
334
|
+ operation: '1',
|
|
|
335
|
+ warning: false,
|
|
|
336
|
+ fatal: false,
|
|
|
337
|
+ // min: 0,
|
|
|
338
|
+ // max: 100,
|
|
|
339
|
+ frequency: 1,
|
|
|
340
|
+ volumeRange: [250, 300],
|
|
|
341
|
+ speedRange: [250, 300],
|
|
|
342
|
+ keywords: [],
|
|
223
|
343
|
};
|
|
224
|
344
|
};
|
|
225
|
|
-const editCondition = (row: any) => {
|
|
226
|
|
- // 编辑条件逻辑
|
|
|
345
|
+const editCondition = async (row: any) => {
|
|
|
346
|
+ console.log('editCondition', row)
|
|
|
347
|
+ await getWords();
|
|
|
348
|
+
|
|
|
349
|
+ await getModelCases(row.type);
|
|
|
350
|
+ nextTick(() => {
|
|
|
351
|
+ showConditionDrawer.value = true;
|
|
|
352
|
+ conditionForm.value = row;
|
|
|
353
|
+ console.log('conditionForm.value', row)
|
|
|
354
|
+ conditionForm.value.keywords = row.keywords?.length ? row.keywords.split(',').map(o => Number(o)) : [];
|
|
|
355
|
+ })
|
|
|
356
|
+
|
|
227
|
357
|
};
|
|
228
|
358
|
|
|
229
|
359
|
const getPageList = async () => {
|
|
|
@@ -232,9 +362,15 @@ const getPageList = async () => {
|
|
232
|
362
|
pageNum: currentPage.value,
|
|
233
|
363
|
pageSize: pageSize,
|
|
234
|
364
|
};
|
|
235
|
|
- const {data} = await getPageListData(`/quality/inspectionRules`, params);
|
|
|
365
|
+ const { data } = await getPageListData(`/quality/inspectionmodel`, params);
|
|
236
|
366
|
if (data?.length) {
|
|
237
|
367
|
modelList.value = modelList.value.concat(data);
|
|
|
368
|
+
|
|
|
369
|
+ if (selectedModel.value === -1 && modelList.value.length) {
|
|
|
370
|
+ // selectedModel.value = 0;
|
|
|
371
|
+ // currentModel.value = modelList.value[0];
|
|
|
372
|
+ selectModel(0);
|
|
|
373
|
+ }
|
|
238
|
374
|
}
|
|
239
|
375
|
}
|
|
240
|
376
|
|
|
|
@@ -261,49 +397,217 @@ const doSearch = () => {
|
|
261
|
397
|
|
|
262
|
398
|
const addModel = () => {
|
|
263
|
399
|
const time = moment().format('YYYY-MM-DD HH:mm:ss');
|
|
|
400
|
+
|
|
|
401
|
+ // 判断是否存在新模型
|
|
|
402
|
+ const index = modelList.value.findIndex((item: any) => item.ruleName === '新模型');
|
|
|
403
|
+ if (index >=0) {
|
|
|
404
|
+ ElMessage.error('请先保存之前的新模型');
|
|
|
405
|
+ return;
|
|
|
406
|
+ }
|
|
264
|
407
|
modelList.value.unshift({
|
|
265
|
408
|
ruleName: '新模型',
|
|
266
|
409
|
updatedAt: time,
|
|
267
|
410
|
});
|
|
|
411
|
+
|
|
|
412
|
+ selectedModel.value = 0;
|
|
268
|
413
|
currentModel.value = {
|
|
269
|
414
|
ruleName: '新模型',
|
|
270
|
|
- createdAt: time,
|
|
271
|
|
- effectiveDate: [],
|
|
272
|
|
- conditions: [
|
|
273
|
|
- {
|
|
274
|
|
- type: '基础检测',
|
|
275
|
|
- name: '开场白',
|
|
276
|
|
- operation: '减分项',
|
|
277
|
|
- warning: '预警',
|
|
278
|
|
- fatal: '致命',
|
|
279
|
|
- frequency: '触发多次加减分一次',
|
|
280
|
|
- score: 5,
|
|
281
|
|
- },
|
|
282
|
|
- {
|
|
283
|
|
- type: '基础检测',
|
|
284
|
|
- name: '结束语',
|
|
285
|
|
- operation: '减分项',
|
|
286
|
|
- warning: '不预警',
|
|
287
|
|
- fatal: '不致命',
|
|
288
|
|
- frequency: '触发多次加减分一次',
|
|
289
|
|
- score: 5,
|
|
290
|
|
- },
|
|
291
|
|
- {
|
|
292
|
|
- type: '通话质量检测',
|
|
293
|
|
- name: '音量',
|
|
294
|
|
- operation: '减分项',
|
|
295
|
|
- warning: '不预警',
|
|
296
|
|
- fatal: '不致命',
|
|
297
|
|
- frequency: '触发多次加减分一次',
|
|
298
|
|
- score: 5,
|
|
299
|
|
- },
|
|
300
|
|
- ],
|
|
|
415
|
+ createdAt: time,
|
|
|
416
|
+ effectiveDate: [],
|
|
|
417
|
+ conditions: [
|
|
|
418
|
+
|
|
|
419
|
+ ],
|
|
301
|
420
|
}
|
|
302
|
421
|
}
|
|
303
|
422
|
|
|
304
|
423
|
onMounted(() => {
|
|
305
|
424
|
getPageList()
|
|
306
|
425
|
})
|
|
|
426
|
+const conditionTypes = ref([
|
|
|
427
|
+ // {
|
|
|
428
|
+ // Condition: ["开场白", "结束语"],
|
|
|
429
|
+ // name: "基础检测"
|
|
|
430
|
+ // },
|
|
|
431
|
+ // {
|
|
|
432
|
+ // Condition: ["清晰度", "打断客户", "答复不清", "脏话辱骂"],
|
|
|
433
|
+ // name: "服务态度检测"
|
|
|
434
|
+ // },
|
|
|
435
|
+ // {
|
|
|
436
|
+ // Condition: ["音量", "语速"],
|
|
|
437
|
+ // name: "通话质量检测"
|
|
|
438
|
+ // }
|
|
|
439
|
+]);
|
|
|
440
|
+
|
|
|
441
|
+const conditionOptions = ref<string[]>([]);
|
|
|
442
|
+
|
|
|
443
|
+// 监听条件分类变化
|
|
|
444
|
+watch(() => conditionForm.value.type, (newVal) => {
|
|
|
445
|
+ const selectedType = conditionTypes.value.find(item => item.name === newVal);
|
|
|
446
|
+ conditionOptions.value = selectedType ? selectedType.Condition : [];
|
|
|
447
|
+ if (conditionForm.value.name && !conditionOptions.value.includes(conditionForm.value.name)) {
|
|
|
448
|
+ conditionForm.value.name = ''; // 重置条件名称
|
|
|
449
|
+ }
|
|
|
450
|
+});
|
|
|
451
|
+
|
|
|
452
|
+const saveCondition = async () => {
|
|
|
453
|
+ try {
|
|
|
454
|
+ await conditionFormRef.value.validate();
|
|
|
455
|
+ const condition = {
|
|
|
456
|
+ id: conditionForm.value.id || '',
|
|
|
457
|
+ type: conditionForm.value.type,
|
|
|
458
|
+ name: conditionForm.value.name,
|
|
|
459
|
+ keywords: conditionForm.value.keywords.join(','), // 将id数组转为逗号分隔的字符串
|
|
|
460
|
+ // 如果需要同时保存关键词文本,可以添加:
|
|
|
461
|
+ keywordTerms: conditionForm.value.keywords.map(
|
|
|
462
|
+ id => keywordOptions.value.find(item => item.id === id)?.term || ''
|
|
|
463
|
+ ).join(','),
|
|
|
464
|
+ operation: conditionForm.value.operation,
|
|
|
465
|
+ warning: conditionForm.value.warning,
|
|
|
466
|
+ fatal: conditionForm.value.fatal,
|
|
|
467
|
+ frequency: conditionForm.value.frequency,
|
|
|
468
|
+ score: conditionForm.value.score,
|
|
|
469
|
+ };
|
|
|
470
|
+
|
|
|
471
|
+ // 如果是编辑模式,找到原条件并更新
|
|
|
472
|
+ const existingIndex = currentModel.value.conditions.findIndex(
|
|
|
473
|
+ (item: any) =>
|
|
|
474
|
+ item.type === conditionForm.value.type &&
|
|
|
475
|
+ item.name === conditionForm.value.name
|
|
|
476
|
+ );
|
|
|
477
|
+
|
|
|
478
|
+ if (existingIndex !== -1) {
|
|
|
479
|
+ currentModel.value.conditions[existingIndex] = condition;
|
|
|
480
|
+ } else {
|
|
|
481
|
+ currentModel.value.conditions.push(condition);
|
|
|
482
|
+ }
|
|
|
483
|
+
|
|
|
484
|
+ showConditionDrawer.value = false;
|
|
|
485
|
+ } catch (error) {
|
|
|
486
|
+ console.log('表单验证失败:', error);
|
|
|
487
|
+ return;
|
|
|
488
|
+ }
|
|
|
489
|
+};
|
|
|
490
|
+const deleteCondition = async (index: number, row: any) => {
|
|
|
491
|
+
|
|
|
492
|
+ if (row.id) {
|
|
|
493
|
+ const res: any = await deletePageData(`/quality/scoringCriteria/${row.id}`);
|
|
|
494
|
+ console.log('删除', res)
|
|
|
495
|
+ if (res.state !== 'success') return;
|
|
|
496
|
+ }
|
|
|
497
|
+console.log('deleteCondition', index, row)
|
|
|
498
|
+ if (index !== -1) {
|
|
|
499
|
+ currentModel.value.conditions.splice(index, 1);
|
|
|
500
|
+ }
|
|
|
501
|
+ ElMessage.success('删除成功');
|
|
|
502
|
+};
|
|
|
503
|
+// 关键词选项数据 - 修改为 id/term 格式
|
|
|
504
|
+const keywordOptions = ref([
|
|
|
505
|
+ // { id: 1, term: '关键词1' },
|
|
|
506
|
+ // { id: 2, term: '关键词2' },
|
|
|
507
|
+ // { id: 3, term: '关键词3' },
|
|
|
508
|
+ // { id: 4, term: '关键词4' },
|
|
|
509
|
+]);
|
|
|
510
|
+
|
|
|
511
|
+const submit = async () => {
|
|
|
512
|
+ // 提交逻辑
|
|
|
513
|
+ console.log('提交', currentModel.value)
|
|
|
514
|
+
|
|
|
515
|
+ const params: any = {
|
|
|
516
|
+ ruleName: currentModel.value.ruleName,
|
|
|
517
|
+ // effectiveDate: currentModel.value.effectiveDate,
|
|
|
518
|
+ scoringCriteria: [],
|
|
|
519
|
+ }
|
|
|
520
|
+
|
|
|
521
|
+ if (currentModel.value.effectiveDate && currentModel.value.effectiveDate.length === 2) {
|
|
|
522
|
+ params.startTime = moment(currentModel.value.effectiveDate[0]).format('YYYY-MM-DD HH:mm:ss');
|
|
|
523
|
+ params.endTime = moment(currentModel.value.effectiveDate[1]).format('YYYY-MM-DD HH:mm:ss');
|
|
|
524
|
+ }
|
|
|
525
|
+
|
|
|
526
|
+ if (!currentModel.value.conditions?.length) {
|
|
|
527
|
+ // 提示添加
|
|
|
528
|
+ ElMessage.error('请添加模型条件');
|
|
|
529
|
+ return;
|
|
|
530
|
+ }
|
|
|
531
|
+
|
|
|
532
|
+ for (const info of currentModel.value.conditions) {
|
|
|
533
|
+ const newInfo: any = {
|
|
|
534
|
+ id: info.id,
|
|
|
535
|
+ conditionCategory: info.type,
|
|
|
536
|
+ conditionName: info.name,
|
|
|
537
|
+ operation: info.operation,
|
|
|
538
|
+ isAlert: info.warning ? 1 : 0,
|
|
|
539
|
+ isCritical: info.fatal ? 1 : 0,
|
|
|
540
|
+ // rulesId: info.rulesId,
|
|
|
541
|
+ frequency: info.frequency,
|
|
|
542
|
+ score: info.score,
|
|
|
543
|
+ content: info.keywords,
|
|
|
544
|
+ type: 1,
|
|
|
545
|
+ };
|
|
|
546
|
+ if (info.name === '音量' && info.volumeRange && info.volumeRange.length === 2) {
|
|
|
547
|
+ newInfo.minValue = info.volumeRange[0];
|
|
|
548
|
+ newInfo.maxValue = info.volumeRange[1];
|
|
|
549
|
+ }
|
|
|
550
|
+
|
|
|
551
|
+ if (info.name === '语速' && info.speedRange && info.speedRange.length === 2) {
|
|
|
552
|
+ newInfo.minValue = info.speedRange[0];
|
|
|
553
|
+ newInfo.maxValue = info.speedRange[1];
|
|
|
554
|
+ }
|
|
|
555
|
+ params.scoringCriteria.push(newInfo)
|
|
|
556
|
+ }
|
|
|
557
|
+ console.log('提交', params)
|
|
|
558
|
+
|
|
|
559
|
+ if (currentModel.value.id) {
|
|
|
560
|
+ params.id = currentModel.value.id;
|
|
|
561
|
+ const res: any = await editPageData(`/quality/inspectionmodel`, params);
|
|
|
562
|
+ if (res?.state === 'success') {
|
|
|
563
|
+ ElMessage.success('修改成功');
|
|
|
564
|
+ currentModel.value.updatedAt = moment().format('YYYY-MM-DD HH:mm:ss');
|
|
|
565
|
+ getCases();
|
|
|
566
|
+ }
|
|
|
567
|
+ } else {
|
|
|
568
|
+ const res: any = await createPageData(`/quality/inspectionmodel`, params);
|
|
|
569
|
+ console.log('提交', res)
|
|
|
570
|
+ if (res?.state === 'success') {
|
|
|
571
|
+ ElMessage.success('提交成功');
|
|
|
572
|
+ currentModel.value.id = res?.data.id;
|
|
|
573
|
+ currentModel.value.updatedAt = moment().format('YYYY-MM-DD HH:mm:ss');
|
|
|
574
|
+ getCases();
|
|
|
575
|
+ }
|
|
|
576
|
+ }
|
|
|
577
|
+
|
|
|
578
|
+}
|
|
|
579
|
+
|
|
|
580
|
+const changeRuleName = () => {
|
|
|
581
|
+ // 更改左侧列表的名字
|
|
|
582
|
+ const index = modelList.value.findIndex((item: any) => item.id === currentModel.value.id);
|
|
|
583
|
+ if (index >= 0) {
|
|
|
584
|
+ modelList.value[index].ruleName = currentModel.value.ruleName;
|
|
|
585
|
+ }
|
|
|
586
|
+}
|
|
|
587
|
+
|
|
|
588
|
+const deleteModel = async (model) => {
|
|
|
589
|
+
|
|
|
590
|
+ ElMessageBox.confirm('确认删除该模型吗?', '提示', {
|
|
|
591
|
+ confirmButtonText: '确定',
|
|
|
592
|
+ cancelButtonText: '取消',
|
|
|
593
|
+ type: 'warning'
|
|
|
594
|
+ }).then(async () => {
|
|
|
595
|
+ if (model.id) {
|
|
|
596
|
+ const res: any = await deletePageData(`/quality/inspectionmodel/${model.id}`);
|
|
|
597
|
+ console.log('删除', res)
|
|
|
598
|
+ if (res.state !== 'success') return;
|
|
|
599
|
+ }
|
|
|
600
|
+ const index = modelList.value.findIndex((item: any) => item.id === model.id);
|
|
|
601
|
+ if (index >= 0) {
|
|
|
602
|
+ modelList.value.splice(index, 1);
|
|
|
603
|
+
|
|
|
604
|
+ selectModel(0);
|
|
|
605
|
+ ElMessage.success('删除成功');
|
|
|
606
|
+ }
|
|
|
607
|
+ })
|
|
|
608
|
+
|
|
|
609
|
+}
|
|
|
610
|
+
|
|
307
|
611
|
</script>
|
|
308
|
612
|
<style scoped>
|
|
309
|
613
|
.el-input :deep(.el-input__wrapper) {
|