浏览代码

reactor:对接部门满意度统计;

zhangchong 1 年之前
父节点
当前提交
32fb072921

+ 32 - 0
.env.st

@@ -0,0 +1,32 @@
+# 宜宾环境
+VITE_MODE_NAME=yibin
+
+# 防止部署多套系统到同一域名不同目录时,变量共用的问题 设置不同的前缀
+VITE_STORAGE_NAME=hotline
+
+# 基础请求地址
+VITE_API_URL=http://218.6.151.146:50102
+
+# socket API
+VITE_API_SOCKET_URL=http://218.6.151.146:50100/hubs/hotline
+
+# #上传 API
+VITE_API_UPLOAD_URL=http://218.6.151.146:50106
+
+# # 文件上传地址前缀
+VITE_FILE_PREFIX=http://218.6.151.146:50106
+
+# 高德地图安全密钥
+VITE_AMAP_SECURITYJSCODE=dd12ddafb11921dbcdc5b9c4484bb4e2
+
+# 高德地图KEY
+VITE_AMAP_KEY=83f51df235e4008e4eaf515cff63785c
+
+# 呼叫中心socket地址
+VITE_CALLCENTER_SOCKET_URL=ws://218.6.151.146:50104/ola_socket
+
+# 智能客服登录地址
+VITE_VOICE_ASSISTANT_API_URL=http://218.6.151.146:50107
+
+# 智能客服socket地址
+VITE_VOICE_ASSISTANT_SOCKET_URL=ws://218.6.151.146:50108

+ 1 - 0
package.json

@@ -8,6 +8,7 @@
 		"dev": "vite --force",
 		"build": "vite build",
 		"build:yibin": "vite build --mode yibin",
+		"build:st": "vite build --mode st",
 		"preview": "vite preview",
 		"serve": "http-server ./dist",
 		"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/"

+ 12 - 1
src/api/statistics/department.ts

@@ -35,4 +35,15 @@ export const departmentList = (params: object) => {
     method: 'get',
     params,
   });
-};
+};
+/**
+ * @description 部门满意度统计
+ * @param {object} params
+ */
+export const departmentSatisfaction = (params: object) => {
+  return request({
+    url: `/api/v1/BiOrder/visit-org-satisfaction-statistics`,
+    method: 'get',
+    params,
+  });
+}

+ 13 - 3
src/layout/navBars/breadcrumb/telControl.vue

@@ -479,7 +479,7 @@
 </template>
 
 <script setup lang="ts" name="telControl">
-import { reactive, ref, computed, defineAsyncComponent, onMounted, onUnmounted } from 'vue';
+import { reactive, ref, computed, defineAsyncComponent, onMounted, onUnmounted, onBeforeUnmount } from 'vue';
 import { ElMessageBox, ElNotification, ElMessage, FormInstance } from 'element-plus';
 import { storeToRefs } from 'pinia';
 import { useTelStatus, TelStates, RestStates } from '@/stores/telStatus';
