Browse Source

reactor:通话记录关联业务;

zhangchong 1 year ago
parent
commit
c719993b51

+ 0 - 91
package-lock.json

@@ -29,9 +29,7 @@
 				"qs": "^6.11.0",
 				"screenfull": "^6.0.2",
 				"sortablejs": "^1.15.0",
-				"v-viewer": "^3.0.10",
 				"vue": "^3.2.45",
-				"vue-clipboard3": "^2.0.0",
 				"vue-router": "^4.1.6",
 				"vue3-seamless-scroll": "^2.0.1",
 				"vuedraggable": "^4.1.0"
@@ -1385,15 +1383,6 @@
 				"node": ">=6.0"
 			}
 		},
-		"node_modules/clipboard": {
-			"version": "2.0.11",
-			"license": "MIT",
-			"dependencies": {
-				"good-listener": "^1.2.2",
-				"select": "^1.1.2",
-				"tiny-emitter": "^2.0.0"
-			}
-		},
 		"node_modules/color-convert": {
 			"version": "2.0.1",
 			"dev": true,
@@ -1505,10 +1494,6 @@
 				"node": ">=0.4.0"
 			}
 		},
-		"node_modules/delegate": {
-			"version": "3.2.0",
-			"license": "MIT"
-		},
 		"node_modules/dir-glob": {
 			"version": "3.0.1",
 			"dev": true,
@@ -2224,13 +2209,6 @@
 				"url": "https://github.com/sponsors/sindresorhus"
 			}
 		},
-		"node_modules/good-listener": {
-			"version": "1.2.2",
-			"license": "MIT",
-			"dependencies": {
-				"delegate": "^3.1.2"
-			}
-		},
 		"node_modules/graceful-fs": {
 			"version": "4.2.10",
 			"dev": true,
@@ -3364,10 +3342,6 @@
 				"compute-scroll-into-view": "^1.0.20"
 			}
 		},
-		"node_modules/select": {
-			"version": "1.1.2",
-			"license": "MIT"
-		},
 		"node_modules/semver": {
 			"version": "7.3.8",
 			"dev": true,
@@ -3611,10 +3585,6 @@
 				"node": ">=12.22"
 			}
 		},
-		"node_modules/tiny-emitter": {
-			"version": "2.1.0",
-			"license": "MIT"
-		},
 		"node_modules/tiny-warning": {
 			"version": "1.0.3",
 			"license": "MIT"
@@ -3758,21 +3728,6 @@
 			"dev": true,
 			"license": "MIT"
 		},
-		"node_modules/v-viewer": {
-			"version": "3.0.11",
-			"license": "MIT",
-			"dependencies": {
-				"lodash": "^4.17.21",
-				"viewerjs": "^1.9.0"
-			},
-			"peerDependencies": {
-				"vue": "^3.0.0"
-			}
-		},
-		"node_modules/viewerjs": {
-			"version": "1.11.1",
-			"license": "MIT"
-		},
 		"node_modules/vite": {
 			"version": "3.2.7",
 			"resolved": "https://registry.npmmirror.com/vite/-/vite-3.2.7.tgz",
@@ -3852,13 +3807,6 @@
 				"@vue/shared": "3.3.4"
 			}
 		},
-		"node_modules/vue-clipboard3": {
-			"version": "2.0.0",
-			"license": "MIT",
-			"dependencies": {
-				"clipboard": "^2.0.6"
-			}
-		},
 		"node_modules/vue-eslint-parser": {
 			"version": "9.1.0",
 			"dev": true,
@@ -4956,14 +4904,6 @@
 			"dev": true,
 			"peer": true
 		},
-		"clipboard": {
-			"version": "2.0.11",
-			"requires": {
-				"good-listener": "^1.2.2",
-				"select": "^1.1.2",
-				"tiny-emitter": "^2.0.0"
-			}
-		},
 		"color-convert": {
 			"version": "2.0.1",
 			"dev": true,
@@ -5037,9 +4977,6 @@
 		"delayed-stream": {
 			"version": "1.0.0"
 		},
-		"delegate": {
-			"version": "3.2.0"
-		},
 		"dir-glob": {
 			"version": "3.0.1",
 			"dev": true,
@@ -5518,12 +5455,6 @@
 				"slash": "^3.0.0"
 			}
 		},
-		"good-listener": {
-			"version": "1.2.2",
-			"requires": {
-				"delegate": "^3.1.2"
-			}
-		},
 		"graceful-fs": {
 			"version": "4.2.10",
 			"dev": true
@@ -6144,9 +6075,6 @@
 				"compute-scroll-into-view": "^1.0.20"
 			}
 		},
