瀏覽代碼

feat:新增知识库词库,工单词库;对接完成;
feat:对接新的呼叫中心;

zhangchong 1 年之前
父節點
當前提交
f536b41a52

+ 2 - 11
.env.development

@@ -17,7 +17,7 @@ VITE_API_SOCKET_URL=http://110.188.24.28:50100/hubs/hotline
 VITE_API_UPLOAD_URL=http://110.188.24.28:50100/hubs/hotline
 
 # #上传 API
-VITE_SOCKET_GROUP_NAME=http://110.188.24.28:50100/hubs/hotline
+VITE_SOCKET_GROUP_NAME=ws://110.188.24.28:50100/hubs/hotline
 
 # #高德地图安全密钥
 VITE_AMAP_SECURITYJSCODE=dd12ddafb11921dbcdc5b9c4484bb4e2
@@ -26,14 +26,5 @@ VITE_AMAP_SECURITYJSCODE=dd12ddafb11921dbcdc5b9c4484bb4e2
 VITE_AMAP_KEY=83f51df235e4008e4eaf515cff63785c
 
 # # 呼叫中心socket地址
-VITE_CALLCENTER_SOCKET_URL=internal.ttf-cti.com:8080
-
-# # 呼叫中心请求地址
-VITE_CALLCENTER_API_URL=http://internal.ttf-cti.com:8080
-
-# # 呼叫中心默认账号
-VITE_CALLCENTER_DEFAULT_ACCOUNT=yscs
-
-# # 呼叫中心默认密码
-VITE_CALLCENTER_DEFAULT_PASSWORD=123456
+VITE_CALLCENTER_SOCKET_URL=ws://192.168.169.105:29003/ola_socket
 

+ 1 - 10
.env.production

@@ -26,13 +26,4 @@ VITE_AMAP_SECURITYJSCODE=dd12ddafb11921dbcdc5b9c4484bb4e2
 VITE_AMAP_KEY=83f51df235e4008e4eaf515cff63785c
 
 # # 呼叫中心socket地址
-VITE_CALLCENTER_SOCKET_URL=internal.ttf-cti.com:8080
-
-# # 呼叫中心请求地址
-VITE_CALLCENTER_API_URL=http://internal.ttf-cti.com:8080
-
-# # 呼叫中心默认账号
-VITE_CALLCENTER_DEFAULT_ACCOUNT=yscs
-
-# # 呼叫中心默认密码
-VITE_CALLCENTER_DEFAULT_PASSWORD=123456
+VITE_CALLCENTER_SOCKET_URL=internal.ttf-cti.com:8080/ola_socket

+ 1 - 10
.env.test

@@ -25,13 +25,4 @@ VITE_AMAP_SECURITYJSCODE=dd12ddafb11921dbcdc5b9c4484bb4e2
 VITE_AMAP_KEY=83f51df235e4008e4eaf515cff63785c
 
 # # 呼叫中心socket地址
-VITE_CALLCENTER_SOCKET_URL=internal.ttf-cti.com:8080
-
-# # 呼叫中心请求地址
-VITE_CALLCENTER_API_URL=https://internal.ttf-cti.com:10085
-
-# # 呼叫中心默认账号
-VITE_CALLCENTER_DEFAULT_ACCOUNT=yscs
-
-# # 呼叫中心默认密码
-VITE_CALLCENTER_DEFAULT_PASSWORD=123456
+VITE_CALLCENTER_SOCKET_URL=internal.ttf-cti.com:8080

+ 68 - 0
src/api/auxiliary/knowledgeLexicon.ts

@@ -0,0 +1,68 @@
+/*
+ * @Author: zc
+ * @description 辅助功能-知识库词库
+ */
+import request from '/@/utils/request';
+/**
+ * @description 知识库词库基础信息
+ */
+export const orderKnowledgeBaseData = () => {
+    return request({
+        url: `/api/v1/Knowledge/knowledge_word/base`,
+        method: 'get'
+    });
+};
+/**
+ * @description 知识库词库列表
+ * @param {object} params
+ */
+export const knowledgeLexiconList = (params: object) => {
+    return request({
+        url: `/api/v1/Knowledge/knowledge_word/list`,
+        method: 'get',
+        params,
+    });
+};
+/**
+ * @description 知识库词库新增
+ * @param {object} data
+ */
+export const knowledgeLexiconAdd = (data: object) => {
+    return request({
+        url: `/api/v1/Knowledge/knowledge_word`,
+        method: 'post',
+        data,
+    });
+};
+/**
+ * @description 知识库词库删除
+ * @param {object} data
+ */
+export const knowledgeLexiconDelete = (data: object) => {
+    return request({
+        url: `/api/v1/Knowledge/knowledge_word`,
+        method: 'delete',
+        data,
+    });
+};
+/**
+ * @description 知识库词库编辑
+ * @param {object} data
+ */
+export const knowledgeLexiconUpdate = (data: object) => {
+    return request({
+        url: `/api/v1/Knowledge/knowledge_word`,
+        method: 'put',
+        data,
+    });
+};
+/**
+ * @description 知识库词库详情
+ * @param {string} id
+ */
+export const knowledgeLexiconDetail = (id: string) => {
+    return request({
+        url: `/api/v1/Knowledge/knowledge_word/${id}`,
+        method: 'get'
+    });
+};

+ 68 - 0
src/api/auxiliary/orderLexicon.ts

@@ -0,0 +1,68 @@
+/*
+ * @Author: zc
+ * @description 辅助功能-工单词库管理
+ */
+import request from '/@/utils/request';
+/**
+ * @description 工单词库基础信息
+ */
+export const orderLexiconBaseData = () => {
+    return request({
+        url: `/api/v1/Order/order_word/base`,
+        method: 'get'
+    });
+}
+/**
+ * @description 工单词库列表
+ * @param {object} params
+ */
+export const orderLexiconList = (params: object) => {
+    return request({
+        url: `/api/v1/Order/order_word/list`,
+        method: 'get',
+        params,
+    });
+};
+/**
+ * @description 工单词库新增
+ * @param {object} data
+ */
+export const orderLexiconAdd = (data: object) => {
+    return request({
+        url: `/api/v1/Order/order_word`,
+        method: 'post',
+        data,
+    });
+};
+/**
+ * @description 工单词库删除
+ * @param {object} data
+ */
+export const orderLexiconDelete = (data: object) => {
+    return request({
+        url: `/api/v1/Order/order_word`,
+        method: 'delete',
+        data,
+    });
+};
+/**
+ * @description 工单词库编辑
+ * @param {object} data
+ */
+export const orderLexiconUpdate = (data: object) => {
+    return request({
+        url: `/api/v1/Order/order_word`,
+        method: 'put',
+        data,
+    });
+};
+/**
+ * @description 工单词库详情
+ * @param {string} id
+ */
+export const orderLexiconDetail = (id: string) => {
+    return request({
+        url: `/api/v1/Order/order_word/${id}`,
+        method: 'get'
+    });
+};

+ 275 - 146
src/layout/navBars/breadcrumb/telControl.vue

@@ -78,7 +78,7 @@
 					@mouseleave="onHover('restSrc', 'phoneControls/rest_blue.png')"
 				>
 					<img :src="state.restSrc" alt="" />
-					<span>结束</span>
+					<span>结束<span v-if="restReason">({{restReason}})</span></span>
 				</div>
 				<div
 					class="item active"
@@ -89,7 +89,7 @@
 					@mouseleave="onHover('restSrc', 'phoneControls/rest_blue.png')"
 				>
 					<img :src="state.restSrc" alt="" />
-					<span>小休</span>
+					<span>小休 </span>
 				</div>
 				<div class="item disabled" title="审批中" v-else-if="telStatusInfo.isRest === 'InReview'">
 					<img :src="getImageUrl('phoneControls/rest_grey.png')" alt="" />
@@ -117,7 +117,7 @@
 					<span>{{ telStatusInfo.isHold ? '取消保持' : '保持' }}</span>
 				</div>
 			</template>
-			<!-- 灰色小休不可用 -->
+			<!-- 灰色保持不可用 -->
 			<template v-else>
 				<div class="item disabled" title="保持">
 					<img :src="getImageUrl('phoneControls/hold_grey.png')" alt="" />
@@ -174,7 +174,7 @@
 					@mouseenter="onHover('conferenceSrc', 'phoneControls/conference_white.png')"
 					title="三方会议"
 					@mouseleave="onHover('conferenceSrc', 'phoneControls/conference_blue.png')"
-					@click="onControlClick( 'conference')"
+					@click="onControlClick('conference')"
 				>
 					<img :src="state.conferenceSrc" alt="" />
 					<span>三方会议</span>
@@ -285,11 +285,11 @@
 							</el-select>
 						</el-form-item>
 					</el-col>
-					<!-- <el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8">
+					<el-col :xs="24" :sm="12" :md="8" :lg="8" :xl="8">
 						<el-form-item label="" prop="acceptSms">
 							<el-checkbox v-model="state.restForm.acceptSms" label="短信通知" />
 						</el-form-item>
-					</el-col> -->
+					</el-col>
 					<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
 						<el-form-item
 							label="是否发起会签"
@@ -312,7 +312,7 @@
 					</el-col>
 					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
 						<el-form-item label="附件" prop="remark" :rules="[{ required: false, message: '请填写诉求内容', trigger: 'change' }]">
-							<annex-list name="小休附件" businessId="" classify="小休上传"/>
+							<annex-list name="小休附件" businessId="" classify="小休上传" />
 						</el-form-item>
 					</el-col>
 				</el-row>
@@ -325,7 +325,12 @@
 					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
 						<el-form-item label="小休" prop="reason" :rules="[{ required: true, message: '请选择小休原因', trigger: 'change' }]">
 							<el-select v-model="state.restForm.reason" placeholder="请选择小休原因" class="w100" clearable>
-								<el-option v-for="item in state.restReasonOptions" :key="item.id" :label="item.content" :value="item.content" />
+              <el-option v-for="item in state.restReasonOptions" :key="item.id" :label="item.content" :value="item.content" />
+								<el-option label="小休中" value="rest" />
+								<el-option label="外出" value="away" />
+								<el-option label="培训" value="trainning" />
+								<el-option label="辅导" value="coach" />
+								<el-option label="会议" value="conference" />
 							</el-select>
 						</el-form-item>
 					</el-col>
