Sfoglia il codice sorgente

Merge branch 'release' into dev

zhangchong 1 mese fa
parent
commit
f721475450
38 ha cambiato i file con 631 aggiunte e 322 eliminazioni
  1. 0 10
      src/App.vue
  2. 68 46
      src/api/business/lzRXFZ.ts
  3. 4 1
      src/components/OrderDetail/Map-view.vue
  4. 46 49
      src/components/OrderDetail/index.vue
  5. 7 4
      src/components/PlayRecord/index.vue
  6. 7 4
      src/components/PlayRecord/tableAudio.vue
  7. 6 9
      src/layout/navBars/breadcrumb/ybTel.vue
  8. 63 19
      src/layout/navBars/breadcrumb/zgTel.vue
  9. 6 0
      src/router/backEnd.ts
  10. 6 0
      src/stores/appConfig.ts
  11. 7 1
      src/types/pinia.d.ts
  12. 5 1
      src/utils/request.ts
  13. 1 1
      src/views/business/discern/YBApply.vue
  14. 3 3
      src/views/business/discern/todo.vue
  15. 0 1
      src/views/business/order/index.vue
  16. 4 6
      src/views/business/order/tableHeader.tsx
  17. 1 1
      src/views/business/publish/index.vue
  18. 3 3
      src/views/business/secondHandle/audit.vue
  19. 11 4
      src/views/business/terminate/apply.vue
  20. 4 1
      src/views/business/visit/components/Visit-detail.vue
  21. 1 1
      src/views/business/visit/todo.vue
  22. 1 1
      src/views/home/components/Home-date.vue
  23. 4 1
      src/views/quality/done/components/Quality-inspection.vue
  24. 4 1
      src/views/quality/done/components/ZG-quality.vue
  25. 4 1
      src/views/quality/index/components/Quality-inspection.vue
  26. 4 1
      src/views/quality/index/components/ZG-quality.vue
  27. 6 3
      src/views/statistics/call/detailIndexCall.vue
  28. 5 2
      src/views/statistics/call/detailSeatDate.vue
  29. 4 4
      src/views/tels/callLog/ybCallLog.vue
  30. 4 1
      src/views/tels/callLog/zgCallLog.vue
  31. 162 107
      src/views/tels/restApply/index.vue
  32. 1 1
      src/views/todo/center/index.vue
  33. 161 26
      src/views/todo/seats/accept/Knowledge.vue
  34. 4 1
      src/views/todo/seats/accept/Map-select.vue
  35. 4 0
      src/views/todo/seats/accept/lzAccept.vue
  36. 5 7
      src/views/todo/seats/accept/ybAccept.vue
  37. 4 0
      src/views/todo/seats/accept/zgAccept.vue
  38. 1 0
      src/views/todo/seats/index.vue

+ 0 - 10
src/App.vue

