瀏覽代碼

reactor:宜宾呼叫中心支持接通弹单和整理中可以签出 小休可以签出;

zhangchong 9 月之前
父節點
當前提交
8a9a865ad7

+ 3 - 3
.env.development

@@ -3,11 +3,11 @@ VITE_MODE_NAME=development
 # 防止部署多套系统到同一域名不同目录时,变量共用的问题 设置不同的前缀
 VITE_STORAGE_NAME=dev
 # 基础请求地址
-VITE_API_URL=http://110.188.24.28:50300
+VITE_API_URL=http://110.188.24.28:50100
 # 数据共享平台请求地址
 VITE_DATASHARE_API_YRL=http://ds.12345lm.cn
 # socket API
-VITE_API_SOCKET_URL=http://110.188.24.28:50300/hubs/hotline
+VITE_API_SOCKET_URL=http://110.188.24.28:50100/hubs/hotline
 # 上传 API
 VITE_API_UPLOAD_URL=http://110.188.24.28:50120
 # 文件上传地址前缀
@@ -25,4 +25,4 @@ VITE_JTHS_API_URL=http://118.121.58.161:19021
 # 捷通华声AppKey
 VITE_JTHS_APPKEY=MTAwMDAx
 # 当前地州市
-VITE_CURRENT_CITY=zigong
+VITE_CURRENT_CITY=yibin

+ 1 - 1
src/components/ProcessAudit/index.vue

@@ -424,7 +424,7 @@
 						</el-col>
 						<el-col v-if="state.dialogTitle === '工单受理'" :span="24" :class="{ mb20: isOverdueTips }">
 							<el-alert type="warning" show-icon title="注意">
-								<template #title> 打开办理弹窗后如有修改工单信息,请关闭本弹窗后重新打开 </template>
+								<template #title> 打开办理弹窗后如有修改工单信息,请关闭本弹窗后保存后重新打开 </template>
 							</el-alert>
 						</el-col>
 						<el-col v-if="isOverdueTips" :span="24">

+ 69 - 28
src/layout/navBars/breadcrumb/ybTel.vue