@@ -999,8 +999,13 @@ const onMessage = async (event: any) => {
 			console.log('呼叫中心:话后整理中');
 			sendMsg('acw');
 		} else if (data.state == 'busy') {
-		} else {
 			console.log(data.state, '其他状态');
+			// 设置振铃中
+			useTelStatusStore.setPhoneControlState(TelStates.ring);
+			sendMsg('busy');
+			console.log('呼叫中心:转接中....');
+		} else {
+			console.log(data.state, '其他状态1');
 		}
 
 		if (data.state == 'busy') {
@@ -1026,6 +1031,9 @@ const onMessage = async (event: any) => {
 				console.log('呼叫中心:三方来电挂断');
 			} else if (data.private_data == 'three_way_ring') {
 				// 三方通话呼出中
+				// 设置振铃中
+				useTelStatusStore.setPhoneControlState(TelStates.ring);
+				sendMsg('busy');
 				console.log('呼叫中心:三方通话呼出中');
 			} else if (data.private_data == 'three_way_answered') {
 				// 三方通话呼出接通
@@ -1623,8 +1631,10 @@ onMounted(async () => {
 	// 加入分组
 	await signalR.joinGroup('CallCenter');
 });
-onUnmounted(() => {
+onBeforeUnmount(() => {
 	mittBus.off('RestApplyPass');
+	isReconnect.value = false; // 不需要重连
+	ola.close();
 });
 </script>
 

+ 195 - 0
src/views/statistics/department/satisfaction.vue

@@ -0,0 +1,195 @@
+<template>
+	<div class="statistics-department-overdue-container layout-pd">
+		<!-- 搜索  -->
+		<el-card shadow="never">
+			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
+				<el-form-item label="部门名称" prop="OrgName">
+					<el-input v-model="state.queryParams.OrgName" placeholder="部门名称" clearable @keyup.enter="queryList" class="keyword-input" />
+				</el-form-item>
+				<el-form-item label="时间段" prop="crTime">
+					<el-date-picker
+						v-model="state.queryParams.crTime"
+						type="datetimerange"
+						unlink-panels
+						range-separator="至"
+						start-placeholder="开始时间"
+						end-placeholder="结束时间"
+						:shortcuts="shortcuts"
+						@change="queryList"
+						value-format="YYYY-MM-DD[T]HH:mm:ss"
+					/>
+				</el-form-item>
+				<el-form-item label="类型" prop="TypeId">
+					<el-select v-model="state.queryParams.TypeId" placeholder="类型" @change="queryList">
+						<el-option label="办件结果" value="1" />
+						<el-option label="办件态度" value="2" />
+					</el-select>
+				</el-form-item>
+				<el-form-item label="电话线路" prop="LineNum">
+					<el-input v-model="state.queryParams.LineNum" placeholder="电话线路" clearable @keyup.enter="queryList" class="keyword-input" />
+				</el-form-item>
+				<el-form-item>
+					<el-button type="primary" @click="queryList" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+					<el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
+						<SvgIcon name="ele-Refresh" class="mr5" />重置
+					</el-button>
+				</el-form-item>
+			</el-form>
+		</el-card>
+		<el-card shadow="never">
+			<ProTable
+				ref="proTableRef"
+				:columns="columns"
+				:data="state.tableData"
+				@updateTable="queryList"
+				:loading="state.loading"
+				show-summary
+				border
+				:pagination="false"
+				:summary-method="getSummaries"
+			>
+				<template #orgName="{ row }">
+					<el-button link type="primary">{{ row.orgName }}</el-button>
+				</template>
+				<template #verySatisfiedCount="{ row }">
+					<el-button link type="primary">{{ row.verySatisfiedCount }}</el-button>
+				</template>
+				<template #satisfiedCount="{ row }">
+					<el-button link type="primary">{{ row.satisfiedCount }}</el-button>
+				</template>
+				<template #generalSatisfiedCount="{ row }">
+					<el-button link type="primary">{{ row.generalSatisfiedCount }}</el-button>
+				</template>
+				<template #noSatisfiedCount="{ row }">
+					<el-button link type="primary">{{ row.noSatisfiedCount }}</el-button>
+				</template>
+				<template #veryNoSatisfiedCount="{ row }">
+					<el-button link type="primary">{{ row.veryNoSatisfiedCount }}</el-button>
+				</template>
+				<template #noEvaluateCount="{ row }">
+					<el-button link type="primary">{{ row.noEvaluateCount }}</el-button>
+				</template>
+				<template #noPutThroughCount="{ row }">
+					<el-button link type="primary">{{ row.noPutThroughCount }}</el-button>
+				</template>
+			</ProTable>
+		</el-card>
+	</div>
+</template>
+<script setup lang="tsx" name="statisticsDepartmentSatisfaction">
+import { onMounted, reactive, ref } from 'vue';
+import { ElButton, FormInstance } from 'element-plus';
+import { throttle } from '@/utils/tools';
+import { departmentSatisfaction } from '@/api/statistics/department';
+import { shortcuts } from '@/utils/constants';
+import dayjs from 'dayjs';
+
+// 表格配置项
+const columns = ref<any[]>([
+	{ type: 'index', fixed: 'left', width: 55, label: '序号', align: 'center' },
+	{ prop: 'orgName', label: '部门名称', minWidth: 200 },
+	{ prop: 'orgType', label: '部门类别', minWidth: 120 },
+	{ prop: 'totalSumCount', label: '小计' },
+	{ prop: 'totalSumRate', label: '总满意率', minWidth: 120 },
+	{ prop: 'verySatisfiedCount', label: '非常满意', minWidth: 120 },
+	{ prop: 'verySatisfiedRate', label: '非常满意率', minWidth: 120 },
+	{ prop: 'satisfiedCount', label: '满意', minWidth: 120 },
+	{ prop: 'satisfiedRate', label: '满意率', minWidth: 120 },
+	{ prop: 'generalSatisfiedCount', label: '视为满意', minWidth: 120 },
+	{ prop: 'generalSatisfiedRate', label: '视为满意率', minWidth: 120 },
+	{ prop: 'noSatisfiedCount', label: '默认满意', minWidth: 120 },
+	{ prop: 'noSatisfiedRate', label: '默认满意率', minWidth: 120 },
+	{ prop: 'veryNoSatisfiedCount', label: '不满意', minWidth: 120 },
+	{ prop: 'veryNoSatisfiedRate', label: '不满意率', minWidth: 120 },
+	{ prop: 'noEvaluateCount', label: '未作评价', minWidth: 120 },
+	{ prop: 'noEvaluateRate', label: '未作评价率', minWidth: 120 },
+	{ prop: 'noPutThroughCount', label: '未接通', minWidth: 120 },
+	{ prop: 'noPutThroughRate', label: '未接通率', minWidth: 120 },
+]);
+// 定义变量内容
+const ruleFormRef = ref<RefType>(); // 表单ref
+const state = reactive({
+	queryParams: {
+		// 查询条件
+		PageIndex: 1,
+		PageSize: 10,
+		TypeId: '1', //
+		LineNum: null,
+		crTime: [dayjs().startOf('day').format('YYYY-MM-DD HH:mm:ss'), dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss')], // 时间默认今天开始到今天结束
+	},
+	tableData: [], //表单
+	loading: false, // 加载
+	total: 0, // 总数
+});
+/** 获取列表 */
+const queryList = throttle(() => {
+	state.loading = true;
+	let StartDate = null;
+	let EndDate = null;
+	if (state.queryParams?.crTime) {
+		StartDate = state.queryParams?.crTime[0];
+		EndDate = state.queryParams?.crTime[1];
+	}
+	const request = {
+		StartDate,
+		EndDate,
+		TypeId: state.queryParams.TypeId,
+		PageIndex: state.queryParams.PageIndex,
+		PageSize: state.queryParams.PageSize,
+		LineNum: state.queryParams.LineNum,
+	};
+	departmentSatisfaction(request)
+		.then((res: any) => {
+			state.tableData = res.result ?? [];
+			state.loading = false;
+		})
+		.catch(() => {
+			state.loading = false;
+		});
+}, 300);
+// 排序
+const sortChange = (val: any) => {
+	state.queryParams.SortField = val.order ? val.prop : null;
+	// 0 升序 1 降序
+	state.queryParams.SortRule = val.order ? (val.order == 'descending' ? 1 : 0) : null;
+	queryList();
+};
+/** 重置按钮操作 */
+const resetQuery = throttle((formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	queryList();
+}, 300);
+// 合计
+const getSummaries = (param: any) => {
+	const { columns, data } = param;
+	const sums: string[] = [];
+	columns.forEach((column: { property: string }, index: number) => {
+		if (index === 0) {
+			sums[index] = '合计';
+			return;
+		}
+		const values = data.map((item: { [x: string]: any }) => Number(item[column.property]));
+		if (['orgName'].includes(column.property)) {
+			//百分比不能计算
+			sums[index] = '';
+			return '';
+		} else if (!values.every((value: unknown) => Number.isNaN(value))) {
+			sums[index] = `${values.reduce((prev: any, curr: any) => {
+				const value = Number(curr);
+				if (!Number.isNaN(value)) {
+					return prev + curr;
+				} else {
+					return prev;
+				}
+			}, 0)}`;
+		} else {
+			sums[index] = ' ';
+		}
+	});
+	return sums;
+};
+onMounted(() => {
+	queryList();
+});
+</script>

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

@@ -543,7 +543,7 @@ const onDownload = (row: any) => {
 		autofocus: false,
 	})
 		.then(() => {
-			downloadFile(row.recordingFileUrl, row.recordingFileName);
+			downloadFile(row.downRecordingFileUrl, row.recordingFileName);
 			// window.open(row.recordUrl);
 		})
 		.catch(() => {});

+ 1 - 1
src/views/todo/seats/accept/Voice-assistant.vue

@@ -165,7 +165,7 @@ const wsReceive = (message: any) => {
 					messageList.value.push(data);
 				}
 				scrollToBottom();
-				console.log('通话消息转写内容:', messageList.value);
+				// console.log('通话消息转写内容:', messageList.value);
 			}
 			if (data.body.content.action === 4) {
 				// 通话结束