@@ -401,14 +406,13 @@ import { commonEnum } from '/@/utils/constants';
 import other from '/@/utils/other';
 import mittBus from '/@/utils/mitt';
 import { workflowStepOptions } from '/@/api/system/workflow';
-import { restFlowStart, restFlowDel, restFlowStartWex, getTelList } from '/@/api/public/wex';
+import {restFlowStart, restFlowDel, restFlowStartWex, getTelList, telRestProcess, telRestAdd} from '/@/api/public/wex';
 import { commonList } from '/@/api/auxiliary/advice';
 import { auth } from '/@/utils/authFunction';
 import { VoiceInterfaceObject } from '/@/utils/PhoneScript';
-import { WebsocketInterface } from '/@/utils/websocket';
 import signalR from '/@/utils/signalR';
 import { Local } from '/@/utils/storage';
-import {getGroup} from '/@/api/tels/group';
+import { ola } from '/@/utils/ola_api';
 
 // 引入组件
 const CommonAdvice = defineAsyncComponent(() => import('/@/components/CommonAdvice/index.vue')); // 常用意见
@@ -472,7 +476,7 @@ const state = reactive<any>({
 		metingId: '', // 三方会议ID
 		phoneNo: '', // 三方会议号码
 	},
-  groupName:'', //坐席组名称
+	groupName: '', //坐席组名称
 });
 
 const useTelStatusStore = useTelStatus();
@@ -505,71 +509,6 @@ const removeTimer = debounce(() => {
 	clearInterval(state.talkTimer);
 }, 1000);
 
-// 小休审批通过消息
-const RestApplyPassFn = (data: any) => {
-	ElNotification({
-		title: '成功',
-		message: '小休审批通过,开始小休',
-		type: 'success',
-	});
-	VoiceInterfaceObject.SetBusy(data); //设置忙碌
-};
-// 链接websocket
-const initWebsocket = () => {
-	if (!userInfos.value.staffNo) {
-		ElMessage.warning('账号暂无工号,请设置工号后重新登录后重试');
-		return;
-	}
-	let telNo: string | number;
-  let groupName:string|number = '';
-	if (telStatusInfo.value.isDutyOn) {
-		// 如果已签入
-		telNo = telStatusInfo.value.telsNo;
-    groupName = telStatusInfo.value.groupName;
-	} else {
-		// 如果未签入
-		telNo = state.dutyForm.telNo;
-    groupName = state.groupName;
-	}
-	// 设置变量
-	VoiceInterfaceObject.SetSendModel({
-		GongHao: userInfos.value.staffNo,
-		FenJi: telNo,
-		DepartmentID: 'Default',
-		AgentGroupName: groupName,
-	});
-	// 初始化参数
-	const wsParams = {
-		url: import.meta.env.VITE_WEX_SOCKET_URL,
-		IsReConnect: true, //是否重连
-		reConnectTime: 40, //重连间隔
-		IsKeepAlive: true, //是否发送心跳
-		KeepAliveTime: 30, //30秒发送1次
-		KeepAliveData: JSON.stringify(VoiceInterfaceObject.GetSendModel('keeplive')), //心跳
-		onOpen: async () => {
-			//登录语音系统
-			VoiceInterfaceObject.Login();
-      VoiceInterfaceObject.GetOnUserState(); //获取用户状态
-		},
-		onMessage: (e: any) => {
-			// 收到消息调用方法
-			let str: string = e.data; // 收到的消息
-			const methodsName = str.split('(')[0]; // 方法名
-			const parsers = str.split('(')[1].split(')')[0]; // 参数
-			VoiceInterfaceObject[methodsName](JSON.parse(parsers));
-		},
-		onClose: () => {
-			console.info('链接关闭了');
-		},
-		onError: (e: any) => {
-			console.info('链接出错', e);
-		},
-	};
-	//初始化WebSocket
-	WebsocketInterface(wsParams);
-	return Promise.resolve();
-};
-
 //  signalR 初始化signalr
 signalR.init();
 // 监听消息
@@ -597,7 +536,7 @@ const activeArr = computed(() => {
 		onCall: ['hangup', 'hold', 'transfer', 'evaluate'], // 单个通话中
 		onHold: ['hangup', 'hold', 'transfer', 'evaluate'], // 保持中
 		onTalkingDeal: ['dutyOff', 'rest', 'outbound', 'callForwarding', 'TalkingDeal'], // 事后处理中
-    onTransferSuccess:['hangup','conference'], // 转接成功
+		onTransferSuccess: ['hangup', 'conference'], // 转接成功
 		onConference: ['hangup'], // 三方会议中 只能挂断
 	};
 	let arr = <EmptyArrayType>[];
@@ -617,13 +556,22 @@ const currentStatusText = computed(() => {
 		onCall: '通话中',
 		onTalkingDeal: '事后处理',
 		onConference: '会议中',
-    onTransferSuccess:'转接成功'
+		onTransferSuccess: '转接成功',
 	};
 	return statusMap[telStatusInfo.value.phoneControlState] || '';
 });
+// 小休审批通过消息
+const RestApplyPassFn = (data: any) => {
+  ElNotification({
+    title: '成功',
+    message: '小休审批通过,开始小休',
+    type: 'success',
+  });
+  VoiceInterfaceObject.SetBusy(data); //设置忙碌
+};
 // 查询所有分机
 const getTelsLists = async (object?: object) => {
-  state.loading = true;
+	state.loading = true;
 	try {
 		const res: any = await getTelList(object);
 		state.telsList = res?.data ?? [];
@@ -632,11 +580,11 @@ const getTelsLists = async (object?: object) => {
 			label: item.device,
 			...item,
 		}));
-    state.loading = false;
+		state.loading = false;
 		return Promise.resolve(state.telsList);
 	} catch (err) {
 		console.log(err);
-    state.loading = false;
+		state.loading = false;
 	}
 };
 // 鼠标移入移出改变图标
@@ -686,10 +634,10 @@ const onControlClick = (val: string) => {
 			if (!auth('public:seat:transfer')) ElMessage.error('抱歉,您没有转接权限!');
 			else onTransfer();
 			break;
-    case 'conference': //三方会议
-      if (!auth('public:seat:meeting')) ElMessage.error('抱歉,您没有三方会议权限!');
-      else onConference();
-      break;
+		case 'conference': //三方会议
+			if (!auth('public:seat:meeting')) ElMessage.error('抱歉,您没有三方会议权限!');
+			else onConference();
+			break;
 		case 'outbound': //外呼
 			if (!auth('public:seat:outbound')) ElMessage.error('抱歉,您没有呼叫权限!');
 			else onOutbound();
@@ -698,10 +646,207 @@ const onControlClick = (val: string) => {
 			break;
 	}
 };