@@ -730,12 +730,12 @@ const activeArr = computed(() => {
 		dutyOff: ['dutyOn'], // 签出状态
 		dutyOn: ['dutyOff', 'callOut', 'rest', 'outbound'], // 已签入无通话状态
 		onCallOut: ['dutyOff', 'callOut', 'outbound'], // 外呼模式中
-		rest: ['rest'], // 小休中状态
+		rest: ['rest', 'dutyOff'], // 小休中状态
 		ring: ['hangup'], //振铃中
 		onCall: ['hangup', 'hold', 'transfer', 'conference', 'mute'], // 单个通话中
 		onMute: ['hangup', 'transfer', 'mute'], // 静音中
 		onHold: ['hangup', 'hold', 'transfer'], // 保持中
-		onTalkingDeal: ['rest','TalkingDeal'], // 话后整理中
+		onTalkingDeal: ['rest', 'TalkingDeal', 'dutyOff'], // 话后整理中
 		onConference: ['hangup'], // 三方会议中 只能挂断
 		onThreeWay: ['hangup', 'conference'], // 三方会议呼出中 只能挂断和踢人
 	};
@@ -918,6 +918,8 @@ const onDisconnected = (event: any) => {
 	callCenterIsSignIn.value = false; // 签出状态
 	console.log(`${getNowDateTime()}:呼叫中心断开链接`, event);
 };
+// 来电弹屏方式 1-接通弹屏;2-振铃弹屏
+const openFlag = ref('2');
 // 呼叫中心消息
 const onMessage = async (event: any) => {
 	const data = JSON.parse(event);
@@ -1042,8 +1044,8 @@ const onMessage = async (event: any) => {
 				break;
 		}
 		if (data.state == 'busy') {
-      useTelStatusStore.setDutyState(true); // 确保一进来消息就是通话中 设置签入状态
-      callCenterIsSignIn.value = true; // 签入状态
+			useTelStatusStore.setDutyState(true); // 确保一进来消息就是通话中 设置签入状态
+			callCenterIsSignIn.value = true; // 签入状态
 			call_direction.value = data.call_direction; // 保存呼叫方向
 			callCenterIsOnThePhone.value = true; // 当前正在通话状态
 			if (['held', 'unheld'].includes(data.private_data)) {
@@ -1152,8 +1154,8 @@ const onMessage = async (event: any) => {
 					// 呼入
 					if (data.private_data == 'ring') {
 						try {
-							const name: string = `弹单消息:分机号:${currentTel.value.telNo},来电号码:${data.ani},转接来源:${data.gateway},按键接收:${data.app_data.dtmf_his},通话ID:${data.other_accept}`;
-							const remark: string = `弹单消息:分机号:${currentTel.value.telNo},来电号码:${data.ani},转接来源:${data.gateway},按键接收:${data.app_data.dtmf_his},通话ID:${data.other_accept}`;
+							const name: string = `振铃消息:分机号:${currentTel.value.telNo},来电号码:${data.ani},转接来源:${data.gateway},按键接收:${data.app_data.dtmf_his},通话ID:${data.other_accept}`;
+							const remark: string = `振铃消息:分机号:${currentTel.value.telNo},来电号码:${data.ani},转接来源:${data.gateway},按键接收:${data.app_data.dtmf_his},通话ID:${data.other_accept}`;
 							const request = {
 								creationTime: new Date(),
 								name,
@@ -1166,35 +1168,74 @@ const onMessage = async (event: any) => {
 						}
 						// 设置电话状态 振铃中
 						useTelStatusStore.setPhoneControlState(TelStates.ring);
-						console.log(`${getNowDateTime()}:接收消息:呼叫中心:来电弹单信息`, data);
-						// 来电才展示弹屏
-						// 跳转到录入工单页面
-						await getWithList(); // 获取白名单列表
-						const isWhite = state.whiteList.find((item: any) => item.phone === data.ani);
-						if (isWhite) {
-							// 如果来电电话在呼入白名单中 需要提示
-							ElNotification({
-								title: '来电提醒',
-								message: '该市民为白名单。',
-								type: 'success',
+						console.log(`${getNowDateTime()}:接收消息:呼叫中心:振铃弹单信息`, data);
+						if (openFlag.value === '2') {
+							// 振铃弹单
+							await getWithList(); // 获取白名单列表
+							const isWhite = state.whiteList.find((item: any) => item.phone === data.ani);
+							if (isWhite) {
+								// 如果来电电话在呼入白名单中 需要提示
+								ElNotification({
+									title: '来电提醒',
+									message: '该市民为白名单。',
+									type: 'success',
+								});
+							}
+							await router.push({
+								name: 'orderAccept',
+								query: {
+									createBy: 'tel',
+									fromTel: data.ani, // 来电号码
+									callId: data.other_accept,
+									transfer: data.gateway, // 转接来源(如12345,12333)
+									identityType: data.app_data.dtmf_his, // 按键接收(1:市民 2:企业 3:智能应答)
+									timeStamp: new Date().getTime(),
+								},
 							});
 						}
-						await router.push({
-							name: 'orderAccept',
-							query: {
-								createBy: 'tel',
-								fromTel: data.ani, // 来电号码
-								callId: data.other_accept,
-								transfer: data.gateway, // 转接来源(如12345,12333)
-								identityType: data.app_data.dtmf_his, // 按键接收(1:市民 2:企业 3:智能应答)
-                timeStamp: new Date().getTime(),
-							},
-						});
 					} else if (data.private_data == 'answered') {
+						try {
+							const name: string = `接通消息:分机号:${currentTel.value.telNo},来电号码:${data.ani},转接来源:${data.gateway},按键接收:${data.app_data.dtmf_his},通话ID:${data.other_accept}`;
+							const remark: string = `接通消息:分机号:${currentTel.value.telNo},来电号码:${data.ani},转接来源:${data.gateway},按键接收:${data.app_data.dtmf_his},通话ID:${data.other_accept}`;
+							const request = {
+								creationTime: new Date(),
+								name,
+								remark,
+								executeUrl: callCenterSocketUrl,
+							};
+							await submitLogFn(request);
+						} catch (e) {
+							console.log(`getNowDateTime():日志记录错误`);
+						}
+						console.log(data, '接通的消息体');
 						// 开始计时
 						startTalkTimer();
 						// 设置电话状态 通话中
 						useTelStatusStore.setPhoneControlState(TelStates.onCall);
+						if (openFlag.value === '1') {
+							// 接通弹单
+							await getWithList(); // 获取白名单列表
+							const isWhite = state.whiteList.find((item: any) => item.phone === data.ani);
+							if (isWhite) {
+								// 如果来电电话在呼入白名单中 需要提示
+								ElNotification({
+									title: '来电提醒',
+									message: '该市民为白名单。',
+									type: 'success',
+								});
+							}
+							await router.push({
+								name: 'orderAccept',
+								query: {
+									createBy: 'tel',
+									fromTel: data.ani, // 来电号码
+									callId: data.other_accept,
+									transfer: data.gateway, // 转接来源(如12345,12333)
+									identityType: data.app_data.dtmf_his, // 按键接收(1:市民 2:企业 3:智能应答)
+									timeStamp: new Date().getTime(),
+								},
+							});
+						}
 						console.log(`${getNowDateTime()}:接收消息:呼叫中心:呼入通话中`);
 					}
 					sendMsg('busy');

+ 1 - 1
src/views/statistics/call/detailIndexCall.vue

@@ -122,7 +122,7 @@ const resetQuery = (formEl: FormInstance | undefined) => {
 const playRecordRef = ref<RefType>();
 const { recordPrefix, recordDownLoadPrefix } = getCurrentCityConfig();
 const onPlaySoundRecording = (val: any) => {
-	playRecordRef.value.openDialog(recordPrefix + val.recordingAbsolutePath);
+	playRecordRef.value.openDialog(recordPrefix + val.recordingAbsolutePath,val.recordingAbsolutePath);
 };
 // 下载录音
 const onDownload = (row: any) => {

+ 1 - 1
src/views/statistics/call/index.vue

@@ -26,7 +26,7 @@
 					<el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
 						<SvgIcon name="ele-Refresh" class="mr5" />重置
 					</el-button>
-<!--					<el-button type="primary" @click="onDetail" :loading="state.loading"> <SvgIcon name="ele-List" class="mr5" /> 话务日期明细 </el-button>-->
+					<el-button type="primary" @click="onDetail" :loading="state.loading"> <SvgIcon name="ele-List" class="mr5" /> 话务日期明细 </el-button>
 				</el-form-item>
 			</el-form>
 		</el-card>

+ 81 - 75
src/views/statistics/center/emergencyList.vue

@@ -1,88 +1,89 @@
 <template>
 	<div class="statistics-center-emergency-List-container layout-pd">
 		<el-card shadow="never">
-			<el-row :gutter="10">
-				<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
-					<el-form-item label="工单标题" prop="Title">
-						<el-input v-model="state.queryParams.Title" placeholder="工单标题" clearable @keyup.enter="handleQuery" />
-					</el-form-item>
-				</el-col>
-				<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
-					<el-form-item label="工单编码" prop="No">
-						<el-input v-model="state.queryParams.No" placeholder="工单编码" clearable @keyup.enter="handleQuery" />
-					</el-form-item>
-				</el-col>
-
-				<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
-					<el-form-item label="热点分类" prop="Hotspot">
-						<el-input v-model="state.queryParams.Hotspot" placeholder="热点分类名称" clearable @keyup.enter="handleQuery" />
-					</el-form-item>
-				</el-col>
-				<transition name="el-zoom-in-top">
-					<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol">
-						<el-form-item label="受理类型" prop="AcceptType">
-							<el-input v-model="state.queryParams.AcceptType" placeholder="受理类型名称" clearable @keyup.enter="handleQuery" />
+			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent>
+				<el-row :gutter="10">
+					<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
+						<el-form-item label="工单标题" prop="Title">
+							<el-input v-model="state.queryParams.Title" placeholder="工单标题" clearable @keyup.enter="handleQuery" />
 						</el-form-item>
 					</el-col>
-				</transition>
-				<transition name="el-zoom-in-top">
-					<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol">
-						<el-form-item label="来源渠道" prop="SourceChannel">
-							<el-input v-model="state.queryParams.SourceChannel" placeholder="来源渠道名称" clearable @keyup.enter="handleQuery" />
+					<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
+						<el-form-item label="工单编码" prop="No">
+							<el-input v-model="state.queryParams.No" placeholder="工单编码" clearable @keyup.enter="handleQuery" />
 						</el-form-item>
 					</el-col>
-				</transition>
-				<transition name="el-zoom-in-top">
-					<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol">
-						<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="handleQuery"
-								value-format="YYYY-MM-DD[T]HH:mm:ss"
-								:default-time="defaultTimeStartEnd"
-							/>
+					<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
+						<el-form-item label="热点分类" prop="Hotspot">
+							<el-input v-model="state.queryParams.Hotspot" placeholder="热点分类名称" clearable @keyup.enter="handleQuery" />
 						</el-form-item>
 					</el-col>
-				</transition>
-				<transition name="el-zoom-in-top">
-					<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol">
-						<el-form-item label="办结时间" prop="bjTime">
-							<el-date-picker
-								v-model="state.queryParams.bjTime"
-								type="datetimerange"
-								unlink-panels
-								range-separator="至"
-								start-placeholder="开始时间"
-								end-placeholder="结束时间"
-								:shortcuts="shortcuts"
-								@change="handleQuery"
-								value-format="YYYY-MM-DD[T]HH:mm:ss"
-								:default-time="defaultTimeStartEnd"
-							/>
+					<transition name="el-zoom-in-top">
+						<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol">
+							<el-form-item label="受理类型" prop="AcceptType">
+								<el-input v-model="state.queryParams.AcceptType" placeholder="受理类型名称" clearable @keyup.enter="handleQuery" />
+							</el-form-item>
+						</el-col>
+					</transition>
+					<transition name="el-zoom-in-top">
+						<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol">
+							<el-form-item label="来源渠道" prop="SourceChannel">
+								<el-input v-model="state.queryParams.SourceChannel" placeholder="来源渠道名称" clearable @keyup.enter="handleQuery" />
+							</el-form-item>
+						</el-col>
+					</transition>
+					<transition name="el-zoom-in-top">
+						<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol">
+							<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="handleQuery"
+									value-format="YYYY-MM-DD[T]HH:mm:ss"
+									:default-time="defaultTimeStartEnd"
+								/>
+							</el-form-item>
+						</el-col>
+					</transition>
+					<transition name="el-zoom-in-top">
+						<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6" v-show="!searchCol">
+							<el-form-item label="办结时间" prop="bjTime">
+								<el-date-picker
+									v-model="state.queryParams.bjTime"
+									type="datetimerange"
+									unlink-panels
+									range-separator="至"
+									start-placeholder="开始时间"
+									end-placeholder="结束时间"
+									:shortcuts="shortcuts"
+									@change="handleQuery"
+									value-format="YYYY-MM-DD[T]HH:mm:ss"
+									:default-time="defaultTimeStartEnd"
+								/>
+							</el-form-item>
+						</el-col>
+					</transition>
+					<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
+						<el-form-item label=" ">
+							<div class="flex-end w100">
+								<el-button type="primary" @click="handleQuery" :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-button link type="primary" @click="closeSearch" :loading="state.loading">
+									{{ searchCol ? '展开' : '收起' }}
+									<SvgIcon :class="{ 'is-reverse': searchCol }" name="ele-ArrowUp" class="mr5 arrow" size="18px" />
+								</el-button>
+							</div>
 						</el-form-item>
 					</el-col>
-				</transition>
-				<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
-					<el-form-item label=" ">
-						<div class="flex-end w100">
-							<el-button type="primary" @click="handleQuery" :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-button link type="primary" @click="closeSearch" :loading="state.loading">
-								{{ searchCol ? '展开' : '收起' }}
-								<SvgIcon :class="{ 'is-reverse': searchCol }" name="ele-ArrowUp" class="mr5 arrow" size="18px" />
-							</el-button>
-						</div>
-					</el-form-item>
-				</el-col>
-			</el-row>
+				</el-row>
+			</el-form>
 		</el-card>
 		<el-card shadow="never">
 			<ProTable
@@ -99,18 +100,23 @@
 				:exportMethod="centerEmergencyListExport"
 				:exportParams="requestParams"
 			>
+				<template #title="{ row }">
+					<order-detail :order="row" @updateList="queryList">{{ row.title }}</order-detail>
+				</template>
 			</ProTable>
 		</el-card>
 	</div>
 </template>
 <script setup lang="tsx" name="statisticsCenterEmergencyList">
-import { onMounted, reactive, ref } from 'vue';
+import { onMounted, reactive, ref, defineAsyncComponent } from 'vue';
 import { FormInstance } from 'element-plus';
 import { centerEmergencyList, centerEmergencyListExport } from '@/api/statistics/center';
 import { defaultTimeStartEnd, shortcuts } from '@/utils/constants';
 import Other from '@/utils/other';
 import { formatDate } from '@/utils/formatTime';
 
+// 引入组件
+const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
 // 表格配置项
 const columns = ref<any[]>([
 	{ prop: 'no', label: '工单编码', minWidth: 140 },

+ 35 - 12
src/views/tels/callLog/component/Play-record.vue

@@ -41,29 +41,52 @@ const openDialog = async (url: any, recordingFileName, recordingPath, phone, tim
 	/*	dialogVisible.value = true;
 	emit('openDialog');*/
 
-	let popup = window.open('', '_blank', 'width=400,height=200');
+	let popup = window.open('', '_blank', 'left=100,top=100,width=400,height=200');
 	if (popup) {
 		popup.document.write(`
         <html>
           <head>
-            <title>自定义弹窗</title>
+            <title>播放录音</title>
             <style>
-              body {
-                font-family: Arial, sans-serif;
-                text-align: center;
-                padding: 20px;
+              body,html {
+               margin: 0;
+              padding: 0;
+              width: 100%;
+              height: 100%;
+              font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
+              font-weight: 400;
+              -webkit-font-smoothing: antialiased;
+              -webkit-tap-highlight-color: transparent;
+              background-color: var(--hotline-bg-main-color);
+              font-size: 14px;
+              overflow: hidden;
+              position: relative;
+              }
+              .play-content{
+                height: calc(100% - 40px);
+                padding:20px;
+                display: flex;
+                align-items: center;
+                justify-content: center;
+                flex-direction: column;
+              }
+              h2{
+                margin:0;
+                padding:0;
               }
               .audio-player {
-                margin-top: 20px;
+                   margin-top: 20px;
               }
             </style>
           </head>
           <body>
-            <h2>播放录音</h2>
-            <audio controls class="audio-player">
-              <source src="${url}" type="audio/wav">
-              Your browser does not support the audio element.
-            </audio>
+             <div class="play-content">
+               <h2>播放录音</h2>
+                <audio controls class="audio-player">
+                  <source src="${url}" type="audio/wav">
+                  您的浏览器不支持音频组件
+                </audio>
+              </div>
           </body>
         </html>
       `);

+ 39 - 26
src/views/todo/seats/accept/ybAccept.vue

@@ -479,14 +479,17 @@
 								</el-col>
 								<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
 									<el-form-item label="附件" prop="files" :rules="[{ required: false, message: '请填写诉求内容', trigger: 'change' }]">
-										<annex-list :businessId="state.orderId" classify="受理上传" v-model="state.ruleForm.files" v-model:format="filesFormat" />
+										<annex-list :businessId="state.ruleForm.id" classify="受理上传" v-model="state.ruleForm.files" v-model:format="filesFormat" />
 									</el-form-item>
 								</el-col>
 								<el-col :xs="24" :sm="12" :md="24" :lg="24" :xl="24">
 									<el-form-item>
 										<el-button class="default-button" @click="onCancel"> 取消 </el-button>
-										<el-button class="default-button" @click="save(ruleFormRef)" :loading="buttonLoading"> 保存 </el-button>
-										<el-button type="primary" @click="submit(ruleFormRef)" :loading="buttonLoading" v-if="canHandle"> 办理 </el-button>
+										<el-button class="default-button" @click="save(ruleFormRef)" :loading="buttonLoading" :disabled="isSaveSuccess"> 保存 </el-button>
+										<el-button type="primary" @click="submit(ruleFormRef)" :loading="buttonLoading" v-if="canHandle" :disabled="!isSaveSuccess">
+											办理
+										</el-button>
+                    <el-text class="ml12" type="danger" tag="b">注意:工单内容填写或者修改后请先保存再办理;</el-text>
 									</el-form-item>
 								</el-col>
 							</el-row>
@@ -502,7 +505,7 @@
 							<el-tab-pane label="历史工单" name="history">
 								<history-order
 									:ruleForm="state.ruleForm"
-									:orderId="state.orderId"
+									:orderId="state.ruleForm.id"
 									@handleSelectionChange="handleSelectionChange"
 									ref="historyOrderRef"
 								/>
@@ -559,13 +562,14 @@ import mittBus from '@/utils/mitt';
 import { orderRepeatEvent } from '@/api/business/repeatEvent';
 import { removeDuplicate } from '@/utils/arrayOperation';
 import { Session } from '@/utils/storage';
+import { watchPausable } from '@vueuse/core';
 
 // 引入组件
 const VoiceAssistant = defineAsyncComponent(() => import('@/views/todo/seats/accept/Voice-assistant.vue')); // 语音助手
 const Knowledge = defineAsyncComponent(() => import('@/views/todo/seats/accept/Knowledge.vue')); // 知识库
 const HistoryOrder = defineAsyncComponent(() => import('@/views/todo/seats/accept/History.vue')); // 历史工单
 const RepeatEvent = defineAsyncComponent(() => import('@/views/todo/seats/accept/Repeat-event.vue')); // 重复事件
-const CitizenPortrait = defineAsyncComponent(() => import('@/views/todo/seats/accept/Citizen-portrait.vue')); // 市民画像
+const CitizenPortrait = defineAsyncComponent(() => import('@/views/todo/seats/accept/Citizen-portrait.vue')); // 市民画像
 const ExpandForm = defineAsyncComponent(() => import('@/views/todo/seats/accept/Expand-form.vue')); // 拓展表单
 const OrderHistory = defineAsyncComponent(() => import('@/views/business/order/components/Order-history.vue')); // 历史工单弹窗列表
 const CommonAdvice = defineAsyncComponent(() => import('@/components/CommonAdvice/index.vue')); // 常用意见
@@ -629,6 +633,7 @@ const state = reactive<any>({
 		isFormalistWorkOrder: false, // 是否形式主义工单
 		isSensitiveWorkOrders: false, // 是否敏感类工单
 		isUrgent: false, // 是否紧急工单
+		id: null,
 	},
 	formLoading: false, // 表单加载状态
 	hotspotExternal: [], // 热点分类外部数据
@@ -654,7 +659,6 @@ const state = reactive<any>({
 		},
 	],
 	focusOnEvents: [], // 重点关注事项
-	orderId: null, // 工单id
 	tagsViewList: [],
 });
 const useTelStatusStore = useTelStatus(); // 来电弹屏
@@ -963,7 +967,27 @@ const shouldOpenDialog = (obj: any) =>
 	obj.orderExtension.orderTypeCode &&
 	['scjgjts,scjgjjb'].includes(obj.orderExtension.orderTypeCode);
 
+// 检测表单数据是否有变化
+const watchPauseAbleFn = watchPausable(
+	state.ruleForm,
+	() => {
+		isSaveSuccess.value = false; // 工单编辑后重新展示保存按钮
+	},
+	{ deep: true }
+);
+watchPauseAbleFn.pause();
+// 是否可以办理(如果有流程id 并且当前账号可以办理 则可以办理 没有流程ID都可以办理)
+const canHandle = computed(() => {
+	if (!state.ruleForm?.workflowId) {
+		// 没有流程ID表示发起流程
+		return true;
+	} else {
+		// 有流程ID表示已经发起流程 判断当前账号是否可以办理
+		return state.ruleForm?.canHandle;
+	}
+});
 const buttonLoading = ref<boolean>(false);
+const isSaveSuccess = ref<boolean>(false); // 是否保存成功 保存成功后才展示办理按钮
 // 保存
 const save = throttle((formEl: FormInstance | undefined) => {
 	if (!formEl) return;
@@ -976,13 +1000,17 @@ const save = throttle((formEl: FormInstance | undefined) => {
 			files: filesFormat.value,
 		};
 		deleteUnnecessaryProperties(orderDetail);
-		const operation = state.orderId ? orderEdit : orderAdd;
+		const operation = state.ruleForm.id ? orderEdit : orderAdd;
 		const addOrderAndNavigate = () => {
 			operation(orderDetail)
-				.then(() => {
+				.then((res: any) => {
 					buttonLoading.value = false;
-					ElMessage.success('操作成功');
-					onCancel();
+					ElMessage.success('保存成功');
+					if (res.result) state.ruleForm.id = res.result;
+					isSaveSuccess.value = true;
+					setTimeout(() => {
+						watchPauseAbleFn.resume();
+					}, 300);
 				})
 				.catch(() => {
 					buttonLoading.value = false;
@@ -1003,16 +1031,6 @@ const selectIdentity = (val: number) => {
 		state.ruleForm.pushTypeCode = state.ruleForm.pushTypeObj.dicDataValue;
 	}
 };
-// 是否可以办理(如果有流程id 并且当前账号可以办理 则可以办理 没有流程ID都可以办理)
-const canHandle = computed(() => {
-	if (!state.ruleForm?.workflowId) {
-		// 没有流程ID表示发起流程
-		return true;
-	} else {
-		// 有流程ID表示已经发起流程 判断当前账号是否可以办理
-		return state.ruleForm?.canHandle;
-	}
-});
 // 流程审批
 const processAuditRef = ref<RefType>();
 const processOrder = (orderDetail: any) => {
@@ -1035,7 +1053,7 @@ const processOrder = (orderDetail: any) => {
 	} else {
 		// 如果没有流程id 说明没有发起过流程  调用工单受理
 		const params = {
-			id: state.orderId,
+			id: state.ruleForm.id,
 			processType: '工单受理',
 			extra: {
 				dialogTitle: '工单受理',
@@ -1059,10 +1077,6 @@ const handleForm = (orderDetail: any) => {
 		processOrder(orderDetail);
 	}
 };
-// 检测表单数据是否有变化
-watch(state.ruleForm, (newValue) => {
-  console.log('Form data changed:', newValue);
-}, { deep: true });
 // 提交
 const submit = throttle((formEl: FormInstance | undefined) => {
 	if (!formEl) return;
@@ -1169,7 +1183,6 @@ const loadForm = async () => {
 
 		if (route.query.id) {
 			// 如果 有id
-			state.orderId = route.query.id;
 			const response = await orderDetail(route.query.id);
 			// 如果获取到id 调用查询详情
 			state.ruleForm = response.result;

+ 21 - 51
src/views/todo/seats/accept/zgAccept.vue

@@ -426,8 +426,11 @@
                 <el-col :xs="24" :sm="12" :md="24" :lg="24" :xl="24">
                   <el-form-item>
                     <el-button class="default-button" @click="onCancel"> 取消 </el-button>
-                    <el-button class="default-button" @click="save(ruleFormRef)" :loading="buttonLoading"> 保存 </el-button>
-                    <el-button type="primary" @click="submit(ruleFormRef)" :loading="buttonLoading" v-if="canHandle"> 办理 </el-button>
+                    <el-button class="default-button" @click="save(ruleFormRef)" :loading="buttonLoading" :disabled="isSaveSuccess"> 保存 </el-button>
+                    <el-button type="primary" @click="submit(ruleFormRef)" :loading="buttonLoading" v-if="canHandle" :disabled="!isSaveSuccess">
+                      办理
+                    </el-button>
+                    <el-text class="ml12" type="danger" tag="b">注意:工单内容填写或者修改后请先保存再办理;</el-text>
                   </el-form-item>
                 </el-col>
               </el-row>
@@ -477,8 +480,6 @@
     <process-audit ref="processAuditRef" @orderProcessSuccess="onCancel" />
     <!-- 地图选点 -->
     <map-dialog ref="mapDialogRef" @confirm="selectMap" />
-    <!-- 企业搜索 -->
-    <company-search ref="companySearchRef" @selectCompany="selectCompany" />
   </div>
 </template>
 
@@ -487,7 +488,7 @@ import { computed, defineAsyncComponent, onMounted, reactive, ref, watch } from
 import type { FormInstance } from 'element-plus';
 import { ElMessage, ElMessageBox, ElNotification } from 'element-plus';
 import { storeToRefs } from 'pinia';
-import { useRoute, useRouter } from 'vue-router';
+import { useRoute } from 'vue-router';
 import { useTelStatus } from '@/stores/telStatus';
 import { useAppConfig } from '@/stores/appConfig';
 import { throttle, transformFile } from '@/utils/tools';
@@ -500,20 +501,19 @@ import mittBus from '@/utils/mitt';
 import { orderRepeatEvent } from '@/api/business/repeatEvent';
 import { removeDuplicate } from '@/utils/arrayOperation';
 import { Session } from '@/utils/storage';
+import {watchPausable} from "@vueuse/core";
 
 // 引入组件
 const Knowledge = defineAsyncComponent(() => import('@/views/todo/seats/accept/Knowledge.vue')); // 知识库
 const HistoryOrder = defineAsyncComponent(() => import('@/views/todo/seats/accept/History.vue')); // 历史工单
 const RepeatEvent = defineAsyncComponent(() => import('@/views/todo/seats/accept/Repeat-event.vue')); // 重复事件
-const CitizenPortrait = defineAsyncComponent(() => import('@/views/todo/seats/accept/Citizen-portrait.vue')); // 市民画像
+const CitizenPortrait = defineAsyncComponent(() => import('@/views/todo/seats/accept/Citizen-portrait.vue')); // 市民画像
 const ExpandForm = defineAsyncComponent(() => import('@/views/todo/seats/accept/Expand-form.vue')); // 拓展表单
 const OrderHistory = defineAsyncComponent(() => import('@/views/business/order/components/Order-history.vue')); // 历史工单弹窗列表
 const CommonAdvice = defineAsyncComponent(() => import('@/components/CommonAdvice/index.vue')); // 常用意见
 const AnnexList = defineAsyncComponent(() => import('@/components/AnnexList/index.vue')); // 附件列表
 const ProcessAudit = defineAsyncComponent(() => import('@/components/ProcessAudit/index.vue')); // 流程审批
 const MapDialog = defineAsyncComponent(() => import('@/views/todo/seats/accept/Map-Dialog.vue')); // 地图定位
-const CompanySearch = defineAsyncComponent(() => import('@/views/todo/seats/accept/Company-search.vue')); // 企业搜索
-const EventSelect = defineAsyncComponent(() => import('@/components/Hotspot/event.vue')); // 选择事件
 const HotSpotSelect = defineAsyncComponent(() => import('@/components/Hotspot/index.vue')); // 选择热点
 // 定义变量内容
 const { cityName, cityCode } = getCurrentCityConfig();
@@ -603,36 +603,6 @@ const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 state.ruleForm.acceptorName = userInfos.value.name; // 员工姓名
 state.ruleForm.acceptorStaffNo = userInfos.value.staffNo; // 员工工号
 const route = useRoute(); // 路由
-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 handleSelect = () => {
-  companySearchRef.value.openDialog();
-};
-// 选择企业
-const selectCompany = (row: any) => {
-  state.ruleForm.enterpriseName = row.enterpriseName;
-  state.ruleForm.enterpriseCode = row.enterpriseCode;
-  state.ruleForm.zhuanBanMingCheng = row.specialTeamName;
-  state.ruleForm.zhuanBanCode = row.specialTeamCode;
-};
 // 证件号码验证
 const licenceNoPattern = computed(() => {
   switch (state.ruleForm.licenceTypeCode) {
@@ -642,12 +612,6 @@ const licenceNoPattern = computed(() => {
       return /^[A-Za-z0-9]+$/;
   }
 });
-// 选择事件分类
-const chooseEvent = (val: any, node: any, externalArr: any) => {
-  state.ruleForm.eventCategoryName = val?.eventName; // 事件分类名称
-  state.ruleForm.eventCategorySpliceName = val?.eventFullName; // 事件分类拼接名称
-  state.ruleForm.eventCategoryExternal = externalArr?.join(',') ?? ''; // 事件分类id
-};
 // 选择热点分类
 const knowledgeRef = ref<RefType>();
 const chooseHotSpot = (val: any, node: any, externalArr: any) => {
@@ -901,6 +865,12 @@ const shouldOpenDialog = (obj: any) =>
     ['scjgjts,scjgjjb'].includes(obj.orderExtension.orderTypeCode);
 
 const buttonLoading = ref<boolean>(false);
+const isSaveSuccess = ref<boolean>(false); // 是否保存成功 保存成功后才展示办理按钮
+// 检测表单数据是否有变化
+const watchPauseAbleFn =  watchPausable(state.ruleForm, () => {
+  isSaveSuccess.value = false; // 工单编辑后重新展示保存按钮
+}, { deep: true });
+watchPauseAbleFn.pause();
 // 保存
 const save = throttle((formEl: FormInstance | undefined) => {
   if (!formEl) return;
@@ -916,10 +886,14 @@ const save = throttle((formEl: FormInstance | undefined) => {
     const operation = state.orderId ? orderEdit : orderAdd;
     const addOrderAndNavigate = () => {
       operation(orderDetail)
-          .then(() => {
+          .then((res:any) => {
             buttonLoading.value = false;
-            ElMessage.success('操作成功');
-            onCancel();
+            ElMessage.success('保存成功');
+            if(res.result) state.ruleForm.id = res.result;
+            isSaveSuccess.value = true;
+            setTimeout(()=>{
+              watchPauseAbleFn.resume();
+            },300)
           })
           .catch(() => {
             buttonLoading.value = false;
@@ -996,10 +970,6 @@ const handleForm = (orderDetail: any) => {
     processOrder(orderDetail);
   }
 };
-// 检测表单数据是否有变化
-watch(state.ruleForm, (newValue) => {
-  console.log('Form data changed:', newValue);
-}, { deep: true });
 // 提交
 const submit = throttle((formEl: FormInstance | undefined) => {
   if (!formEl) return;