-		"select": {
-			"version": "1.1.2"
-		},
 		"semver": {
 			"version": "7.3.8",
 			"dev": true,
@@ -6285,9 +6213,6 @@
 		"throttle-debounce": {
 			"version": "5.0.0"
 		},
-		"tiny-emitter": {
-			"version": "2.1.0"
-		},
 		"tiny-warning": {
 			"version": "1.0.3"
 		},
@@ -6371,16 +6296,6 @@
 			"version": "1.0.2",
 			"dev": true
 		},
-		"v-viewer": {
-			"version": "3.0.11",
-			"requires": {
-				"lodash": "^4.17.21",
-				"viewerjs": "^1.9.0"
-			}
-		},
-		"viewerjs": {
-			"version": "1.11.1"
-		},
 		"vite": {
 			"version": "3.2.7",
 			"resolved": "https://registry.npmmirror.com/vite/-/vite-3.2.7.tgz",
@@ -6419,12 +6334,6 @@
 				"@vue/shared": "3.3.4"
 			}
 		},
-		"vue-clipboard3": {
-			"version": "2.0.0",
-			"requires": {
-				"clipboard": "^2.0.6"
-			}
-		},
 		"vue-eslint-parser": {
 			"version": "9.1.0",
 			"dev": true,

+ 1 - 1
src/App.vue

@@ -44,7 +44,7 @@ const setLockScreen = computed(() => {
 	return !themeConfig.value.isLockScreen;
 });
 
-// 设置锁屏时组件显示隐藏
+// 水印字符串
 const watermarkText = computed(() => {
   // 防止锁屏后,刷新出现不相关界面
   // https://gitee.com/lyt-top/vue-next-admin/issues/I6AF8P

+ 37 - 1
src/api/tels/callLog.ts

@@ -29,4 +29,40 @@ export const callBaseData = () => {
 		url: `/api/v1/IPPbx/calls/basedata`,
 		method: 'get',
 	});
-};
+};
+/**
+ * @description 查询可关联工单
+ * @param {object} params
+ * @return {*}
+ */
+export const callLogOrder = (params?: object) => {
+	return request({
+		url: `/api/v1/IPPbx/canlink-order`,
+		method: 'get',
+		params
+	});
+}
+/**
+ * @description 查询可关联回访
+ * @param {object} params
+ * @return {*}
+ */
+export const callLogVisit = (params?: object) => {
+	return request({
+		url: `/api/v1/IPPbx/canlink-ordervisit`,
+		method: 'get',
+		params
+	});
+}
+/**
+ * @description 提交关联
+ * @param {object} data
+ * @return {*}
+ */
+export const callLogLink = (data: object) => {
+	return request({
+		url: `/api/v1/IPPbx/calls/link`,
+		method: 'post',
+		data
+	});
+}

+ 16 - 11
src/components/OrderDetail/index.vue

@@ -32,16 +32,21 @@
 							<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6" v-if="state.ruleForm.fromPhone">
 								<el-form-item label="来电号码">
 									{{ state.ruleForm.fromPhone }}
-									<el-button
-										plain
-										title="录音文件"
-										size="small"
-										type="primary"
-										class="ml8"
-										@click="recordFile(state.ruleForm.callId)"
-										v-if="state.ruleForm.callId"
-										>录音文件</el-button
-									>
+                  <el-popover :width="480" trigger="click" v-if="state.ruleForm.recordingFileUrl">
+                    <template #reference>
+                      <el-button
+                          plain
+                          title="录音文件"
+                          size="small"
+                          type="primary"
+                          class="ml8"
+                          @click="recordFile(state.ruleForm.recordingFileUrl)"
+                          v-if="state.ruleForm.recordingFileUrl"
+                      >录音文件</el-button
+                      >
+                      <AudioPlayer :url="state.ruleForm.recordingFileUrl" />
+                    </template>
+                  </el-popover>
 								</el-form-item>
 							</el-col>
 							<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