+
+// 当前分机对象
+const ola_object = {
+  ola_extn: '1001', //分机hao
+  ola_password: '!@#123Qw', //分机密码
+  queues: '10010', //队列
+};
+// 链接呼叫中心
+const websocket_connect = () => {
+  ola.onConnect = onConnect;
+  ola.onClose = onClose;
+  ola.onMessage = onMessage;
+  ola.connect(import.meta.env.VITE_CALLCENTER_SOCKET_URL, ola_object.ola_extn, ola_object.ola_password,);
+};
+// 呼叫中心链接
+const onConnect = () => {
+  ola.subscribe('ola.agent.' + ola_object.ola_extn);
+  ola.subscribe('ola.caller.' + ola_object.ola_extn);
+  ola.get_agent_state(ola_object.ola_extn);
+
+  callCenterLogin();
+};
+// 呼叫中心登录
+const callCenterLogin = () => {
+  ola.logout(ola_object.ola_extn); //连接之后,先登出一次,防止其他地方已经登陆
+  let array_ola_queue: EmptyArrayType = []; // 队列
+  if (ola_object.queues) {
+    let array = ola_object.queues.split(',');
+    for (let i = 0; i < array.length; i++) {
+      array_ola_queue[i] = array[i];
+    }
+    ola.login(array_ola_queue, ola_object.ola_extn, { type: 'onhook' });
+  }
+};
+// 呼叫中心消息
+const onMessage = (event: any) => {
+  const data = JSON.parse(event.data);
+  console.log('onMessage', data);
+  if (data.event_type == 'agent_state') {
+    // 坐席状态
+    if (data.state == 'login') {
+      console.log('已签入');
+      // 设置分机号和坐席组
+      useTelStatusStore.setCallInfo({ telsNo: ola_object.ola_extn });
+      // 设置签入状态
+      useTelStatusStore.setDutyState(true);
+      // 设置电话状态
+      useTelStatusStore.setPhoneControlState(TelStates.dutyOn);
+      setTimeout(() => {
+        // 设置示闲状态
+       ola.go_ready();
+      }, 1000);
+    } else if (data.state == 'logout') {
+      console.log('未签入');
+      state.loading = true;
+      // 重置所有状态
+      useTelStatusStore.resetState();
+      state.loading = false;
+    } else if (data.state == 'ready') {
+      // 设置休息状态 设置未正常状态
+      useTelStatusStore.setRest(RestStates.unRest);
+      // 设置话机状态 结束休息改为签入状态
+      useTelStatusStore.setPhoneControlState(TelStates.dutyOn);
+      console.log('示闲中');
+    } else if (data.state == 'unready') {
+      useTelStatusStore.setPhoneControlState(TelStates.rest);
+      useTelStatusStore.setRest(RestStates.resting);
+      /*if (AppConfigInfo.value.IsRestApproval) {
+        // 如果小休需要审核
+        telRestProcess()
+            .then((res: any) => {
+              console.log('小休申请成功', res);
+              // 设置电话状态小休中
+              useTelStatusStore.setPhoneControlState(TelStates.rest);
+              useTelStatusStore.setRest(RestStates.resting);
+              ElMessage.success('小休开始!');
+            })
+            .catch((err: any) => {
+              console.log('小休申请失败', err);
+              restFlowDel().then(() => {
+                // 删除小休流程
+              });
+              ola.go_ready();// 示闲
+            });
+      } else {
+        // ElMessage.success('小休开始!');
+        // 设置电话状态小休中
+        useTelStatusStore.setPhoneControlState(TelStates.rest);
+        useTelStatusStore.setRest(RestStates.resting);
+        // 添加小休记录
+        telRestAdd({ reason: data.private_data })
+            .then((res: any) => {
+              console.log('小休记录添加成功 开始休息', res);
+              ElMessage.success('小休开始!');
+            })
+            .catch((err: any) => {
+              console.log('小休记录添加失败 开始休息', err);
+
+            });
+      }*/
+      console.log('示忙中');
+      break_reason(data.private_data);
+    } else if (data.state == 'acw') {
+      console.log('话后整理中');
+      const time: number = AppConfigInfo.value.TalkingDealTime * 1000; // 事后处理时间
+
+      ElNotification({
+        title: '自动开启事后处理成功',
+        message: `${AppConfigInfo.value.TalkingDealTime}秒后自动结束事后处理,或者手动结束事后处理`,
+        type: 'success',
+        duration: time,
+      });
+      // 设置事后处理
+      useTelStatusStore.setTalkingDeal(true);
+      // 设置话机状态 设置为事后处理中
+      useTelStatusStore.setPhoneControlState(TelStates.onTalkingDeal);
+      setTimeout(() => {
+        // 设置事后处理
+        useTelStatusStore.setTalkingDeal(false);
+        // 设置话机状态 取消事后处理修改为空闲状态
+        useTelStatusStore.setPhoneControlState(TelStates.dutyOn);
+        ola.go_ready(); // 示闲
+      }, 10000);
+
+    } else if (data.state == 'busy') {
+      console.log('通话中');
+    } else {
+      console.log(data.state);
+    }
+
+    if (data.state == 'busy') {
+      if (data.call_direction == 'outbound') {
+        if (data.private_data == 'calling') {
+          console.log('拨号中');
+        } else if (data.private_data == 'answered') {
+          if (data.other_answered == false) {
+            console.log('振铃中');
+          } else if (data.other_answered == true) {
+            console.log('通话中');
+          }
+        }
+      } else {
+        if (data.private_data == 'ring') {
+          console.log('振铃中');
+        } else if (data.private_data == 'answered') {
+          console.log('通话中');
+        }
+      }
+    } else if (data.old_state == 'busy') {
+      //挂机后系统可以返回两种状态:acw 话后整理状态 ready 示闲状态,如果不需要acw,可以联系我们后台修改配置,如果需要保留,如果需要再次
+      //拨打电话的话,需要手动点击示闲按钮
+      alert('已挂机');
+    }
+  } else if (data.event_type == 'agent_caller_state') {
+    //通话状态
+    // special feature, never mind
+    if (data.action == 'in') {
+      console.log('呼入', data.caller.cid_number, data.caller.uuid);
+      // ola.take_call(data.caller.uuid);
+    } else {
+      console.log('呼出', data.caller.uuid);
+    }
+  } else if (data.event_type == 'command/reply') {
+    // 其他消息
+    // console.log('command/reply', data);
+  }
+};
+// 呼叫中心链接关闭
+const onClose = () => {
+  ElMessage.error('呼叫中心断开链接');
+};
+// 小休原因
+const restReason = ref(''); // 小休原因
+const break_reason = (reason: string) => {
+  switch (reason) {
+    case 'away':
+      restReason.value = '外出中';
+      break;
+    case 'rest':
+      restReason.value = '小休中';
+      break;
+    case 'conference':
+      restReason.value = '会议中';
+      break;
+    case 'trainning':
+      restReason.value = '培训中';
+      break;
+    case 'coach':
+      restReason.value = '辅导中';
+      break;
+    default:
+      restReason.value = '示忙中';
+      break;
+  }
+  console.log(restReason.value)
+};
 //签入
 const dutyFormRef = ref<RefType>();
 const onDutyFn = async () => {
-	dutyFormRef.value?.resetFields();
+  websocket_connect();
+	/*dutyFormRef.value?.resetFields();
 	// 获取所有分机列表(未签入的)
 	const list = await getTelsLists({ sigin: 0 });
 	const isDefaultTelNo = list.some((item: any) => item.value === userInfos.value.defaultTelNo);
@@ -709,7 +854,7 @@ const onDutyFn = async () => {
 		// 如果默认分机号是空闲的,就默认选中
 		state.dutyForm.telNo = userInfos.value.defaultTelNo;
 	}
-	state.dutyDialogVisible = true;
+	state.dutyDialogVisible = true;*/
 };
 // 确认签入
 const clickOnDuty = (formEl: FormInstance | undefined) => {
@@ -718,12 +863,7 @@ const clickOnDuty = (formEl: FormInstance | undefined) => {
 		if (!valid) return;
 		state.loading = true;
 		// {telNo:state.dutyForm.telNo}
-    getGroup(state.dutyForm.telNo).then((res:any)=>{// 获取坐席分组
-      state.groupName = res.result.groupName ?? '';
-      state.loading = false;
-      state.dutyDialogVisible = false;
-      initWebsocket(); //开启消息监听
-    })
+    websocket_connect(); //开启消息监听
 	});
 };
 // 签出
@@ -738,10 +878,11 @@ const offDutyFn = () => {
 	})
 		.then(() => {
 			state.loading = true;
-			VoiceInterfaceObject.LogOut(); // 退出语音系统
+			ola.logout(ola_object.ola_extn); //签出
 			// 重置所有状态
 			useTelStatusStore.resetState();
 			state.loading = false;
+      state.dutyOnSrc =  getImageUrl('phoneControls/dutyOn_blue.png'); //签入图片
 		})
 		.catch(() => {
 			state.loading = false;
@@ -758,7 +899,9 @@ const onHangup = () => {
 		autofocus: false,
 	})
 		.then(() => {
-			VoiceInterfaceObject.HangUp(); // 挂断
+			state.loading = true;
+      ola.hangup(); //挂断
+      state.loading = false;
 		})
 		.catch(() => {});
 };
@@ -847,7 +990,7 @@ const clickOnRest = (formEl: FormInstance | undefined) => {
 				});
 		} else {
 			//不需要审核直接开始小休
-			VoiceInterfaceObject.SetBusy(state.restForm.reason); //设置忙碌
+			ola.go_break(state.restForm.reason); //设置忙碌
 			state.restDialogVisible = false;
 			state.loading = false;
 		}
@@ -874,7 +1017,7 @@ const onRestEnd = () => {
 	})
 		.then(() => {
 			state.loading = true;
-			VoiceInterfaceObject.SetIdle(); //设置空
+      ola.go_ready(); // 示
 			state.loading = false;
 		})
 		.catch(() => {});
@@ -891,7 +1034,7 @@ const onHold = () => {
 	})
 		.then(() => {
 			state.loading = true;
-			VoiceInterfaceObject.KeepInTouch();
+      ola.hold(); //保持
 			state.loading = false;
 		})
 		.catch(() => {});
@@ -908,30 +1051,14 @@ const onUnHold = () => {
 	})
 		.then(() => {
 			state.loading = true;
-			VoiceInterfaceObject.KeepCancelInTouch();
+      ola.hold(); //保持
 			state.loading = false;
 		})
 		.catch(() => {});
 };
-// 事后处理
+// 事后处理(系统默认进入)
 const onTalkingDeal = () => {
-	ElMessageBox.confirm(`确定要事后处理,是否继续?`, '提示', {
-		confirmButtonText: '确认',
-		cancelButtonText: '取消',
-		type: 'warning',
-		draggable: true,
-		cancelButtonClass: 'default-button',
-		autofocus: false,
-	})
-		.then(() => {
-			state.loading = true;
-			// 设置事后处理
-			useTelStatusStore.setTalkingDeal(true);
-			// 设置话机状态 设置为事后处理中
-			useTelStatusStore.setPhoneControlState(TelStates.onTalkingDeal);
-			state.loading = false;
-		})
-		.catch(() => {});
+
 };
 // 取消事后处理
 const unTalkingDeal = () => {
@@ -945,11 +1072,11 @@ const unTalkingDeal = () => {
 	})
 		.then(() => {
 			state.loading = true;
-			// 设置事后处理
-			useTelStatusStore.setTalkingDeal(false);
-			// 设置话机状态 取消时候处理修改为空闲状态
-			useTelStatusStore.setPhoneControlState(TelStates.dutyOn);
-			VoiceInterfaceObject.EndTalkingDeal(); //结束事后处理
+      // 设置事后处理
+      useTelStatusStore.setTalkingDeal(false);
+      // 设置话机状态 取消事后处理修改为空闲状态
+      useTelStatusStore.setPhoneControlState(TelStates.dutyOn);
+      ola.go_ready(); // 示闲
 			state.loading = false;
 		})
 		.catch(() => {});
@@ -960,33 +1087,33 @@ const onTransfer = () => {
 	//  重置表单
 	transferFormRef.value?.resetFields();
 	// 获取所有分机列表
-	getTelsLists().then(()=>{
-    state.transferDialogVisible = true;
-  })
+	getTelsLists().then(() => {
+		state.transferDialogVisible = true;
+	});
 };
 // 确认转接
 const clickOnTransfer = (formEl: FormInstance | undefined) => {
 	if (!formEl) return;
 	formEl.validate((valid: boolean) => {
 		if (!valid) return;
-		VoiceInterfaceObject.TeleSwitch(state.transferForm.telNo);
+    ola.transfer(state.transferForm.telNo); //转接
 		state.transferDialogVisible = false;
 	});
 };
 // 三方会议开始
 const onConference = () => {
-  ElMessageBox.confirm(`确定确定要开启三方会议,是否继续?`, '提示', {
-    confirmButtonText: '确认',
-    cancelButtonText: '取消',
-    type: 'warning',
-    draggable: true,
-    cancelButtonClass: 'default-button',
-    autofocus: false,
-  })
-      .then(() => {
-          VoiceInterfaceObject.Dtmf('0'); // 开启dtmf 三方通话
-      })
-      .catch(() => {});
+	ElMessageBox.confirm(`确定确定要开启三方会议,是否继续?`, '提示', {
+		confirmButtonText: '确认',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		cancelButtonClass: 'default-button',
+		autofocus: false,
+	})
+		.then(() => {
+			VoiceInterfaceObject.Dtmf('0'); // 开启dtmf 三方通话
+		})
+		.catch(() => {});
 };
 // 外呼
 const outboundFormRef = ref<RefType>(); //外呼