@@ -250,11 +250,9 @@ onBeforeMount(async () => {
 		const loginImage = result.loginImage ? result.loginImage : `${getImageUrl('default/login_bg.png')}`; // 登录页背景图
 		const isLoginMessageCode = result.isLoginMessageCode; // 是否开启短信验证码
 		const appScope = result.appScope ?? 'YiBin'; // 应用范围
-		const callCenterType = result.callCenterType ?? 'TianRun'; // 呼叫中心类型
 		const cityName = result.cityName ?? ''; // 城市名称
 		const cityCode = result.cityCode ?? ''; // 城市编码
 		const cityAbbr = result.cityAbbr ?? ''; // 城市简称
-		const locationCenter = result.locationCenter ?? []; // 城市中心点
 		const operate = result.operate ?? ''; // 管理运营 页脚
 		const techSupport = result.techSupport ?? ''; // 技术支持 页脚
 		const recordNumber = result.recordNumber ?? ''; // 备案号 页脚
@@ -262,20 +260,15 @@ onBeforeMount(async () => {
 		const menuLogoImage = result.menuLogoImage ?? ``; // 菜单logo
 		const menuLogoImageMini = result.menuLogoImageMini ?? ``; // 菜单logo-mini
 		const changPwdImage = result.changPwdImage ?? ``; // 修改密码图片
-		const callCenterSocketUrl = result.callCenterSocketUrl ?? ''; // 呼叫中心socket地址
-		const recordPrefix = result.recordPrefix ?? ''; // 录音前缀
-		const recordDownLoadPrefix = result.recordDownLoadPrefix ?? ''; // 录音下载前缀
 		storesThemeConfig.setThemeConfig(
 			Object.assign(themeConfig.value, {
 				globalTitle,
 				loginImage,
 				isLoginMessageCode,
 				appScope,
-				callCenterType,
 				cityName,
 				cityCode,
 				cityAbbr,
-				locationCenter,
 				operate,
 				techSupport,
 				recordNumber,
@@ -283,9 +276,6 @@ onBeforeMount(async () => {
 				menuLogoImage,
 				menuLogoImageMini,
 				changPwdImage,
-				callCenterSocketUrl,
-				recordPrefix,
-				recordDownLoadPrefix,
 			})
 		);
 	} catch (e) {

+ 68 - 46
src/api/business/lzRXFZ.ts

@@ -8,73 +8,95 @@ import { Cookie } from '@/utils/storage';
  * @description  认证授权
  */
 export const lzRXFZAuth = (data: object) => {
-	return request({
-		baseURL: 'http://110.188.24.28:50107/lzhcp',
-		url: `/third/user/auth/token`,
-		method: 'post',
-		data,
-	});
+	return request(
+		{
+			baseURL: import.meta.env.VITE_RXFZ_API_URL,
+			url: `/user/auth/token`,
+			method: 'post',
+			data,
+		},
+		{
+			is_need_token: false,
+		}
+	);
 };
 /**
  * @description  知识推荐
  */
 export const lzRXFZKnowledge = (data: object) => {
-	return request({
-		baseURL: import.meta.env.VITE_RXFZ_API_URL,
-		url: `/knowledge/knowledge_following`,
-		method: 'post',
-		data,
-		headers: {
-			Authentication: `Bearer ${Cookie.get('lzRXFZToken')}`,
+	return request(
+		{
+			baseURL: import.meta.env.VITE_RXFZ_API_URL,
+			url: `/knowledge/knowledge_following`,
+			method: 'post',
+			data,
+			headers: {
+				Authorization: `Bearer ${Cookie.get('lzRXFZToken')}`,
+			},
 		},
-	},{
-		error_message_show: false,
-	});
+		{
+			error_message_show: false,
+			is_need_token: false,
+		}
+	);
 };
 /**
  * @description  办事指南文档类型
  */
-export const lzRXFZDocumentType = () => {
-	return request({
-		baseURL: import.meta.env.VITE_RXFZ_API_URL,
-		url: `/guide/contentType`,
-		method: 'get',
-		headers: {
-			Authentication: `Bearer ${Cookie.get('lzRXFZToken')}`,
+export const lzRXFZDocumentType = (params: object) => {
+	return request(
+		{
+			baseURL: import.meta.env.VITE_RXFZ_API_URL,
+			url: `/guide/contentType`,
+			method: 'get',
+			headers: {
+				Authorization: `Bearer ${Cookie.get('lzRXFZToken')}`,
+			},
+			params
 		},
-	},{
-		error_message_show: false,
-	});
+		{
+			error_message_show: false,
+			is_need_token: false,
+		}
+	);
 };
 /**
  * @description  办事指南列表
  */
 export const lzRXFZDocumentList = (data: object) => {
-	return request({
-		baseURL: import.meta.env.VITE_RXFZ_API_URL,
-		url: ` /guide/documentList`,
-		method: 'post',
-		data,
-		headers: {
-			Authentication: `Bearer ${Cookie.get('lzRXFZToken')}`,
+	return request(
+		{
+			baseURL: import.meta.env.VITE_RXFZ_API_URL,
+			url: `/guide/documentList`,
+			method: 'post',
+			data,
+			headers: {
+				Authorization: `Bearer ${Cookie.get('lzRXFZToken')}`,
+			},
 		},
-	},{
-		error_message_show: false,
-	});
+		{
+			error_message_show: false,
+			is_need_token: false,
+		}
+	);
 };
 /**
  * @description  办事指南详情
  */
 export const lzRXFZDocumentDetail = (params: object) => {
-	return request({
-		baseURL: import.meta.env.VITE_RXFZ_API_URL,
-		url: `/guide/documentDetail`,
-		method: 'get',
-		params,
-		headers: {
-			Authentication: `Bearer ${Cookie.get('lzRXFZToken')}`,
+	return request(
+		{
+			baseURL: import.meta.env.VITE_RXFZ_API_URL,
+			url: `/guide/documentDetail`,
+			method: 'get',
+			params,
+			headers: {
+				Authorization: `Bearer ${Cookie.get('lzRXFZToken')}`,
+			},
 		},
-	},{
-		error_message_show: false,
-	});
+		{
+			error_message_show: false,
+			is_need_token: false,
+		}
+	);
 };

+ 4 - 1
src/components/OrderDetail/Map-view.vue

@@ -9,12 +9,15 @@ import { nextTick, onMounted, shallowRef } from 'vue';
 import AMapLoader from '@amap/amap-jsapi-loader';
 import { useThemeConfig } from '@/stores/themeConfig';
 import { storeToRefs } from 'pinia';
+import { useAppConfig } from '@/stores/appConfig';
 /*在Vue3中使用时,需要引入Vue3中的shallowRef方法(使用shallowRef进行非深度监听,
 因为在Vue3中所使用的Proxy拦截操作会改变JSAPI原生对象,所以此处需要区别Vue2使用方式对地图对象进行非深度监听,
 否则会出现问题,建议JSAPI相关对象采用非响应式的普通对象来存储)*/
 
 const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 const map: any = shallowRef(null);
 let AMapObj, marker;
 const initMap = () => {
@@ -28,7 +31,7 @@ const initMap = () => {
 		.then((AMap) => {
 			AMapObj = AMap;
 			map.value = new AMap.Map('mapBox', {
-				center: themeConfig.value.locationCenter, //初始化地图中心点位置
+				center: AppConfigInfo.value.locationCenter, //初始化地图中心点位置
 				zoom: 15, //初始化地图级别
 			});
 

+ 46 - 49
src/components/OrderDetail/index.vue

@@ -778,6 +778,7 @@ const MapView = defineAsyncComponent(() => import('@/components/OrderDetail/Map-
 const ZGSSPProcess = defineAsyncComponent(() => import('@/components/ProcessAudit/ZGSSPProcess.vue')); // 自贡随手拍办理流程
 const YBProcess = defineAsyncComponent(() => import('@/components/ProcessAudit/YBProcess.vue')); // 宜宾工单办理流程
 
+
 type ButtonType = '' | 'default' | 'success' | 'warning' | 'info' | 'text' | 'primary' | 'danger';
 const props = defineProps({
 	order: {
@@ -911,12 +912,10 @@ const getPortraitList = async () => {
 };
 // 查询地图信息
 const mapViewRef = ref<RefType>();
-const getMapInfo = async (id: string) => {
+const getMapInfo = async () => {
 	state.loading = true;
 	try {
-		const { result } = await orderDetail(id);
-		state.ruleForm = result;
-		mapViewRef.value.addMarker(result);
+		mapViewRef.value.addMarker(state.ruleForm);
 		state.loading = false;
 	} catch (error) {
 		console.log(error);
@@ -932,46 +931,48 @@ const openDialog = (val: any) => {
 	}
 	state.dialogVisible = true;
 	state.orderId = val.id;
-	if (['LuZhou'].includes(themeConfig.value.appScope) && !userInfos.value.isCenter) {
-		// 自贡的部门部展示历史工单和副本工单
-		state.tabPaneList = [
-			{
-				label: '工单详情',
-				value: '0',
-			},
-			{
-				label: '历史工单',
-				value: '1',
-			},
-			{
-				label: '回访详情',
-				value: '2',
-			},
-		];
-	} else if (['YiBin'].includes(themeConfig.value.appScope) && !userInfos.value.isCenter) {
-		state.tabPaneList = [
-			{
-				label: '工单详情',
-				value: '0',
-			},
-			{
-				label: '历史工单',
-				value: '1',
-			},
-			{
-				label: '回访详情',
-				value: '2',
-			},
-			{
-				label: '市民画像',
-				value: '3',
-			},
-			/*		{
-				label: '地图信息',
-				value: '5',
-			},*/
-		];
-	} else if (['ZiGong'].includes(themeConfig.value.appScope) && !userInfos.value.isCenter) {
+	if(['LuZhou','ZiGong'].includes(themeConfig.value.appScope)){
+		if(userInfos.value.isCenter){// 中心
+			state.tabPaneList = [
+				{
+					label: '工单详情',
+					value: '0',
+				},
+				{
+					label: '历史工单',
+					value: '1',
+				},
+				{
+					label: '回访详情',
+					value: '2',
+				},
+				{
+					label: '副本工单',
+					value: '4',
+				},
+			/*	{
+					label: '地图信息',
+					value: '5',
+				},*/
+			];
+		}else{
+			// 部门
+			state.tabPaneList = [
+				{
+					label: '工单详情',
+					value: '0',
+				},
+				{
+					label: '历史工单',
+					value: '1',
+				},
+				{
+					label: '回访详情',
+					value: '2',
+				},
+			];
+		}
+	}else if (['YiBin'].includes(themeConfig.value.appScope) && !userInfos.value.isCenter) {
 		state.tabPaneList = [
 			{
 				label: '工单详情',
@@ -989,10 +990,6 @@ const openDialog = (val: any) => {
 				label: '市民画像',
 				value: '3',
 			},
-			{
-				label: '地图信息',
-				value: '5',
-			},
 		];
 	}
 	if (val.activeName) {
@@ -1024,7 +1021,7 @@ const handleClick = (val: string) => {
 			getCopyOrder();
 			break;
 		case '5': // 地图信息
-			getMapInfo(state.orderId);
+			getMapInfo();
 			break;
 		default:
 			getOrderDetail(state.orderId);

+ 7 - 4
src/components/PlayRecord/index.vue

@@ -51,6 +51,7 @@ import { formatDate } from '@/utils/formatTime';
 import { useThemeConfig } from '@/stores/themeConfig';
 import { storeToRefs } from 'pinia';
 import { useRouter } from 'vue-router';
+import { useAppConfig } from '@/stores/appConfig';
 // 引入组件
 const AudioPlayer = defineAsyncComponent(() => import('@/components/AudioPlayer/index.vue'));
 // 定义子组件向父组件传值/事件
@@ -87,11 +88,13 @@ const closeDialog = () => {
 	emit('closeDialog');
 };
 // 下载录音
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 const download = (row: any) => {
 	loading.value = true;
 	switch (themeConfig.value.appScope) {
 		case 'YiBin':
-			fileDownload({ path: themeConfig.value.recordDownLoadPrefix + row.audioFile })
+			fileDownload({ path: AppConfigInfo.value.recordDownLoadPrefix + row.audioFile })
 				.then((res: any) => {
 					downloadFileByStream(res, row.audioFile);
 					loading.value = false;
@@ -102,8 +105,8 @@ const download = (row: any) => {
 			break;
 		case 'ZiGong':
 		case 'LuZhou':
-			downloadFileBySrc(themeConfig.value.recordPrefix + row.audioFile, row.audioFile);
-			// window.open(themeConfig.value.recordPrefix + row.audioFile)
+			downloadFileBySrc(AppConfigInfo.value.recordPrefix + row.audioFile, row.audioFile);
+			// window.open(AppConfigInfo.value.recordPrefix + row.audioFile)
 			loading.value = false;
 			break;
 	}
@@ -172,7 +175,7 @@ const playRecordPath = async (path: string) => {
 // 点击播放录音
 const audioPlayerRef = ref<RefType>();
 const onPlay = (row: any) => {
-	recordUrl.value = themeConfig.value.recordPrefix + row.audioFile;
+	recordUrl.value = AppConfigInfo.value.recordPrefix + row.audioFile;
 };
 watch(
 	() => audioPlayerRef.value,

+ 7 - 4
src/components/PlayRecord/tableAudio.vue

@@ -26,6 +26,7 @@ import { useThemeConfig } from '@/stores/themeConfig';
 import { storeToRefs } from 'pinia';
 import { fileDownload } from '@/api/public/file';
 import { downloadFileBySrc, downloadFileByStream } from '@/utils/tools';
+import { useAppConfig } from '@/stores/appConfig';
 const loading = ref(false);
 const tableData = ref<EmptyArrayType>([]);
 NextLoading.done();
@@ -44,11 +45,13 @@ const getData = async () => {
 		loading.value = false;
 	}
 };
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 // 点击播放录音
 const audioPlayerRef = ref<RefType>();
 const recordUrl = ref('');
 const onPlay = (row: any) => {
-	recordUrl.value = themeConfig.value.recordPrefix + row.audioFile;
+	recordUrl.value = AppConfigInfo.value.recordPrefix + row.audioFile;
 	if (audioPlayerRef.value) {
 		setTimeout(() => {
 			audioPlayerRef.value.play();
@@ -62,7 +65,7 @@ const download = (row: any) => {
 	loading.value = true;
 	switch (themeConfig.value.appScope) {
 		case 'YiBin':
-			fileDownload({ path: themeConfig.value.recordDownLoadPrefix + row.audioFile })
+			fileDownload({ path: AppConfigInfo.value.recordDownLoadPrefix + row.audioFile })
 				.then((res: any) => {
 					downloadFileByStream(res, row.audioFile);
 					loading.value = false;
@@ -73,8 +76,8 @@ const download = (row: any) => {
 			break;
 		case 'ZiGong':
 		case 'LuZhou':
-			downloadFileBySrc(themeConfig.value.recordPrefix + row.audioFile, row.audioFile);
-			// window.open(themeConfig.value.recordPrefix + row.audioFile)
+			downloadFileBySrc(AppConfigInfo.value.recordPrefix + row.audioFile, row.audioFile);
+			// window.open(AppConfigInfo.value.recordPrefix + row.audioFile)
 			loading.value = false;
 			break;
 	}

+ 6 - 9
src/layout/navBars/breadcrumb/ybTel.vue

@@ -541,7 +541,6 @@ import { useWebSocket } from '@/hooks/useWebsocket';
 import { olaFn } from '@/utils/olaFn';
 import { useIntervalFn, useTimeoutFn } from '@vueuse/shared/index';
 import { useGlobalState } from '@/utils/callCenter';
-import { useThemeConfig } from '@/stores/themeConfig';
 import { extensionList } from '@/api/tels/extension';
 import XEUtils from 'xe-utils';
 import { getSpecialNumberDetailByPhone } from '@/api/auxiliary/specialNumber';
@@ -889,10 +888,8 @@ const onControlClick = (val: string) => {
 };
 // 链接呼叫中心
 const olaRef = ref();
-const storesThemeConfig = useThemeConfig();
-const { themeConfig } = storeToRefs(storesThemeConfig);
 const websocket_connect = () => {
-	olaRef.value = olaFn(themeConfig.value.callCenterSocketUrl, {
+	olaRef.value = olaFn(AppConfigInfo.value.callCenterSocketUrl, {
 		username: currentTel.value.telNo,
 		password: currentTel.value.password,
 		onConnected: onConnected, // 连接成功
@@ -940,7 +937,7 @@ const onConnected = () => {
 		creationTime: new Date(),
 		name,
 		remark,
-		executeUrl: themeConfig.value.callCenterSocketUrl,
+		executeUrl: AppConfigInfo.value.callCenterSocketUrl,
 	};
 	submitLogFn(request);
 	console.log(`${getNowDateTime()}:呼叫中心链接成功`);
@@ -957,7 +954,7 @@ const onDisconnected = (event: any) => {
 		creationTime: new Date(),
 		name,
 		remark,
-		executeUrl: themeConfig.value.callCenterSocketUrl,
+		executeUrl: AppConfigInfo.value.callCenterSocketUrl,
 	};
 	submitLogFn(request);
 	console.log(`${getNowDateTime()}:呼叫中心断开链接`, event);
@@ -1008,7 +1005,7 @@ const onMessage = async (event: any) => {
 					creationTime: new Date(),
 					name,
 					remark,
-					executeUrl: themeConfig.value.callCenterSocketUrl,
+					executeUrl: AppConfigInfo.value.callCenterSocketUrl,
 				};
 				await submitLogFn(request);
 				seatAssistOff(); // 坐席助手关闭
@@ -1215,7 +1212,7 @@ const onMessage = async (event: any) => {
 								creationTime: new Date(),
 								name,
 								remark,
-								executeUrl: themeConfig.value.callCenterSocketUrl,
+								executeUrl: AppConfigInfo.value.callCenterSocketUrl,
 							};
 							await submitLogFn(request);
 						} catch (e) {
@@ -1270,7 +1267,7 @@ const onMessage = async (event: any) => {
 								creationTime: new Date(),
 								name,
 								remark,
-								executeUrl: themeConfig.value.callCenterSocketUrl,
+								executeUrl: AppConfigInfo.value.callCenterSocketUrl,
 							};
 							await submitLogFn(request);
 						} catch (e) {

+ 63 - 19
src/layout/navBars/breadcrumb/zgTel.vue

@@ -334,6 +334,7 @@ import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue';
 import { getNowDateTime } from '@/utils/constants';
 import { ElMessage, ElMessageBox, ElNotification, FormInstance } from 'element-plus';
 import { useRouter } from 'vue-router';
+// import { useWebSocket } from '@/hooks/useWebsocket';
 import { useWebSocket } from '@/hooks/useWebsocket';
 import { useIntervalFn } from '@vueuse/shared';
 import { formatDuration } from '@/utils/formatTime';
@@ -345,13 +346,12 @@ import mittBus from '@/utils/mitt';
 import { callCenterSignIn, callCenterSignOut, getCallCenterList, getCallCenterStatus } from '@/api/callCenter';
 import { useTimeoutFn } from '@vueuse/shared/index';
 import { useGlobalState } from '@/utils/callCenter';
-import { useThemeConfig } from '@/stores/themeConfig';
 import { getDataByCode } from '@/api/system/dict';
 import { trimCompat } from '@/utils/tools';
 import XEUtils from 'xe-utils';
 import { submitLog } from '@/api/public/log';
 import { useTransition } from '@vueuse/core';
-import { busyOff, busyOn } from '@/api/public/wex';
+import { busyOff, busyOn, endAfterCall, startAfterCall } from '@/api/public/wex';
 import { getSpecialNumberDetailByPhone } from '@/api/auxiliary/specialNumber';
 import signalR from '@/utils/signalR';
 import { restApply, restBaseData } from '@/api/tels/restApply';
@@ -436,10 +436,8 @@ const currentStatusText = computed(() => {
 });
 // ws实例对象
 const wsRef = ref();
-const storesThemeConfig = useThemeConfig();
-const { themeConfig } = storeToRefs(storesThemeConfig);
 const initWs = () => {
-	wsRef.value = useWebSocket(themeConfig.value.callCenterSocketUrl, {
+	wsRef.value = useWebSocket(AppConfigInfo.value.callCenterSocketUrl, {
 		heartbeat: {
 			message: JSON.stringify({ Action: 'ReqHealthCheck', Param: { Extension: m_strUserNo.value } }),
 			interval: 5000,
@@ -448,7 +446,7 @@ const initWs = () => {
 		autoReconnect: {
 			delay: 2000,
 		}, // 自动重连
-		immediate: false, // 是否立即链接
+		immediate: true, // 是否立即链接
 		onMessage: e_TelMsgReceive, // 消息接收
 		onError: e_websocketError, // 错误
 		onDisconnected: e_websocketClose, // 断开
@@ -597,6 +595,15 @@ const evtSeatState = (data: any) => {
 		// 正在保持通话状态下
 		return;
 	}
+
+	const request = {
+		creationTime: new Date(),
+		name: `收到兴唐呼叫中心分机状态变化,分机号:${m_strUserNo.value},工号:${m_strJobNum.value},技能组:${m_strSkillId.value}`,
+		remark: JSON.stringify(data),
+		executeUrl: AppConfigInfo.value.callCenterSocketUrl,
+	};
+	submitLogFn(request);
+
 	// 状态 0:闲 1:忙 2:会议 3:登出 4:呼入 5:呼出 6:咨询 7:其他 8:通话
 	const strState = data.Param.State;
 	switch (strState) {
@@ -676,6 +683,7 @@ const evtSeatState = (data: any) => {
 		case '9': // 工单整理
 			m_strTelState.value = '900';
 			startArrangeTime(); // 开始整理时长
+			// onBeginRecord('1'); // 开始记录整理
 			e_TopStateChange(m_strTelState.value);
 			m_IsTalkingDeal.value = true;
 			break;
@@ -791,7 +799,7 @@ const sendSignIn = () => {
 		creationTime: new Date(),
 		name: `向兴唐呼叫中心发起签入,分机号:${m_strUserNo.value},工号:${m_strJobNum.value},技能组:${m_strSkillId.value}`,
 		remark: JSON.stringify(sendObj),
-		executeUrl: themeConfig.value.callCenterSocketUrl,
+		executeUrl: AppConfigInfo.value.callCenterSocketUrl,
 	};
 	submitLogFn(request);
 };
@@ -834,6 +842,7 @@ const startIdleTime = () => {
 	idleTimer.resume();
 	stopBusyTime(); // 结束小休时长
 	stopArrangeTime(); // 结束整理时长
+	// onEndRecord('1'); // 记录结束整理
 };
 //  空闲时长计时结束
 const stopIdleTime = () => {
@@ -862,7 +871,8 @@ const onSignIn = () => {
 			telGroup: userInfos.value.defaultTelGroup,
 			jobNum: <string>userInfos.value.staffNo,
 		};
-		wsRef.value.open();
+		// wsRef.value.open();
+		initWs(); // 开启链接
 	}
 };
 const dutyFormRef = ref();
@@ -884,7 +894,8 @@ const clickOnDuty = (formEl: FormInstance | undefined) => {
 			telGroup: m_strSkillId.value,
 			jobNum: state.dutyForm.telNo,
 		};
-		wsRef.value.open();
+		// wsRef.value.open();
+		initWs(); // 开启链接
 		state.dutyDialogVisible = false;
 		state.loading = false;
 	});
@@ -938,7 +949,7 @@ const retSignIn = (data: any) => {
 		creationTime: new Date(),
 		name: `兴唐呼叫中心签入返回消息,分机号:${m_strUserNo.value},工号:${m_strJobNum.value},技能组:${m_strSkillId.value}`,
 		remark: JSON.stringify(data),
-		executeUrl: themeConfig.value.callCenterSocketUrl,
+		executeUrl: AppConfigInfo.value.callCenterSocketUrl,
 	};
 	submitLogFn(request);
 };
@@ -975,7 +986,7 @@ const e_websocketOpen = () => {
 		creationTime: new Date(),
 		name: `兴唐呼叫中心链接开启成功,分机号:${m_strUserNo.value},工号:${m_strJobNum.value},技能组:${m_strSkillId.value}`,
 		remark: JSON.stringify(sendObj),
-		executeUrl: themeConfig.value.callCenterSocketUrl,
+		executeUrl: AppConfigInfo.value.callCenterSocketUrl,
 	};
 	submitLogFn(request);
 };
@@ -1001,9 +1012,11 @@ const e_websocketClose = () => {
 		creationTime: new Date(),
 		name: `兴唐呼叫中心链接关闭,分机号:${m_strUserNo.value},工号:${m_strJobNum.value},技能组:${m_strSkillId.value}`,
 		remark: JSON.stringify(sendObj),
-		executeUrl: themeConfig.value.callCenterSocketUrl,
+		executeUrl: AppConfigInfo.value.callCenterSocketUrl,
 	};
 	submitLogFn(request);
+ // 迁出
+	// e_TelSignOut(m_strUserNo.value, m_strSkillId.value);
 };
 // 链接错误
 const e_websocketError = () => {
@@ -1185,7 +1198,7 @@ const sendSignOut = () => {
 		creationTime: new Date(),
 		name: `向兴唐呼叫中心发起签出,分机号:${m_strUserNo.value},工号:${m_strJobNum.value},技能组:${m_strSkillId.value}`,
 		remark: JSON.stringify(objMsg),
-		executeUrl: themeConfig.value.callCenterSocketUrl,
+		executeUrl: AppConfigInfo.value.callCenterSocketUrl,
 	};
 	submitLogFn(request);
 };
@@ -1248,7 +1261,7 @@ const retSignOut = () => {
 		creationTime: new Date(),
 		name: `兴唐呼叫中心签出事件回调,分机号:${m_strUserNo.value},工号:${m_strJobNum.value},技能组:${m_strSkillId.value}`,
 		remark: JSON.stringify(objMsg),
-		executeUrl: themeConfig.value.callCenterSocketUrl,
+		executeUrl: AppConfigInfo.value.callCenterSocketUrl,
 	};
 	submitLogFn(request);
 };
@@ -1469,6 +1482,7 @@ const onCancelTalkDeal = () => {
 			}
 			// 发送请求
 			e_TelSendMsg(objMsg);
+			// onEndRecord('1'); // 结束话后整理
 		})
 		.catch(() => {
 			state.loading = false;
@@ -1509,6 +1523,7 @@ const retHold = (data: any) => {
 		m_IsHold.value = true;
 		m_strTelState.value = '310';
 		e_TopStateChange(m_strTelState.value);
+		// onBeginRecord('2'); // 开始保持
 	} else {
 		ElMessage.error('保持操作失败');
 	}
@@ -1554,6 +1569,7 @@ const retRehold = (data: any) => {
 			m_strTelState.value = '303';
 		}
 		e_TopStateChange(m_strTelState.value);
+		// onEndRecord('2'); // 结束保持
 	} else {
 		ElMessage.error('取消保持操作失败');
 	}
@@ -2124,7 +2140,7 @@ const evtCallAlerting = (data: any) => {
 		creationTime: new Date(),
 		name: `兴唐呼叫中心呼入振铃事件消息,分机号:${m_strUserNo.value},工号:${m_strJobNum.value},技能组:${m_strSkillId.value}`,
 		remark: JSON.stringify(data),
-		executeUrl: themeConfig.value.callCenterSocketUrl,
+		executeUrl: AppConfigInfo.value.callCenterSocketUrl,
 	};
 	submitLogFn(request);
 };
@@ -2303,7 +2319,7 @@ const evtEvtCallAnswer = (data: any) => {
 		creationTime: new Date(),
 		name: `兴唐呼叫中心应答事件消息,分机号:${m_strUserNo.value},工号:${m_strJobNum.value},技能组:${m_strSkillId.value}`,
 		remark: JSON.stringify(data),
-		executeUrl: themeConfig.value.callCenterSocketUrl,
+		executeUrl: AppConfigInfo.value.callCenterSocketUrl,
 	};
 	submitLogFn(request);
 };
@@ -2364,7 +2380,7 @@ const evtEvtCalling = (data: any) => {
 		creationTime: new Date(),
 		name: `兴唐呼叫中心外呼振铃消息,分机号:${m_strUserNo.value},工号:${m_strJobNum.value},技能组:${m_strSkillId.value}`,
 		remark: JSON.stringify(data),
-		executeUrl: themeConfig.value.callCenterSocketUrl,
+		executeUrl: AppConfigInfo.value.callCenterSocketUrl,
 	};
 	submitLogFn(request);
 };
@@ -2524,6 +2540,34 @@ const e_TelSignOut = async (telNo: string | null, groupId: string) => {
 		console.log(e);
 	}
 };
+// 业务系统记录开始 1话后整理 2保持
+const onBeginRecord = async (type: string) => {
+	// type 1话后整理 2保持 3静音
+	const typeMap = {
+		'1': '话后整理',
+		'2': '保持',
+	};
+	try {
+		const res: any = await startAfterCall({ actionType: type });
+		console.log(`${getNowDateTime()}:业务系统记录开始,业务类型:${typeMap[type]}`, res);
+	} catch (err) {
+		console.log(`${getNowDateTime()}:业务系统记录开始失败,业务类型:${typeMap[type]}`, err);
+	}
+};
+// 业务系统记录结束
+const onEndRecord = async (type: string) => {
+	// 映射中文
+	const typeMap = {
+		'1': '话后整理',
+		'2': '保持',
+	};
+	try {
+		const res: any = await endAfterCall({ actionType: type });
+		console.log(`${getNowDateTime()}:业务系统记录结束,业务类型:${typeMap[type]}`, res);
+	} catch (err) {
+		console.log(`${getNowDateTime()}:业务系统记录结束失败,业务类型:${typeMap[type]}`, err);
+	}
+};
 /**
  * 保存队列信息
  * @param {any} strUserNum
@@ -2564,7 +2608,7 @@ const checkLogin = async () => {
 		console.log(`${getNowDateTime()}:检测呼叫中心签入状态:`, result);
 		if (result) {
 			// 如果查询到登录状态
-			wsRef.value.open();
+			// wsRef.value.open();
 			userAlreadyLogin.value = true;
 			m_strUserNo.value = result.telNo; // 分机号
 			m_strJobNum.value = <string>result.staffNo; // 工号
@@ -2575,6 +2619,7 @@ const checkLogin = async () => {
 				telGroup: m_strSkillId.value,
 				jobNum: m_strJobNum.value,
 			};
+			initWs(); // 初始化websocket
 		} else {
 			userAlreadyLogin.value = false;
 		}
@@ -2627,7 +2672,6 @@ onMounted(async () => {
 	await getBaseInfo(); // 查询可以签入的分机
 	await getThreeWayAndTransfer(); // 查询呼叫转接的号码列表
 	await getReason(); // 获取小休原因
-	initWs();
 	await checkLogin();
 	signalRStart();
 	// 是否在通话中

+ 6 - 0
src/router/backEnd.ts

@@ -72,6 +72,12 @@ const getAppConfigFn = async () => {
 			isTelRest: result.isTelRest ?? false, // 是否启用小休计时提示
 			telRestNum: result.telRestNum ?? 780, // 小休多久之后提示 默认13分钟提示 单位秒
 			isOpenSpecialPhone: result.isOpenSpecialPhone ?? false, // 是否开启特殊号码功能
+			callCenterType: result.callCenterType ?? 'TianRun', // 呼叫中心类型
+			callCenterSocketUrl: result.callCenterSocketUrl ?? '', // 呼叫中心socket地址
+			recordPrefix: result.recordPrefix ?? '', // 录音前缀
+			recordDownLoadPrefix: result.recordDownLoadPrefix ?? '', // 录音下载前缀
+			luzhouhcp: result.luzhouhcp ?? false, // 是否开启泸州好差评
+			locationCenter: result.locationCenter ?? [], // 城市中心点
 		});
 		/*	console.log(
 			`是否开启小休审批${result.isRestApproval},自动话后整理时间${result.talkingDealTime}秒,

+ 6 - 0
src/stores/appConfig.ts

@@ -26,6 +26,12 @@ export const useAppConfig = defineStore('AppConfig', {
 			isTelRest: false, // 是否启用小休计时提示
 			telRestNum: 780, // 小休多久之后提示 默认13分钟提示 单位秒
 			isOpenSpecialPhone: false, // 是否开启特殊号码功能
+			callCenterType: '', // 呼叫中心类型
+			callCenterSocketUrl: '', // 呼叫中心socket地址
+			recordPrefix: '', // 录音前缀
+			recordDownLoadPrefix: '', // 录音下载前缀
+			locationCenter: [], // 城市中心点
+			luzhouhcp:false, // 是否开启泸州好差评
 		},
 	}),
 	actions: {

+ 7 - 1
src/types/pinia.d.ts

@@ -135,7 +135,13 @@ declare interface AppConfigState {
 		snapshot: boolean; // 随手拍开关
 		isTelRest: boolean; // 是否启用小休计时提示
 		telRestNum: number; // 小休多久之后提示
-		isOpenSpecialPhone:boolean // 是否开启特殊号码功能
+		isOpenSpecialPhone: boolean; // 是否开启特殊号码功能
+		callCenterType: string; // 呼叫中心类型
+		callCenterSocketUrl: string; // 呼叫中心socket地址
+		recordPrefix: string; // 录音前缀
+		recordDownLoadPrefix: string; // 录音下载前缀
+		locationCenter: number[]; // 城市中心点
+		luzhouhcp: boolean; // 是否开启泸州好差评
 		fileExt: string;
 		[x: string]: any;
 	};

+ 5 - 1
src/utils/request.ts

@@ -15,6 +15,7 @@ type customOptionsType = {
 	reduce_data_format?: boolean; // 是否开启简洁的数据结构响应 减少一层data, 默认为true
 	error_message_show?: boolean; // 是否开启接口错误信息展示,默认为true
 	code_message_show?: boolean; // 是否开启code不为0时的信息提示, 默认为false
+	is_need_token?: boolean; // 是否需要token
 };
 export default function myAxios(axiosConfig: any, customOptions?: customOptionsType, loadingOptions?: LoadingOptionsResolved) {
 	// 配置新建一个 axios 实例
@@ -32,6 +33,7 @@ export default function myAxios(axiosConfig: any, customOptions?: customOptionsT
 			reduce_data_format: true, // 是否开启简洁的数据结构响应 减少一层data, 默认为true
 			error_message_show: true, // 是否开启接口错误信息展示,默认为true
 			code_message_show: false, // 是否开启code不为0时的信息提示, 默认为false
+			is_need_token: true, // 是否需要token
 		},
 		customOptions
 	);
@@ -50,7 +52,9 @@ export default function myAxios(axiosConfig: any, customOptions?: customOptionsT
 			}
 			// 在发送请求之前做些什么 token
 			if (Cookie.get('token')) {
-				(<any>config.headers)['Authorization'] = `Bearer ${Cookie.get('token')}`;
+				if(custom_options.is_need_token){
+					(<any>config.headers)['Authorization'] = `Bearer ${Cookie.get('token')}`;
+				}
 			}
 			return config;
 		},

+ 1 - 1
src/views/business/discern/YBApply.vue

@@ -88,7 +88,7 @@
 					</vxe-column>
 					<vxe-column field="order.isUrgentText" title="是否紧急" width="90">
 						<template #default="{ row }">
-							<span class="color-danger font-bold">{{row.isUrgentText}}</span>
+							<span class="color-danger font-bold">{{row.order?.isUrgentText}}</span>
 						</template>
 					</vxe-column>
 					<vxe-column field="order.sensitiveText" title="敏感词" width="150"></vxe-column>

+ 3 - 3
src/views/business/discern/todo.vue

@@ -91,7 +91,7 @@
 					</vxe-column>
 					<vxe-column field="order.isUrgentText" title="是否紧急" width="90">
 						<template #default="{ row }">
-							<span class="color-danger font-bold">{{row.isUrgentText}}</span>
+							<span class="color-danger font-bold">{{row.order?.isUrgentText}}</span>
 						</template>
 					</vxe-column>
 					<vxe-column field="order.sensitiveText" title="敏感词" width="150"></vxe-column>
@@ -130,7 +130,7 @@
 								@click="onAudit(row)"
 								title="甄别审批"
 								v-auth="'business:discern:audit:todo'"
-								v-if="[0, 1, 5].includes(row.status)"
+								v-show="[0, 1, 5].includes(row.status)"
 							>
 								审批
 							</el-button>
@@ -140,7 +140,7 @@
 								@click="onReturn(row)"
 								title="甄别退回"
 								v-auth="'business:discern:return:todo'"
-								v-if="[0, 1, 5].includes(row.status)"
+								v-show="[0, 1, 5].includes(row.status)"
 							>
 								退回
 							</el-button>

+ 0 - 1
src/views/business/order/index.vue

@@ -123,7 +123,6 @@
 					>
 						退回</el-button
 					>
-					<order-detail :order="row" @updateList="refreshList" />
 				</template>
 				<template #pager>
 					<pagination

+ 4 - 6
src/views/business/order/tableHeader.tsx

@@ -81,7 +81,7 @@ export const YBTableHeader = [
 	{ field: 'focusOnEventsName', title: '重点关注事件', width: 120 },
 	{ field: 'content', title: '受理内容', width: 200, visible: false },
 	{ field: 'fileOpinion', title: '承办意见', width: 200, visible: false },
-	{ title: '操作', width: 140, fixed: 'right', align: 'center', slots: { default: 'action' } },
+	{ title: '操作', width: 80, fixed: 'right', align: 'center', slots: { default: 'action' } },
 ];
 
 export const ZGTableHeader = [
@@ -171,8 +171,8 @@ export const ZGTableHeader = [
 	{ field: 'fileOpinion', title: '承办意见', width: 200, visible: false },
 	{ field: 'seatEvaluateTxt', title: '坐席满意度', width: 150 },
 	{ field: 'orgEvaluateValue', title: '部门满意度', width: 150 },
-	{ field: 'SecondaryHandlingDurationWorkdayDayText', title: '重办时长', width: 150, visible: false },
-	{ title: '操作', width: 140, fixed: 'right', align: 'center', slots: { default: 'action' } },
+	{ field: 'secondaryHandlingDurationWorkdayDayText', title: '重办时长', width: 150, visible: false },
+	{ title: '操作', width: 80, fixed: 'right', align: 'center', slots: { default: 'action' } },
 ];
 
 export const LZTableHeader = [
@@ -258,8 +258,6 @@ export const LZTableHeader = [
 	{ field: 'counterSignTypeText', title: '是否会签', width: 110 },
 	{ field: 'orderTag', title: '工单标签', width: 140 },
 	{ field: 'allDurationHour', title: '办理时长(小时)', width: 150 },
-	{ field: 'hotspotSpliceName', title: '热点全称', width: 150 },
-	{ field: 'hotspotName', title: '热点分类', width: 150 },
 	{ field: 'sensitiveText', title: '敏感词', width: 150 },
 	{ field: 'content', title: '受理内容', width: 200, visible: false },
 	{ field: 'fileOpinion', title: '承办意见', width: 200, visible: false },
@@ -270,5 +268,5 @@ export const LZTableHeader = [
 	{ field: 'threeHotspotName', title: '三级热点', width: 150 },
 	{ field: 'fourHotspotName', title: '四级热点', width: 150 },
 	{ field: 'fiveHotspotName', title: '五级热点', width: 150 },
-	{ title: '操作', width: 140, fixed: 'right', align: 'center', slots: { default: 'action' } },
+	{ title: '操作', width: 80, fixed: 'right', align: 'center', slots: { default: 'action' } },
 ];

+ 1 - 1
src/views/business/publish/index.vue

@@ -33,7 +33,7 @@
 						link
 						type="primary"
 						@click="editPublish(row)"
-						v-if="!row.order?.isProvince"
+						v-show="!row.order?.isProvince"
 						title="编辑发布"
 						v-auth="'business:publish:edit'"
 					>

+ 3 - 3
src/views/business/secondHandle/audit.vue

@@ -100,18 +100,18 @@
 					<vxe-column field="order.hotspotName" title="热点分类" width="140"></vxe-column>
 					<vxe-column title="操作" fixed="right" width="120" align="center">
 						<template #default="{ row }">
-							<el-button link type="primary" @click="onView(row)" title="查看办理明细" v-if="![1].includes(row.state)"> 办理明细 </el-button>
+							<el-button link type="primary" @click="onView(row)" title="查看办理明细" v-show="![1].includes(row.state)"> 办理明细 </el-button>
 							<el-button
 								link
 								type="primary"
 								@click="onReturn(row)"
 								title="退回"
 								v-auth="'business:secondHandle:return'"
-								v-if="[1].includes(row.state)"
+								v-show="[1].includes(row.state)"
 							>
 								退回
 							</el-button>
-							<el-button link type="primary" @click="onAudit(row)" title="审批" v-auth="'business:secondHandle:audit'" v-if="[1].includes(row.state)">
+							<el-button link type="primary" @click="onAudit(row)" title="审批" v-auth="'business:secondHandle:audit'" v-show="[1].includes(row.state)">
 								审批
 							</el-button>
 						</template>

+ 11 - 4
src/views/business/terminate/apply.vue

@@ -84,11 +84,18 @@
 								@click="onReApply(row)"
 								title="重提申请"
 								v-auth="'business:terminate:apply:apply'"
-								v-if="row.orderTerminates?.length"
+								v-show="row.orderTerminates.length > 0"
 							>
 								重提申请
 							</el-button>
-							<el-button link type="primary" @click="onApply(row)" title="终止申请" v-auth="'business:terminate:apply:apply'" v-else>
+							<el-button
+								link
+								type="primary"
+								@click="onApply(row)"
+								title="终止申请"
+								v-auth="'business:terminate:apply:apply'"
+								v-show="row.orderTerminates.length === 0"
+							>
 								终止申请
 							</el-button>
 						</template>
@@ -191,7 +198,7 @@ const handleQuery = () => {
 };
 // 刷新列表
 const refreshList = () => {
-  queryList();
+	queryList();
 };
 /** 获取列表 */
 const requestParams = ref<EmptyObjectType>({});
@@ -247,7 +254,7 @@ const onApply = (row: any) => {
 			annexName: '终止附件',
 		},
 	};
-	terminateApplyRef.value.openDialog(params)
+	terminateApplyRef.value.openDialog(params);
 };
 // 终止详情
 const terminateDetailRef = ref<RefType>();

+ 4 - 1
src/views/business/visit/components/Visit-detail.vue

@@ -585,6 +585,7 @@ import { formatDate } from '@/utils/formatTime';
 import { specialApplyBase } from '@/api/business/special';
 import { submitLog } from '@/api/public/log';
 import { Local, Session } from '@/utils/storage';
+import { useAppConfig } from '@/stores/appConfig';
 
 // 引入组件
 const CommonAdvice = defineAsyncComponent(() => import('@/components/CommonAdvice/index.vue')); // 常用意见
@@ -718,6 +719,8 @@ const submitLogFn = async (request: any) => {
 };
 // 打开弹窗
 const callId = ref<string>('');
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 const openDialog = (row: any, type: string = '回访') => {
 	const callIdSession = Session.get(row.id);
 	if (callIdSession) callId.value = callIdSession;
@@ -732,7 +735,7 @@ const openDialog = (row: any, type: string = '回访') => {
 			creationTime: new Date(),
 			name: `回访外呼已经接通`,
 			remark: JSON.stringify({ ...data, visitId: row.id }),
-			executeUrl: themeConfig.value.callCenterSocketUrl,
+			executeUrl: AppConfigInfo.value.callCenterSocketUrl,
 			ipUrl: row.id,
 		};
 		submitLogFn(request);

+ 1 - 1
src/views/business/visit/todo.vue

@@ -339,7 +339,7 @@ const gridOptions = reactive<any>({
 			width: 90,
 			slots: {
 				default: ({ row }) => {
-					return <span class="color-danger font-bold">{row.order.isUrgentText}</span>;
+					return <span class="color-danger font-bold">{row.order?.isUrgentText}</span>;
 				},
 			},
 		},

+ 1 - 1
src/views/home/components/Home-date.vue

@@ -8,7 +8,7 @@
 				><SvgIcon name="iconfont icon-daohang" class="mr5" size="18px" /> 一键登录到旧系统</el-button
 			>
 		</el-badge>
-<!--		<el-button class="ml10" type="primary" @click="linkUrl" v-auth="'home:rxzf'"><SvgIcon name="iconfont icon-daohang" class="mr5" size="18px" /> 热线赋智</el-button>-->
+		<el-button class="ml10" type="primary" @click="linkUrl" v-auth="'home:rxzf'" v-show="AppConfigInfo.luzhouhcp"><SvgIcon name="iconfont icon-daohang" class="mr5" size="18px" /> 热线赋智</el-button>
 	</el-card>
 </template>
 <script setup lang="ts">

+ 4 - 1
src/views/quality/done/components/Quality-inspection.vue

@@ -194,6 +194,7 @@ import { templateList } from '@/api/quality/template';
 import { useThemeConfig } from '@/stores/themeConfig';
 import { storeToRefs } from 'pinia';
 import { useUserInfo } from '@/stores/userInfo';
+import { useAppConfig } from '@/stores/appConfig';
 
 // 引入组件
 const PlayRecord = defineAsyncComponent(() => import('@/components/PlayRecord/index.vue')); // 播放录音
@@ -315,13 +316,15 @@ const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
 const storesUserInfo = useUserInfo();
 const { userInfos } = storeToRefs(storesUserInfo); // 用户信息
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 const recordFile = (obj: any, type: string) => {
 	switch (type) {
 		case 'order':
 			playRecordRef.value.playRecord(obj.callId);
 			break;
 		case 'visit':
-			playRecordRef.value.playRecord(themeConfig.value.recordPrefix + obj.recordingAbsolutePath);
+			playRecordRef.value.playRecord(AppConfigInfo.value.recordPrefix + obj.recordingAbsolutePath);
 			break;
 	}
 };

+ 4 - 1
src/views/quality/done/components/ZG-quality.vue

@@ -231,6 +231,7 @@ import { storeToRefs } from 'pinia';
 import { useUserInfo } from '@/stores/userInfo';
 import { Splitpanes, Pane } from 'splitpanes';
 import 'splitpanes/dist/splitpanes.css';
+import { useAppConfig } from '@/stores/appConfig';
 
 // 引入组件
 const PlayRecord = defineAsyncComponent(() => import('@/components/PlayRecord/index.vue')); // 播放录音
@@ -368,13 +369,15 @@ const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
 const storesUserInfo = useUserInfo();
 const { userInfos } = storeToRefs(storesUserInfo); // 用户信息
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 const recordFile = (obj: any, type: string) => {
 	switch (type) {
 		case 'order':
 			playRecordRef.value.playRecord(obj.callId);
 			break;
 		case 'visit':
-			playRecordRef.value.playRecord(themeConfig.value.recordPrefix + obj.recordingAbsolutePath);
+			playRecordRef.value.playRecord(AppConfigInfo.value.recordPrefix + obj.recordingAbsolutePath);
 			break;
 	}
 };

+ 4 - 1
src/views/quality/index/components/Quality-inspection.vue

@@ -193,6 +193,7 @@ import { qualityUpdate, qualityDetail } from '@/api/quality';
 import { useThemeConfig } from '@/stores/themeConfig';
 import { storeToRefs } from 'pinia';
 import { useUserInfo } from '@/stores/userInfo';
+import { useAppConfig } from '@/stores/appConfig';
 
 // 引入组件
 const PlayRecord = defineAsyncComponent(() => import('@/components/PlayRecord/index.vue')); // 播放录音
@@ -309,13 +310,15 @@ const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
 const storesUserInfo = useUserInfo();
 const { userInfos } = storeToRefs(storesUserInfo); // 用户信息
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 const recordFile = (obj: any, type: string) => {
 	switch (type) {
 		case 'order':
 			playRecordRef.value.playRecord(obj.callId);
 			break;
 		case 'visit':
-			playRecordRef.value.playRecord(themeConfig.value.recordPrefix + obj.recordingAbsolutePath);
+			playRecordRef.value.playRecord(AppConfigInfo.value.recordPrefix + obj.recordingAbsolutePath);
 			break;
 	}
 };

+ 4 - 1
src/views/quality/index/components/ZG-quality.vue

@@ -247,6 +247,7 @@ import { storeToRefs } from 'pinia';
 import { useUserInfo } from '@/stores/userInfo';
 import { Splitpanes, Pane } from 'splitpanes';
 import 'splitpanes/dist/splitpanes.css';
+import { useAppConfig } from '@/stores/appConfig';
 
 // 引入组件
 const PlayRecord = defineAsyncComponent(() => import('@/components/PlayRecord/index.vue')); // 播放录音
@@ -379,13 +380,15 @@ const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
 const storesUserInfo = useUserInfo();
 const { userInfos } = storeToRefs(storesUserInfo); // 用户信息
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 const recordFile = (obj: any, type: string) => {
 	switch (type) {
 		case 'order':
 			playRecordRef.value.playRecord(obj.callId);
 			break;
 		case 'visit':
-			playRecordRef.value.playRecord(themeConfig.value.recordPrefix + obj.recordingAbsolutePath);
+			playRecordRef.value.playRecord(AppConfigInfo.value.recordPrefix + obj.recordingAbsolutePath);
 			break;
 	}
 };

+ 6 - 3
src/views/statistics/call/detailIndexCall.vue

@@ -86,6 +86,7 @@ import { downloadFileBySrc, downloadFileByStream } from '@/utils/tools';
 import { useThemeConfig } from '@/stores/themeConfig';
 import { storeToRefs } from 'pinia';
 import { exportOrder } from '@/api/business/order';
+import { useAppConfig } from '@/stores/appConfig';
 
 const PlayRecord = defineAsyncComponent(() => import('@/components/PlayRecord/index.vue')); // 播放录音
 const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
@@ -134,6 +135,8 @@ const queryList = async () => {
 const playRecordRef = ref<RefType>();
 const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 const onPlaySoundRecording = (val: any) => {
 	playRecordRef.value.playRecord(val.otherAccept);
 };
@@ -150,7 +153,7 @@ const onDownload = (row: any) => {
 		.then(() => {
 			switch (themeConfig.value.appScope) {
 				case 'YiBin':
-					fileDownload({ path: themeConfig.value.recordDownLoadPrefix + row.audioFile })
+					fileDownload({ path: AppConfigInfo.value.recordDownLoadPrefix + row.audioFile })
 						.then((res: any) => {
 							downloadFileByStream(res, row.audioFile);
 						})
@@ -158,8 +161,8 @@ const onDownload = (row: any) => {
 					break;
 				case 'ZiGong':
 				case 'LuZhou':
-					downloadFileBySrc(themeConfig.value.recordPrefix + row.audioFile, row.audioFile);
-					// window.open(themeConfig.value.recordPrefix + row.audioFile)
+					downloadFileBySrc(AppConfigInfo.value.recordPrefix + row.audioFile, row.audioFile);
+					// window.open(AppConfigInfo.value.recordPrefix + row.audioFile)
 					break;
 			}
 		})

+ 5 - 2
src/views/statistics/call/detailSeatDate.vue

@@ -131,6 +131,7 @@ import { downloadFileBySrc, downloadFileByStream } from '@/utils/tools';
 import { useThemeConfig } from '@/stores/themeConfig';
 import { storeToRefs } from 'pinia';
 import { defaultTimeStartEnd, shortcuts } from '@/utils/constants';
+import { useAppConfig } from '@/stores/appConfig';
 
 const PlayRecord = defineAsyncComponent(() => import('@/components/PlayRecord/index.vue')); // 播放录音
 const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
@@ -188,6 +189,8 @@ const queryList = async () => {
 const playRecordRef = ref<RefType>();
 const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 const onPlaySoundRecording = (val: any) => {
 	playRecordRef.value.playRecord(val.id);
 };
@@ -204,7 +207,7 @@ const onDownload = (row: any) => {
 		.then(() => {
 			switch (themeConfig.value.appScope) {
 				case 'YiBin':
-					fileDownload({ path: themeConfig.value.recordDownLoadPrefix + row.audioFile })
+					fileDownload({ path: AppConfigInfo.value.recordDownLoadPrefix + row.audioFile })
 						.then((res: any) => {
 							downloadFileByStream(res, row.audioFile);
 						})
@@ -212,7 +215,7 @@ const onDownload = (row: any) => {
 					break;
 				case 'ZiGong':
 				case 'LuZhou':
-					downloadFileBySrc(themeConfig.value.recordPrefix + row.audioFile, row.audioFile);
+					downloadFileBySrc(AppConfigInfo.value.recordPrefix + row.audioFile, row.audioFile);
 					break;
 			}
 		})

+ 4 - 4
src/views/tels/callLog/ybCallLog.vue

@@ -473,8 +473,8 @@ import { fileDownload } from '@/api/public/file';
 import mittBus from '@/utils/mitt';
 import Other from '@/utils/other';
 import { Local } from '@/utils/storage';
-import { useThemeConfig } from '@/stores/themeConfig';
 import { storeToRefs } from 'pinia';
+import { useAppConfig } from '@/stores/appConfig';
 
 // 引入组件
 const PlayRecord = defineAsyncComponent(() => import('@/components/PlayRecord/index.vue')); // 播放录音
@@ -651,8 +651,8 @@ const resetQuery = (formEl: FormInstance | undefined) => {
 };
 // 播放录音
 const playRecordRef = ref<RefType>();
-const storesThemeConfig = useThemeConfig();
-const { themeConfig } = storeToRefs(storesThemeConfig);
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 const onPlaySoundRecording = (val: any) => {
 	playRecordRef.value.playRecord(val.otherAccept);
 };
@@ -667,7 +667,7 @@ const onDownload = (row: any) => {
 		autofocus: false,
 	})
 		.then(() => {
-			fileDownload({ path: themeConfig.value.recordDownLoadPrefix + row.recordingAbsolutePath }).then((res: any) => {
+			fileDownload({ path: AppConfigInfo.value.recordDownLoadPrefix + row.recordingAbsolutePath }).then((res: any) => {
 				downloadFileByStream(res, row.recordingFileName);
 			});
 		})

+ 4 - 1
src/views/tels/callLog/zgCallLog.vue

@@ -199,6 +199,7 @@ import Other from '@/utils/other';
 import { getCallCenterCallRecord, getCallCenterCallRecordBaseData, getCallCenterCallRecordTotal } from '@/api/callCenter';
 import { useThemeConfig } from '@/stores/themeConfig';
 import { storeToRefs } from 'pinia';
+import { useAppConfig } from '@/stores/appConfig';
 
 // 引入组件
 const PlayRecord = defineAsyncComponent(() => import('@/components/PlayRecord/index.vue')); // 播放录音
@@ -304,6 +305,8 @@ const resetQuery = (formEl: FormInstance | undefined) => {
 const playRecordRef = ref<RefType>();
 const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 const onPlaySoundRecording = (val: any) => {
 	playRecordRef.value.playRecord(val.id);
 };
@@ -318,7 +321,7 @@ const onDownload = (row: any) => {
 		autofocus: false,
 	})
 		.then(() => {
-			downloadFileBySrc(themeConfig.value.recordPrefix + row.audioFile, row.audioFile);
+			downloadFileBySrc(AppConfigInfo.value.recordPrefix + row.audioFile, row.audioFile);
 		})
 		.catch(() => {});
 };

+ 162 - 107
src/views/tels/restApply/index.vue

@@ -1,13 +1,22 @@
 <template>
 	<div class="tels-restApply-container layout-padding">
 		<div class="layout-padding-auto layout-padding-view pd20">
-			<el-form :model="state.queryParams" ref="ruleFormRef" inline @submit.native.prevent >
-				<el-form-item label="关键词" prop="KeyWords">
-					<el-input v-model="state.queryParams.KeyWords" placeholder="坐席名称/工号" clearable @keyup.enter="queryList" />
+			<el-tabs v-model="state.queryParams.Type" @tab-change="handleQuery">
+				<el-tab-pane :name="0" label="待审批" :disabled="state.loading"></el-tab-pane>
+				<el-tab-pane :name="1" label="已审批" :disabled="state.loading"></el-tab-pane>
+			</el-tabs>
+			<el-form :model="state.queryParams" ref="ruleFormRef" inline @submit.native.prevent>
+				<el-form-item label="申请人" prop="ApplyUserName">
+					<el-input v-model="state.queryParams.ApplyUserName" placeholder="申请人" clearable @keyup.enter="handleQuery" class="keyword-input" />
 				</el-form-item>
-				<el-form-item label="申请时间" prop="time">
+				<el-form-item label="小休原因" prop="ReasonId">
+					<el-select v-model="state.queryParams.ReasonId" placeholder="请选择小休原因" @change="handleQuery" clearable>
+						<el-option v-for="item in state.restReason" :key="item.dicDataValue" :label="item.dicDataName" :value="item.dicDataValue" />
+					</el-select>
+				</el-form-item>
+				<el-form-item label="申请时间" prop="crTime">
 					<el-date-picker
-						v-model="state.queryParams.time"
+						v-model="state.queryParams.crTime"
 						type="datetimerange"
 						range-separator="至"
 						start-placeholder="开始时间"
@@ -15,29 +24,14 @@
 						value-format="YYYY-MM-DD[T]HH:mm:ss"
 						:shortcuts="shortcuts"
 						:default-time="defaultTimeStartEnd"
-						@change="
-							(val: any[]) => {
-								state.queryParams.BeginTime = val[0];
-								state.queryParams.EndTime = val[1];
-							}
-						"
+						@change="handleQuery"
 					/>
 				</el-form-item>
-				<el-form-item label="小休原因" prop="Reason">
-					<el-select v-model="state.queryParams.Reason" placeholder="请选择小休原因" class="w100">
-						<el-option v-for="item in state.restReason" :key="item.id" :label="item.content" :value="item.content" />
-					</el-select>
-				</el-form-item>
-				<el-form-item label="审批状态" prop="Status">
-					<el-select v-model="state.queryParams.Status" placeholder="请选择审批状态" class="w100">
-						<el-option v-for="item in state.restApplyStatus" :key="item.key" :label="item.value" :value="item.key" />
-					</el-select>
-				</el-form-item>
 				<el-form-item>
-					<el-button type="primary" @click="handleQuery" :loading="state.loading" v-waves> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
-					<el-button @click="resetQuery(ruleFormRef)" v-waves class="default-button" :loading="state.loading">
-						<SvgIcon name="ele-Refresh" class="mr5" />重置
-					</el-button>
+					<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+					<el-button @click="drawer = true" class="default-button" :loading="state.loading">
+						<SvgIcon name="ele-Search" class="mr5" />更多查询</el-button
+					>
 				</el-form-item>
 			</el-form>
 			<vxe-toolbar
@@ -47,7 +41,19 @@
 				:refresh="{
 					queryMethod: handleQuery,
 				}"
+				:tools="[{ toolRender: { name: 'exportCurrent' } }, { toolRender: { name: 'exportAll' } }]"
 			>
+				<template #buttons>
+					<el-button
+						type="primary"
+						@click="onAuditBatch"
+						:disabled="isChecked"
+						:loading="state.loading"
+						v-auth="'tels:restApply:audit:batch'"
+						v-show="state.queryParams.Type === 0"
+					>批量审批</el-button
+					>
+				</template>
 			</vxe-toolbar>
 			<div style="overflow: hidden; width: 100%; height: 100%; flex: 1">
 				<vxe-table
@@ -62,43 +68,32 @@
 					auto-resize
 					show-overflow
 					:scrollY="{ enabled: true, gt: 100 }"
-					id="restApply"
+					id="telsRestApply"
 					:custom-config="{ storage: true }"
+					:params="{ exportMethod: restApplyExport, exportParams: requestParams }"
+					@sort-change="sortChange"
+					@checkbox-all="selectAllChangeEvent"
+					@checkbox-change="selectChangeEvent"
 				>
-
-					<vxe-column field="userName" title="坐席" width="140"></vxe-column>
-					<vxe-column field="creationTime" title="申请时间" sortable width="160">
+					<vxe-column type="checkbox" width="50" align="center"></vxe-column>
+					<vxe-column field="reason" title="小休原因"></vxe-column>
+					<vxe-column field="applyUserName" title="申请人"></vxe-column>
+					<vxe-column field="applyTime" title="申请时间" sortable width="160">
 						<template #default="{ row }">
-							{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}
+							{{ formatDate(row.applyTime, 'YYYY-mm-dd HH:MM:SS') }}
 						</template>
 					</vxe-column>
-					<vxe-column field="creationTime" title="开始时间" sortable width="160">
+					<vxe-column field="auditStatusText" title="审核结果"> </vxe-column>
+					<vxe-column field="auditOpinion" title="审核意见" min-width="140"></vxe-column>
+					<vxe-column field="auditUserName" title="审核人" min-width="140"></vxe-column>
+					<vxe-column field="auditTime" title="审核时间" sortable width="160">
 						<template #default="{ row }">
-							{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}
+							{{ formatDate(row.auditTime, 'YYYY-mm-dd HH:MM:SS') }}
 						</template>
 					</vxe-column>
-					<vxe-column field="creationTime" title="结束时间" sortable width="160">
+					<vxe-column title="操作" fixed="right" width="90" align="center">
 						<template #default="{ row }">
-							{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}
-						</template>
-					</vxe-column>
-					<vxe-column field="restDuration" title="时长(分钟)" width="140">
-						<template #default="{ row }">
-							{{ (row.restDuration / 60).toFixed(2) }}
-						</template>
-					</vxe-column>
-					<vxe-column field="applyStatus" title="审批状态" width="140">
-						<template #default="{ row }">
-							{{ state.restApplyStatus[row.applyStatus].value }}
-						</template>
-					</vxe-column>
-					<vxe-column field="restReason" title="小休原因" min-width="140"></vxe-column>
-					<vxe-column title="操作" fixed="right" width="140" align="center">
-						<template #default="{ row }">
-							<el-button link type="primary" @click="onRecord(row)" v-auth="'system:workflow:record'" title="审批记录" v-show="row.workflowId">
-								审批记录
-							</el-button>
-							<el-button link type="primary" @click="onSubmit(row)" v-auth="'system:workflow:handle'" title="审批" v-show="[0].includes(row.applyStatus)">
+							<el-button link type="primary" @click="onAudit(row)" v-auth="'tels:restApply:audit'" title="审批" v-show="[0].includes(row.auditStatus)">
 								审批
 							</el-button>
 						</template>
@@ -113,24 +108,53 @@
 				:disabled="state.loading"
 			/>
 		</div>
-		<!-- 流程审配 -->
-		<process-audit ref="processAuditRef" @orderProcessSuccess="orderProcessSuccess" />
-		<!-- 流转记录 -->
-		<audit-record ref="AuditRecordRef" />
+		<!-- 更多查询 -->
+		<el-drawer v-model="drawer" title="更多查询" size="500px">
+			<el-form :model="state.queryParams" ref="drawerRuleFormRef" @submit.native.prevent label-width="100px" :disabled="state.loading">
+				<template v-if="state.queryParams.Type === 1">
+					<el-form-item label="审批状态" prop="AuditStatus">
+						<el-select v-model="state.queryParams.AuditStatus" placeholder="请选择审批状态" class="w100" @change="handleQuery" clearable>
+							<el-option v-for="item in state.restApplyStatus" :key="item.key" :label="item.value" :value="item.key" />
+						</el-select>
+					</el-form-item>
+					<el-form-item label="审批人" prop="AuditUserName">
+						<el-input v-model="state.queryParams.AuditUserName" placeholder="审批人" clearable @keyup.enter="handleQuery" />
+					</el-form-item>
+					<el-form-item label="审批时间" prop="spTime">
+						<el-date-picker
+							v-model="state.queryParams.spTime"
+							type="datetimerange"
+							range-separator="至"
+							start-placeholder="开始时间"
+							end-placeholder="结束时间"
+							value-format="YYYY-MM-DD[T]HH:mm:ss"
+							:shortcuts="shortcuts"
+							:default-time="defaultTimeStartEnd"
+							@change="handleQuery"
+						/>
+					</el-form-item>
+				</template>
+			</el-form>
+			<template #footer>
+				<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+				<el-button @click="resetQuery(drawerRuleFormRef)" class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+			</template>
+		</el-drawer>
+		<!-- 审核 -->
+		<rest-audit ref="restAuditRef" @updateList="queryList" />
 	</div>
 </template>
 
-<script lang="tsx" setup name="restApply">
-import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
+<script lang="tsx" setup name="telsRestApply">
+import { computed, defineAsyncComponent, onMounted, reactive, ref } from 'vue';
 import type { FormInstance } from 'element-plus';
 import { formatDate } from '@/utils/formatTime';
-import { baseData, restApplyPaged } from '@/api/tels/restApply';
+import { restBaseData, restApplyExport, restApplyPaged } from '@/api/tels/restApply';
 import { debounce } from '@/utils/tools';
-import { commonEnum, defaultTimeStartEnd, shortcuts } from "@/utils/constants";
-import other from '@/utils/other';
+import { defaultTimeStartEnd, shortcuts } from '@/utils/constants';
+import Other from '@/utils/other';
 // 引入组件
-const AuditRecord = defineAsyncComponent(() => import('@/components/AuditRecord/index.vue')); // 流转记录
-const ProcessAudit = defineAsyncComponent(() => import('@/components/ProcessAudit/index.vue')); // 审批流程
+const RestAudit = defineAsyncComponent(() => import('@/views/tels/restApply/components/Audit.vue')); // 审批
 const pagination = defineAsyncComponent(() => import('@/components/ProTable/components/Pagination.vue')); // 分页
 
 // 定义变量内容
@@ -138,12 +162,19 @@ const state = reactive<any>({
 	queryParams: {
 		PageIndex: 1, // 当前页码
 		PageSize: 10, // 每页条数
-		KeyWords: null, // 关键字
-		Reason: null, // 小休原因
-		Status: null, // 审批状态
-		time: [], // 申请时间
-		BeginTime: null, // 开始时间
-		EndTime: null, // 结束时间
+		Type: 0, // 默认待审批
+		ApplyUserName: null, // 申请人
+		ReasonId: null, // 小休原因
+		crTime: [], // 申请时间
+		ApplyStartTime: null, // 开始时间
+		ApplyEndTime: null, // 结束时间
+		AuditStatus: null, // 审批状态
+		AuditUserName: null, // 审批人
+		spTime: [], // 审批时间
+		AuditStartTime: null, // 审批开始时间
+		AuditEndTime: null, // 审批结束时间
+		SortRule: null, // 排序规则
+		SortField: null, // 排序字段
 	},
 	loading: false, // 加载状态
 	total: 0, // 总条数
@@ -153,71 +184,95 @@ const state = reactive<any>({
 });
 const ruleFormRef = ref<FormInstance>(); // 表单实例
 /** 搜索按钮操作 节流操作 */
-const handleQuery = debounce(() => {
+const handleQuery = () => {
 	state.queryParams.PageIndex = 1;
 	queryList();
-}, 300);
-const orderProcessSuccess = () => {
-	console.log('审批成功');
-	handleQuery();
 };
 /** 获取用户列表 */
+const requestParams = ref<EmptyObjectType>({});
 const queryList = () => {
 	state.loading = true;
-	let request = other.deepClone(state.queryParams);
-	Reflect.deleteProperty(request, 'time'); // 删除无用的参数
-	restApplyPaged(request)
+	requestParams.value = Other.deepClone(state.queryParams);
+	requestParams.value.ApplyStartTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
+	requestParams.value.ApplyEndTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
+	Reflect.deleteProperty(requestParams.value, 'crTime'); // 申请时间
+	requestParams.value.AuditStartTime = state.queryParams.spTime === null ? null : state.queryParams.spTime[0];
+	requestParams.value.AuditEndTime = state.queryParams.spTime === null ? null : state.queryParams.spTime[1];
+	Reflect.deleteProperty(requestParams.value, 'spTime'); // 审批时间
+	restApplyPaged(requestParams.value)
 		.then((response: any) => {
 			state.tableData = response?.result.items;
 			state.total = response?.result.total;
+			tableRef.value?.clearCheckboxRow();
+			checkTable.value = [];
 			state.loading = false;
 		})
 		.catch(() => {
 			state.loading = false;
 		});
 };
+// 排序
+const sortChange = (val: any) => {
+	state.queryParams.SortField = val.order ? val.field : null;
+	// 0 升序 1 降序
+	state.queryParams.SortRule = val.order ? (val.order == 'desc' ? 1 : 0) : null;
+	handleQuery();
+};
 /** 重置按钮操作 */
+const drawer = ref(false);
+const drawerRuleFormRef = ref();
 const resetQuery = debounce((formEl: FormInstance | undefined) => {
 	if (!formEl) return;
-	state.queryParams.BeginTime = null;
-	state.queryParams.EndTime = null;
 	formEl.resetFields();
+	ruleFormRef.value?.resetFields();
 	handleQuery();
 }, 300);
-// 办理 下一步
-const processAuditRef = ref<RefType>();
-const onSubmit = debounce((row: any) => {
-	const params = {
-		id: row.workflowId,
-		commonEnum: commonEnum.OrderCirculation,
-		processType: '小休办理',
-		extra: {
-			dialogTitle: '小休办理',
-			inputPlaceholder: '办理意见',
-			annexName: '办理附件',
-		},
-	};
-	processAuditRef.value.openDialog(params);
-}, 1000);
-// 审核记录
-const AuditRecordRef = ref<RefType>();
-const onRecord = (row: any) => {
-	const params = {
-		dialogTitle: '审核记录 (小休申请)',
-		...row,
-	};
-	console.log(params);
-	AuditRecordRef.value.openDialog(params);
+// 审核
+const restAuditRef = ref<RefType>();
+const onAudit = (row: any) => {
+	restAuditRef.value.openDialog([row.id]);
+};
+const checkTable = ref<EmptyArrayType>([]);
+const selectAllChangeEvent = ({ checked }) => {
+	if (tableRef.value) {
+		const records = tableRef.value.getCheckboxRecords();
+		checkTable.value = records;
+		console.log(checked ? '所有勾选事件' : '所有取消事件', records);
+	}
+};
+
+const selectChangeEvent = ({ checked }) => {
+	if (tableRef.value) {
+		const records = tableRef.value.getCheckboxRecords();
+		checkTable.value = records;
+		console.log(checked ? '勾选事件' : '取消事件', records);
+	}
+};
+const isChecked = computed(() => {
+	return !checkTable.value.length;
+});
+// 批量审批
+const onAuditBatch = () => {
+	const ids = checkTable.value.map((row: any) => row.id);
+	restAuditRef.value.openDialog(ids);
 };
 // 获取基础数据
 const baseDataFn = () => {
-	baseData().then((res: any) => {
-		state.restApplyStatus = res.result?.restApplyStatus;
+	restBaseData().then((res: any) => {
+		state.restApplyStatus = res.result?.auditStatus;
+		state.restApplyStatus = state.restApplyStatus.filter((item: any) => {
+			return [1, 2].includes(item.key);
+		});
 		state.restReason = res.result?.restReason;
-		queryList();
 	});
 };
+const toolbarRef = ref<RefType>();
+const tableRef = ref<RefType>();
 onMounted(() => {
+	queryList();
 	baseDataFn();
+	if (tableRef.value && toolbarRef.value) {
+		tableRef.value.connect(toolbarRef.value);
+	}
 });
 </script>

+ 1 - 1
src/views/todo/center/index.vue

@@ -275,7 +275,7 @@ const gridOptions = reactive<any>({
 		{ field: 'hotspotName', title: '热点分类', width: 150 },
 		{ field: 'sensitive', title: '敏感词', width: 150 },
 		{ field: 'reTransactNum', title: '重办次数', width: 130 },
-		{ title: '操作', width: 140, fixed: 'right', align: 'center', slots: { default: 'action' } },
+		{ title: '操作', width: 150, fixed: 'right', align: 'center', slots: { default: 'action' } },
 	],
 	data: [],
 	sortConfig: {

+ 161 - 26
src/views/todo/seats/accept/Knowledge.vue

@@ -4,8 +4,8 @@
 			<el-tab-pane label="推荐知识库" name=""> </el-tab-pane>
 			<el-tab-pane label="中心知识库" name="中心知识库"> </el-tab-pane>
 			<el-tab-pane label="部门知识库" name="部门知识库"> </el-tab-pane>
-			<el-tab-pane label="办事指南" name="guide" v-if="['LuZhou'].includes(themeConfig.appScope)"> </el-tab-pane>
-			<el-tab-pane label="知识推荐" name="recommend" v-if="['LuZhou'].includes(themeConfig.appScope)"> </el-tab-pane>
+			<el-tab-pane label="办事指南" name="guide" v-if="['LuZhou'].includes(themeConfig.appScope) && AppConfigInfo.luzhouhcp"> </el-tab-pane>
+			<el-tab-pane label="知识推荐" name="recommend" v-if="['LuZhou'].includes(themeConfig.appScope) && AppConfigInfo.luzhouhcp"> </el-tab-pane>
 		</el-tabs>
 		<div class="knowledge-input" v-if="['', '中心知识库', '部门知识库'].includes(state.queryParams.Attribution)">
 			<el-input v-model="state.queryParams.Keyword" placeholder="关键词" clearable class="mr10 w100" @keyup.enter="knowledgeRetrievalPaged">
@@ -46,7 +46,7 @@
 				<div v-for="(v, i) in state.knowledgeList" :key="i" class="retrieval-content-item" @click="onPreview(v)">
 					<div class="mb10" style="display: flex">
 						<p class="text-no-wrap" style="flex: 1">{{ v.title }}</p>
-						<el-button type="primary" size="small" @click.stop="changeYYType(v)" v-if="['ZiGong','YiBin'].includes(themeConfig.appScope)">{{
+						<el-button type="primary" size="small" @click.stop="changeYYType(v)" v-if="['ZiGong', 'YiBin'].includes(themeConfig.appScope)">{{
 							v.isChoose ? '取消引用' : '引用'
 						}}</el-button>
 					</div>
@@ -75,30 +75,65 @@
 		class="pt10"
 		v-if="['', '中心知识库', '部门知识库'].includes(state.queryParams.Attribution)"
 	/>
-	<div v-if="['guide'].includes(state.queryParams.Attribution)">
-		<el-input v-model="guideKeyword" placeholder="请输入搜索内容" clearable class="mr10 w100" @keyup.enter="sendGuide">
-			<template #prepend>
-				<el-select v-model="selectType" style="width: 80px">
-					<el-option label="个人" value="1" />
-					<el-option label="企业" value="2" />
-				</el-select>
-			</template>
+	<!--	办事指南 -->
+	<div v-if="['guide'].includes(state.queryParams.Attribution)" class="guide">
+		<div class="flex flex-center-between mt10">
+			<el-radio-group v-model="selectType" @change="getGuideType">
+				<el-radio-button label="个人" value="1" />
+				<el-radio-button label="企业" value="2" />
+			</el-radio-group>
+			<el-select v-model="guideType" placeholder="请选择办事分类" style="width: 240px" @change="handleQueryGuide">
+				<el-option v-for="item in guideTypeList" :key="item.code" :label="item.describe" :value="item.code" />
+			</el-select>
+		</div>
+		<el-input v-model="guideKeyword" placeholder="请输入文档名称" clearable class="mr10 mt10 w100" @keyup.enter="sendGuide">
 			<template #append>
 				<el-button type="primary" @click="sendGuide" size="small" round>搜索</el-button>
 			</template>
 		</el-input>
-		<el-empty description="暂无数据" v-if="!guideList.length" class="mb20"> </el-empty>
-		<el-scrollbar max-height="400px"> </el-scrollbar>
+		<div v-loading="state.loading" class="guide-content">
+			<el-empty description="暂无数据" v-if="!guideList.length" class="mb20"> </el-empty>
+			<el-scrollbar max-height="350px">
+				<div v-for="(item, index) in guideList" :key="index" class="guide-content-item">
+					<el-button link type="primary" @click="guideDetail(item)">{{ item.name }}</el-button>
+				</div>
+			</el-scrollbar>
+			<pagination
+				@pagination="getGuideDataList"
+				:total="guideListTotal"
+				v-model:current-page="guidePageIndex"
+				v-model:page-size="guidePageSize"
+				class="pt10"
+			/>
+		</div>
 	</div>
-	<div v-if="['recommend'].includes(state.queryParams.Attribution)">
+	<!--	推荐知识 -->
+	<div v-if="['recommend'].includes(state.queryParams.Attribution)" class="recommend">
 		<el-input v-model="recommendKeyword" placeholder="请输入问题内容" clearable class="mr10 w100" @keyup.enter="sendRecommend">
 			<template #append>
 				<el-button type="primary" @click="sendRecommend" size="small" round>搜索</el-button>
 			</template>
 		</el-input>
-		<el-empty description="暂无数据" v-if="!recommendList.length" class="mb20"> </el-empty>
-		<el-scrollbar max-height="400px"> </el-scrollbar>
+		<div v-loading="state.loading" class="recommend-content">
+			<el-empty description="暂无数据" v-if="!recommendList.length" class="mb20"> </el-empty>
+			<el-scrollbar max-height="400px">
+				<div v-for="(item, index) in recommendList" :key="index" class="recommend-content-item">
+					<div class="recommend-content-item-question">问:{{ item.question }}</div>
+					<div class="recommend-content-item-answer" v-html="item.answer" style="text-indent: 1em"></div>
+				</div>
+			</el-scrollbar>
+		</div>
 	</div>
+	<el-dialog :title="dialogTitle" v-model="dialogVisible" draggable destroy-on-close append-to-body>
+		<div v-loading="loading" class="formatted-text">
+			{{ documentContent }}
+		</div>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="dialogVisible = false" class="default-button">关闭</el-button>
+			</span>
+		</template>
+	</el-dialog>
 </template>
 <script setup lang="ts" name="orderAcceptKnowledge">
 // 定义变量内容
@@ -110,8 +145,10 @@ import { throttle } from '@/utils/tools';
 import { useThemeConfig } from '@/stores/themeConfig';
 import { storeToRefs } from 'pinia';
 import { removeDuplicate } from '@/utils/arrayOperation';
-import { lzRXFZAuth } from '@/api/business/lzRXFZ';
+import { lzRXFZAuth, lzRXFZDocumentDetail, lzRXFZDocumentList, lzRXFZDocumentType, lzRXFZKnowledge } from '@/api/business/lzRXFZ';
 import { useUserInfo } from '@/stores/userInfo';
+import { Cookie } from '@/utils/storage';
+import { useAppConfig } from '@/stores/appConfig';
 
 const pagination = defineAsyncComponent(() => import('@/components/ProTable/components/Pagination.vue')); // 分页
 
@@ -132,6 +169,8 @@ const props = defineProps({
 
 const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 const state = reactive<any>({
 	loading: false, // 知识检索加载状态
 	knowledgeList: [],
@@ -148,7 +187,11 @@ const state = reactive<any>({
 });
 // 手动查询,将页码设置为1
 const handleQuery = () => {
-	if (['guide', 'recommend'].includes(state.queryParams.Attribution)) return;
+	if (['recommend'].includes(state.queryParams.Attribution)) return;
+	if (state.queryParams.Attribution === 'guide') {
+		getGuideType();
+		return;
+	}
 	state.queryParams.PageIndex = 1;
 	knowledgeRetrievalPaged();
 };
@@ -267,12 +310,70 @@ watch(
 // 指南关键词
 const guideKeyword = ref('');
 const selectType = ref('1'); // 选择类型 1 个人 2 企业
-// 发送问题
+const guideType = ref(null); // 指南类型
+const guideTypeList = ref<EmptyArrayType>([]); // 指南类型列表
+// 获取指南类型列表
+const getGuideType = () => {
+	lzRXFZDocumentType({ type: selectType.value })
+		.then((res: any) => {
+			guideTypeList.value = res.data;
+			guideType.value = res.data[0].code;
+			handleQueryGuide();
+		})
+		.catch((err: any) => {
+			console.log(err);
+		});
+};
+// 根据分类获取指南数据列表
+const guideListTotal = ref(0);
+const guidePageIndex = ref(1);
+const guidePageSize = ref(10);
 const guideList = ref<EmptyArrayType>([]); // 指南列表
+const handleQueryGuide = () => {
+	guidePageIndex.value = 1;
+	getGuideDataList();
+};
+const getGuideDataList = () => {
+	state.loading = true;
+	lzRXFZDocumentList({
+		type: selectType.value,
+		contentType: guideType.value,
+		pageNum: guidePageIndex.value,
+		pageSize: guidePageSize.value,
+		name: guideKeyword.value,
+	})
+		.then((res: any) => {
+			guideListTotal.value = parseInt(res.data?.total);
+			guideList.value = res.data.rows;
+			state.loading = false;
+		})
+		.catch((err: any) => {
+			console.log(err);
+			state.loading = false;
+		});
+};
+// 发送问题
 const sendGuide = () => {
-	if (!guideKeyword.value) {
-		return;
-	}
+	handleQueryGuide();
+};
+// 点击查看文档详情
+const dialogVisible = ref(false);
+const dialogTitle = ref('文档详情');
+const loading = ref(false); // 加载
+const documentContent = ref(null);
+const guideDetail = (item: any) => {
+	dialogVisible.value = true;
+	loading.value = true;
+	dialogTitle.value = `文档详情(${item.name})`;
+	lzRXFZDocumentDetail({ documentId: item.id })
+		.then((res: any) => {
+			documentContent.value = res.data.content;
+			loading.value = false;
+		})
+		.catch((err: any) => {
+			console.log(err);
+			loading.value = false;
+		});
 };
 // 推荐知识关键词
 const recommendKeyword = ref('');
@@ -280,17 +381,27 @@ const recommendKeyword = ref('');
 const recommendList = ref<EmptyArrayType>([]); // 推荐列表
 const sendRecommend = () => {
 	if (!recommendKeyword.value) {
+		recommendList.value = [];
 		return;
 	}
+	state.loading = true;
+	lzRXFZKnowledge({ content: recommendKeyword.value })
+		.then((res: any) => {
+			recommendList.value = res.data;
+			state.loading = false;
+		})
+		.catch((err: any) => {
+			console.log(err);
+			state.loading = false;
+		});
 };
 // 热线赋值授权
 const stores = useUserInfo(); // 用户信息
 const { userInfos } = storeToRefs(stores); // 用户信息
 const getRXFZAuth = () => {
-	console.log(userInfos.value, '111');
-	lzRXFZAuth({ uuid: '08dbba85-02b4-4c0d-83e9-a6e35977c105' })
+	lzRXFZAuth({ uuid: userInfos.value.id })
 		.then((res: any) => {
-			console.log(res);
+			Cookie.set('lzRXFZToken', res.data.accessToken);
 		})
 		.catch((err: any) => {
 			console.log(err);
@@ -298,7 +409,7 @@ const getRXFZAuth = () => {
 };
 onMounted(() => {
 	knowledgeRetrievalPaged();
-	if (['LuZhou'].includes(themeConfig.value.appScope)) {
+	if (['LuZhou'].includes(themeConfig.value.appScope) && AppConfigInfo.value.luzhouhcp) {
 		getRXFZAuth();
 	}
 });
@@ -334,4 +445,28 @@ defineExpose({
 		}
 	}
 }
+.recommend-content {
+	margin-top: 10px;
+	.recommend-content-item {
+		padding: 5px;
+		border-bottom: var(--el-border);
+		&:last-child {
+			border: none;
+		}
+		.recommend-content-item-question {
+			font-weight: bold;
+			margin-bottom: 5px;
+		}
+	}
+}
+.guide-content {
+	margin-top: 10px;
+	.guide-content-item {
+		padding: 5px;
+		border-bottom: var(--el-border);
+		&:last-child {
+			border: none;
+		}
+	}
+}
 </style>

+ 4 - 1
src/views/todo/seats/accept/Map-select.vue

@@ -22,6 +22,7 @@ import AMapLoader from '@amap/amap-jsapi-loader';
 import { onMounted, ref, shallowRef, watch } from 'vue';
 import { storeToRefs } from 'pinia';
 import { useThemeConfig } from '@/stores/themeConfig';
+import { useAppConfig } from '@/stores/appConfig';
 
 const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
@@ -54,6 +55,8 @@ watch(location, (val: any) => {
 		drawMarker();
 	}
 });
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 const keyword = ref('');
 let placeSearch, AMapObj, marker, geocoder;
 const initMap = () => {
@@ -63,7 +66,7 @@ const initMap = () => {
 	}).then((AMap) => {
 		AMapObj = AMap;
 		map.value = new AMap.Map('map-container', {
-			center: themeConfig.value.locationCenter,
+			center: AppConfigInfo.value.locationCenter,
 		});
 		// 添加点击事件
 		map.value.on('click', onMapClick);

+ 4 - 0
src/views/todo/seats/accept/lzAccept.vue

@@ -516,6 +516,8 @@ const state = reactive<any>({
 			dicDataName: '咨询',
 		},
 		tags: [], // 工单标签
+		longitude:null,//经度
+		latitude:null,//纬度
 	},
 	formLoading: false, // 表单加载状态
 	hotspotExternal: [], // 热点分类外部数据
@@ -551,6 +553,8 @@ const appConfigStore = useAppConfig();
 const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 state.ruleForm.acceptorName = userInfos.value.name; // 员工姓名
 state.ruleForm.acceptorStaffNo = userInfos.value.staffNo; // 员工工号
+state.ruleForm.longitude = AppConfigInfo.value.locationCenter[0]; // 默认经度
+state.ruleForm.latitude = AppConfigInfo.value.locationCenter[1]; // 默认纬度
 const route = useRoute(); // 路由
 // 选择来源渠道
 const changeChannel = (val: any) => {

+ 5 - 7
src/views/todo/seats/accept/ybAccept.vue

@@ -8,7 +8,7 @@
 						<div class="flex-center-between pb10">
 							<p class="border-title mb10">语音助手</p>
 						</div>
-						<voice-assistant @orderOverwrite="orderOverwrite" ref="voiceAssistantRef" />
+						<voice-assistant @orderOverwrite="orderOverwrite" />
 					</el-card>
 					<el-card shadow="never">
 						<el-tabs v-model="leftTopActive" @tab-change="handleLeftTop" stretch>
@@ -614,6 +614,8 @@ const state = reactive<any>({
 			dicDataName: '咨询',
 		},
 		knowledgeQuote: [], // 知识库引用
+		longitude:null,//经度
+		latitude:null,//纬度
 	},
 	formLoading: false, // 表单加载状态
 	hotspotExternal: [], // 热点分类外部数据
@@ -647,13 +649,9 @@ const appConfigStore = useAppConfig();
 const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 state.ruleForm.acceptorName = userInfos.value.name; // 员工姓名
 state.ruleForm.acceptorStaffNo = userInfos.value.staffNo; // 员工工号
+state.ruleForm.longitude = AppConfigInfo.value.locationCenter[0]; // 默认经度
+state.ruleForm.latitude = AppConfigInfo.value.locationCenter[1]; // 默认纬度
 const route = useRoute(); // 路由
-const voiceType = ref('');
-// 选择坐席还是市民通话内容
-const voiceAssistantRef = ref<RefType>();
-const changeVoiceType = () => {
-	voiceAssistantRef.value.filterMessage(voiceType.value);
-};
 const leftTopActive = ref('realtime');
 // 切换工单小结和实时质检
 const callSummaryRef = ref<RefType>();

+ 4 - 0
src/views/todo/seats/accept/zgAccept.vue

@@ -540,6 +540,8 @@ const state = reactive<any>({
 		industryName: null, // 行业分类名称
 		knowledgeQuote: [], // 知识库引用
 		tags: [], // 工单标签
+		longitude:null,//经度
+		latitude:null,//纬度
 	},
 	formLoading: false, // 表单加载状态
 	hotspotExternal: [], // 热点分类外部数据
@@ -576,6 +578,8 @@ const appConfigStore = useAppConfig();
 const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 state.ruleForm.acceptorName = userInfos.value.name; // 员工姓名
 state.ruleForm.acceptorStaffNo = userInfos.value.staffNo; // 员工工号
+state.ruleForm.longitude = AppConfigInfo.value.locationCenter[0]; // 默认经度
+state.ruleForm.latitude = AppConfigInfo.value.locationCenter[1]; // 默认纬度
 const route = useRoute(); // 路由
 // 选择来源渠道
 const changeChannel = (val: any) => {

+ 1 - 0
src/views/todo/seats/index.vue

@@ -45,6 +45,7 @@
 					</template>
 					<template #action="{ row }">
 						<el-button link type="success" @click="onOrderEdit(row)" title="编辑工单" v-show="row.canEdit" v-auth="'todo:seats:edit'"> 修改 </el-button>
+						<span></span>
 						<el-button link type="primary" @click="onSign(row)" title="签收工单" v-show="row.canSign" v-auth="'todo:seats:sign'"> 签收 </el-button>
 					</template>
 					<template #pager>