@@ -522,7 +527,7 @@ const ProcessAudit = defineAsyncComponent(() => import('/@/components/ProcessAud
 const HistoryOrder = defineAsyncComponent(() => import('/@/views/todo/seats/accept/History.vue')); // 历史工单
 const CitizenPortrait = defineAsyncComponent(() => import('/@/views/todo/seats/accept/Citizen-portrait.vue')); // 市民坏画像
 const SpecialHandleOrder = defineAsyncComponent(() => import('/@/views/business/special/components/Special-apply-order.vue')); // 特提申请
-// const AudioPlayer = defineAsyncComponent(() => import('/@/components/AudioPlayer/index.vue'));
+const AudioPlayer = defineAsyncComponent(() => import('/@/components/AudioPlayer/index.vue'));
 
 const props = defineProps({
 	order: {

+ 0 - 4
src/layout/navBars/breadcrumb/index.vue

@@ -108,10 +108,6 @@ onMounted(() => {
 	});
   // 加入分组
   signalR.joinGroup('CallCenter');
-  signalR.SR.on('Send', (data: any) => {
-    // 加入分组成功
-    console.log(data, '加入分组成功');
-  });
 });
 // 页面卸载时
 onUnmounted(() => {

+ 40 - 10
src/utils/signalR.ts

@@ -1,14 +1,14 @@
 // 官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/signalr/javascript-client?view=aspnetcore-6.0&viewFallbackFrom=aspnetcore-2.2&tabs=visual-studio
 import * as signalR from '@microsoft/signalr';
 import { ElNotification } from 'element-plus';
-import {Cookie} from '/@/utils/storage';
+import { Cookie } from '/@/utils/storage';
 export default {
 	// signalR对象
 	SR: null as any,
 	// 失败连接重试次数
 	failNum: 4,
 	baseUrl: import.meta.env.VITE_API_SOCKET_URL,
-	groupName:'',
+	groupName: '',
 	init() {
 		const token = Cookie.get('token');
 		const connection = new signalR.HubConnectionBuilder()
@@ -32,6 +32,10 @@ export default {
 				message: `断线重连成功`,
 			});*/
 		});
+		// 服务端推送消息
+		connection.on('Send', (message: any) => {
+			console.log('加入分组成功:', message);
+		});
 	},
 	/**
 	 * @description 调用 this.signalR.start().then(async () => { await this.SR.invoke("method")})
@@ -70,15 +74,24 @@ export default {
 	async joinGroup(groupName: string) {
 		if (this.SR.state === 'Connected') {
 			// 判断是否已经建立链接 如果没有 先链接
-			await this.SR.invoke('JoinGroupAsync', {GroupName:groupName});
+			await this.SR.invoke('JoinGroupAsync', { GroupName: groupName });
 		} else {
-			await this.start().then(async () => {
+			// 等待链接成功再发送
+			if (this.SR.state === 'Connecting') {
 				setTimeout(async () => {
-					await this.SR.invoke('JoinGroupAsync', {GroupName:groupName});
-				},500)
-			}).catch((err) => {
-				console.log(err);
-			})
+					await this.SR.invoke('JoinGroupAsync', { GroupName: groupName });
+				}, 500);
+				return;
+			}
+			await this.start()
+				.then(async () => {
+					setTimeout(async () => {
+						await this.SR.invoke('JoinGroupAsync', { GroupName: groupName });
+					}, 500);
+				})
+				.catch((err) => {
+					console.log(err);
+				});
 		}
 	},
 	/**
@@ -91,7 +104,24 @@ export default {
 	async leaveGroup(groupName: string) {
 		if (this.SR.state === 'Connected') {
 			// 判断是否已经建立链接 如果没有 先链接
-			await this.SR.invoke('LeaveGroupAsync', {GroupName:groupName});
+			await this.SR.invoke('LeaveGroupAsync', { GroupName: groupName });
+		} else {
+			// 等待链接成功再发送
+			if (this.SR.state === 'Connecting') {
+				setTimeout(async () => {
+					await this.SR.invoke('LeaveGroupAsync', { GroupName: groupName });
+				}, 500);
+				return;
+			}
+			await this.start()
+				.then(async () => {
+					setTimeout(async () => {
+						await this.SR.invoke('LeaveGroupAsync', { GroupName: groupName });
+					}, 500);
+				})
+				.catch((err) => {
+					console.log(err);
+				});
 		}
 	},
 

+ 21 - 33
src/views/business/visit/component/Visit-detail.vue

@@ -74,13 +74,20 @@
 							<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
 								<el-form-item label="来电号码" class="mb5">
 									{{ state.orderDetail.fromPhone }}
-									<el-button plain title="查看录音文件" size="small" type="primary" class="ml8" @click="onCall">录音文件</el-button>
-									<!-- <el-popover :width="480" trigger="hover">
-                        <template #reference>
-                          <el-button link type="primary" class="ml5" title="播放录音"><SvgIcon name="ele-Headset" size="16px" /></el-button>
-                        </template>
-                        <AudioPlayer ref="AudioPlayerRef" :url="state.ruleForm.url" />
-                      </el-popover> -->
+                  <el-popover :width="480" trigger="click" v-if="state.orderVisitMode?.recordingFileUrl">
+                    <template #reference>
+                      <el-button
+                          plain
+                          title="录音文件"
+                          size="small"
+                          type="primary"
+                          class="ml8"
+                          v-if="state.orderVisitMode?.recordingFileUrl"
+                      >录音文件</el-button
+                      >
+                      <AudioPlayer :url="state.orderVisitMode?.recordingFileUrl" />
+                    </template>
+                  </el-popover>
 								</el-form-item>
 							</el-col>
 							<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
@@ -89,9 +96,6 @@
 							<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
 								<el-form-item label="联系电话">
 									{{ state.orderDetail.contact }}
-									<!--									<el-checkbox-group v-model="checkedCities" :min="0" :max="1" class="ml10">
-										<el-checkbox v-for="city in cities" :key="city.value" :label="city.value">{{ city.label }}</el-checkbox>
-									</el-checkbox-group>-->
 									<el-button plain title="呼叫" size="small" type="primary" class="ml8" @click="onCall">外呼</el-button>
 								</el-form-item>
 							</el-col>
@@ -115,7 +119,7 @@
 							<template v-if="disabled">
 								<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
 									<el-form-item label="当前回访人">
-										{{ state.creatorName }}
+										{{ state.orderVisitModel.employeeName }}
 									</el-form-item>
 								</el-col>
 								<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" v-if="visitCount">
@@ -352,7 +356,7 @@
 </template>
 <script setup lang="ts" name="orderFollowUpDetail">
 import { computed, defineAsyncComponent, reactive, ref, watch } from 'vue';
-import { ElMessage, FormInstance } from 'element-plus';
+import {ElButton, ElMessage, FormInstance} from 'element-plus';
 import { commonEnum } from '/@/utils/constants';
 import { storeToRefs } from 'pinia';
 import { useUserInfo } from '/@/stores/userInfo';
@@ -362,6 +366,7 @@ import { visitDetailBaseData, visitOrder } from '/@/api/business/visit';
 
 // 引入组件
 const CommonAdvice = defineAsyncComponent(() => import('/@/components/CommonAdvice/index.vue')); // 常用意见
+const AudioPlayer = defineAsyncComponent(() => import('/@/components/AudioPlayer/index.vue'));
 // 定义子组件向父组件传值/事件
 const emit = defineEmits(['updateList']);
 // 定义变量内容
@@ -375,14 +380,9 @@ const state = reactive<any>({
 		visitDetails: {},
 	},
 	orderDetail: {}, // 工单详情
-	creatorName: '', // 创建人
+  orderVisitModel: {}, // 回访详情
 });
 const ruleFormRef = ref<RefType>();
-const checkedCities = ref([]);
-const cities = [
-	{ label: '加0', value: '+0' },
-	{ label: '去0', value: '-0' },
-];
 
 const storesUserInfo = useUserInfo();
 const { userInfos } = storeToRefs(storesUserInfo); // 用户信息
@@ -406,7 +406,7 @@ const getBaseData = async (id: string) => {
 		visitSatisfaction.value = res.result?.visitSatisfaction ?? [];
 		visitId.value = res.result?.orderVisitModel?.id ?? '';
 		state.orderDetail = res.result?.orderVisitModel?.order ?? {};
-		state.creatorName = res.result?.orderVisitModel?.creatorName ?? '';
+		state.orderVisitModel = res.result?.orderVisitModel ?? {};
 		if (res.result?.orderVisitModel?.isPutThrough !== null) {
 			state.ruleForm.isPutThrough = !res.result?.orderVisitModel?.isPutThrough ?? false;
 		} else {
@@ -479,20 +479,8 @@ const dialOut = (phoneNumber: string) => {
 	ola.dial(phoneNumber);
 };
 const onCall = () => {
-	if (checkedCities.value && checkedCities.value.length > 0) {
-		let phoneNumber = state.orderDetail.fromPhone;
-		if (checkedCities.value[0] === '+0') {
-			// 呼叫外部电话 +0
-			dialOut('0' + phoneNumber);
-		} else if (checkedCities.value[0] === '-0') {
-			// 去掉电话号码的第一个字符如果它是'0'
-			phoneNumber = phoneNumber.charAt(0) === '0' ? phoneNumber.substring(1) : phoneNumber;
-			dialOut(phoneNumber);
-		}
-	} else {
-		// 呼叫外部电话
-		dialOut(state.orderDetail.fromPhone);
-	}
+  // 呼叫外部电话
+  dialOut(state.orderDetail.fromPhone);
 };
 // 选择不满意原因
 const selectReason = (val: any, index: number | string) => {

+ 9 - 5
src/views/quality/index/components/Quality-inspection.vue

@@ -8,7 +8,7 @@
 				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
 					<el-form-item label="来电号码:">
 						{{ state.orderDetail.fromPhone }}
-						<el-popover :width="480" trigger="click">
+						<el-popover :width="480" trigger="click" v-if="state.orderDetail.recordingFileUrl">
 							<template #reference>
 								<el-button plain title="录音文件" size="small" type="primary" class="ml8" @click="recordFile(state.orderDetail.recordingFileUrl)"
 									>录音文件</el-button
@@ -128,7 +128,7 @@ import { ElInput, ElMessage, ElMessageBox, FormInstance } from 'element-plus';
 import { formatDate, formatDuration } from '/@/utils/formatTime';
 import { templateList } from '/@/api/quality/template';
 import Other from '/@/utils/other';
-import { qualityUpdate } from '/@/api/quality';
+import { qualityUpdate, qualityDetail } from '/@/api/quality';
 
 // 引入组件
 const AudioPlayer = defineAsyncComponent(() => import('/@/components/AudioPlayer/index.vue')); // 录音播放
@@ -159,12 +159,16 @@ const tableData = ref<EmptyArrayType>([]); // 表格数据
 const qualityId = ref<string>(''); // 质检ID
 // 打开弹窗
 const openDialog = async (row: any, source?: string | number | undefined) => {
-	state.orderDetail = row.order ?? {};
+
 	qualityId.value = row.id;
 	if (source) {
 		state.source = source;
-		const { result } = await templateList({ IsEnable: 1, Grouping: source, PageIndex: 1, PageSize: 999 });
-		projectArray.value = result?.items[0]?.templateDetails ?? [];
+		const [temRes, qualityRes] = await Promise.all([
+			templateList({ IsEnable: 1, Grouping: source, PageIndex: 1, PageSize: 999 }),
+			qualityDetail(row.id),
+		]);
+		projectArray.value = temRes.result?.items[0]?.templateDetails ?? [];
+    state.orderDetail = qualityRes.result?.order ?? {};
 		switch (source) {
 			case 1:
 				dialogTitle.value = '受理质检';

+ 1 - 1
src/views/tels/blacklist/component/Blacklist-add.vue

@@ -1,5 +1,5 @@
 <template>
-	<div class="system-blacklist-add-container">
+	<div class="tels-blacklist-add-container">
 		<el-dialog v-model="state.dialogVisible" width="500px" draggable title="新增黑名单">
 			<el-form :model="state.ruleForm" ref="blacklistFormRef" label-width="80px" label-position="left">
 				<el-row :gutter="35">

+ 1 - 1
src/views/tels/blacklist/index.vue

@@ -38,7 +38,7 @@
 				</el-table-column>
         <el-table-column label="操作" width="200" fixed="right" align="center">
           <template #default="{ row }">
-            <el-button link type="primary" @click="onRemove(row)" title="删除黑名单"> 删除 </el-button>
+            <el-button link type="primary" @click="onRemove(row)" title="删除黑名单" v-auth="'tels:blackList:delete'"> 删除 </el-button>
           </template>
         </el-table-column>
 				<template #empty>

+ 290 - 0
src/views/tels/callLog/component/Connect-business.vue

@@ -0,0 +1,290 @@
+<template>
+	<div class="tels-callLog-connect-container">
+		<el-dialog v-model="state.dialogVisible" draggable title="关联业务" @close="close">
+			<el-form :model="state.ruleForm" label-width="80px" label-position="left">
+				<el-row :gutter="35">
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+						<el-form-item label="关联类型">
+							<el-radio-group v-model="state.ruleForm.isOrder" @change="queryList">
+								<el-radio :label="true">工单</el-radio>
+								<el-radio :label="false">回访</el-radio>
+							</el-radio-group>
+						</el-form-item>
+					</el-col>
+				</el-row>
+			</el-form>
+			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent>
+        <el-row :gutter="10">
+        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+          <el-form-item label="" prop="Keyword">
+            <el-input v-model="state.queryParams.Keyword" placeholder="工单编码/标题" clearable @keyup.enter="queryList" />
+          </el-form-item>
+        </el-col>
+        <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+          <el-form-item label=" ">
+            <el-button type="primary" @click="queryList" :loading="loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+            <el-button @click="state.queryParams.Keyword = null;queryList()" v-waves class="default-button" :loading="loading">
+              <SvgIcon name="ele-Refresh" class="mr5" />重置
+            </el-button>
+          </el-form-item>
+        </el-col>
+        </el-row>
+			</el-form>
+			<!-- 表格 -->
+			<el-table :data="state.tableData" v-loading="loading"  @current-change="handleSelectionChange">
+        <el-table-column label="选择" width="70" fixed="left" align="center">
+          <template #default="{ row }">
+            <el-radio v-model="tableRadio" :label="row.id" @change="handleRowChange(row)">&nbsp;</el-radio>
+          </template>
+        </el-table-column>
+        <!-- 工单 -->
+        <template v-if="state.ruleForm.isOrder">
+          <el-table-column prop="no" label="工单编码" show-overflow-tooltip width="150"></el-table-column>
+          <el-table-column width="100" label="省/市工单" prop="isProvince">
+            <template #default="{ row }">
+              <span>{{ row.isProvince ? '省工单' : '市工单' }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="currentStepName" label="办理节点" show-overflow-tooltip width="150"></el-table-column>
+          <el-table-column label="工单状态" show-overflow-tooltip width="100" prop="statusText"></el-table-column>
+          <el-table-column label="标题" show-overflow-tooltip width="300">
+            <template #default="{ row }">
+              <span class="color-primary">{{ row.title }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="受理时间" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+              <span>{{ formatDate(row.startTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="" label="延期申请" show-overflow-tooltip width="150"></el-table-column>
+          <el-table-column prop="" label="重办" show-overflow-tooltip width="150"></el-table-column>
+          <el-table-column prop="" label="甄别状态" show-overflow-tooltip width="150"></el-table-column>
+          <el-table-column prop="expiredTime" label="工单期满时间" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+              <span>{{ formatDate(row.expiredTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="办结时间" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+              <span>{{ formatDate(row.filedTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="orgLevelOneName" label="一级部门" show-overflow-tooltip width="170"></el-table-column>
+          <el-table-column prop="actualHandleOrgName" label="接办部门" show-overflow-tooltip width="170"></el-table-column>
+          <el-table-column prop="acceptType" label="受理类型" show-overflow-tooltip width="150"></el-table-column>
+          <el-table-column prop="counterSignTypeText" label="中心会签" show-overflow-tooltip width="100"></el-table-column>
+          <el-table-column prop="sourceChannel" label="来源方式" show-overflow-tooltip width="100"></el-table-column>
+          <el-table-column prop="hotspotName" label="热点分类" show-overflow-tooltip width="200"></el-table-column>
+          <el-table-column prop="tagNames" label="工单标签" show-overflow-tooltip width="200"></el-table-column>
+          <el-table-column prop="employeeName" label="受理人" show-overflow-tooltip width="120">
+            <template #default="{ row }">
+						<span
+            >{{ row.acceptorName }} <span v-if="row.acceptorStaffNo">[{{ row.acceptorStaffNo }}]</span>
+						</span>
+            </template>
+          </el-table-column>
+        </template>
+        <!-- 回访 -->
+        <template v-else>
+          <el-table-column prop="order.no" label="工单编码" show-overflow-tooltip width="150"></el-table-column>
+          <el-table-column width="100" label="省/市工单" prop="isProvince">
+            <template #default="{ row }">
+              <span>{{ row.order?.isProvince ? '省工单' : '市工单' }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="工单标题" show-overflow-tooltip width="300">
+            <template #default="{ row }">
+              <span class="color-primary">{{ row.order?.title }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="order.sourceChannel" label="来源方式" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="visitStateText" label="回访状态" show-overflow-tooltip width="100"></el-table-column>
+          <el-table-column prop="visitTypeText" label="回访方式" show-overflow-tooltip width="100"></el-table-column>
+          <el-table-column prop="order.acceptType" label="受理类型" show-overflow-tooltip width="120"></el-table-column>
+          <el-table-column prop="order.hotspotName" label="热点分类" show-overflow-tooltip width="200"></el-table-column>
+          <el-table-column prop="expiredTime" label="受理人" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+						<span
+            >{{ row.order?.acceptorName }} <span v-if="row.order?.acceptorStaffNo">[{{ row.order?.acceptorStaffNo }}]</span>
+						</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="order.orgLevelOneName" label="一级部门" show-overflow-tooltip width="150"></el-table-column>
+          <el-table-column prop="order.actualHandleOrgName" label="接办部门" show-overflow-tooltip width="150"></el-table-column>
+          <el-table-column prop="order.startTime" label="受理时间" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+              <span>{{ formatDate(row.order?.startTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="办结时间" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+              <span>{{ formatDate(row.order?.filedTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="publishTime" label="发布时间" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+              <span>{{ formatDate(row.publishTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="creationTime" 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="employeeName" label="回访人" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="visitTime" label="回访时间" show-overflow-tooltip width="170">
+            <template #default="{ row }">
+              <span>{{ formatDate(row.visitTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="order.counterSignTypeText" label="中心会签" show-overflow-tooltip></el-table-column>
+          <el-table-column label="语音评价" show-overflow-tooltip width="150">
+            <template #default="{ row }">
+						<span v-for="item in row.orderVisitDetails">
+							<span v-if="item.visitTarget === 10">{{ item.voiceEvaluateText }}</span>
+						</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="话务员满意度" show-overflow-tooltip width="150">
+            <template #default="{ row }">
+						<span v-for="item in row.orderVisitDetails">
+							<span v-if="item.visitTarget === 10">{{ item.seatEvaluateText }}</span>
+						</span>
+            </template>
+          </el-table-column>
+        </template>
+				<template #empty>
+					<Empty />
+				</template>
+			</el-table>
+			<!-- 分页 -->
+			<pagination
+				:total="state.total"
+				v-model:page="state.queryParams.PageIndex"
+				v-model:limit="state.queryParams.PageSize"
+				@pagination="queryList"
+			/>
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="closeDialog" class="default-button">取 消</el-button>
+					<el-button type="primary" @click="onSubmit" :disabled="!tableRadio" :loading="loading">保 存</el-button>
+				</span>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+
+<script lang="ts" setup name="blackAdd">
+import { ref, reactive } from 'vue';
+import { ElButton, ElMessage, FormInstance } from 'element-plus';
+import { formatDate } from '/@/utils/formatTime';
+import {callLogLink, callLogOrder, callLogVisit} from '/@/api/tels/callLog';
+
+const props = defineProps({
+	specialFlagList: {
+		type: Array,
+		default: () => [],
+	},
+});
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+
+// 定义变量内容
+
+const state = reactive<any>({
+	ruleForm: {
+		isOrder: true, // 是否工单
+		specialFlag: null,
+	},
+	queryParams: {
+		// 查询条件
+		PageIndex: 1, // 当前页
+		PageSize: 10, // 每页条数
+		Keyword: null, // 关键字
+	},
+	tableData: [],
+	total: 0,
+	dialogVisible: false, // 弹窗显示隐藏
+  currentCall: {},// 当前通话记录
+});
+const loading  = ref<Boolean>(false);
+// 打开弹窗
+const openDialog = (val:any) => {
+  state.currentCall = val;
+  queryList();
+	state.dialogVisible = true;
+};
+const queryList = () => {
+  loading.value = true;
+	if (state.ruleForm.isOrder) {
+		callLogOrder(state.queryParams).then((res: any) => {
+			state.tableData = res.result?.items ?? [];
+			state.total = res.result?.total ?? 0;
+      loading.value = false;
+		}).catch((err: any) => {
+      state.tableData = [];
+      state.total = 0;
+      loading.value = false;
+    });
+	} else {
+		callLogVisit(state.queryParams).then((res: any) => {
+			state.tableData = res.result?.items ?? [];
+			state.total = res.result?.total ?? 0;
+      loading.value = false;
+		}).catch((err: any) => {
+      state.tableData = [];
+      state.total = 0;
+      loading.value = false;
+    });
+	}
+};
+// 关闭弹窗
+const closeDialog = () => {
+	state.dialogVisible = false;
+};
+const close = ()=>{
+  state.ruleForm.isOrder = true;
+  state.queryParams.PageIndex = 1;
+  state.queryParams.PageSize = 10;
+  state.queryParams.Keyword = null;
+  state.tableData = [];
+  state.total = 0;
+  tableRadio.value = '';
+  selectRow.value = {};
+}
+const tableRadio = ref<String>(''); // 选择的单选框
+const selectRow = ref<EmptyObjectType>({}); // 选择的行
+// 选择重复件
+const handleSelectionChange = (row: any) => {
+  if (row) {
+    tableRadio.value = row.id;
+    selectRow.value = row;
+  }
+};
+const handleRowChange = (row: any) => {
+  tableRadio.value = row.id;
+  selectRow.value = row;
+};
+// 保存
+const onSubmit = () => {
+  loading.value = true;
+  const request = {
+    callId: state.currentCall.callAccept,
+    id: tableRadio.value,
+    isOrder: state.ruleForm.isOrder,
+  }
+  console.log(request);
+  return;
+  callLogLink(request).then((res: any) => {
+    loading.value = false;
+    ElMessage.success('关联成功');
+    closeDialog();
+    emit('updateList');
+  }).catch((err: any) => {
+    loading.value = false;
+  });
+};
+//暴漏变量和方法
+defineExpose({ closeDialog, openDialog });
+</script>

+ 20 - 16
src/views/tels/callLog/index.vue

@@ -92,10 +92,11 @@
 						<span>{{ formatDate(row.overTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
 					</template>
 				</el-table-column>
-				<el-table-column label="操作" width="160" fixed="right" align="center">
+				<el-table-column label="操作" width="240" fixed="right" align="center">
 					<template #default="{ row }">
 						<el-button type="primary" @click="onPlaySoundRecording(row)" title="播放录音" link v-if="row.recordingFileUrl">播放录音</el-button>
-						<el-button link type="success" @click="onDownload(row)" title="下载录音" v-if="row.recordingFileUrl"> 下载录音 </el-button>
+						<el-button link type="primary" @click="onDownload(row)" title="下载录音" v-if="row.recordingFileUrl"> 下载录音 </el-button>
+						<el-button link type="primary" @click="onConnect(row)" title="关联业务" v-auth="'tels:callLog:connect'"> 关联业务 </el-button>
 					</template>
 				</el-table-column>
 				<template #empty>
@@ -111,20 +112,21 @@
 			/>
 		</el-card>
 		<play-record ref="playRecordRef" />
+    <connect-business ref="connectBusinessRef" @updateList="queryList"/>
 	</div>
 </template>
 
 <script lang="ts" setup name="callLog">
 import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
 import type { FormInstance } from 'element-plus';
-import { ElButton, ElMessage, ElMessageBox } from 'element-plus';
-import { auth } from '/@/utils/authFunction';
+import { ElButton, ElMessageBox } from 'element-plus';
 import { downloadFile, throttle } from '/@/utils/tools';
 import { callBaseData, callLogPaged } from '/@/api/tels/callLog';
 import { formatDate } from '/@/utils/formatTime';
 
 // 引入组件
 const PlayRecord = defineAsyncComponent(() => import('/@/views/tels/callLog/component/Play-record.vue')); // 播放录音
+const ConnectBusiness = defineAsyncComponent(() => import('/@/views/tels/callLog/component/Connect-business.vue')); // 关联工单还是回访
 
 // 定义变量内容
 const state = reactive(<any>{
@@ -149,18 +151,15 @@ const closeSearch = () => {
 };
 /** 通话记录列表 */
 const queryList = throttle(async () => {
-	if (!auth('tels:callLog:query')) ElMessage.error('抱歉,您没有权限查询通话记录!');
-	else {
-		state.loading = true;
-		try {
-			const response = await callLogPaged(state.queryParams);
-			state.tableList = response.result?.items ?? [];
-			state.total = response.result?.total ?? 0;
-			state.loading = false;
-		} catch (e) {
-			state.loading = false;
-			console.log(e);
-		}
+	state.loading = true;
+	try {
+		const response = await callLogPaged(state.queryParams);
+		state.tableList = response.result?.items ?? [];
+		state.total = response.result?.total ?? 0;
+		state.loading = false;
+	} catch (e) {
+		state.loading = false;
+		console.log(e);
 	}
 }, 300);
 /** 重置按钮操作 */
@@ -190,6 +189,11 @@ const onDownload = (row: any) => {
 		})
 		.catch(() => {});
 };
+// 关联业务
+const connectBusinessRef = ref<RefType>();
+const onConnect = (row:any) => {
+  connectBusinessRef.value.openDialog(row);
+};
 // 基础信息
 const getBaseData = async () => {
 	const response = await callBaseData();

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

@@ -651,6 +651,7 @@ const getParentId = (val: any, arr: string[]) => {
 const areaRef = ref<RefType>();
 const changeArea = () => {
 	const currentNode = areaRef.value.getCheckedNodes();
+  console.log(currentNode[0],'事发地址')
 	state.ruleForm.address = currentNode[0].pathLabels.join(''); // 事发地址
 };
 // 根据热点和事发地址去查询重复性事件 是否展示重复性事件

+ 0 - 8
vite.config.ts

@@ -26,14 +26,6 @@ const viteConfig = defineConfig((mode: ConfigEnv) => {
 			host: '0.0.0.0',
 			port: env.VITE_PORT as unknown as number,
 			open: JSON.parse(env.VITE_OPEN), // 是否打开浏览器
-			proxy: {
-				'/api': {
-					target: 'http://hotline.fw.com',
-					ws: true,
-					changeOrigin: true,
-					rewrite: (path) => path.replace(/^\/api/, ''),
-				},
-			}
 		},
 		build: {
 			outDir: 'dist',