@@ -994,9 +1121,9 @@ const onOutbound = () => {
 	//  重置表单
 	outboundFormRef.value?.resetFields();
 	// 获取所有分机列表
-	getTelsLists().then(()=>{
-    state.outboundDialogVisible = true;
-  })
+	getTelsLists().then(() => {
+		state.outboundDialogVisible = true;
+	});
 };
 // 外呼保存
 const clickOnOutbound = (formEl: FormInstance | undefined) => {
@@ -1005,7 +1132,7 @@ const clickOnOutbound = (formEl: FormInstance | undefined) => {
 		if (!valid) return;
 		state.loading = true;
 		setTimeout(() => {
-			VoiceInterfaceObject.DialOut(state.outboundForm.telNo);
+			ola.dial(state.outboundForm.telNo, 'dsadasdsa');
 			state.outboundDialogVisible = false;
 			state.loading = false;
 		}, 300);
@@ -1015,12 +1142,14 @@ onMounted(() => {
 	signalRStart(); //开启消息监听
 	if (telStatusInfo.value.telsNo) {
 		// 有分机号
-		initWebsocket(); // 初始化websocket
+    websocket_connect(); // 链接呼叫中心
 	}
-	mittBus.on('startTalkTime', (message:string) => { // 开始计时
+	mittBus.on('startTalkTime', (message: string) => {
+		// 开始计时
 		startTime();
 	});
-	mittBus.on('endTalkTime', () => { // 结束计时
+	mittBus.on('endTalkTime', () => {
+		// 结束计时
 		removeTimer();
 	});
 });

+ 1 - 1
src/stores/telStatus.ts

@@ -55,7 +55,7 @@ export const useTelStatus = defineStore('telStatus', {
 		setRest(data: RestStates): void {
 			this.telStatusInfo.isRest = data;
 		},
-		// 设置静音状态
+		// 设置时候处理状态
 		setTalkingDeal(data: boolean): void {
 			this.telStatusInfo.isTalkingDeal = data;
 		},

+ 12 - 16
src/utils/ola_api.ts

@@ -1,6 +1,7 @@
 /**
  * @description 呼叫中心对接接口
  */
+import { ElMessage } from 'element-plus';
 export const ola: any = {
 	version: '2.0.1',
 	ws: undefined,
@@ -16,7 +17,7 @@ export const ola: any = {
 	_password: undefined,
 	_extn: undefined,
 
-	connect: function (url: string | URL, username: any, password: any, success: any, error: any) {
+	connect: function (url: string | URL, username: any, password: any, success?: any, error?: any) {
 		if (!url) url = 'ws://' + document.location.hostname + ':' + document.location.port + '/ola_socket';
 
 		if ('WebSocket' in window) {
@@ -33,12 +34,12 @@ export const ola: any = {
 			}
 		} else {
 			// browser does not support websockets
+			ElMessage.error("您的浏览器不支持websocket!")
 			if ('console' in window) {
 				console.log("you don't have websocket");
 			}
 			return false;
 		}
-
 		return this;
 	},
 
@@ -50,9 +51,7 @@ export const ola: any = {
 		ola.auth(ola._username, ola._password);
 	},
 
-	_onMessage: function (evt: { data: string; }) {
-		console.log(evt.data);
-
+	_onMessage: function (evt: any) { //获取消息
 		const msg = JSON.parse(evt.data);
 		if (msg.event_name == 'command/reply' && msg.code == 200) {
 			ola.ws.onmessage = this.onMessage;
@@ -65,8 +64,8 @@ export const ola: any = {
 		return ola.send({ cmd: 'auth', args: { username, password, accept: 'application/json' } });
 	},
 
-	get_agent_state: function () {
-		return this.send({ action: 'api', cmd: 'get_agent_state', args: { extn: this._extn } });
+	get_agent_state: function (extn:any) {
+		return this.send({ action: 'api', cmd: 'get_agent_state', args: { extn} });
 	},
 
 	get_trunk_state: function () {
@@ -80,8 +79,8 @@ export const ola: any = {
 		return ola.send({ action: 'api', cmd: 'login', args: args });
 	},
 
-	logout: function () {
-		return this.send({ action: 'api', cmd: 'logout', args: { extn: this._extn } });
+	logout: function (extn:string) {
+		return this.send({ action: 'api', cmd: 'logout', args: { extn } });
 	},
 
 	collect_dtmf: function (extn: any, soundfile: any) {
@@ -131,11 +130,11 @@ export const ola: any = {
 		return this.send({ action: 'api', cmd: 'hangup_other', args: { extn: this._extn } });
 	},
 
-	dial: function (dst: any, otherStr: any, gateway: any) {
+	dial: function (dst: any, otherStr: any, gateway?: any) {
 		return this.send({ action: 'api', cmd: 'dial', args: { extn: this._extn, dest: dst, gateway: gateway, otherStr: otherStr } });
 	},
 
-	transfer: function (dst: any, src: any) {
+	transfer: function (dst: any, src?: any) {
 		let extn = src;
 
 		if (extn == null || typeof extn == 'undefined') {
@@ -176,13 +175,11 @@ export const ola: any = {
 		return this.send({ action: 'api', cmd: 'intercept', args: { extn: this._extn, channel_uuid: uuid } });
 	},
 
-	three_way: function (dst: any, src: any, gateway: any) {
+	three_way: function (dst: any, src: any, gateway?: any) {
 		let extn = src;
-
 		if (extn == null || typeof extn == 'undefined') {
 			extn = this._extn;
 		}
-
 		return this.send({ action: 'api', cmd: 'monitor', args: { extn: extn, dest: dst, three_way: 'true', goip_gateway: gateway } });
 	},
 	/* hangup the thrid party */
@@ -319,9 +316,8 @@ export const ola: any = {
 		return ola.ws.readyState;
 	},
 
-	send: function (msg: { uuid: any; }) {
+	send: function (msg: any) { //发送消息
 		msg.uuid = ola.next_uuid();
-		console.log(JSON.stringify(msg));
 		ola.ws.send(JSON.stringify(msg));
 		return msg.uuid;
 	},

+ 1 - 1
src/utils/request.ts

@@ -143,7 +143,7 @@ function httpErrorStatusHandle(error: any) {
 								`/login?redirect=${router.currentRoute.value.path}&params=${JSON.stringify(
 									router.currentRoute.value.query ? router.currentRoute.value.query : router.currentRoute.value.params
 								)}`
-							); // 去登录页
+							).then(() => {}); // 去登录页
 							location.reload(); //刷新页面
 						})
 						.catch((): void => {});

+ 0 - 5
src/views/auxiliary/businessTag/component/Business-tag-add.vue → src/views/auxiliary/businessTag/components/Business-tag-add.vue

@@ -121,11 +121,6 @@ const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
 				emit('updateList');
 			})
 			.catch((error) => {
-				// 新增失败
-				ElMessage({
-					message: `操作失败: ${error.message}`,
-					type: 'error',
-				});
 			})
 			.finally(() => {
 				loading.value = false;

+ 0 - 5
src/views/auxiliary/businessTag/component/Business-tag-binding.vue → src/views/auxiliary/businessTag/components/Business-tag-binding.vue

@@ -79,11 +79,6 @@ const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
           emit('updateList');
         })
         .catch((error) => {
-          // 新增失败
-          ElMessage({
-            message: `操作失败: ${error.message}`,
-            type: 'error',
-          });
         })
         .finally(() => {
           loading.value = false;

+ 3 - 4
src/views/auxiliary/businessTag/component/Business-tag-edit.vue → src/views/auxiliary/businessTag/components/Business-tag-edit.vue

@@ -132,10 +132,9 @@ const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
 				emit('updateList');
 			})
 			.catch(() => {
-				// 新增失败
-				loading.value = false;
-				closeDialog();
-			});
+			}).finally(() => {
+        loading.value = false;
+        closeDialog();
 	});
 }, 300);
 // 暴露变量

+ 14 - 14
src/views/auxiliary/businessTag/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="system-business-tag-container layout-pd">
+  <div class="auxiliary-business-tag-container layout-pd">
     <el-card shadow="never">
       <el-form :model="state.queryParams" ref="ruleFormRef" :inline="true" @submit.native.prevent>
         <el-form-item label="关键字" prop="Keyword">
@@ -49,7 +49,7 @@
         <el-table-column prop="creatorOrgName" label="创建人部门" show-overflow-tooltip></el-table-column>
         <el-table-column label="操作" width="120" fixed="right" align="center">
           <template #default="{ row }">
-            <el-button link type="primary" @click="updateBusinessTah(row)" v-auth="'system:systemBusinessTag:edit'" title="修改参数"> 修改 </el-button>
+            <el-button link type="primary" @click="updateBusinessTag(row)" v-auth="'system:systemBusinessTag:edit'" title="修改业务标签"> 编辑 </el-button>
             <el-button link type="info" @click="viewBusinessTag(row)" v-auth="'auxiliary:businessTag:detail'" title="查看详情"> 查看 </el-button>
           </template>
         </el-table-column>
@@ -65,9 +65,9 @@
           @pagination="queryList"
       />
     </el-card>
-    <!--  参数新增  -->
+    <!--  新增标签  -->
     <business-tag-add ref="businessTagAddRef" @updateList="queryList" :businessTagType="businessTagType" :tagType="tagType"/>
-    <!--  参数编辑  -->
+    <!--  编辑标签  -->
     <business-tag-edit ref="businessTagEditRef" @updateList="queryList" :businessTagType="businessTagType" :tagType="tagType"/>
     <!--  批量绑定  -->
     <business-tag-binding-com ref="businessTagBindingRef" @updateList="queryList"/>
@@ -81,9 +81,9 @@ import { formatDate } from '/@/utils/formatTime';
 import {auth} from "/@/utils/authFunction";
 import { businessTagList,businessTagBaseData,businessTagDelete } from '/@/api/auxiliary/businessTag';
 // 引入组件
-const BusinessTagBindingCom = defineAsyncComponent(() => import('/@/views/auxiliary/businessTag/component/Business-tag-binding.vue')); // 绑定标签
-const BusinessTagAdd = defineAsyncComponent(() => import('/@/views/auxiliary/businessTag/component/Business-tag-add.vue')); // 参数标签
-const BusinessTagEdit = defineAsyncComponent(() => import('/@/views/auxiliary/businessTag/component/Business-tag-edit.vue')); // 编辑标签
+const BusinessTagBindingCom = defineAsyncComponent(() => import('/@/views/auxiliary/businessTag/components/Business-tag-binding.vue')); // 绑定标签
+const BusinessTagAdd = defineAsyncComponent(() => import('/@/views/auxiliary/businessTag/components/Business-tag-add.vue')); // 新增标签
+const BusinessTagEdit = defineAsyncComponent(() => import('/@/views/auxiliary/businessTag/components/Business-tag-edit.vue')); // 编辑标签
 
 // 定义变量内容
 const state = reactive<any>({
@@ -134,14 +134,14 @@ const resetQuery = (formEl: FormInstance | undefined) => {
   formEl.resetFields();
   queryList();
 };
-// 新增参数
-const businessTagAddRef = ref<RefType>(); // 参数新增
+// 新增标签
+const businessTagAddRef = ref<RefType>(); // 新增标签
 const addParameter = () => {
   businessTagAddRef.value.openDialog();
 };
-// 修改参数
-const businessTagEditRef = ref<RefType>(); // 参数编辑
-const updateBusinessTah = (row: any) => {
+// 修改标签
+const businessTagEditRef = ref<RefType>(); // 修改标签
+const updateBusinessTag = (row: any) => {
   businessTagEditRef.value.openDialog(row.id);
 };
 // 查看详情
@@ -154,7 +154,7 @@ const multipleSelection = ref<any>([]);
 const handleSelectionChange = (val: any[]) => {
   multipleSelection.value = val;
 };
-// 删除参数
+// 删除标签
 const businessTagRemove = (row: any) => {
   const ids = multipleSelection.value.map((item: any) => item.id);
   const names = multipleSelection.value.map((item: any) => item.name);
@@ -188,7 +188,7 @@ onMounted(() => {
 </script>
 
 <style lang="scss" scoped>
-.system-business-tag-container{
+.auxiliary-business-tag-container{
 
 }
 </style>

+ 158 - 0
src/views/auxiliary/knowledgeLexicon/components/Knowledge-lexicon-add.vue

@@ -0,0 +1,158 @@
+<template>
+		<el-dialog v-model="state.dialogVisible" width="800px" draggable title="新增知识库词库" @close="close">
+      <el-form :model="state.ruleForm" label-width="110px" ref="ruleFormRef">
+        <el-row :gutter="10">
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="知识库关键词" prop="tag" :rules="[{ required: true, message: '请输入知识库关键词', trigger: 'blur' }]">
+              <el-input v-model="state.ruleForm.tag" placeholder="请输入知识库关键词" clearable></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+            <el-form-item label="标签分类" prop="classifyArray" :rules="[{ required: true, message: '请选择标签分类', trigger: 'change' }]">
+              <el-select v-model="state.ruleForm.classifyArray" placeholder="请选择标签分类" class="w100" multiple collapse-tags collapse-tags-tooltip>
+                <el-option v-for="item in knowledgeWordClassify" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="是否启用" prop="isEnable" :rules="[{ required: false, message: '请选择是否启用性', trigger: 'change' }]">
+              <el-switch v-model="state.ruleForm.isEnable" inline-prompt active-text="是" inactive-text="否" :active-value="1" :inactive-value="0" />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="标签近义词" prop="synonym" :rules="[{ required: false, message: '请输入标签近义词', trigger: 'change' }]">
+              <el-tag v-for="tag in dynamicTags" :key="tag" class="mr10 mb10" size="large" closable @close="handleClose(tag)">
+                {{ tag }}
+              </el-tag>
+              <el-input
+                  v-if="inputVisible"
+                  ref="InputRef"
+                  v-model="inputValue"
+                  @keyup.enter="handleInputConfirm"
+                  @blur="handleInputConfirm"
+                  style="max-width: 200px"
+                  class="mb10"
+                  placeholder="请输入标签近义词"
+              />
+              <el-button v-else @click="showInput" class="mb10"> 添加近义词 </el-button>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="备注说明" prop="remark" :rules="[{ required: false, message: '请输入备注说明', trigger: 'blur' }]">
+              <el-input v-model="state.ruleForm.remark" placeholder="请输入备注说明" type="textarea" :autosize="{ minRows: 4, maxRows: 8 }"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="closeDialog" class="default-button">取 消</el-button>
+					<el-button type="primary" @click="onSubmit(ruleFormRef)" :loading="loading">确 定</el-button>
+				</span>
+			</template>
+		</el-dialog>
+</template>
+
+<script setup lang="ts" name="knowledgeLexiconAdd">
+import {nextTick, reactive, ref} from 'vue';
+import {ElInput, ElMessage, FormInstance} from 'element-plus';
+import { throttle } from '/@/utils/tools';
+import { knowledgeLexiconAdd } from '/@/api/auxiliary/knowledgeLexicon';
+
+const props = defineProps({
+  knowledgeWordClassify: {
+    type: Array,
+    default: () => <EmptyArrayType>[],
+  }
+})
+
+const inputValue = ref('');
+const dynamicTags = ref<EmptyArrayType>([]);
+const inputVisible = ref(false);
+const InputRef = ref<InstanceType<typeof ElInput>>();
+// 删除同义词
+const handleClose = (tag: string) => {
+  dynamicTags.value.splice(dynamicTags.value.indexOf(tag), 1);
+};
+// 展示输入框
+const showInput = () => {
+  inputVisible.value = true;
+  nextTick(() => {
+    InputRef.value!.input!.focus();
+  });
+};
+// 确定添加
+const handleInputConfirm = () => {
+  if (inputValue.value) {
+    dynamicTags.value.push(inputValue.value);
+  }
+  inputVisible.value = false;
+  inputValue.value = '';
+};
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+
+// 定义变量内容
+const state = reactive<any>({
+	dialogVisible: false,
+	ruleForm: {
+    tag: '', // 关键词
+    classifyArray: [], // 标签分类
+    isEnable: 1, // 是否启用
+    synonym: '', // 违禁同义词
+    remark: '', // 备注说明
+	},
+});
+let loading = ref<boolean>(false);  // 加载状态
+// 打开弹窗
+const ruleFormRef = ref<RefType>();
+const openDialog = async () => {
+	ruleFormRef.value?.resetFields();
+	try {
+		state.dialogVisible = true;
+	} catch (error) {
+		console.log(error);
+	}
+};
+// 关闭弹窗
+const closeDialog = () => {
+	state.dialogVisible = false;
+};
+const close = ()=>{
+  ruleFormRef.value?.resetFields();
+  ruleFormRef.value?.resetFields();
+}
+// 新增
+const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	await formEl.validate((valid: boolean) => {
+		if (!valid) return;
+		loading.value = true;
+    const request = {
+      ...state.ruleForm,
+      synonym: dynamicTags.value.join(','),
+      classify: state.ruleForm.classifyArray.join(','),
+    };
+    knowledgeLexiconAdd(request)
+			.then(() => {
+				ElMessage({
+					message: '操作成功',
+					type: 'success',
+				});
+				emit('updateList');
+			})
+			.catch(() => {
+			})
+			.finally(() => {
+				loading.value = false;
+				closeDialog();
+			});
+	});
+}, 300);
+// 暴露变量
+defineExpose({
+	openDialog,
+	closeDialog,
+});
+</script>

+ 167 - 0
src/views/auxiliary/knowledgeLexicon/components/Knowledge-lexicon-edit.vue

@@ -0,0 +1,167 @@
+<template>
+	<el-dialog v-model="state.dialogVisible" width="800px" draggable title="编辑知识库词库" @close="close">
+		<el-form :model="state.ruleForm" label-width="110px" ref="ruleFormRef">
+			<el-row :gutter="10">
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="知识库关键词" prop="tag" :rules="[{ required: true, message: '请输入知识库关键词', trigger: 'blur' }]">
+						<el-input v-model="state.ruleForm.tag" placeholder="请输入知识库关键词" clearable></el-input>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="标签分类" prop="classifyArray" :rules="[{ required: true, message: '请选择标签分类', trigger: 'change' }]">
+						<el-select v-model="state.ruleForm.classifyArray" placeholder="请选择标签分类" class="w100" multiple collapse-tags collapse-tags-tooltip>
+							<el-option v-for="item in knowledgeWordClassify" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+						</el-select>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="是否启用" prop="isEnable" :rules="[{ required: false, message: '请选择是否启用性', trigger: 'change' }]">
+						<el-switch v-model="state.ruleForm.isEnable" inline-prompt active-text="是" inactive-text="否" :active-value="1" :inactive-value="0" />
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="标签近义词" prop="synonym" :rules="[{ required: false, message: '请输入标签近义词', trigger: 'change' }]">
+						<el-tag v-for="tag in dynamicTags" :key="tag" class="mr10 mb10" size="large" closable @close="handleClose(tag)">
+							{{ tag }}
+						</el-tag>
+						<el-input
+							v-if="inputVisible"
+							ref="InputRef"
+							v-model="inputValue"
+							@keyup.enter="handleInputConfirm"
+							@blur="handleInputConfirm"
+							style="max-width: 200px"
+							class="mb10"
+							placeholder="请输入标签近义词"
+						/>
+						<el-button v-else @click="showInput" class="mb10"> 添加近义词 </el-button>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="备注说明" prop="remark" :rules="[{ required: false, message: '请输入备注说明', trigger: 'blur' }]">
+						<el-input v-model="state.ruleForm.remark" placeholder="请输入备注说明" type="textarea" :autosize="{ minRows: 4, maxRows: 8 }"></el-input>
+					</el-form-item>
+				</el-col>
+			</el-row>
+		</el-form>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="closeDialog" class="default-button">取 消</el-button>
+				<el-button type="primary" @click="onSubmit(ruleFormRef)" :loading="loading">确 定</el-button>
+			</span>
+		</template>
+	</el-dialog>
+</template>
+
+<script setup lang="ts" name="knowledgeLexiconEdit">
+import { nextTick, reactive, ref } from 'vue';
+import { ElInput, ElMessage, FormInstance } from 'element-plus';
+import { throttle } from '/@/utils/tools';
+import { knowledgeLexiconUpdate, knowledgeLexiconDetail } from '/@/api/auxiliary/knowledgeLexicon';
+
+const props = defineProps({
+  knowledgeWordClassify: {
+		type: Array,
+		default: () => <EmptyArrayType>[],
+	}
+});
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+
+const inputValue = ref('');
+const dynamicTags = ref<EmptyArrayType>([]);
+const inputVisible = ref(false);
+const InputRef = ref<InstanceType<typeof ElInput>>();
+// 删除同义词
+const handleClose = (tag: string) => {
+	dynamicTags.value.splice(dynamicTags.value.indexOf(tag), 1);
+};
+// 展示输入框
+const showInput = () => {
+	inputVisible.value = true;
+	nextTick(() => {
+		InputRef.value!.input!.focus();
+	});
+};
+// 确定添加
+const handleInputConfirm = () => {
+	if (inputValue.value) {
+		dynamicTags.value.push(inputValue.value);
+	}
+	inputVisible.value = false;
+	inputValue.value = '';
+};
+
+// 定义变量内容
+const state = reactive<any>({
+	dialogVisible: false,
+	ruleForm: {
+		tag: '', // 关键词
+		classifyArray: [], // 标签分类
+		isEnable: 1, // 是否启用
+		synonym: '', // 违禁同义词
+		remark: '', // 备注说明
+	},
+	isDisabled: false, // 是否禁用
+});
+let loading = ref<boolean>(false); // 加载状态
+// 打开弹窗
+const ruleFormRef = ref<RefType>();
+const openDialog = async (id: string) => {
+	try {
+		const res = await knowledgeLexiconDetail(id);
+		state.ruleForm = {
+			tag: res.result?.tag, // 工单关键词
+			classifyArray: res.result?.classify.split(','), // 标签分类
+			isEnable: res.result?.isEnable, // 是否启用
+			synonym: res.result?.synonym.split(','), // 违禁同义词
+			remark: res.result?.remark, // 备注说明
+			...res.result,
+		};
+		state.dialogVisible = true;
+	} catch (error) {
+		console.log(error);
+	}
+};
+// 关闭弹窗
+const closeDialog = () => {
+	state.dialogVisible = false;
+};
+const close = () => {
+	ruleFormRef.value?.resetFields();
+	ruleFormRef.value?.resetFields();
+};
+// 新增
+const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	await formEl.validate((valid: boolean) => {
+		if (!valid) return;
+		loading.value = true;
+		const request = {
+			...state.ruleForm,
+			synonym: dynamicTags.value.join(','),
+			classify: state.ruleForm.classifyArray.join(','),
+		};
+		knowledgeLexiconUpdate(request)
+			.then(() => {
+				ElMessage({
+					message: '操作成功',
+					type: 'success',
+				});
+				loading.value = false;
+				closeDialog();
+				emit('updateList');
+			})
+			.catch(() => {
+				// 新增失败
+				loading.value = false;
+				closeDialog();
+			});
+	});
+}, 300);
+// 暴露变量
+defineExpose({
+	openDialog,
+	closeDialog,
+});
+</script>

+ 184 - 0
src/views/auxiliary/knowledgeLexicon/index.vue

@@ -0,0 +1,184 @@
+<template>
+  <div class="auxiliary-knowledge-lexicon-container layout-pd">
+    <el-card shadow="never">
+      <el-form :model="state.queryParams" ref="ruleFormRef" :inline="true" @submit.native.prevent>
+        <el-form-item label="标签" prop="Tag">
+          <el-input v-model="state.queryParams.Tag" placeholder="请输入标签" clearable @keyup.enter="queryList" />
+        </el-form-item>
+        <el-form-item label="分类" prop="Classify">
+          <el-select v-model="state.queryParams.Classify" placeholder="请选择分类">
+            <el-option v-for="item in knowledgeWordClassify" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="近义词" prop="Synonym">
+          <el-input v-model="state.queryParams.Synonym" placeholder="请输入近义词" clearable @keyup.enter="queryList" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="queryList" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+          <el-button @click="resetQuery(ruleFormRef)" class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+    <el-card shadow="never">
+      <div class="mb20">
+        <el-button type="primary" @click="addParameter" v-auth="'auxiliary:knowledgeLexicon:add'">
+          <SvgIcon name="ele-Plus" class="mr5" />新增
+        </el-button>
+        <el-button type="primary" @click="businessTagRemove" v-auth="'auxiliary:knowledgeLexicon:delete'" :disabled="!multipleSelection.length">
+          <SvgIcon name="ele-Delete" class="mr5" />删除
+         </el-button>
+      </div>
+      <!-- 表格 -->
+      <el-table :data="state.tableData" v-loading="state.loading" row-key="id" ref="multipleTableRef" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="classify" label="词性分类" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="tag" label="关键词" show-overflow-tooltip width="130"></el-table-column>
+        <el-table-column prop="synonym" label="同义词" show-overflow-tooltip width="130"></el-table-column>
+        <el-table-column label="是否启用" show-overflow-tooltip>
+          <template #default="{ row }">
+            <span>{{ row.isEnable === 1 ? '启用' : '禁用' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="creatorName" label="创建人" show-overflow-tooltip></el-table-column>
+        <el-table-column label="创建时间" show-overflow-tooltip width="170">
+          <template #default="{ row }">
+            <span>{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="lastModificationName" label="更新人" show-overflow-tooltip></el-table-column>
+        <el-table-column label="更新时间" show-overflow-tooltip width="170">
+          <template #default="{ row }">
+            <span>{{ formatDate(row.lastModificationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="120" fixed="right" align="center">
+          <template #default="{ row }">
+            <el-button link type="primary" @click="updateLexicon(row)" v-auth="'auxiliary:knowledgeLexicon:edit'" title="编辑知识库词库">
+              编辑
+            </el-button>
+          </template>
+        </el-table-column>
+        <template #empty>
+          <Empty />
+        </template>
+      </el-table>
+      <!-- 分页 -->
+      <pagination
+          :total="state.total"
+          v-model:page="state.queryParams.PageIndex"
+          v-model:limit="state.queryParams.PageSize"
+          @pagination="queryList"
+      />
+    </el-card>
+    <!--  新增知识库词库  -->
+    <knowledge-lexicon-add ref="knowledgeLexiconAddRef" @updateList="queryList" :knowledgeWordClassify="knowledgeWordClassify"/>
+    <!--  编辑知识库词库  -->
+    <knowledge-lexicon-edit ref="knowledgeLexiconEditRef" @updateList="queryList" :knowledgeWordClassify="knowledgeWordClassify"/>
+  </div>
+</template>
+
+<script lang="ts" setup name="auxiliaryKnowledgeLexicon">
+import { reactive, ref, onMounted, defineAsyncComponent } from 'vue';
+import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
+import { formatDate } from '/@/utils/formatTime';
+import {auth} from "/@/utils/authFunction";
+import { knowledgeLexiconList,knowledgeLexiconDelete,orderKnowledgeBaseData } from '/@/api/auxiliary/knowledgeLexicon';
+// 引入组件
+const KnowledgeLexiconAdd = defineAsyncComponent(() => import('/@/views/auxiliary/knowledgeLexicon/components/Knowledge-lexicon-add.vue')); // 新增知识库词库
+const KnowledgeLexiconEdit = defineAsyncComponent(() => import('/@/views/auxiliary/knowledgeLexicon/components/Knowledge-lexicon-edit.vue')); // 编辑知识库词库
+
+// 定义变量内容
+const state = reactive<any>({
+  loading: false, // 加载状态
+  queryParams: {
+    // 查询参数
+    PageIndex: 1,
+    PageSize: 10,
+    Tag: null, // 标签
+    Classify: null, // 标签类型
+    Synonym: null, // 近义词
+  },
+  total: 0, // 总条数
+  tableData: [], // 表格数据
+});
+const ruleFormRef = ref<any>(null); // 表单ref
+const knowledgeWordClassify = ref<EmptyArrayType>();// 标签类型
+// 获取基础数据
+const getBaseData = async ()=>{
+  try {
+    const res = await orderKnowledgeBaseData();
+    knowledgeWordClassify.value = res.result?.knowledgeWordClassify ?? [];
+  }catch (error){
+    console.log(error)
+  }
+}
+// 获取参数列表
+const queryList = () => {
+  state.loading = true;
+  if (!auth('auxiliary:knowledgeLexicon:query')) ElMessage.error('抱歉,您没有权限获取知识库词库列表!');
+  else {
+    knowledgeLexiconList(state.queryParams)
+        .then((res) => {
+          state.loading = false;
+          state.tableData = res.result.items ?? [];
+          state.total = res.result.total ?? 0;
+        })
+        .finally(() => {
+          state.loading = false;
+        });
+  }
+};
+// 重置表单
+const resetQuery = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+  queryList();
+};
+// 新增词库
+const knowledgeLexiconAddRef = ref<RefType>();
+const addParameter = () => {
+  knowledgeLexiconAddRef.value.openDialog();
+};
+// 编辑知识库词库
+const knowledgeLexiconEditRef = ref<RefType>();
+const updateLexicon = (row: any) => {
+  knowledgeLexiconEditRef.value.openDialog(row.id);
+};
+// 表格多选
+const multipleTableRef = ref<RefType>();
+const multipleSelection = ref<any>([]);
+const handleSelectionChange = (val: any[]) => {
+  multipleSelection.value = val;
+};
+// 删除词库
+const businessTagRemove = (row: any) => {
+  const ids = multipleSelection.value.map((item: any) => item.id);
+  const names = multipleSelection.value.map((item: any) => item.name);
+  ElMessageBox.confirm(`您确定要删除:【${names}】,是否继续?`, '提示', {
+    confirmButtonText: '确认',
+    cancelButtonText: '取消',
+    type: 'warning',
+    draggable: true,
+    cancelButtonClass: 'default-button',
+    autofocus: false,
+  })
+      .then(() => {
+        knowledgeLexiconDelete({ids}).then(() => {
+          ElMessage.success('操作成功');
+          queryList();
+        });
+      })
+      .catch(() => {});
+};
+// 页面加载时
+onMounted(() => {
+  getBaseData()
+  queryList();
+});
+</script>
+
+<style lang="scss" scoped>
+.auxiliary-knowledge-lexicon-container{
+
+}
+</style>

+ 157 - 0
src/views/auxiliary/orderLexicon/components/Order-lexicon-add.vue

@@ -0,0 +1,157 @@
+<template>
+	<el-dialog v-model="state.dialogVisible" width="800px" draggable title="新增工单词库" @close="close">
+		<el-form :model="state.ruleForm" label-width="100px" ref="ruleFormRef">
+			<el-row :gutter="10">
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="工单关键词" prop="tag" :rules="[{ required: true, message: '请输入工单关键词', trigger: 'blur' }]">
+						<el-input v-model="state.ruleForm.tag" placeholder="请输入工单关键词" clearable></el-input>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="标签分类" prop="classifyArray" :rules="[{ required: true, message: '请选择标签分类', trigger: 'change' }]">
+						<el-select v-model="state.ruleForm.classifyArray" placeholder="请选择标签分类" class="w100" multiple collapse-tags collapse-tags-tooltip>
+							<el-option v-for="item in orderWordClassify" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+						</el-select>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="是否启用" prop="isEnable" :rules="[{ required: false, message: '请选择是否启用性', trigger: 'change' }]">
+						<el-switch v-model="state.ruleForm.isEnable" inline-prompt active-text="是" inactive-text="否" :active-value="1" :inactive-value="0" />
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="标签近义词" prop="synonym" :rules="[{ required: false, message: '请输入标签近义词', trigger: 'change' }]">
+						<el-tag v-for="tag in dynamicTags" :key="tag" class="mr10 mb10" size="large" closable @close="handleClose(tag)">
+							{{ tag }}
+						</el-tag>
+						<el-input
+							v-if="inputVisible"
+							ref="InputRef"
+							v-model="inputValue"
+							@keyup.enter="handleInputConfirm"
+							@blur="handleInputConfirm"
+							style="max-width: 200px"
+							class="mb10"
+							placeholder="请输入标签近义词"
+						/>
+						<el-button v-else @click="showInput" class="mb10"> 添加近义词 </el-button>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="备注说明" prop="remark" :rules="[{ required: false, message: '请输入备注说明', trigger: 'blur' }]">
+						<el-input v-model="state.ruleForm.remark" placeholder="请输入备注说明" type="textarea" :autosize="{ minRows: 4, maxRows: 8 }"></el-input>
+					</el-form-item>
+				</el-col>
+			</el-row>
+		</el-form>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="closeDialog" class="default-button">取 消</el-button>
+				<el-button type="primary" @click="onSubmit(ruleFormRef)" :loading="loading">确 定</el-button>
+			</span>
+		</template>
+	</el-dialog>
+</template>
+
+<script setup lang="ts" name="orderLexiconAdd">
+import { nextTick, reactive, ref } from 'vue';
+import { ElInput, ElMessage, FormInstance } from 'element-plus';
+import { throttle } from '/@/utils/tools';
+import { orderLexiconAdd } from '/@/api/auxiliary/orderLexicon';
+
+const props = defineProps({
+	orderWordClassify: {
+		type: Array,
+		default: () => <EmptyArrayType>[],
+	},
+});
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+
+const inputValue = ref('');
+const dynamicTags = ref<EmptyArrayType>([]);
+const inputVisible = ref(false);
+const InputRef = ref<InstanceType<typeof ElInput>>();
+// 删除同义词
+const handleClose = (tag: string) => {
+	dynamicTags.value.splice(dynamicTags.value.indexOf(tag), 1);
+};
+// 展示输入框
+const showInput = () => {
+	inputVisible.value = true;
+	nextTick(() => {
+		InputRef.value!.input!.focus();
+	});
+};
+// 确定添加
+const handleInputConfirm = () => {
+	if (inputValue.value) {
+		dynamicTags.value.push(inputValue.value);
+	}
+	inputVisible.value = false;
+	inputValue.value = '';
+};
+
+// 定义变量内容
+const state = reactive<any>({
+	dialogVisible: false,
+	ruleForm: {
+		tag: '', // 工单关键词
+    classifyArray: [], // 标签分类
+		isEnable: 1, // 是否启用
+		synonym: '', // 违禁同义词
+		remark: '', // 备注说明
+	},
+});
+let loading = ref<boolean>(false); // 加载状态
+// 打开弹窗
+const ruleFormRef = ref<RefType>();
+const openDialog = async () => {
+	ruleFormRef.value?.resetFields();
+	try {
+		state.dialogVisible = true;
+	} catch (error) {
+		console.log(error);
+	}
+};
+// 关闭弹窗
+const closeDialog = () => {
+	state.dialogVisible = false;
+};
+const close = ()=>{
+  ruleFormRef.value?.resetFields();
+  ruleFormRef.value?.resetFields();
+}
+// 新增
+const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	await formEl.validate((valid: boolean) => {
+		if (!valid) return;
+		loading.value = true;
+		const request = {
+			...state.ruleForm,
+			synonym: dynamicTags.value.join(','),
+      classify: state.ruleForm.classifyArray.join(','),
+		};
+		orderLexiconAdd(request)
+			.then(() => {
+				ElMessage({
+					message: '操作成功',
+					type: 'success',
+				});
+				emit('updateList');
+			})
+			.catch((error) => {})
+			.finally(() => {
+				loading.value = false;
+				closeDialog();
+			});
+	});
+}, 300);
+// 暴露变量
+defineExpose({
+	openDialog,
+	closeDialog,
+});
+</script>

+ 174 - 0
src/views/auxiliary/orderLexicon/components/Order-lexicon-edit.vue

@@ -0,0 +1,174 @@
+<template>
+	<el-dialog v-model="state.dialogVisible" width="800px" draggable title="编辑工单词库" @close="close">
+		<el-form :model="state.ruleForm" label-width="100px" ref="ruleFormRef">
+			<el-row :gutter="10">
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="工单关键词" prop="tag" :rules="[{ required: true, message: '请输入工单关键词', trigger: 'blur' }]">
+						<el-input v-model="state.ruleForm.tag" placeholder="请输入工单关键词" clearable></el-input>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="标签分类" prop="classifyArray" :rules="[{ required: false, message: '请选择标签分类', trigger: 'change' }]">
+						<el-select v-model="state.ruleForm.classifyArray" placeholder="请选择标签分类" class="w100" multiple collapse-tags collapse-tags-tooltip>
+							<el-option v-for="item in orderWordClassify" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+						</el-select>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="是否启用" prop="isEnable" :rules="[{ required: false, message: '请选择是否启用性', trigger: 'change' }]">
+						<el-switch v-model="state.ruleForm.isEnable" inline-prompt active-text="是" inactive-text="否" :active-value="1" :inactive-value="0" />
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="标签近义词" prop="synonym" :rules="[{ required: false, message: '请输入标签近义词', trigger: 'change' }]">
+						<el-tag
+							v-for="tag in dynamicTags"
+							:key="tag"
+							class="mr10 mb10"
+							size="large"
+							closable
+							:disable-transitions="false"
+							@close="handleClose(tag)"
+						>
+							{{ tag }}
+						</el-tag>
+						<el-input
+							v-if="inputVisible"
+							ref="InputRef"
+							v-model="inputValue"
+							@keyup.enter="handleInputConfirm"
+							@blur="handleInputConfirm"
+							style="max-width: 200px"
+							class="mb10"
+							placeholder="请输入标签近义词"
+						/>
+						<el-button v-else @click="showInput" class="mb10"> 添加近义词 </el-button>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="备注说明" prop="remark" :rules="[{ required: false, message: '请输入备注说明', trigger: 'blur' }]">
+						<el-input v-model="state.ruleForm.remark" placeholder="请输入备注说明" type="textarea" :autosize="{ minRows: 4, maxRows: 8 }"></el-input>
+					</el-form-item>
+				</el-col>
+			</el-row>
+		</el-form>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="closeDialog" class="default-button">取 消</el-button>
+				<el-button type="primary" @click="onSubmit(ruleFormRef)" :loading="loading">确 定</el-button>
+			</span>
+		</template>
+	</el-dialog>
+</template>
+
+<script setup lang="ts" name="orderLexiconEdit">
+import {  nextTick, reactive, ref } from 'vue';
+import { ElInput, ElMessage, FormInstance } from 'element-plus';
+import { throttle } from '/@/utils/tools';
+import { orderLexiconUpdate, orderLexiconDetail } from '/@/api/auxiliary/orderLexicon';
+
+const props = defineProps({
+	orderWordClassify: {
+		type: Array,
+		default: () => <EmptyArrayType>[],
+	},
+});
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+
+const inputValue = ref('');
+const dynamicTags = ref<EmptyArrayType>([]);
+const inputVisible = ref(false);
+const InputRef = ref<InstanceType<typeof ElInput>>();
+// 删除同义词
+const handleClose = (tag: string) => {
+	dynamicTags.value.splice(dynamicTags.value.indexOf(tag), 1);
+};
+// 展示输入框
+const showInput = () => {
+	inputVisible.value = true;
+	nextTick(() => {
+		InputRef.value!.input!.focus();
+	});
+};
+// 确定添加
+const handleInputConfirm = () => {
+	if (inputValue.value) {
+		dynamicTags.value.push(inputValue.value);
+	}
+	inputVisible.value = false;
+	inputValue.value = '';
+};
+
+// 定义变量内容
+const state = reactive<any>({
+	dialogVisible: false,
+	ruleForm: {
+		tag: '', // 工单关键词
+    classifyArray: [], // 标签分类
+		isEnable: 1, // 是否启用
+		synonym: '', // 违禁同义词
+		remark: '', // 备注说明
+	},
+});
+let loading = ref<boolean>(false); // 加载状态
+// 打开弹窗
+const ruleFormRef = ref<RefType>();
+const openDialog = async (id: string) => {
+	try {
+    const res = await orderLexiconDetail(id);
+    state.ruleForm = {
+      tag: res.result?.tag, // 工单关键词
+      classifyArray: res.result?.classify.split(','), // 标签分类
+      isEnable: res.result?.isEnable, // 是否启用
+      synonym: res.result?.synonym.split(','), // 违禁同义词
+      remark: res.result?.remark, // 备注说明
+      ...res.result
+    }
+    state.dialogVisible = true;
+	} catch (error) {
+		console.log(error);
+	}
+};
+// 关闭弹窗
+const closeDialog = () => {
+	state.dialogVisible = false;
+};
+const close = ()=>{
+  ruleFormRef.value?.resetFields();
+  ruleFormRef.value?.resetFields();
+}
+// 新增
+const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	await formEl.validate((valid: boolean) => {
+		if (!valid) return;
+		loading.value = true;
+    const request = {
+      ...state.ruleForm,
+      synonym: dynamicTags.value.join(','),
+      classify: state.ruleForm.classifyArray.join(','),
+    };
+		orderLexiconUpdate(request)
+			.then(() => {
+				ElMessage({
+					message: '操作成功',
+					type: 'success',
+				});
+				loading.value = false;
+				closeDialog();
+				emit('updateList');
+			})
+			.catch(() => {
+				// 新增失败
+				loading.value = false;
+				closeDialog();
+			});
+	});
+}, 300);
+// 暴露变量
+defineExpose({
+	openDialog,
+	closeDialog,
+});
+</script>

+ 184 - 0
src/views/auxiliary/orderLexicon/index.vue

@@ -0,0 +1,184 @@
+<template>
+	<div class="auxiliary-order-lexicon-container layout-pd">
+		<el-card shadow="never">
+			<el-form :model="state.queryParams" ref="ruleFormRef" :inline="true" @submit.native.prevent>
+				<el-form-item label="标签" prop="Tag">
+					<el-input v-model="state.queryParams.Tag" placeholder="请输入标签" clearable @keyup.enter="queryList" />
+				</el-form-item>
+				<el-form-item label="分类" prop="Classify">
+					<el-select v-model="state.queryParams.Classify" placeholder="请选择分类">
+						<el-option v-for="item in orderWordClassify" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+					</el-select>
+				</el-form-item>
+        <el-form-item label="近义词" prop="Synonym">
+          <el-input v-model="state.queryParams.Synonym" placeholder="请输入近义词" clearable @keyup.enter="queryList" />
+        </el-form-item>
+				<el-form-item>
+					<el-button type="primary" @click="queryList" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+					<el-button @click="resetQuery(ruleFormRef)" class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+				</el-form-item>
+			</el-form>
+		</el-card>
+		<el-card shadow="never">
+			<div class="mb20">
+				<el-button type="primary" @click="addParameter" v-auth="'auxiliary:orderLexicon:add'">
+					<SvgIcon name="ele-Plus" class="mr5" />新增
+				</el-button>
+				<el-button type="primary" @click="businessTagRemove" v-auth="'auxiliary:orderLexicon:delete'" :disabled="!multipleSelection.length">
+					<SvgIcon name="ele-Delete" class="mr5" />删除
+				</el-button>
+			</div>
+			<!-- 表格 -->
+			<el-table :data="state.tableData" v-loading="state.loading" row-key="id" ref="multipleTableRef" @selection-change="handleSelectionChange">
+				<el-table-column type="selection" width="55" />
+				<el-table-column prop="classify" label="词性分类" show-overflow-tooltip></el-table-column>
+				<el-table-column prop="tag" label="关键词" show-overflow-tooltip width="130"></el-table-column>
+        <el-table-column prop="synonym" label="同义词" show-overflow-tooltip width="130"></el-table-column>
+				<el-table-column label="是否启用" show-overflow-tooltip>
+          <template #default="{ row }">
+            <span>{{ row.isEnable === 1 ? '启用' : '禁用' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="creatorName" label="创建人" show-overflow-tooltip></el-table-column>
+				<el-table-column label="创建时间" show-overflow-tooltip width="170">
+					<template #default="{ row }">
+						<span>{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+					</template>
+				</el-table-column>
+				<el-table-column prop="lastModificationName" label="更新人" show-overflow-tooltip></el-table-column>
+        <el-table-column label="更新时间" show-overflow-tooltip width="170">
+          <template #default="{ row }">
+            <span>{{ formatDate(row.lastModificationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+          </template>
+        </el-table-column>
+				<el-table-column label="操作" width="120" fixed="right" align="center">
+					<template #default="{ row }">
+						<el-button link type="primary" @click="updateLexicon(row)" v-auth="'auxiliary:orderLexicon:edit'" title="编辑工单词库">
+							编辑
+						</el-button>
+					</template>
+				</el-table-column>
+				<template #empty>
+					<Empty />
+				</template>
+			</el-table>
+			<!-- 分页 -->
+			<pagination
+				:total="state.total"
+				v-model:page="state.queryParams.PageIndex"
+				v-model:limit="state.queryParams.PageSize"
+				@pagination="queryList"
+			/>
+		</el-card>
+		<!--  新增工单词库  -->
+		<order-lexicon-add ref="orderLexiconAddRef" @updateList="queryList" :orderWordClassify="orderWordClassify"/>
+		<!--  编辑工单词库  -->
+		<order-lexicon-edit ref="orderLexiconEditRef" @updateList="queryList" :orderWordClassify="orderWordClassify"/>
+	</div>
+</template>
+
+<script lang="ts" setup name="auxiliaryOrderLexicon">
+import { reactive, ref, onMounted, defineAsyncComponent } from 'vue';
+import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
+import { formatDate } from '/@/utils/formatTime';
+import { auth } from '/@/utils/authFunction';
+import { orderLexiconDelete, orderLexiconList,orderLexiconBaseData } from '/@/api/auxiliary/orderLexicon';
+// 引入组件
+const OrderLexiconAdd = defineAsyncComponent(() => import('/@/views/auxiliary/orderLexicon/components/Order-lexicon-add.vue')); // 新增工单词库
+const OrderLexiconEdit = defineAsyncComponent(() => import('/@/views/auxiliary/orderLexicon/components/Order-lexicon-edit.vue')); // 编辑工单词库
+
+// 定义变量内容
+const state = reactive<any>({
+	loading: false, // 加载状态
+	queryParams: {
+		// 查询参数
+		PageIndex: 1,
+		PageSize: 10,
+    Tag: null, // 标签
+    Classify: null, // 标签类型
+    Synonym: null, // 近义词
+	},
+	total: 0, // 总条数
+	tableData: [], // 表格数据
+});
+const ruleFormRef = ref<any>(null); // 表单ref
+const businessTagType = ref<EmptyArrayType>(); // 业务类型
+const orderWordClassify = ref<EmptyArrayType>(); // 标签类型
+// 获取基础数据
+const getBaseData = async ()=>{
+  try {
+    const res = await orderLexiconBaseData();
+    orderWordClassify.value = res.result?.orderWordClassify ?? [];
+  }catch (error){
+    console.log(error)
+  }
+}
+// 获取参数列表
+const queryList = () => {
+	state.loading = true;
+	if (!auth('auxiliary:orderLexicon:query')) ElMessage.error('抱歉,您没有权限获取工单词库列表!');
+	else {
+		orderLexiconList(state.queryParams)
+			.then((res) => {
+				state.loading = false;
+				state.tableData = res.result.items ?? [];
+				state.total = res.result.total ?? 0;
+			})
+			.finally(() => {
+				state.loading = false;
+			});
+	}
+};
+// 重置表单
+const resetQuery = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	queryList();
+};
+// 新增词库
+const orderLexiconAddRef = ref<RefType>();
+const addParameter = () => {
+	orderLexiconAddRef.value.openDialog();
+};
+// 修改参词库
+const orderLexiconEditRef = ref<RefType>();
+const updateLexicon = (row: any) => {
+	orderLexiconEditRef.value.openDialog(row.id);
+};
+// 表格多选
+const multipleTableRef = ref<RefType>();
+const multipleSelection = ref<any>([]);
+const handleSelectionChange = (val: any[]) => {
+	multipleSelection.value = val;
+};
+// 删除词库
+const businessTagRemove = (row: any) => {
+	const ids = multipleSelection.value.map((item: any) => item.id);
+	const names = multipleSelection.value.map((item: any) => item.tag);
+	ElMessageBox.confirm(`您确定要删除:【${names}】,是否继续?`, '提示', {
+		confirmButtonText: '确认',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		cancelButtonClass: 'default-button',
+		autofocus: false,
+	})
+		.then(() => {
+			orderLexiconDelete({ ids }).then(() => {
+				ElMessage.success('操作成功');
+				queryList();
+			});
+		})
+		.catch(() => {});
+};
+// 页面加载时
+onMounted(() => {
+  getBaseData();
+	queryList();
+});
+</script>
+
+<style lang="scss" scoped>
+.auxiliary-order-lexicon-container {
+}
+</style>

+ 0 - 5
src/views/system/businessTag/component/Business-tag-add.vue

@@ -121,11 +121,6 @@ const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
 				emit('updateList');
 			})
 			.catch((error) => {
-				// 新增失败
-				ElMessage({
-					message: `操作失败: ${error.message}`,
-					type: 'error',
-				});
 			})
 			.finally(() => {
 				loading.value = false;

+ 0 - 5
src/views/system/businessTag/component/Business-tag-binding.vue

@@ -79,11 +79,6 @@ const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
           emit('updateList');
         })
         .catch((error) => {
-          // 新增失败
-          ElMessage({
-            message: `操作失败: ${error.message}`,
-            type: 'error',
-          });
         })
         .finally(() => {
           loading.value = false;

+ 0 - 5
src/views/system/parameter/component/Parameter-add.vue

@@ -94,11 +94,6 @@ const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
 				emit('updateList');
 			})
 			.catch((error) => {
-				// 新增失败
-				ElMessage({
-					message: `操作失败: ${error.message}`,
-					type: 'error',
-				});
 			})
 			.finally(() => {
 				loading.value = false;