Browse Source

reactor:工单受理页面调整;

zhangchong 1 year ago
parent
commit
e11ae7b538

+ 14 - 14
src/layout/navBars/breadcrumb/telControl.vue

@@ -1103,20 +1103,20 @@ const onMessage = async (event: any) => {
 							type: 'success',
 							type: 'success',
 						});
 						});
 					}
 					}
-					router.push({
-						name: 'orderAccept',
-						state: {
-							createBy: 'tel',
-							fromTel: data.ani,
-							telGuid: data.call_accept,
-							transfer: data.gateway,
-							telArea: '',
-						},
-						params: {
-							callId: data.call_accept,
-							tagsViewName: '工单受理',
-						},
-					});
+					await router.push({
+            name: 'orderAccept',
+            state: {
+              createBy: 'tel',
+              fromTel: data.ani,
+              telGuid: data.call_accept,
+              transfer: data.gateway,
+              telArea: '',
+            },
+            params: {
+              callId: data.call_accept,
+              tagsViewName: '工单受理',
+            },
+          });
 				} else if (data.private_data == 'answered') {
 				} else if (data.private_data == 'answered') {
 					// 开始计时
 					// 开始计时
 					startTime();
 					startTime();

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

@@ -517,7 +517,7 @@ const callId = ref<string>('');
 onMounted(() => {
 onMounted(() => {
 	mittBus.on('outboundConnect', (data) => {
 	mittBus.on('outboundConnect', (data) => {
 		console.log(data, '外呼已经接通辣');
 		console.log(data, '外呼已经接通辣');
-		if (data.dnis === state.orderDetail.contact) callId.value = data.call_id;
+		if (data.dnis === state.orderDetail.contact) callId.value = data.call_accept;
 	});
 	});
 });
 });
 onBeforeUnmount(() => {
 onBeforeUnmount(() => {

+ 28 - 15
src/views/judicial/order/index.vue

@@ -131,12 +131,26 @@
 					<transition name="el-zoom-in-top">
 					<transition name="el-zoom-in-top">
 						<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol">
 						<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol">
 							<el-form-item label="热点分类" prop="HotspotIds">
 							<el-form-item label="热点分类" prop="HotspotIds">
-								<hot-spot-select
+								<el-tree-select
 									v-model="state.queryParams.HotspotIds"
 									v-model="state.queryParams.HotspotIds"
-									class="w100"
-									:hotspotExternal="state.hotspotExternal"
+									:data="state.enforcementHotspot"
+									multiple
+									:render-after-expand="false"
 									show-checkbox
 									show-checkbox
-									ref="hotSpotRef"
+									class="w100"
+									node-key="id"
+									:props="{
+										isLeaf: 'hasChild',
+										children: 'children',
+										label: 'hotSpotFullName',
+									}"
+									check-strictly
+									check-on-click-node
+									collapse-tags
+									collapse-tags-tooltip
+									:max-collapse-tags="2"
+									placeholder="请选择热点分类"
+									filterable
 								/>
 								/>
 							</el-form-item>
 							</el-form-item>
 						</el-col>
 						</el-col>
@@ -354,7 +368,7 @@
 				</template>
 				</template>
 				<!-- 表格操作 -->
 				<!-- 表格操作 -->
 				<template #operation="{ row }">
 				<template #operation="{ row }">
-					<el-button link type="primary" @click="onVerify(row)" title="线索核实" v-if="!row.isTheClueTrue" v-auth="'judicial:order:verify'">
+					<el-button link type="primary" @click="onVerify(row)" title="线索核实" v-if="row.isTheClueTrue === null" v-auth="'judicial:order:verify'">
 						线索核实
 						线索核实
 					</el-button>
 					</el-button>
 					<el-button link type="primary" @click="onEdit(row)" title="修改" v-if="row.isShowUpdateButton"> 修改 </el-button>
 					<el-button link type="primary" @click="onEdit(row)" title="修改" v-if="row.isShowUpdateButton"> 修改 </el-button>
@@ -378,7 +392,6 @@ import { getCluesBaseData, getWorkList, listBaseData } from '@/api/judicial';
 
 
 // 引入组件
 // 引入组件
 const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
 const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
-const HotSpotSelect = defineAsyncComponent(() => import('@/components/Hotspot/index.vue')); // 选择热点
 const Verify = defineAsyncComponent(() => import('@/views/judicial/order/components/verify.vue')); // 线索核实
 const Verify = defineAsyncComponent(() => import('@/views/judicial/order/components/verify.vue')); // 线索核实
 
 
 // 定义变量内容
 // 定义变量内容
@@ -431,6 +444,7 @@ const state = reactive<any>({
 	identityTypeOptions: [], // 来电主体
 	identityTypeOptions: [], // 来电主体
 	orgsOptions: [], // 部门
 	orgsOptions: [], // 部门
 	pushTypeOptions: [], //推送分类
 	pushTypeOptions: [], //推送分类
+	enforcementHotspot: [], // 热点类型
 	orgData: [], // 机构数据
 	orgData: [], // 机构数据
 	areaOptions: [], // 省市区数据
 	areaOptions: [], // 省市区数据
 });
 });
@@ -452,7 +466,7 @@ const fastSearchChange = (val: string) => {
 			state.queryParams.IsTheClueTrue = true;
 			state.queryParams.IsTheClueTrue = true;
 			break;
 			break;
 		case 'NoTheClueTrue':
 		case 'NoTheClueTrue':
-			state.queryParams.IsTheClueTrue = null;
+			state.queryParams.IsTheClueTrue = false;
 			break;
 			break;
 		case 'IsPassTheBuckOrder':
 		case 'IsPassTheBuckOrder':
 			state.queryParams.IsPassTheBuckOrder = true;
 			state.queryParams.IsPassTheBuckOrder = true;
@@ -581,6 +595,7 @@ const getBaseData = async () => {
 			orderStatusOptions: 'orderStatusOptions',
 			orderStatusOptions: 'orderStatusOptions',
 			identityTypeOptions: 'identityTypeOptions',
 			identityTypeOptions: 'identityTypeOptions',
 			currentStepOptions: 'currentStepOptions',
 			currentStepOptions: 'currentStepOptions',
+			enforcementHotspot: 'enforcementHotspot',
 		};
 		};
 		for (const key in mappings) {
 		for (const key in mappings) {
 			state[key] = res.result?.[mappings[key]] ?? [];
 			state[key] = res.result?.[mappings[key]] ?? [];
@@ -616,7 +631,6 @@ const queryList = () => {
 			state.loading = false;
 			state.loading = false;
 		});
 		});
 };
 };
-const hotSpotRef = ref<RefType>();
 /** 重置按钮操作 */
 /** 重置按钮操作 */
 const resetQuery = (formEl: FormInstance | undefined) => {
 const resetQuery = (formEl: FormInstance | undefined) => {
 	if (!formEl) return;
 	if (!formEl) return;
@@ -625,14 +639,13 @@ const resetQuery = (formEl: FormInstance | undefined) => {
 	state.queryParams.CreationTimeEnd = null;
 	state.queryParams.CreationTimeEnd = null;
 	state.queryParams.ExpiredTimeStart = null;
 	state.queryParams.ExpiredTimeStart = null;
 	state.queryParams.ExpiredTimeEnd = null;
 	state.queryParams.ExpiredTimeEnd = null;
-  state.queryParams.ActualHandleTimeStart = null;
-  state.queryParams.ActualHandleTimeEnd = null;
+	state.queryParams.ActualHandleTimeStart = null;
+	state.queryParams.ActualHandleTimeEnd = null;
 	fastSearch.value = 'all';
 	fastSearch.value = 'all';
 	state.queryParams.AreaCodes = [];
 	state.queryParams.AreaCodes = [];
-  state.queryParams.IsEnforcementOrder = null;
-  state.queryParams.IsPassTheBuckOrder = null;
-  state.queryParams.IsTheClueTrue = null;
-	hotSpotRef.value.reset();
+	state.queryParams.IsEnforcementOrder = null;
+	state.queryParams.IsPassTheBuckOrder = null;
+	state.queryParams.IsTheClueTrue = null;
 	queryList();
 	queryList();
 };
 };
 // 线索核实
 // 线索核实
@@ -651,7 +664,7 @@ onMounted(() => {
 });
 });
 </script>
 </script>
 <style scoped lang="scss">
 <style scoped lang="scss">
-.business-order-container {
+.judicial-order-container {
 	.arrow {
 	.arrow {
 		transition: transform var(--el-transition-duration);
 		transition: transform var(--el-transition-duration);
 		cursor: pointer;
 		cursor: pointer;

+ 0 - 1
src/views/judicial/statistics/area.vue

@@ -95,7 +95,6 @@ const queryList = () => {
     .catch(() => {
     .catch(() => {
       state.loading = false;
       state.loading = false;
     });
     });
-  state.loading = false;
 }
 }
 /** 重置按钮操作 */
 /** 重置按钮操作 */
 const resetQuery = (formEl: FormInstance | undefined) => {
 const resetQuery = (formEl: FormInstance | undefined) => {

+ 1 - 2
src/views/judicial/statistics/department.vue

@@ -14,7 +14,7 @@
 						:shortcuts="shortcuts"
 						:shortcuts="shortcuts"
 						@change="handleQuery"
 						@change="handleQuery"
 						value-format="YYYY-MM-DD"
 						value-format="YYYY-MM-DD"
-            :clearable="false"
+						:clearable="false"
 					/>
 					/>
 				</el-form-item>
 				</el-form-item>
 				<el-form-item>
 				<el-form-item>
@@ -95,7 +95,6 @@ const queryList = () => {
 		.catch(() => {
 		.catch(() => {
 			state.loading = false;
 			state.loading = false;
 		});
 		});
-	state.loading = false;
 };
 };
 /** 重置按钮操作 */
 /** 重置按钮操作 */
 const resetQuery = (formEl: FormInstance | undefined) => {
 const resetQuery = (formEl: FormInstance | undefined) => {

+ 143 - 144
src/views/judicial/statistics/satisfaction.vue

@@ -14,7 +14,7 @@
 						:shortcuts="shortcuts"
 						:shortcuts="shortcuts"
 						@change="handleQuery"
 						@change="handleQuery"
 						value-format="YYYY-MM-DD"
 						value-format="YYYY-MM-DD"
-            :clearable="false"
+						:clearable="false"
 					/>
 					/>
 				</el-form-item>
 				</el-form-item>
 				<el-form-item>
 				<el-form-item>
@@ -38,78 +38,78 @@
 				:pagination="false"
 				:pagination="false"
 				:summary-method="getSummaries"
 				:summary-method="getSummaries"
 			>
 			>
-        <template #orgName="{ row }">
-          <el-button link type="primary" @click="onDetailOrg(row)" v-if="!['市直合计', '区县合计'].includes(row.orgName)">{{
-              row.orgName
-            }}</el-button>
-          <span v-else>{{ row.orgName }}</span>
-        </template>
-        <template #verySatisfiedCount="{ row }">
-          <el-button
-            link
-            type="primary"
-            @click="onDetail(row.verySatisfiedKey, row, '非常满意')"
-            v-if="!['市直合计', '区县合计'].includes(row.orgName)"
-          >{{ row.verySatisfiedCount }}</el-button
-          >
-          <span v-else>{{ row.verySatisfiedCount }}</span>
-        </template>
-        <template #satisfiedCount="{ row }">
-          <el-button link type="primary" @click="onDetail(row.satisfiedKey, row, '满意')" v-if="!['市直合计', '区县合计'].includes(row.orgName)">{{
-              row.satisfiedCount
-            }}</el-button>
-          <span v-else>{{ row.satisfiedCount }}</span>
-        </template>
-        <template #regardedAsSatisfiedCount="{ row }">
-          <el-button
-            link
-            type="primary"
-            @click="onDetail(row.regardedAsSatisfiedKey, row, '视为满意')"
-            v-if="!['市直合计', '区县合计'].includes(row.orgName)"
-          >{{ row.regardedAsSatisfiedCount }}</el-button
-          >
-          <span v-else>{{ row.regardedAsSatisfiedCount }}</span>
-        </template>
-        <template #defaultSatisfiedCount="{ row }">
-          <el-button
-            link
-            type="primary"
-            @click="onDetail(row.defaultSatisfiedKey, row, '默认满意')"
-            v-if="!['市直合计', '区县合计'].includes(row.orgName)"
-          >{{ row.defaultSatisfiedCount }}</el-button
-          >
-          <span v-else>{{ row.defaultSatisfiedCount }}</span>
-        </template>
-        <template #noSatisfiedCount="{ row }">
-          <el-button
-            link
-            type="primary"
-            @click="onDetail(row.noSatisfiedKey, row, '不满意')"
-            v-if="!['市直合计', '区县合计'].includes(row.orgName)"
-          >{{ row.noSatisfiedCount }}</el-button
-          >
-          <span v-else>{{ row.noSatisfiedCount }}</span>
-        </template>
-        <template #noEvaluateCount="{ row }">
-          <el-button
-            link
-            type="primary"
-            @click="onDetail(row.noEvaluateKey, row, '未作评价')"
-            v-if="!['市直合计', '区县合计'].includes(row.orgName)"
-          >{{ row.noEvaluateCount }}</el-button
-          >
-          <span v-else>{{ row.noEvaluateCount }}</span>
-        </template>
-        <template #noPutThroughCount="{ row }">
-          <el-button
-            link
-            type="primary"
-            @click="onDetail(row.noPutThroughKey, row, '未接通')"
-            v-if="!['市直合计', '区县合计'].includes(row.orgName)"
-          >{{ row.noPutThroughCount }}</el-button
-          >
-          <span v-else>{{ row.noPutThroughCount }}</span>
-        </template>
+				<template #orgName="{ row }">
+					<el-button link type="primary" @click="onDetailOrg(row)" v-if="!['市直合计', '区县合计'].includes(row.orgName)">{{
+						row.orgName
+					}}</el-button>
+					<span v-else>{{ row.orgName }}</span>
+				</template>
+				<template #verySatisfiedCount="{ row }">
+					<el-button
+						link
+						type="primary"
+						@click="onDetail(row.verySatisfiedKey, row, '非常满意')"
+						v-if="!['市直合计', '区县合计'].includes(row.orgName)"
+						>{{ row.verySatisfiedCount }}</el-button
+					>
+					<span v-else>{{ row.verySatisfiedCount }}</span>
+				</template>
+				<template #satisfiedCount="{ row }">
+					<el-button link type="primary" @click="onDetail(row.satisfiedKey, row, '满意')" v-if="!['市直合计', '区县合计'].includes(row.orgName)">{{
+						row.satisfiedCount
+					}}</el-button>
+					<span v-else>{{ row.satisfiedCount }}</span>
+				</template>
+				<template #regardedAsSatisfiedCount="{ row }">
+					<el-button
+						link
+						type="primary"
+						@click="onDetail(row.regardedAsSatisfiedKey, row, '视为满意')"
+						v-if="!['市直合计', '区县合计'].includes(row.orgName)"
+						>{{ row.regardedAsSatisfiedCount }}</el-button
+					>
+					<span v-else>{{ row.regardedAsSatisfiedCount }}</span>
+				</template>
+				<template #defaultSatisfiedCount="{ row }">
+					<el-button
+						link
+						type="primary"
+						@click="onDetail(row.defaultSatisfiedKey, row, '默认满意')"
+						v-if="!['市直合计', '区县合计'].includes(row.orgName)"
+						>{{ row.defaultSatisfiedCount }}</el-button
+					>
+					<span v-else>{{ row.defaultSatisfiedCount }}</span>
+				</template>
+				<template #noSatisfiedCount="{ row }">
+					<el-button
+						link
+						type="primary"
+						@click="onDetail(row.noSatisfiedKey, row, '不满意')"
+						v-if="!['市直合计', '区县合计'].includes(row.orgName)"
+						>{{ row.noSatisfiedCount }}</el-button
+					>
+					<span v-else>{{ row.noSatisfiedCount }}</span>
+				</template>
+				<template #noEvaluateCount="{ row }">
+					<el-button
+						link
+						type="primary"
+						@click="onDetail(row.noEvaluateKey, row, '未作评价')"
+						v-if="!['市直合计', '区县合计'].includes(row.orgName)"
+						>{{ row.noEvaluateCount }}</el-button
+					>
+					<span v-else>{{ row.noEvaluateCount }}</span>
+				</template>
+				<template #noPutThroughCount="{ row }">
+					<el-button
+						link
+						type="primary"
+						@click="onDetail(row.noPutThroughKey, row, '未接通')"
+						v-if="!['市直合计', '区县合计'].includes(row.orgName)"
+						>{{ row.noPutThroughCount }}</el-button
+					>
+					<span v-else>{{ row.noPutThroughCount }}</span>
+				</template>
 			</ProTable>
 			</ProTable>
 		</el-card>
 		</el-card>
 	</div>
 	</div>
@@ -208,7 +208,7 @@ const state = reactive({
 	tableData: [],
 	tableData: [],
 	loading: false, // 加载
 	loading: false, // 加载
 	total: 0, // 总数
 	total: 0, // 总数
-  totalCount:{}
+	totalCount: {},
 });
 });
 /** 搜索按钮操作 */
 /** 搜索按钮操作 */
 const handleQuery = () => {
 const handleQuery = () => {
@@ -227,22 +227,21 @@ const queryList = () => {
 	const request = {
 	const request = {
 		StartDate,
 		StartDate,
 		EndDate,
 		EndDate,
-    TypeId:'1'
+		TypeId: '1',
 	};
 	};
 	departmentSatisfaction(request)
 	departmentSatisfaction(request)
 		.then((res: any) => {
 		.then((res: any) => {
-      state.tableData = res.result?.dataList ?? [];
-      if (res.result.dataList.length) {
-        state.tableData.push(res.result.citySumModel);
-        state.tableData.push(res.result.countySumModel);
-      }
-      state.totalCount = res.result.sumModel;
+			state.tableData = res.result?.dataList ?? [];
+			if (res.result.dataList.length) {
+				state.tableData.push(res.result.citySumModel);
+				state.tableData.push(res.result.countySumModel);
+			}
+			state.totalCount = res.result.sumModel;
 			state.loading = false;
 			state.loading = false;
 		})
 		})
 		.catch(() => {
 		.catch(() => {
 			state.loading = false;
 			state.loading = false;
 		});
 		});
-	state.loading = false;
 };
 };
 /** 重置按钮操作 */
 /** 重置按钮操作 */
 const resetQuery = (formEl: FormInstance | undefined) => {
 const resetQuery = (formEl: FormInstance | undefined) => {
@@ -252,68 +251,68 @@ const resetQuery = (formEl: FormInstance | undefined) => {
 };
 };
 // 合计
 // 合计
 const getSummaries = (param: any) => {
 const getSummaries = (param: any) => {
-  const { columns } = param;
-  const sums: string[] = [];
-  columns.forEach((column: { property: string }, index: number) => {
-    if (index === 0) {
-      sums[index] = '合计';
-      return;
-    }
-    switch (column.property) {
-      case 'totalSumCount':
-        sums[index] = state.totalCount?.totalSumCount;
-        break;
-      case 'totalSumRate':
-        sums[index] = `${state.totalCount?.totalSumRate}%`;
-        break;
-      case 'verySatisfiedCount':
-        sums[index] = state.totalCount?.verySatisfiedCount;
-        break;
-      case 'verySatisfiedRate':
-        sums[index] = `${state.totalCount?.verySatisfiedRate}%`;
-        break;
-      case 'satisfiedCount':
-        sums[index] = state.totalCount?.satisfiedCount;
-        break;
-      case 'satisfiedRate':
-        sums[index] = `${state.totalCount?.satisfiedRate}%`;
-        break;
-      case 'regardedAsSatisfiedCount':
-        sums[index] = state.totalCount?.regardedAsSatisfiedCount;
-        break;
-      case 'regardedAsSatisfiedRate':
-        sums[index] = `${state.totalCount?.regardedAsSatisfiedRate}%`;
-        break;
-      case 'defaultSatisfiedCount':
-        sums[index] = state.totalCount?.defaultSatisfiedCount;
-        break;
-      case 'defaultSatisfiedRate':
-        sums[index] = `${state.totalCount?.defaultSatisfiedRate}%`;
-        break;
-      case 'noSatisfiedCount':
-        sums[index] = state.totalCount?.noSatisfiedCount;
-        break;
-      case 'noSatisfiedRate':
-        sums[index] = `${state.totalCount?.noSatisfiedRate}%`;
-        break;
-      case 'noEvaluateCount':
-        sums[index] = state.totalCount?.noEvaluateCount;
-        break;
-      case 'noEvaluateRate':
-        sums[index] = `${state.totalCount?.noEvaluateRate}%`;
-        break;
-      case 'noPutThroughCount':
-        sums[index] = state.totalCount?.noPutThroughCount;
-        break;
-      case 'noPutThroughRate':
-        sums[index] = `${state.totalCount?.noPutThroughRate}%`;
-        break;
-      default:
-        sums[index] = '';
-        break;
-    }
-  });
-  return sums;
+	const { columns } = param;
+	const sums: string[] = [];
+	columns.forEach((column: { property: string }, index: number) => {
+		if (index === 0) {
+			sums[index] = '合计';
+			return;
+		}
+		switch (column.property) {
+			case 'totalSumCount':
+				sums[index] = state.totalCount?.totalSumCount;
+				break;
+			case 'totalSumRate':
+				sums[index] = `${state.totalCount?.totalSumRate}%`;
+				break;
+			case 'verySatisfiedCount':
+				sums[index] = state.totalCount?.verySatisfiedCount;
+				break;
+			case 'verySatisfiedRate':
+				sums[index] = `${state.totalCount?.verySatisfiedRate}%`;
+				break;
+			case 'satisfiedCount':
+				sums[index] = state.totalCount?.satisfiedCount;
+				break;
+			case 'satisfiedRate':
+				sums[index] = `${state.totalCount?.satisfiedRate}%`;
+				break;
+			case 'regardedAsSatisfiedCount':
+				sums[index] = state.totalCount?.regardedAsSatisfiedCount;
+				break;
+			case 'regardedAsSatisfiedRate':
+				sums[index] = `${state.totalCount?.regardedAsSatisfiedRate}%`;
+				break;
+			case 'defaultSatisfiedCount':
+				sums[index] = state.totalCount?.defaultSatisfiedCount;
+				break;
+			case 'defaultSatisfiedRate':
+				sums[index] = `${state.totalCount?.defaultSatisfiedRate}%`;
+				break;
+			case 'noSatisfiedCount':
+				sums[index] = state.totalCount?.noSatisfiedCount;
+				break;
+			case 'noSatisfiedRate':
+				sums[index] = `${state.totalCount?.noSatisfiedRate}%`;
+				break;
+			case 'noEvaluateCount':
+				sums[index] = state.totalCount?.noEvaluateCount;
+				break;
+			case 'noEvaluateRate':
+				sums[index] = `${state.totalCount?.noEvaluateRate}%`;
+				break;
+			case 'noPutThroughCount':
+				sums[index] = state.totalCount?.noPutThroughCount;
+				break;
+			case 'noPutThroughRate':
+				sums[index] = `${state.totalCount?.noPutThroughRate}%`;
+				break;
+			default:
+				sums[index] = '';
+				break;
+		}
+	});
+	return sums;
 };
 };
 onMounted(() => {
 onMounted(() => {
 	queryList();
 	queryList();

+ 2 - 2
src/views/statistics/center/detailEventFrequently.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-	<div class="business-order-container layout-pd">
+	<div class="statistics-center-detail-event-frequently layout-pd">
 		<el-card shadow="never">
 		<el-card shadow="never">
 			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent label-width="100px">
 			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent label-width="100px">
 				<el-row :gutter="10">
 				<el-row :gutter="10">
@@ -467,7 +467,7 @@ onMounted(() => {
 });
 });
 </script>
 </script>
 <style scoped lang="scss">
 <style scoped lang="scss">
-.business-order-container {
+.statistics-center-detail-event-frequently {
 	.arrow {
 	.arrow {
 		transition: transform var(--el-transition-duration);
 		transition: transform var(--el-transition-duration);
 		cursor: pointer;
 		cursor: pointer;

+ 5 - 5
src/views/statistics/center/detailTelFrequently.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-	<div class="business-order-container layout-pd">
+	<div class="statistics-center-detail-tel-frequently layout-pd">
 		<el-card shadow="never">
 		<el-card shadow="never">
 			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent label-width="100px">
 			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent label-width="100px">
 				<el-row :gutter="10">
 				<el-row :gutter="10">
@@ -529,9 +529,9 @@ const resetQuery = (formEl: FormInstance | undefined) => {
 	state.queryParams.CreationTimeEnd = null;
 	state.queryParams.CreationTimeEnd = null;
 	state.queryParams.ExpiredTimeStart = null;
 	state.queryParams.ExpiredTimeStart = null;
 	state.queryParams.ExpiredTimeEnd = null;
 	state.queryParams.ExpiredTimeEnd = null;
-  state.queryParams.ActualHandleTimeStart = null;
-  state.queryParams.ActualHandleTimeEnd = null;
-  state.queryParams.AreaCodes = [];
+	state.queryParams.ActualHandleTimeStart = null;
+	state.queryParams.ActualHandleTimeEnd = null;
+	state.queryParams.AreaCodes = [];
 	hotSpotRef.value.reset();
 	hotSpotRef.value.reset();
 	queryList();
 	queryList();
 };
 };
@@ -547,7 +547,7 @@ onMounted(() => {
 });
 });
 </script>
 </script>
 <style scoped lang="scss">
 <style scoped lang="scss">
-.business-order-container {
+.statistics-center-detail-tel-frequently {
 	.arrow {
 	.arrow {
 		transition: transform var(--el-transition-duration);
 		transition: transform var(--el-transition-duration);
 		cursor: pointer;
 		cursor: pointer;

+ 32 - 0
src/views/tels/callLog/index.vue

@@ -408,6 +408,22 @@ const inColumns = [
 			return <span>{formatDate(scope.row.endQueueTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
 			return <span>{formatDate(scope.row.endQueueTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
 		},
 		},
 	},
 	},
+  {
+    prop: 'beginRingTime',
+    label: '开始振铃时间',
+    width: 170,
+    render: (scope) => {
+      return <span>{formatDate(scope.row.beginRingTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
+    },
+  },
+  {
+    prop: 'endRingTimg',
+    label: '结束振铃时间',
+    width: 170,
+    render: (scope) => {
+      return <span>{formatDate(scope.row.endRingTimg, 'YYYY-mm-dd HH:MM:SS')}</span>;
+    },
+  },
 	{
 	{
 		prop: 'createdTime',
 		prop: 'createdTime',
 		label: '应答开始时间',
 		label: '应答开始时间',
@@ -481,6 +497,22 @@ const noColumns = [
 			return <span>{formatDate(scope.row.endQueueTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
 			return <span>{formatDate(scope.row.endQueueTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
 		},
 		},
 	},
 	},
+  {
+    prop: 'beginRingTime',
+    label: '开始振铃时间',
+    width: 170,
+    render: (scope) => {
+      return <span>{formatDate(scope.row.beginRingTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
+    },
+  },
+  {
+    prop: 'endRingTimg',
+    label: '结束振铃时间',
+    width: 170,
+    render: (scope) => {
+      return <span>{formatDate(scope.row.endRingTimg, 'YYYY-mm-dd HH:MM:SS')}</span>;
+    },
+  },
 	{
 	{
 		prop: 'createdTime',
 		prop: 'createdTime',
 		label: '应答开始时间',
 		label: '应答开始时间',

+ 140 - 0
src/views/todo/seats/accept/Call-summary.vue

@@ -0,0 +1,140 @@
+<template>
+	<div class="call-summary">
+		<el-scrollbar class="h100 transition-box-content" noresize ref="scrollbarRef" max-height="400" v-loading="loading">
+			<div class="call-item">
+				<el-text tag="p" class="call-item-label">客户姓名:</el-text>
+				<p class="call-item-value">{{ recognizeList?.name }}</p>
+			</div>
+			<!--      <div class="call-item">
+        <el-text tag="p" class="call-item-label">年龄:</el-text>
+        <p class="call-item-value">{{ recognizeList?.age }}</p>
+      </div>
+      <div class="call-item">
+        <el-text tag="p" class="call-item-label">性别:</el-text>
+        <p class="call-item-value">{{ recognizeList?.sex }}</p>
+      </div>
+      <div class="call-item">
+        <el-text tag="p" class="call-item-label">身份证号:</el-text>
+        <p class="call-item-value">{{ recognizeList?.id_card }}</p>
+      </div>-->
+			<div class="call-item">
+				<el-text tag="p" class="call-item-label">地址:</el-text>
+				<p class="call-item-value">{{ recognizeList?.address }}</p>
+			</div>
+			<!--      						<div class="call-item">
+        <el-text tag="p" class="call-item-label">公司名称:</el-text>
+        <p class="call-item-value">{{ recognizeList?.company_name }}</p>
+      </div>
+      <div class="call-item">
+        <el-text tag="p" class="call-item-label">通话小结:</el-text>
+        <p class="call-item-value">{{ recognizeList?.call_detail_content }}</p>
+      </div>
+      <div class="call-item">
+        <el-text tag="p" class="call-item-label">受理类型:</el-text>
+        <p class="call-item-value">{{ recognizeList?.acceptance_type }}</p>
+      </div>
+      <div class="call-item">
+        <el-text tag="p" class="call-item-label">推送分类:</el-text>
+        <p class="call-item-value">{{ recognizeList?.push_classification }}</p>
+      </div>
+      <div class="call-item">
+        <el-text tag="p" class="call-item-label">热点分类:</el-text>
+        <p class="call-item-value">{{ recognizeList?.hotspot_classification }}</p>
+      </div>
+      <div class="call-item">
+        <el-text tag="p" class="call-item-label">事件目的:</el-text>
+        <p class="call-item-value">{{ recognizeList?.event_purpose }}</p>
+      </div>
+      <div class="call-item">
+        <el-text tag="p" class="call-item-label">工单标题:</el-text>
+        <p class="call-item-value">{{ recognizeList?.record_title }}</p>
+      </div>
+      <div class="call-item">
+        <el-text tag="p" class="call-item-label">诉求详情:</el-text>
+        <p class="call-item-value">{{ recognizeList?.appeal_detatls }}</p>
+      </div>-->
+			<div class="flex-center-center mt20">
+				<el-button type="primary" @click="fillSingle" round>一键填单</el-button>
+				<el-button @click="onCancel" class="default-button" round>刷新</el-button>
+			</div>
+		</el-scrollbar>
+	</div>
+</template>
+<script setup lang="ts" name="orderAcceptCallSummary">
+import { ref } from 'vue';
+import { voiceAssistantContent } from '@/api/todo/voiceAssistant';
+import { useRoute } from 'vue-router';
+import { ElMessage, ElMessageBox } from 'element-plus';
+
+const emit = defineEmits(['orderOverwrite', 'close']);
+const recognizeList = ref<EmptyObjectType>({}); // 识别信息
+// 获取识别内容
+const route = useRoute();
+const loading = ref(false);
+const getRecognize = async () => {
+	loading.value = true;
+	try {
+		const callId = route.params.callId;
+		if (!callId) {
+			ElMessage.info('暂未获取到通话ID,请关闭页面重新进入重试');
+			loading.value = false;
+			return;
+		}
+		const { result } = await voiceAssistantContent(typeof callId === 'string' ? callId : '');
+		recognizeList.value = result;
+		loading.value = false;
+	} catch (error) {
+		console.log('获取识别内容失败', error);
+		loading.value = false;
+	}
+};
+// 一键填单
+const fillSingle = () => {
+	ElMessageBox.confirm(`确定要一键填单吗?填单后会覆盖之前填写的内容,请谨慎操作`, '提示', {
+		confirmButtonText: '确认',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		cancelButtonClass: 'default-button',
+		autofocus: false,
+	})
+		.then(() => {
+			emit('orderOverwrite', recognizeList.value);
+		})
+		.catch(() => {});
+};
+const onCancel = () => {
+	getRecognize();
+};
+defineExpose({
+	getRecognize,
+});
+</script>
+<style scoped lang="scss">
+.call-summary {
+	.transition-box-content {
+		padding: 20px 30px;
+		max-height: 400px;
+		.call-item {
+			margin-bottom: 30px;
+		}
+		.call-item-label {
+			color: var(--el-text-color);
+		}
+		.transition-box-content-item {
+			display: flex;
+			align-items: center;
+			margin-bottom: 30px;
+
+			.transition-box-content-item-title {
+				width: 75px;
+				margin-right: 3px;
+			}
+
+			.transition-box-content-item-content {
+				flex: 1;
+			}
+		}
+	}
+}
+</style>

+ 2 - 11
src/views/todo/seats/accept/Citizen-portrait.vue

@@ -1,7 +1,7 @@
 <template>
 <template>
 	<div class="order-accept-citizen-portrait" v-loading="loading">
 	<div class="order-accept-citizen-portrait" v-loading="loading">
 		<el-row :gutter="20">
 		<el-row :gutter="20">
-			<el-col :xs="24" :sm="24" :md="24" :lg="8" :xl="8">
+			<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
 				<el-card shadow="never">
 				<el-card shadow="never">
 					<p class="border-title mb10">基本信息</p>
 					<p class="border-title mb10">基本信息</p>
 					<div class="info-form">
 					<div class="info-form">
@@ -45,15 +45,7 @@
 					</div>
 					</div>
 				</el-card>
 				</el-card>
 			</el-col>
 			</el-col>
-			<el-col :xs="24" :sm="24" :md="24" :lg="8" :xl="8" style="display: flex; align-items: center">
-				<el-card class="w100" shadow="never">
-					<p class="citizen-title mb10">市民画像</p>
-					<div class="citizen-img-box">
-						<img v-lazy="getImageUrl('citizen.png')" alt="" />
-					</div>
-				</el-card>
-			</el-col>
-			<el-col :xs="24" :sm="24" :md="24" :lg="8" :xl="8">
+			<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
 				<el-card shadow="never">
 				<el-card shadow="never">
 					<p class="border-title mb10">来电历史:</p>
 					<p class="border-title mb10">来电历史:</p>
 					<div class="info-form">
 					<div class="info-form">
@@ -109,7 +101,6 @@ import { computed, reactive, ref, watch } from 'vue';
 import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
 import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
 import { citizenDetailByPhone, citizenAdd, citizenLabelAdd, citizenLabelDelete } from '@/api/auxiliary/citizen';
 import { citizenDetailByPhone, citizenAdd, citizenLabelAdd, citizenLabelDelete } from '@/api/auxiliary/citizen';
 import { formatDate } from '@/utils/formatTime';
 import { formatDate } from '@/utils/formatTime';
-import { getImageUrl } from '@/utils/tools';
 
 
 const props = defineProps({
 const props = defineProps({
 	editable: {
 	editable: {

+ 7 - 7
src/views/todo/seats/accept/History.vue

@@ -19,14 +19,14 @@
 		ref="multipleTableRef"
 		ref="multipleTableRef"
 	>
 	>
 		<el-table-column type="selection" width="80" :reserve-selection="true" v-if="props.ruleForm.isRepeat === 'true'" />
 		<el-table-column type="selection" width="80" :reserve-selection="true" v-if="props.ruleForm.isRepeat === 'true'" />
-		<el-table-column prop="phoneNo" label="工单标题" show-overflow-tooltip width="180">
-			<template #default="{ row }">
-        <order-detail :order="row" @updateList="searchHistory">{{ row.title }}</order-detail>
-			</template>
-		</el-table-column>
-		<el-table-column prop="hotspotName" label="热点分类" show-overflow-tooltip> </el-table-column>
+<!--		<el-table-column prop="hotspotName" label="热点分类" show-overflow-tooltip> </el-table-column>
+    <el-table-column prop="actualHandleStepName" label="当前环节" show-overflow-tooltip></el-table-column>-->
 		<el-table-column prop="no" label="工单编码" show-overflow-tooltip> </el-table-column>
 		<el-table-column prop="no" label="工单编码" show-overflow-tooltip> </el-table-column>
-		<el-table-column prop="actualHandleStepName" label="当前环节" show-overflow-tooltip></el-table-column>
+    <el-table-column prop="phoneNo" label="工单标题" show-overflow-tooltip width="180">
+      <template #default="{ row }">
+        <order-detail :order="row" @updateList="searchHistory">{{ row.title }}</order-detail>
+      </template>
+    </el-table-column>
 		<el-table-column prop="statusText" label="状态" width="100" fixed="right" align="center"></el-table-column>
 		<el-table-column prop="statusText" label="状态" width="100" fixed="right" align="center"></el-table-column>
 	</el-table>
 	</el-table>
   <pagination
   <pagination

+ 145 - 0
src/views/todo/seats/accept/Real-time-quality.vue

@@ -0,0 +1,145 @@
+<template>
+	<div class="real-time-quality">
+		<el-scrollbar class="h100" noresize ref="scrollbarRef" max-height="400px" v-if="tagList.length" @click="stopScroll">
+			<div class="tag-box" ref="chatBoxRef">
+				<div v-for="(item, index) in tagList" :key="index" class="tag-item flex-center-between">
+					<el-tag>{{ item.tag }}</el-tag>
+					<el-text type="info">{{ formatDate(item.timestamps, 'YYYY-mm-dd HH:MM:SS') }}</el-text>
+				</div>
+				<el-text class="end-call" tag="p" v-if="talkEnd">-- 通话结束 --</el-text>
+			</div>
+		</el-scrollbar>
+		<Empty v-else />
+		<el-button @click.stop="keepScroll" class="keep-scroll" title="回到底部" circle v-if="!isScrollBottom && !talkEnd">
+			<SvgIcon name="ele-ArrowDown" size="18px" />
+		</el-button>
+	</div>
+</template>
+<script setup lang="ts" name="orderAcceptRealtimeQuality">
+import { nextTick, onActivated, onDeactivated, onMounted, ref, watch } from 'vue';
+import mittBus from '@/utils/mitt';
+import other from '@/utils/other';
+import { useRoute } from 'vue-router';
+import { formatDate } from '@/utils/formatTime';
+
+const tagList = ref([
+/*	{
+		tag: '语速过快',
+		timestamps: new Date().getTime(),
+	},*/
+]);
+const talkEnd = ref(false);
+const wsReceive = (message: any) => {
+	try {
+		const data = JSON.parse(message.data);
+		if (data.body.bisType === 3) {
+			// 转写消息
+			if (data.body.content.action === 0) {
+				// 通话开始
+				console.log('通话转写开始了');
+				talkEnd.value = false;
+			}
+			if (data.body.content.action === 1) {
+				// 通话中
+				if (tagList.value.length) {
+					const item = tagList.value.find((item: any) => item.body.content.callSentenceInfo.index === data.body.content.callSentenceInfo.index);
+					if (item) {
+						item.body.content.callSentenceInfo.text = data.body.content.callSentenceInfo.text;
+					} else {
+						tagList.value.push(data);
+					}
+				} else {
+					tagList.value.push(data);
+				}
+				scrollToBottom();
+				showMessageList.value = other.deepClone(tagList.value);
+				console.log('通话消息转写内容:', tagList.value);
+			}
+			if (data.body.content.action === 4) {
+				// 通话结束
+				setTimeout(() => {
+					//通话结束
+					talkEnd.value = true;
+					scrollToBottom(); //滚动到底部
+					stopScroll(); //停止滚动
+				}, 1000);
+				console.log('通话转写结束了');
+			}
+		}
+	} catch (error) {
+		console.log('坐席辅助收到消息', message);
+	}
+};
+const scrollbarRef = ref<RefType>();
+const chatBoxRef = ref<RefType>();
+// 停止滚动
+const stopScroll = () => {
+	isScrollBottom.value = false;
+};
+watch(
+	() => scrollbarRef.value?.wrapRef,
+	() => {
+		scrollbarRef.value?.wrapRef.addEventListener('mousewheel', () => {
+			stopScroll();
+		});
+	}
+);
+// 继续滚动
+const keepScroll = () => {
+	isScrollBottom.value = true;
+	scrollToBottom();
+};
+// 滚动到底部
+const isScrollBottom = ref(true); // 是否需要滚动到底部
+const isAutoScroll = ref(true); // 是否自动滚动
+const scrollToBottom = async () => {
+	if (!isScrollBottom.value) return;
+	await nextTick(); // 等待 DOM 更新
+	const max = chatBoxRef.value?.clientHeight;
+	scrollbarRef.value?.setScrollTop(max);
+	isAutoScroll.value = true;
+};
+// 订阅消息
+const route = useRoute();
+const subscribe = () => {
+	// 接受消息
+	mittBus.on('wsReceive', (message: any) => {
+		const data = JSON.parse(message.data);
+		if (data.body.content.callId === route.params.callId) {
+			// 判断是否是当前通话
+			wsReceive(message);
+		}
+	});
+};
+onMounted(() => {
+	// 进入页面订阅
+	subscribe();
+});
+onActivated(() => {
+	// 缓存进入重新订阅
+	subscribe();
+});
+onDeactivated(() => {
+	// 缓存离开取消订阅
+	mittBus.off('wsReceive');
+});
+</script>
+<style scoped lang="scss">
+.real-time-quality {
+  width: 100%;
+  height: 100%;
+  position: relative;
+	.keep-scroll {
+		position: absolute;
+		right: 10px;
+		bottom: 30px;
+		z-index: 100;
+	}
+	.tag-box {
+		padding: 10px 30px;
+		.tag-item {
+			margin-bottom: 10px;
+		}
+	}
+}
+</style>

+ 26 - 0
src/views/todo/seats/accept/Script-navigation.vue

@@ -0,0 +1,26 @@
+<template>
+<!--	<el-button @click="next">下一步</el-button>-->
+	<div class="script-navigation">
+		<el-steps direction="vertical" :active="active">
+			<el-step title="开场白" />
+			<el-step title="确认受理内容" />
+			<el-step title="确认市民基本信息" />
+			<el-step title="结束语" />
+		</el-steps>
+	</div>
+</template>
+<script setup lang="ts" name="orderAcceptScriptNavigation">
+import { ref } from 'vue';
+const active = ref(0);
+const next = () => {
+	if (active.value++ > 3) active.value = 0;
+};
+</script>
+
+<style scoped lang="scss">
+.script-navigation {
+	padding: 20px 50px;
+	height: 300px;
+	max-width: 600px;
+}
+</style>

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

@@ -1,20 +1,30 @@
 <template>
 <template>
 	<div class="voice-assistant">
 	<div class="voice-assistant">
 		<!-- 聊天框 -->
 		<!-- 聊天框 -->
-		<el-scrollbar class="h100" noresize ref="scrollbarRef" max-height="400px" v-if="messageList.length" @click="stopScroll">
+		<el-scrollbar class="h100" noresize ref="scrollbarRef" max-height="400px" v-if="showMessageList.length" @click="stopScroll">
 			<div class="chat-box" ref="chatBoxRef">
 			<div class="chat-box" ref="chatBoxRef">
-				<div v-for="(item, index) in messageList" :key="index" class="chat-item" :class="item.body?.content?.callSentenceInfo?.role">
+				<div v-for="(item, index) in showMessageList" :key="index" class="chat-item" :class="item.body?.content?.callSentenceInfo?.role">
 					<div v-if="item.body?.content?.callSentenceInfo?.role === 'user'" class="user">
 					<div v-if="item.body?.content?.callSentenceInfo?.role === 'user'" class="user">
 						<img v-lazy="getImageUrl('order/user.png')" alt="" class="user-avatar" src="" />
 						<img v-lazy="getImageUrl('order/user.png')" alt="" class="user-avatar" src="" />
-						<div class="user-name">{{ item.body?.content?.callerNumber }}</div>
+						<div class="user-name">
+							{{ item.body?.content?.callerNumber }}
+							<div class="user-date">{{ formatDate(item.timestamps, 'YYYY-mm-dd HH:MM:SS') }}</div>
+						</div>
 						<div class="user-content">{{ item.body?.content?.callSentenceInfo.text }}</div>
 						<div class="user-content">{{ item.body?.content?.callSentenceInfo.text }}</div>
-						<div class="user-date">{{ formatDate(item.timestamps, 'YYYY-mm-dd HH:MM:SS') }}</div>
+            <div class="user-tag">
+              <el-tag v-for="(items, index) in item.body?.content?.callSentenceInfo.tags" size="small">{{items}}</el-tag>
+            </div>
 					</div>
 					</div>
 					<div v-else class="agent">
 					<div v-else class="agent">
 						<img v-lazy="getImageUrl('order/service.png')" alt="" class="agent-avatar" src="" />
 						<img v-lazy="getImageUrl('order/service.png')" alt="" class="agent-avatar" src="" />
-						<div class="agent-name">{{ item.body?.content?.calledNumber }}</div>
+						<div class="agent-name">
+							<div class="agent-date">{{ formatDate(item.timestamps, 'YYYY-mm-dd HH:MM:SS') }}</div>
+							{{ item.body?.content?.calledNumber }}
+						</div>
 						<div class="agent-content">{{ item.body?.content?.callSentenceInfo.text }}</div>
 						<div class="agent-content">{{ item.body?.content?.callSentenceInfo.text }}</div>
-						<div class="agent-date">{{ formatDate(item.timestamps, 'YYYY-mm-dd HH:MM:SS') }}</div>
+            <div class="agent-tag">
+              <el-tag v-for="(items, index) in item.body?.content?.callSentenceInfo.tags" size="small">{{items}}</el-tag>
+            </div>
 					</div>
 					</div>
 				</div>
 				</div>
 				<el-text class="end-call" tag="p" v-if="talkEnd">-- 通话结束 --</el-text>
 				<el-text class="end-call" tag="p" v-if="talkEnd">-- 通话结束 --</el-text>
@@ -25,7 +35,7 @@
 			<SvgIcon name="ele-ArrowDown" size="18px" />
 			<SvgIcon name="ele-ArrowDown" size="18px" />
 		</el-button>
 		</el-button>
 		<!-- 识别内容 通话结束才展示-->
 		<!-- 识别内容 通话结束才展示-->
-		<div class="recognize-box" v-if="talkEnd && messageList.length">
+		<div class="recognize-box" v-if="talkEnd && showMessageList.length">
 			<transition name="el-zoom-in-bottom">
 			<transition name="el-zoom-in-bottom">
 				<div v-show="!searchCol" class="transition-box">
 				<div v-show="!searchCol" class="transition-box">
 					<el-button link @click="closeSearch" class="transition-box-close">
 					<el-button link @click="closeSearch" class="transition-box-close">
@@ -55,7 +65,7 @@
 							<el-text tag="b" class="call-item-label">地址:</el-text>
 							<el-text tag="b" class="call-item-label">地址:</el-text>
 							<p class="call-item-value">{{ recognizeList?.address }}</p>
 							<p class="call-item-value">{{ recognizeList?.address }}</p>
 						</div>
 						</div>
-            <!--						<div class="call-item">
+						<!--						<div class="call-item">
               <el-text tag="b" class="call-item-label">公司名称:</el-text>
               <el-text tag="b" class="call-item-label">公司名称:</el-text>
               <p class="call-item-value">{{ recognizeList?.company_name }}</p>
               <p class="call-item-value">{{ recognizeList?.company_name }}</p>
             </div>
             </div>
@@ -107,17 +117,20 @@ import { ElMessageBox } from 'element-plus';
 import { getImageUrl } from '@/utils/tools';
 import { getImageUrl } from '@/utils/tools';
 import { useRoute } from 'vue-router';
 import { useRoute } from 'vue-router';
 import { formatDate } from '@/utils/formatTime';
 import { formatDate } from '@/utils/formatTime';
-const emit = defineEmits(['orderOverwrite']);
 import mittBus from '@/utils/mitt';
 import mittBus from '@/utils/mitt';
-import { voiceAssistantContent } from "@/api/todo/voiceAssistant";
+import { voiceAssistantContent } from '@/api/todo/voiceAssistant';
+import other from '@/utils/other';
+
+const emit = defineEmits(['orderOverwrite']);
 // 消息列表
 // 消息列表
 const messageList = ref<any>([
 const messageList = ref<any>([
-	/*{
+/*	{
 		body: {
 		body: {
 			content: {
 			content: {
 				callSentenceInfo: {
 				callSentenceInfo: {
 					text: '你好,我是小智,有什么可以帮您的吗?',
 					text: '你好,我是小智,有什么可以帮您的吗?',
 					role: 'agent',
 					role: 'agent',
+          tags:['语速过快','情绪激动']
 				},
 				},
 				calledNumber: '1009',
 				calledNumber: '1009',
 				callerNumber: '19136073037',
 				callerNumber: '19136073037',
@@ -129,16 +142,47 @@ const messageList = ref<any>([
 		body: {
 		body: {
 			content: {
 			content: {
 				callSentenceInfo: {
 				callSentenceInfo: {
-					text: '你好,我是小智,有什么可以帮您的吗?',
+					text: '12311?',
 					role: 'user',
 					role: 'user',
+          tags:['语速过快','情绪激动']
 				},
 				},
+				calledNumber: '1009',
+				callerNumber: '19136073037',
 			},
 			},
-			calledNumber: '1009',
-			callerNumber: '19136073037',
 		},
 		},
 		timestamps: new Date().getTime(),
 		timestamps: new Date().getTime(),
 	},*/
 	},*/
 ]); // 消息列表
 ]); // 消息列表
+const showMessageList = ref([
+/*	{
+		body: {
+			content: {
+				callSentenceInfo: {
+					text: '你好,我是小智,有什么可以帮您的吗?',
+					role: 'agent',
+          tags:['语速过快','情绪激动']
+				},
+				calledNumber: '1009',
+				callerNumber: '19136073037',
+			},
+		},
+		timestamps: new Date().getTime(),
+	},
+	{
+		body: {
+			content: {
+				callSentenceInfo: {
+					text: '12311?',
+					role: 'user',
+          tags:['语速过快','情绪激动']
+				},
+				calledNumber: '1009',
+				callerNumber: '19136073037',
+			},
+		},
+		timestamps: new Date().getTime(),
+	},*/
+]);
 const recognizeList = ref<EmptyObjectType>({}); // 识别信息
 const recognizeList = ref<EmptyObjectType>({}); // 识别信息
 const route = useRoute();
 const route = useRoute();
 const talkEnd = ref(false); // 通话结束
 const talkEnd = ref(false); // 通话结束
@@ -165,6 +209,7 @@ const wsReceive = (message: any) => {
 					messageList.value.push(data);
 					messageList.value.push(data);
 				}
 				}
 				scrollToBottom();
 				scrollToBottom();
+				showMessageList.value = other.deepClone(messageList.value);
 				console.log('通话消息转写内容:', messageList.value);
 				console.log('通话消息转写内容:', messageList.value);
 			}
 			}
 			if (data.body.content.action === 4) {
 			if (data.body.content.action === 4) {
@@ -173,7 +218,7 @@ const wsReceive = (message: any) => {
 					//通话结束
 					//通话结束
 					talkEnd.value = true;
 					talkEnd.value = true;
 					scrollToBottom(); //滚动到底部
 					scrollToBottom(); //滚动到底部
-          stopScroll(); //停止滚动
+					stopScroll(); //停止滚动
 				}, 1000);
 				}, 1000);
 				console.log('通话转写结束了');
 				console.log('通话转写结束了');
 			}
 			}
@@ -187,22 +232,22 @@ const chatBoxRef = ref<RefType>();
 const searchCol = ref(true); // 展开/收起
 const searchCol = ref(true); // 展开/收起
 // 展开/收起 通话小结
 // 展开/收起 通话小结
 const closeSearch = () => {
 const closeSearch = () => {
-  if (!searchCol.value) {
-    // 展开
-    // 获取识别内容
-    getRecognize();
-  }
+	if (!searchCol.value) {
+		// 展开
+		// 获取识别内容
+		getRecognize();
+	}
 	searchCol.value = !searchCol.value;
 	searchCol.value = !searchCol.value;
 };
 };
 // 获取识别内容
 // 获取识别内容
 const getRecognize = async () => {
 const getRecognize = async () => {
-  try {
-    const callId = route.params.callId;
-    const {result} = await voiceAssistantContent(typeof callId === "string" ? callId :'');
-    recognizeList.value = result;
-  }catch (error) {
-    console.log('获取识别内容失败', error);
-  }
+	try {
+		const callId = route.params.callId;
+		const { result } = await voiceAssistantContent(typeof callId === 'string' ? callId : '');
+		recognizeList.value = result;
+	} catch (error) {
+		console.log('获取识别内容失败', error);
+	}
 };
 };
 // 停止滚动
 // 停止滚动
 const stopScroll = () => {
 const stopScroll = () => {
@@ -261,6 +306,24 @@ const subscribe = () => {
 		}
 		}
 	});
 	});
 };
 };
+// 消息筛选
+const staticMessage = other.deepClone(messageList.value);
+const filterMessage = (type: string) => {
+	switch (type) {
+		case '市民':
+			showMessageList.value = staticMessage.filter((item: any) => item.body.content.callSentenceInfo.role === 'user');
+			break;
+		case '坐席':
+			showMessageList.value = staticMessage.filter((item: any) => item.body.content.callSentenceInfo.role === 'agent');
+			break;
+		case '全部':
+			showMessageList.value = staticMessage;
+			break;
+		default:
+			showMessageList.value = staticMessage;
+			break;
+	}
+};
 onMounted(() => {
 onMounted(() => {
 	// 进入页面订阅
 	// 进入页面订阅
 	subscribe();
 	subscribe();
@@ -273,6 +336,9 @@ onDeactivated(() => {
 	// 缓存离开取消订阅
 	// 缓存离开取消订阅
 	mittBus.off('wsReceive');
 	mittBus.off('wsReceive');
 });
 });
+defineExpose({
+	filterMessage,
+});
 </script>
 </script>
 
 
 <style scoped lang="scss">
 <style scoped lang="scss">
@@ -298,7 +364,7 @@ onDeactivated(() => {
 			word-break: break-all;
 			word-break: break-all;
 			position: relative;
 			position: relative;
 			color: var(--el-color-white);
 			color: var(--el-color-white);
-			margin: 30px 10px 10px 10px;
+			margin: 40px 10px 10px 10px;
 			display: flex;
 			display: flex;
 
 
 			.user {
 			.user {
@@ -329,15 +395,25 @@ onDeactivated(() => {
 					color: var(--el-text-color-regular);
 					color: var(--el-text-color-regular);
 					margin-bottom: 5px;
 					margin-bottom: 5px;
 					margin-left: 65px;
 					margin-left: 65px;
+
+          display: flex;
+          justify-content: flex-end;
+          align-items: center;
 				}
 				}
 
 
 				&-date {
 				&-date {
 					font-size: var(--el-font-size-extra-small);
 					font-size: var(--el-font-size-extra-small);
 					color: var(--el-text-color-placeholder);
 					color: var(--el-text-color-placeholder);
-					position: absolute;
-					bottom: -20px;
-					left: 65px;
+          margin-left: 10px;
 				}
 				}
+        &-tag{
+          position: absolute;
+          bottom: -30px;
+          left: 65px;
+          :deep(.el-tag){
+            margin-right: 10px;
+          }
+        }
 
 
 				&-avatar {
 				&-avatar {
 					width: 40px;
 					width: 40px;
@@ -379,16 +455,24 @@ onDeactivated(() => {
 					margin-bottom: 5px;
 					margin-bottom: 5px;
 					text-align: right;
 					text-align: right;
 					margin-right: 65px;
 					margin-right: 65px;
+          display: flex;
+          justify-content: flex-end;
+          align-items: center;
 				}
 				}
 
 
 				&-date {
 				&-date {
 					font-size: var(--el-font-size-extra-small);
 					font-size: var(--el-font-size-extra-small);
 					color: var(--el-text-color-placeholder);
 					color: var(--el-text-color-placeholder);
-					position: absolute;
-					bottom: -20px;
-					right: 65px;
+          margin-right: 10px;
 				}
 				}
-
+        &-tag{
+          position: absolute;
+          bottom: -30px;
+          right: 65px;
+          :deep(.el-tag){
+            margin-left: 10px;
+          }
+        }
 				&-avatar {
 				&-avatar {
 					width: 40px;
 					width: 40px;
 					height: 40px;
 					height: 40px;

+ 57 - 11
src/views/todo/seats/accept/index.vue

@@ -1,8 +1,34 @@
 <template>
 <template>
 	<div class="order-add-container layout-padding">
 	<div class="order-add-container layout-padding">
-		<el-row :gutter="15" class="h100">
-			<!-- 左边工单信息 -->
-			<el-col :span="12" class="left-content mb20 h100" v-loading="state.formLoading">
+		<el-row :gutter="10" class="h100">
+			<!--  左侧语音助手  -->
+			<el-col :span="7" class="left-content mb20 h100">
+				<el-scrollbar class="h100" noresize>
+					<el-card shadow="never">
+						<div class="flex-center-between">
+							<p class="border-title mb10">语音助手</p>
+							<el-radio-group v-model="voiceType" @change="changeVoiceType">
+								<el-radio-button label="全部" />
+								<el-radio-button label="市民" />
+								<el-radio-button label="坐席" />
+							</el-radio-group>
+						</div>
+						<voice-assistant @orderOverwrite="orderOverwrite" ref="voiceAssistantRef" />
+					</el-card>
+					<el-card shadow="never">
+						<el-tabs v-model="leftTopActive" @tab-change="handleLeftTop" stretch>
+							<el-tab-pane label="实时质检" name="realtime">
+								<real-time-quality />
+							</el-tab-pane>
+							<el-tab-pane label="工单小结" name="summary">
+								<call-summary ref="callSummaryRef" />
+							</el-tab-pane>
+						</el-tabs>
+					</el-card>
+				</el-scrollbar>
+			</el-col>
+			<!-- 中间工单信息 -->
+			<el-col :span="10" class="left-content mb20 h100" v-loading="state.formLoading">
 				<el-scrollbar class="h100" noresize>
 				<el-scrollbar class="h100" noresize>
 					<el-card shadow="never">
 					<el-card shadow="never">
 						<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="110px" label-position="right" scroll-to-error>
 						<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="110px" label-position="right" scroll-to-error>
@@ -452,7 +478,7 @@
 										:rules="[{ required: true, message: '请选择是否行政执法工单', trigger: 'change' }]"
 										:rules="[{ required: true, message: '请选择是否行政执法工单', trigger: 'change' }]"
 									>
 									>
 										<el-radio-group v-model="state.ruleForm.isEnforcementOrder">
 										<el-radio-group v-model="state.ruleForm.isEnforcementOrder">
-                      <el-radio  :label="true">是</el-radio>
+											<el-radio :label="true">是</el-radio>
 											<el-radio :label="false">否</el-radio>
 											<el-radio :label="false">否</el-radio>
 										</el-radio-group>
 										</el-radio-group>
 									</el-form-item>
 									</el-form-item>
@@ -492,10 +518,10 @@
 				</el-scrollbar>
 				</el-scrollbar>
 			</el-col>
 			</el-col>
 			<!-- 右侧内容 -->
 			<!-- 右侧内容 -->
-			<el-col :span="12" class="right-content h100">
+			<el-col :span="7" class="right-content h100">
 				<el-scrollbar class="h100">
 				<el-scrollbar class="h100">
 					<el-card shadow="never">
 					<el-card shadow="never">
-						<el-tabs v-model="rightActive" @tab-change="handleRight">
+						<el-tabs v-model="rightActive" @tab-change="handleRight" stretch>
 							<el-tab-pane label="历史工单" name="history">
 							<el-tab-pane label="历史工单" name="history">
 								<history-order
 								<history-order
 									:ruleForm="state.ruleForm"
 									:ruleForm="state.ruleForm"
@@ -513,9 +539,9 @@
 						</el-tabs>
 						</el-tabs>
 					</el-card>
 					</el-card>
 					<el-card shadow="never">
 					<el-card shadow="never">
-						<el-tabs v-model="rightBottomActive" @tab-change="handleRightBottom">
-							<el-tab-pane label="语音助手" name="voice">
-								<voice-assistant @orderOverwrite="orderOverwrite" />
+						<el-tabs v-model="rightBottomActive" @tab-change="handleRightBottom" stretch>
+							<el-tab-pane label="话术导航" name="navigation">
+								<script-navigation />
 							</el-tab-pane>
 							</el-tab-pane>
 							<el-tab-pane label="市民画像" name="draw">
 							<el-tab-pane label="市民画像" name="draw">
 								<citizen-portrait :orderInfo="state.ruleForm" ref="citizenPortraitRef" />
 								<citizen-portrait :orderInfo="state.ruleForm" ref="citizenPortraitRef" />
@@ -570,6 +596,9 @@ const ProcessAudit = defineAsyncComponent(() => import('@/components/ProcessAudi
 const MapDialog = defineAsyncComponent(() => import('@/views/todo/seats/accept/Map-Dialog.vue')); // 地图定位
 const MapDialog = defineAsyncComponent(() => import('@/views/todo/seats/accept/Map-Dialog.vue')); // 地图定位
 const CompanySearch = defineAsyncComponent(() => import('@/views/todo/seats/accept/Company-search.vue')); // 企业搜索
 const CompanySearch = defineAsyncComponent(() => import('@/views/todo/seats/accept/Company-search.vue')); // 企业搜索
 const HotSpotSelect = defineAsyncComponent(() => import('@/components/Hotspot/index.vue')); // 选择热点
 const HotSpotSelect = defineAsyncComponent(() => import('@/components/Hotspot/index.vue')); // 选择热点
+const RealTimeQuality = defineAsyncComponent(() => import('@/views/todo/seats/accept/Real-time-quality.vue')); // 实时质检
+const ScriptNavigation = defineAsyncComponent(() => import('@/views/todo/seats/accept/Script-navigation.vue')); // 话术导航
+const CallSummary = defineAsyncComponent(() => import('@/views/todo/seats/accept/Call-summary.vue')); // 呼叫小结
 // 定义变量内容
 // 定义变量内容
 const state = reactive<any>({
 const state = reactive<any>({
 	createBy: 'manual', // 工单创建方式 默认手动创建  tel:来电弹单  letter:互联网来信 默认表示手动创建
 	createBy: 'manual', // 工单创建方式 默认手动创建  tel:来电弹单  letter:互联网来信 默认表示手动创建
@@ -615,7 +644,7 @@ const state = reactive<any>({
 		repeatableEventDetails: [], //重复性事件
 		repeatableEventDetails: [], //重复性事件
 		orderExtension: null, // 拓展信息
 		orderExtension: null, // 拓展信息
 		transpond: false, // 是否市州互转
 		transpond: false, // 是否市州互转
-		isEnforcementOrder: null, // 是否行政执法工单
+		isEnforcementOrder: false, // 是否行政执法工单
 	},
 	},
 	formLoading: false, // 表单加载状态
 	formLoading: false, // 表单加载状态
 	hotspotExternal: [], // 热点分类外部数据
 	hotspotExternal: [], // 热点分类外部数据
@@ -655,6 +684,23 @@ state.ruleForm.acceptorStaffNo = userInfos.value.staffNo; // 员工工号
 const route = useRoute(); // 路由
 const route = useRoute(); // 路由
 const router = useRouter(); // 路由
 const router = useRouter(); // 路由
 
 
+const voiceType = ref('全部');
+// 选择坐席还是市民通话内容
+const voiceAssistantRef = ref<RefType>();
+const changeVoiceType = () => {
+	voiceAssistantRef.value.filterMessage(voiceType.value);
+};
+const leftTopActive = ref('realtime');
+// 切换工单小结和实时质检
+const callSummaryRef = ref<RefType>();
+const handleLeftTop = (val: string) => {
+	if (val === 'summary') {
+		setTimeout(() => {
+			callSummaryRef.value.getRecognize();
+		}, 300);
+	}
+};
+
 // 选择企业
 // 选择企业
 const companySearchRef = ref<RefType>();
 const companySearchRef = ref<RefType>();
 const handleSelect = (item: Record<string, any>) => {
 const handleSelect = (item: Record<string, any>) => {
@@ -894,7 +940,7 @@ const inputTitle = (val: string) => {
 };
 };
 const rightActive = ref<string>('history'); // 右侧顶部Tab
 const rightActive = ref<string>('history'); // 右侧顶部Tab
 const handleRight = (val: string) => {};
 const handleRight = (val: string) => {};
-const rightBottomActive = ref<string>('voice'); // 右侧底部Tab
+const rightBottomActive = ref<string>('navigation'); // 右侧底部Tab
 const handleRightBottom = (val: string) => {};
 const handleRightBottom = (val: string) => {};
 
 
 // 打开拓展表单
 // 打开拓展表单