Jelajahi Sumber

feat:工单受理新增地图选点,重复性事件,市民画像;
reactor:工单受理调整(知识库,重复性事件,历史工单,市民画像)重构拆分为组件;

zhangchong 1 tahun lalu
induk
melakukan
467dbae1ac

+ 6 - 0
.env.development

@@ -19,6 +19,12 @@ VITE_API_UPLOAD_URL=http://110.188.24.28:50100/hubs/hotline
 # #上传 API
 VITE_SOCKET_GROUP_NAME=http://110.188.24.28:50100/hubs/hotline
 
+# #高德地图安全密钥
+VITE_AMAP_SECURITYJSCODE=dd12ddafb11921dbcdc5b9c4484bb4e2
+
+# #高德地图KEY
+VITE_AMAP_KEY=83f51df235e4008e4eaf515cff63785c
+
 # # 维尔信websocket地址
 VITE_WEX_SOCKET_URL=ws://222.212.82.225:1003
 

+ 6 - 0
.env.production

@@ -19,6 +19,12 @@ VITE_API_UPLOAD_URL=http://110.188.24.28:50100/hubs/hotline
 # #上传 API
 VITE_SOCKET_GROUP_NAME=http://110.188.24.28:50100/hubs/hotline
 
+# #高德地图安全密钥
+VITE_AMAP_SECURITYJSCODE=dd12ddafb11921dbcdc5b9c4484bb4e2
+
+# #高德地图KEY
+VITE_AMAP_KEY=83f51df235e4008e4eaf515cff63785c
+
 # # 维尔信websocket地址
 VITE_WEX_SOCKET_URL=ws://222.212.82.225:1003
 

+ 6 - 0
.env.test

@@ -18,6 +18,12 @@ VITE_API_UPLOAD_URL=http://110.188.24.28:50100/hubs/hotline
 # #上传 API
 VITE_SOCKET_GROUP_NAME=http://110.188.24.28:50100/hubs/hotline
 
+# #高德地图安全密钥
+VITE_AMAP_SECURITYJSCODE=dd12ddafb11921dbcdc5b9c4484bb4e2
+
+# #高德地图KEY
+VITE_AMAP_KEY=83f51df235e4008e4eaf515cff63785c
+
 # # 维尔信websocket地址
 VITE_WEX_SOCKET_URL=ws://222.212.82.225:1003
 

+ 11 - 0
package-lock.json

@@ -9,6 +9,7 @@
 			"version": "1.0.0",
 			"license": "MIT",
 			"dependencies": {
+				"@amap/amap-jsapi-loader": "^1.0.1",
 				"@element-plus/icons-vue": "^2.0.10",
 				"@logicflow/core": "^1.1.31",
 				"@logicflow/extension": "^1.1.31",
@@ -66,6 +67,11 @@
 				"npm": ">= 6.0.0"
 			}
 		},
+		"node_modules/@amap/amap-jsapi-loader": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmmirror.com/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz",
+			"integrity": "sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw=="
+		},
 		"node_modules/@babel/parser": {
 			"version": "7.22.7",
 			"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.22.7.tgz",
@@ -4213,6 +4219,11 @@
 		}
 	},
 	"dependencies": {
+		"@amap/amap-jsapi-loader": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmmirror.com/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz",
+			"integrity": "sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw=="
+		},
 		"@babel/parser": {
 			"version": "7.22.7",
 			"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.22.7.tgz",

+ 1 - 0
package.json

@@ -13,6 +13,7 @@
 		"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/"
 	},
 	"dependencies": {
+		"@amap/amap-jsapi-loader": "^1.0.1",
 		"@element-plus/icons-vue": "^2.0.10",
 		"@logicflow/core": "^1.1.31",
 		"@logicflow/extension": "^1.1.31",

+ 9 - 7
src/App.vue

@@ -60,19 +60,21 @@ const openSetingsDrawer = () => {
 	setingsRef.value.openDrawer();
 };
 // 设置初始化,防止刷新时恢复默认
-onBeforeMount(() => {
+onBeforeMount( async() => {
+  if(!themeConfig.value.loginImage) {
+    // 获取登录页的背景图和系统名称等
+    const res: any = await loginPageInfo();
+    const globalTitle = res.result.sysName.join('|') ?? ''; // 标题名称
+    const  loginImage = res.result.loginImage ? `url${res.result.loginImage}` : `url(${getImageUrl('login/bg.png')})`; // 登录页背景图
+    storesThemeConfig.setThemeConfig(Object.assign(themeConfig.value, { globalTitle, loginImage }));
+  }
 	// 设置批量第三方 icon 图标
 	setIntroduction.cssCdn();
 	// 设置批量第三方 js
 	setIntroduction.jsCdn();
 });
 // 页面加载时
-onMounted( async() => {
-  // 获取登录页的背景图和系统名称等
-  const res: any = await loginPageInfo();
-  const globalTitle = res.result.sysName.join('|') ?? ''; // 标题名称
-  const  loginImage = res.result.loginImage ? `url${res.result.loginImage}` : `url(${getImageUrl('login/bg.png')})`; // 登录页背景图
-  storesThemeConfig.setThemeConfig(Object.assign(themeConfig.value, { globalTitle, loginImage }));
+onMounted( () => {
 	nextTick(async () => {
     try {
       // 获取缓存中的布局配置

+ 0 - 124
src/directive/customDirective.ts

@@ -53,130 +53,6 @@ export function wavesDirective(app: App) {
 		},
 	});
 }
-
-/**
- * 自定义拖动指令
- * @description  使用方式:v-drag="[dragDom,dragHeader]",如 `<div v-drag="['.drag-container .el-dialog', '.drag-container .el-dialog__header']"></div>`
- * @description dragDom 要拖动的元素,dragHeader 要拖动的 Header 位置
- * @link 注意:https://github.com/element-plus/element-plus/issues/522
- * @lick 参考:https://blog.csdn.net/weixin_46391323/article/details/105228020?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-10&spm=1001.2101.3001.4242
- */
-export function dragDirective(app: App) {
-	app.directive('drag', {
-		mounted(el, binding) {
-			if (!binding.value) return false;
-
-			const dragDom = document.querySelector(binding.value[0]) as HTMLElement;
-			const dragHeader = document.querySelector(binding.value[1]) as HTMLElement;
-
-			dragHeader.onmouseover = () => (dragHeader.style.cursor = `move`);
-
-			function down(e: any, type: string) {
-				// 鼠标按下,计算当前元素距离可视区的距离
-				const disX = type === 'pc' ? e.clientX - dragHeader.offsetLeft : e.touches[0].clientX - dragHeader.offsetLeft;
-				const disY = type === 'pc' ? e.clientY - dragHeader.offsetTop : e.touches[0].clientY - dragHeader.offsetTop;
-
-				// body当前宽度
-				const screenWidth = document.body.clientWidth;
-				// 可见区域高度(应为body高度,可某些环境下无法获取)
-				const screenHeight = document.documentElement.clientHeight;
-
-				// 对话框宽度
-				const dragDomWidth = dragDom.offsetWidth;
-				// 对话框高度
-				const dragDomHeight = dragDom.offsetHeight;
-
-				const minDragDomLeft = dragDom.offsetLeft;
-				const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;
-
-				const minDragDomTop = dragDom.offsetTop;
-				const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight;
-
-				// 获取到的值带px 正则匹配替换
-				let styL: any = getComputedStyle(dragDom).left;
-				let styT: any = getComputedStyle(dragDom).top;
-
-				// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
-				if (styL.includes('%')) {
-					styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100);
-					styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100);
-				} else {
-					styL = +styL.replace(/\px/g, '');
-					styT = +styT.replace(/\px/g, '');
-				}
-
-				return {
-					disX,
-					disY,
-					minDragDomLeft,
-					maxDragDomLeft,
-					minDragDomTop,
-					maxDragDomTop,
-					styL,
-					styT,
-				};
-			}
-
-			function move(e: any, type: string, obj: any) {
-				let { disX, disY, minDragDomLeft, maxDragDomLeft, minDragDomTop, maxDragDomTop, styL, styT } = obj;
-
-				// 通过事件委托,计算移动的距离
-				let left = type === 'pc' ? e.clientX - disX : e.touches[0].clientX - disX;
-				let top = type === 'pc' ? e.clientY - disY : e.touches[0].clientY - disY;
-
-				// 边界处理
-				if (-left > minDragDomLeft) {
-					left = -minDragDomLeft;
-				} else if (left > maxDragDomLeft) {
-					left = maxDragDomLeft;
-				}
-
-				if (-top > minDragDomTop) {
-					top = -minDragDomTop;
-				} else if (top > maxDragDomTop) {
-					top = maxDragDomTop;
-				}
-
-				// 移动当前元素
-				dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
-			}
-
-			/**
-			 * pc端
-			 * onmousedown 鼠标按下触发事件
-			 * onmousemove 鼠标按下时持续触发事件
-			 * onmouseup 鼠标抬起触发事件
-			 */
-			dragHeader.onmousedown = (e) => {
-				const obj = down(e, 'pc');
-				document.onmousemove = (e) => {
-					move(e, 'pc', obj);
-				};
-				document.onmouseup = () => {
-					document.onmousemove = null;
-					document.onmouseup = null;
-				};
-			};
-
-			/**
-			 * 移动端
-			 * ontouchstart 当按下手指时,触发ontouchstart
-			 * ontouchmove 当移动手指时,触发ontouchmove
-			 * ontouchend 当移走手指时,触发ontouchend
-			 */
-			dragHeader.ontouchstart = (e) => {
-				const obj = down(e, 'app');
-				document.ontouchmove = (e) => {
-					move(e, 'app', obj);
-				};
-				document.ontouchend = () => {
-					document.ontouchmove = null;
-					document.ontouchend = null;
-				};
-			};
-		},
-	});
-}
 export function lazyImgDirective(app: App) {
     // 图片懒加载指令
     app.directive('lazy', {

+ 0 - 2
src/directive/index.ts

@@ -14,8 +14,6 @@ export function directive(app: App) {
 	authDirective(app);
 	// 按钮波浪指令
 	wavesDirective(app);
-	// 自定义拖动指令
-	dragDirective(app);
 	// 图片懒加载指令
 	lazyImgDirective(app)
 }

+ 2 - 2
src/layout/navBars/breadcrumb/setings.vue

@@ -261,12 +261,12 @@
 						</el-switch>
 					</div>
 				</div>
-				<!-- <div class="layout-breadcrumb-seting-bar-flex mt15">
+				 <div class="layout-breadcrumb-seting-bar-flex mt15">
 					<div class="layout-breadcrumb-seting-bar-flex-label">开启水印</div>
 					<div class="layout-breadcrumb-seting-bar-flex-value">
 						<el-switch v-model="getThemeConfig.isWatermark" size="small" @change="onWatermarkChange"></el-switch>
 					</div>
-				</div> -->
+				</div>
 				<!-- <div class="layout-breadcrumb-seting-bar-flex mt14">
 					<div class="layout-breadcrumb-seting-bar-flex-label">水印文案</div>
 					<div class="layout-breadcrumb-seting-bar-flex-value">

+ 1 - 1
src/stores/themeConfig.ts

@@ -138,7 +138,7 @@ export const useThemeConfig = defineStore('themeConfig', {
 			// 默认全局组件大小,可选值"<large|'default'|small>",默认 'default'
 			globalComponentSize: 'default',
 			// 登录页面背景图
-			loginImage: `url(${getImageUrl('login/bg.png')})`
+			loginImage: ``
 		},
 	}),
 	actions: {

+ 164 - 0
src/views/business/order/accept/Citizen-portrait.vue

@@ -0,0 +1,164 @@
+<template>
+	<div class="order-accept-citizen-portrait">
+		<el-row :gutter="20">
+			<el-col :xs="24" :sm="24" :md="24" :lg="8" :xl="8">
+				<el-card shadow="never">
+					<p class="border-title mb10">基本信息</p>
+					<div class="info-form">
+						<p class="form-item">
+							<span class="form-label">来电电话</span>
+							{{ formData.phoneNo }}
+						</p>
+						<p class="form-item">
+							<span class="form-label">姓名</span>
+							{{ formData.phoneNo }}
+						</p>
+						<p class="form-item">
+							<span class="form-label">首次来电</span>
+							{{ formData.phoneNo }}
+						</p>
+						<p class="form-item">
+							<span class="form-label">上次来电</span>
+							{{ formData.phoneNo }}
+						</p>
+					</div>
+				</el-card>
+				<el-card shadow="never" class="mt20">
+					<p class="border-title mb10">工单历史</p>
+					<div class="info-form">
+						<p class="form-item">
+							<span class="form-label">全部工单</span>
+							{{ formData.phoneNo }}
+						</p>
+						<p class="form-item">
+							<span class="form-label">已办工单</span>
+							{{ formData.phoneNo }}
+						</p>
+						<p class="form-item">
+							<span class="form-label">在办工单</span>
+							{{ formData.phoneNo }}
+						</p>
+						<p class="form-item">
+							<span class="form-label">不满意工单</span>
+							{{ formData.phoneNo }}
+						</p>
+					</div>
+				</el-card>
+			</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="'https://cdn.pixabay.com/photo/2016/11/18/23/38/child-1837375_1280.png'" alt="">
+          </div>
+				</el-card>
+			</el-col>
+			<el-col :xs="24" :sm="24" :md="24" :lg="8" :xl="8">
+				<el-card shadow="never">
+					<p class="border-title mb10">来电历史</p>
+					<div class="info-form">
+						<p class="form-item">
+							<span class="form-label">来电次数</span>
+							{{ formData.phoneNo }}
+						</p>
+						<p class="form-item">
+							<span class="form-label">接通次数</span>
+							{{ formData.phoneNo }}
+						</p>
+						<p class="form-item">
+							<span class="form-label">回拨次数</span>
+							{{ formData.phoneNo }}
+						</p>
+					</div>
+				</el-card>
+				<el-card shadow="never" class="mt20">
+					<p class="border-title mb10">关注诉求</p>
+					<div class="tag-list">
+						<el-tag v-for="tag in formData.tags" effect="dark" :key="tag">{{ tag }}</el-tag>
+					</div>
+				</el-card>
+			</el-col>
+			<el-col :span="24" class="mt20">
+				<el-card shadow="never">
+					<p class="border-title mb10">市民标签</p>
+          <div class="tag-list">
+            <el-tag v-for="tag in formData.tags" effect="dark" :key="tag">{{ tag }}</el-tag>
+          </div>
+          <div class="flex-center-align mt20">
+            <el-input v-model="input" placeholder="请输入标签内容" clearable show-word-limit maxlength="20" @keyup.enter="addTag"/>
+            <el-button type="primary" @click="addTag" class="ml10">添加标签</el-button>
+          </div>
+				</el-card>
+			</el-col>
+		</el-row>
+	</div>
+</template>
+<script setup lang="ts" name="orderAcceptCitizenPortrait">
+import {reactive, ref} from 'vue';
+import {ElMessage} from "element-plus";
+
+const formData = reactive({
+	phoneNo: '12345678901',
+	tags: [
+		'城市管理',
+		'工地噪音',
+		'市政供电',
+		'网络游戏违法信息',
+    '市政供电/临时电'
+	],
+});
+const input = ref('');
+const addTag = () => {
+  if(!input.value){
+    ElMessage.warning('请输入标签内容');
+    return;
+  }
+  if(input.value){
+    formData.tags.push(input.value);
+    input.value = '';
+  }
+};
+</script>
+
+<style scoped lang="scss">
+.order-accept-citizen-portrait {
+	.el-card {
+		background-color: var(--el-color-info-light-9);
+		.info-form {
+			.form-item {
+				display: flex;
+				align-items: center;
+				margin-bottom: 10px;
+				text-align: left;
+				.form-label {
+					width: 70px;
+					text-align: right;
+					margin-right: 10px;
+				}
+				&:last-child {
+					margin-bottom: 0;
+				}
+			}
+		}
+    .citizen-title{
+      font-size: 16px;
+      font-weight: bold;
+      text-align: center;
+    }
+    .citizen-img-box{
+      img{
+        width: 100%;
+      }
+    }
+    .tag-list{
+      margin-top: 20px;
+      .el-tag{
+        margin:0 10px 10px 0;
+        &:last-child{
+          margin:0 0 10px 0;
+        }
+      }
+    }
+	}
+}
+</style>

+ 210 - 0
src/views/business/order/accept/History.vue

@@ -0,0 +1,210 @@
+<template>
+  <el-form :model="state.queryParams" ref="queryParamsRef" :inline="true" @submit.native.prevent>
+    <el-form-item label="关键词" prop="Keyword">
+      <el-input v-model="state.queryParams.Keyword" placeholder="工单标题/工单编码" clearable @keyup.enter="handleQuery" />
+    </el-form-item>
+    <el-form-item>
+      <el-button type="primary" @click="handleQuery" :loading="state.loading">
+        <SvgIcon name="ele-Search" class="mr5" />查询
+      </el-button>
+      <el-button @click="resetQuery(queryParamsRef)" :loading="state.loading" class="default-button">
+        <SvgIcon name="ele-Refresh" class="mr5" />重置
+      </el-button>
+    </el-form-item>
+  </el-form>
+  <el-table
+      :data="state.tableData"
+      v-loading="state.loading"
+      row-key="id"
+      @selection-change="handleSelectionChange"
+      max-height="300"
+      ref="multipleTableRef"
+  >
+    <el-table-column type="selection" label="重复件" width="80" :reserve-selection="true" v-if="props.formData.isRepeat === 'true'" />
+    <el-table-column prop="phoneNo" label="工单标题" show-overflow-tooltip width="180">
+      <template #default="{ row }">
+        {{ row.title }}
+      </template>
+    </el-table-column>
+    <el-table-column prop="hotspotName" label="热点分类" show-overflow-tooltip> </el-table-column>
+    <el-table-column prop="no" label="工单编码" show-overflow-tooltip> </el-table-column>
+    <el-table-column prop="currentStepName" label="当前环节" show-overflow-tooltip></el-table-column>
+    <el-table-column prop="statusText" label="状态" width="70" fixed="right" align="center"></el-table-column>
+    <el-table-column prop="statusText" label="操作" width="170" fixed="right" align="center">
+      <template #default="{ row }">
+        <el-button @click="onSupply(row)" link type="primary" v-auth="'business:order:supply'"> 补充 </el-button>
+        <el-button @click="onRevoke(row)" link type="primary" v-auth="'business:order:revoke'"> 撤销 </el-button>
+        <el-button @click="onSupervise(row)" link type="primary"> 督办 </el-button>
+      </template>
+    </el-table-column>
+  </el-table>
+  <pagination
+      :total="state.total"
+      v-model:page="state.queryParams.PageIndex"
+      v-model:limit="state.queryParams.PageSize"
+      @pagination="searchHistory"
+  />
+  <!-- 补充信息 -->
+  <order-supply ref="SupplyRef" @onSupplySuccess="onSupplySuccess" />
+  <!-- 工单撤销 -->
+  <order-revoke ref="orderRevokeRef" @onRevokeSuccess="onRevokeSuccess" />
+  <!-- 工单督办 -->
+  <order-super-vise ref="orderSuperviseRef" @onSuperviseSuccess="onSuperviseSuccess" />
+</template>
+<script setup lang="ts" name="orderAcceptHistory">
+import {reactive, ref, defineAsyncComponent, onMounted, watch} from "vue";
+import {ElMessage, FormInstance} from "element-plus";
+import {throttle} from "/@/utils/tools";
+import {auth} from "/@/utils/authFunction";
+import {historyOrder} from "/@/api/business/order";
+import {useRoute} from "vue-router";
+
+const OrderSuperVise = defineAsyncComponent(() => import('/@/views/business/supervise/components/Order-supervise.vue')); // 工单督办
+const OrderSupply = defineAsyncComponent(() => import('/@/views/business/order/components/Order-supply.vue')); // 补充信息
+const OrderRevoke = defineAsyncComponent(() => import('/@/views/business/order/components/Order-revoke.vue')); // 工单撤销
+const props = defineProps({
+  orderId: {
+    type: String,
+    default: '',
+  },
+  formData:{ // 表单填写的数据
+    type: Object,
+    default: () => {
+      return {};
+    },
+  }
+});
+const emit = defineEmits(['handleSelectionChange']);
+const state = reactive<any>({
+  tableData: [], // 历史工单
+  total: 0, // 历史工单总条数
+  queryParams: {
+    PageIndex: 1, // 当前页
+    PageSize: 10, // 每页条数
+    Keyword: '', // 关键字
+  },
+  loading:false,
+})
+const queryParamsRef = ref<RefType>(); // 历史工单查询参数
+const multipleSelection = ref<any[]>([]); // 重复件表格选中项
+const multipleTableRef = ref<RefType>(); // 重复件表格ref
+/** 搜索按钮操作 */
+const handleQuery = throttle(() => {
+  state.queryParams.PageIndex = 1;
+  searchHistory();
+}, 500);
+/** 重置按钮操作 */
+const resetQuery = throttle((formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+  handleQuery();
+}, 300);
+watch(()=>props.formData,(val)=>{
+  if(val.id){
+    searchHistory(props.formData);
+  }
+})
+/** 获取历史工单 */
+const searchHistory = throttle(async (orderDetail?: any) => {
+  if (!auth('business:order:history')) ElMessage.error('抱歉,您没有权限查询历史工单!');
+  else {
+    state.loading = true;
+    let request = {
+      ...state.queryParams,
+      PhoneNo: props.formData.contact,
+      OrderId: props.orderId, //传入id 排除重复工单选择自己
+    };
+    try {
+      const response = await historyOrder(request);
+      state.tableData = response?.result.items ?? [];
+      state.total = response?.result.total;
+      state.loading = false;
+      if (orderDetail) {
+        if (orderDetail.duplicateIds && orderDetail.duplicateIds.length) {
+          multipleSelection.value = orderDetail.duplicateIds;
+          for (let i of multipleSelection.value) {
+            for (let j of state.tableData) {
+              if (i === j.id) {
+                setTimeout(() => {
+                  multipleTableRef.value!.toggleRowSelection(j, true);
+                }, 0);
+              }
+            }
+          }
+        }
+      }
+    } catch (error) {
+      state.loading = false;
+    }
+  }
+}, 300);
+// 右边表格选中重复件
+const handleSelectionChange = (row: any) => {
+  if (row && row.length) {
+    multipleSelection.value = row;
+  } else {
+    multipleSelection.value = [];
+  }
+  emit('handleSelectionChange', multipleSelection.value);
+};
+// 弹窗选择历史工单(保持选择一致)
+const dialogConfirmRepeat = (val:any)=>{
+  multipleSelection.value = val;
+  for (let i of multipleSelection.value) {
+    for (let j of state.tableData) {
+      if (i.id === j.id) {
+        setTimeout(() => {
+          multipleTableRef.value!.toggleRowSelection(j, true);
+        }, 0);
+      }
+    }
+  }
+}
+// 清除重复选择
+const clearRepeat=()=>{
+  multipleTableRef.value!.clearSelection();
+}
+// 补充信息
+const SupplyRef = ref<RefType>();
+const onSupply = (val: any) => {
+  SupplyRef.value.openDialog(val);
+};
+// 补充意见提交成功
+const onSupplySuccess = () => {
+  searchHistory();
+};
+// 撤销
+const orderRevokeRef = ref<RefType>();
+const onRevoke = (row: any) => {
+  orderRevokeRef.value.openDialog(row);
+};
+// 撤销提交成功
+const onRevokeSuccess = () => {
+  searchHistory();
+};
+// 督办
+const orderSuperviseRef = ref<RefType>(); // 工单督办
+const onSupervise = (row:any) => {
+  orderSuperviseRef.value.openDialog(row);
+};
+// 督办提交成功
+const onSuperviseSuccess = () => {
+  // 刷新列表
+  searchHistory();
+};
+const route = useRoute(); // 路由
+onMounted(()=>{
+
+})
+defineExpose({
+  multipleSelection,
+  multipleTableRef,
+  searchHistory,
+  dialogConfirmRepeat,
+  clearRepeat
+})
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 175 - 0
src/views/business/order/accept/Knowledge.vue

@@ -0,0 +1,175 @@
+
+<template>
+  <div class="knowledge-container">
+    <el-input
+        v-model="state.KnowledgeKeyword"
+        class="knowledge-input mb20"
+        placeholder="请填写搜索内容"
+        @keyup.enter="knowledgeRetrievalPaged(state.KnowledgeKeyword)"
+    >
+      <template #prefix>
+        <SvgIcon name="ele-Search" size="16px" />
+      </template>
+      <template #suffix>
+        <el-button
+            class="knowledge-search-button"
+            type="primary"
+            :loading="state.loading"
+            round
+            @click="knowledgeRetrievalPaged(state.KnowledgeKeyword)"
+        >
+          <SvgIcon name="ele-Search" size="16px" color="#fff" />
+        </el-button>
+      </template>
+    </el-input>
+    <div>
+      <span class="mr10" v-if="state.hotWords.length">搜索热词</span>
+      <el-tag
+          v-for="(item, index) in state.hotWords"
+          :key="index"
+          class="mr10 mb10"
+          style="cursor: pointer"
+          @click="knowledgeRetrievalPaged(item)"
+          round
+      >
+        {{ item }}
+      </el-tag>
+    </div>
+    <ul class="mt10" v-loading="state.loading">
+      <el-empty description="暂无数据" v-if="!state.knowledgeList.length" class="mb20">
+        <template #image>
+          <span></span>
+        </template>
+      </el-empty>
+      <li v-for="(item, index) in state.knowledgeList" :key="index" class="mb20 knowledge-item" @click="onPreview(item)" v-else>
+        <p class="font16">
+          <SvgIcon name="iconfont icon-dian" size="16px" /> <b>{{ item.title }}</b>
+        </p>
+        <p class="pt6 indent text-ellipsis2" v-html="item.content"></p>
+      </li>
+    </ul>
+  </div>
+  <!-- 分页 -->
+  <pagination
+      :total="state.knowledgeTotal"
+      v-model:page="state.knowledgeQuery.PageIndex"
+      v-model:limit="state.knowledgeQuery.PageSize"
+      @pagination="knowledgeRetrievalPaged(state.KnowledgeKeyword)"
+      :pageSizes="[5, 10, 15, 20]"
+      layout="total, prev, pager, next"
+      class="pt10"
+  />
+</template>
+<script setup lang="ts" name="orderAcceptKnowledge">
+// 定义变量内容
+import {onMounted, reactive} from "vue";
+import { knowPopScreen, getKeyWord } from '/@/api/knowledge';
+import {useRoute, useRouter} from "vue-router";
+
+const props = defineProps({
+  id: {
+    type: String,
+    default: '',
+  },
+  type: { // 知识库类型 (中心|部门)
+    type: String,
+    default: '',
+  },
+  formData:{ // 表单填写的数据
+    type: Object,
+    default: () => {
+      return {};
+    },
+  }
+});
+
+const state = reactive<any>({
+  loading: false, // 知识检索加载状态
+  hotWords: [],
+  knowledgeList: [],
+  knowledgeTotal: 0,
+  knowledgeQuery: {
+    PageIndex: 1,
+    PageSize: 10,
+    Keyword:'',
+  },
+  KnowledgeKeyword: '',
+});
+
+//  知识检索
+const knowledgeRetrievalPaged = async (val?: string) => {
+  state.knowledgeQuery.Keyword = val ?? '';
+  state.KnowledgeKeyword = val ?? '';
+  try {
+    state.loading = true;
+    const res: any = await knowPopScreen(state.knowledgeQuery);
+    state.knowledgeList = res.result?.items ?? [];
+    state.knowledgeTotal = res.result?.total ?? 0;
+    state.loading = false;
+  } catch (error) {
+    state.loading = false;
+  }
+};
+const router = useRouter(); // 路由
+const route = useRoute(); // 路由
+// 预览知识
+const onPreview = (row: any) => {
+  router.push({
+    name: 'knowledgePreview',
+    params: {
+      id: row.id,
+      tagsViewName: '知识预览',
+    },
+  });
+};
+onMounted(()=>{
+  getKeyWord().then((res: any) => {
+    state.hotWords = res.result ?? [];
+  });
+  if (route.params.id) {
+    knowledgeRetrievalPaged(props.formData.hotSpotName);
+  }
+})
+defineExpose({
+  knowledgeRetrievalPaged,
+});
+</script>
+
+<style scoped lang="scss">
+.knowledge-container {
+  position: relative;
+
+  .knowledge-input {
+    :deep(.el-input__wrapper) {
+      border-radius: 20px;
+      background: var(--hotline-bg-main-color);
+    }
+  }
+
+  .knowledge-search-button {
+    height: calc(100% - 6px);
+  }
+
+  .knowledge-item {
+    &:last-child {
+      margin-bottom: 0;
+    }
+
+    cursor: pointer;
+
+    &:hover {
+      color: var(--el-color-primary);
+    }
+
+    .indent {
+      text-indent: 1em;
+      color: var(--hotline-color-text-main-light);
+      line-height: 20px;
+
+      &:hover {
+        color: var(--el-color-primary);
+      }
+    }
+  }
+}
+</style>

+ 167 - 0
src/views/business/order/accept/Repeat-event.vue

@@ -0,0 +1,167 @@
+>
+
+<template>
+  <div>
+    <el-form :model="state.queryParams" ref="queryParamsRef" :inline="true" @submit.native.prevent>
+      <el-form-item label="关键词" prop="Keyword">
+        <el-input v-model="state.queryParams.Keyword" placeholder="事件标题/关键词" clearable @keyup.enter="handleQuery" />
+      </el-form-item>
+      <el-form-item label="创建时间" prop="exTime">
+        <el-date-picker
+            v-model="state.queryParams.exTime"
+            type="datetimerange"
+            unlink-panels
+            range-separator="至"
+            start-placeholder="开始时间"
+            end-placeholder="结束时间"
+            :shortcuts="shortcuts"
+            @change="timeStartChangeCr"
+            value-format="YYYY-MM-DD[T]HH:mm:ss"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="handleQuery" :loading="state.loading">
+          <SvgIcon name="ele-Search" class="mr5" />查询
+        </el-button>
+        <el-button @click="resetQuery(queryParamsRef)" :loading="state.loading" class="default-button">
+          <SvgIcon name="ele-Refresh" class="mr5" />重置
+        </el-button>
+      </el-form-item>
+    </el-form>
+    <div class="mb10">
+      <el-button type="primary" @click="onAdd" v-auth="'business:order:repeatEvent:add'"> <SvgIcon name="ele-Plus" class="mr5" />创建重复事件 </el-button>
+    </div>
+    <el-table
+        :data="state.tableData"
+        v-loading="state.loading"
+        max-height="300"
+    >
+      <el-table-column prop="phoneNo" label="标题" show-overflow-tooltip width="180">
+        <template #default="{ row }">
+          {{ row.title }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="hotspotName" label="关键词" show-overflow-tooltip> </el-table-column>
+      <el-table-column prop="no" label="创建时间" show-overflow-tooltip width="170">
+        <template #default="{ row }">
+
+        </template>
+      </el-table-column>
+      <el-table-column prop="currentStepName" label="创建人" show-overflow-tooltip></el-table-column>
+      <el-table-column prop="statusText" label="事件工单数" width="100" fixed="right" align="center"></el-table-column>
+    </el-table>
+
+    <el-dialog v-model="state.dialogVisible" width="500px" draggable title="新增重复性事件" @close="close">
+      <el-form :model="state.ruleForm" label-width="80px" ref="ruleFormRef">
+        <el-row :gutter="10">
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="标题" prop="title" :rules="[{ required: true, message: '请输入标题', trigger: 'blur' }]">
+              <el-input v-model="state.ruleForm.title" placeholder="请输入标题" clearable show-word-limit maxlength="200"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+            <el-form-item label="关键词" prop="keyword" :rules="[{ required: true, message: '请输入关键词', trigger: 'blur' }]">
+              <el-input v-model="state.ruleForm.keyword" placeholder="请输入关键词" clearable type="text" show-word-limit maxlength="200"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+				<span class="dialog-footer">
+					<el-button @click="state.dialogVisible = false" class="default-button">取 消</el-button>
+					<el-button type="primary" @click="onSubmit(ruleFormRef)" :loading="state.loading">确 定</el-button>
+				</span>
+      </template>
+    </el-dialog>
+
+  </div>
+</template>
+<script setup lang="ts" name="orderAcceptRepeatEvent">
+import {reactive,ref} from "vue";
+import {ElButton, ElMessage, FormInstance} from "element-plus";
+import {shortcuts} from "/@/utils/constants";
+import {throttle} from "/@/utils/tools";
+import {auth} from "/@/utils/authFunction";
+import {addCommon} from "/@/api/system/commonAdvice";
+const state = reactive<any>({
+  queryParams: {
+    // 查询条件
+    PageIndex: 1,
+    PageSize: 10,
+    Keyword: '', // 关键字
+    CreationTimeStart: '', // 创建时间 开始
+    CreationTimeEnd: '', // 创建时间 结束
+    exTime: [], // 办理期限
+  },
+  tableData: [], //表格
+  loading: false, // 加载
+  total: 0, // 总数
+  dialogVisible: false, // 弹窗
+  ruleForm:{
+
+  }
+})
+
+const queryParamsRef = ref<RefType>(); // 查询参数
+const handleTimeChange = (val: string[], startKey: string, endKey: string) => {
+  if (val) {
+    state.queryParams[startKey] = val[0];
+    state.queryParams[endKey] = val[1];
+  } else {
+    state.queryParams[startKey] = '';
+    state.queryParams[endKey] = '';
+  }
+};
+// 时间
+const timeStartChangeCr = (val: string[]) => {
+  handleTimeChange(val, 'CreationTimeStart', 'CreationTimeEnd');
+};
+/** 搜索按钮操作 */
+const handleQuery = throttle(() => {
+  state.queryParams.PageIndex = 1;
+  queryList();
+}, 500);
+/** 重置按钮操作 */
+const resetQuery = throttle((formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+  handleQuery();
+}, 300);
+const queryList = ()=>{
+
+}
+// 创建重复事件
+const onAdd = ()=>{
+  state.dialogVisible = true;
+}
+const ruleFormRef = ref<RefType>();
+const close = ()=>{
+  ruleFormRef.value.clearValidate();
+  ruleFormRef.value.resetFields();
+}
+const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  await formEl.validate((valid: boolean) => {
+    if (!valid) return;
+    state.loading = true;
+    addCommon(state.ruleForm)
+        .then(() => {
+          ElMessage({
+            message: '操作成功',
+            type: 'success',
+          });
+          state.dialogVisible = false;
+        })
+        .catch((error) => {
+
+        })
+        .finally(() => {
+          state.loading = false;
+          state.dialogVisible = false;
+        });
+  });
+}, 300);
+</script>
+<style scoped lang="scss">
+
+</style>

+ 11 - 0
src/views/business/order/accept/Voice-assistant.vue

@@ -0,0 +1,11 @@
+
+<template>
+  语音助手
+</template>
+<script setup lang="ts">
+
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 101 - 425
src/views/business/order/accept/index.vue

@@ -351,13 +351,13 @@
 													<el-input v-model="state.ruleForm.street" placeholder="请填写详细地址" clearable> </el-input>
 												</el-col>
 												<el-col :xs="24" :sm="24" :md="24" :lg="7" :xl="7" :offset="1">
-													<el-button type="primary" link><SvgIcon name="ele-Location" size="16px" /> 地图定位</el-button>
+													<el-button type="primary" link @click="selectLocation"><SvgIcon name="ele-Location" size="16px" /> 地图定位</el-button>
 												</el-col>
 											</el-form-item>
 										</el-col>
-										<div v-if="state.ruleForm.address" class="color-danger mb10 flex-center-align" style="margin-left: 110px">
-											【{{ state.ruleForm.address }}】下存在多起【热点类型】时间,点击前往查看或右侧添加重复性事件
-											<el-button type="primary" link> 查看详情</el-button>
+										<div v-if="showRepeatEvent" class="color-danger mb10" style="margin-left: 110px">
+											【{{ state.ruleForm.address }}】下存在多起【热点类型】事件,点击前往查看或右侧添加重复性事件
+											<el-button type="primary" link style="padding: 0 0 3px" @click="onRepeatEvent"> 查看详情</el-button>
 										</div>
 									</el-row>
 								</el-col>
@@ -451,200 +451,29 @@
 							<el-tab-pane label="知识库" name="knowledge">
 								<el-tabs v-model="knowledgeActive" @tab-change="handleKnowledge">
 									<el-tab-pane label="中心知识库" name="center">
-										<div class="knowledge-container">
-											<el-input
-												v-model="state.KnowledgeKeyword"
-												class="knowledge-input mb20"
-												placeholder="请填写搜索内容"
-												@keyup.enter="knowledgeRetrievalPaged(state.KnowledgeKeyword)"
-											>
-												<template #prefix>
-													<SvgIcon name="ele-Search" size="16px" />
-												</template>
-												<template #suffix>
-													<el-button
-														class="knowledge-search-button"
-														type="primary"
-														:loading="state.loading"
-														round
-														@click="knowledgeRetrievalPaged(state.KnowledgeKeyword)"
-													>
-														<SvgIcon name="ele-Search" size="16px" color="#fff" />
-													</el-button>
-												</template>
-											</el-input>
-											<div>
-												<span class="mr10" v-if="state.hotWords.length">搜索热词</span>
-												<el-tag
-													v-for="(item, index) in state.hotWords"
-													:key="index"
-													class="mr10 mb10"
-													style="cursor: pointer"
-													@click="knowledgeRetrievalPaged(item)"
-													round
-												>
-													{{ item }}
-												</el-tag>
-											</div>
-											<ul class="mt10" v-loading="state.loading">
-												<el-empty description="暂无数据" v-if="!state.knowledgeList.length" class="mb20">
-													<template #image>
-														<span></span>
-													</template>
-												</el-empty>
-												<li v-for="(item, index) in state.knowledgeList" :key="index" class="mb20 knowledge-item" @click="onPreview(item)" v-else>
-													<p class="font16">
-														<SvgIcon name="iconfont icon-dian" size="16px" /> <b>{{ item.title }}</b>
-													</p>
-													<p class="pt6 indent text-ellipsis2" v-html="item.content"></p>
-												</li>
-											</ul>
-										</div>
-										<!-- 分页 -->
-										<pagination
-											:total="state.knowledgeTotal"
-											v-model:page="state.knowledgeQuery.PageIndex"
-											v-model:limit="state.knowledgeQuery.PageSize"
-											@pagination="knowledgeRetrievalPaged(state.KnowledgeKeyword)"
-											:pageSizes="[5, 10, 15, 20]"
-											layout="total, prev, pager, next"
-											class="pt10"
-										/>
 									</el-tab-pane>
 									<el-tab-pane label="部门知识库" name="org">
-										<div class="knowledge-container">
-											<el-input
-												v-model="state.KnowledgeKeyword"
-												class="knowledge-input mb20"
-												placeholder="请填写搜索内容"
-												@keyup.enter="knowledgeRetrievalPaged(state.KnowledgeKeyword)"
-											>
-												<template #prefix>
-													<SvgIcon name="ele-Search" size="16px" />
-												</template>
-												<template #suffix>
-													<el-button
-														class="knowledge-search-button"
-														type="primary"
-														:loading="state.loading"
-														round
-														@click="knowledgeRetrievalPaged(state.KnowledgeKeyword)"
-													>
-														<SvgIcon name="ele-Search" size="16px" color="#fff" />
-													</el-button>
-												</template>
-											</el-input>
-											<div>
-												<span class="mr10" v-if="state.hotWords.length">搜索热词</span>
-												<el-tag
-													v-for="(item, index) in state.hotWords"
-													:key="index"
-													class="mr10 mb10"
-													style="cursor: pointer"
-													@click="knowledgeRetrievalPaged(item)"
-													round
-												>
-													{{ item }}
-												</el-tag>
-											</div>
-											<ul class="mt10" v-loading="state.loading">
-												<el-empty description="暂无数据" v-if="!state.knowledgeList.length" class="mb20">
-													<template #image>
-														<span></span>
-													</template>
-												</el-empty>
-												<li v-for="(item, index) in state.knowledgeList" :key="index" class="mb20 knowledge-item" @click="onPreview(item)" v-else>
-													<p class="font16">
-														<SvgIcon name="iconfont icon-dian" size="16px" /> <b>{{ item.title }}</b>
-													</p>
-													<p class="pt6 indent text-ellipsis2" v-html="item.content"></p>
-												</li>
-											</ul>
-										</div>
-										<!-- 分页 -->
-										<pagination
-											:total="state.knowledgeTotal"
-											v-model:page="state.knowledgeQuery.PageIndex"
-											v-model:limit="state.knowledgeQuery.PageSize"
-											@pagination="knowledgeRetrievalPaged(state.KnowledgeKeyword)"
-											:pageSizes="[5, 10, 15, 20]"
-											layout="total, prev, pager, next"
-											class="pt10"
-										/>
 									</el-tab-pane>
+                  <Knowledge :type="knowledgeActive" :formData="state.ruleForm" ref="knowledgeActiveRef" v-if="knowledgeActive==='center'"/>
+                  <Knowledge :type="knowledgeActive" :formData="state.ruleForm" ref="knowledgeActiveRef" v-if="knowledgeActive==='org'"/>
 								</el-tabs>
 							</el-tab-pane>
-							<el-tab-pane label="重复性事件" name="repeat"> </el-tab-pane>
+							<el-tab-pane label="重复性事件" name="repeat">
+                <repeat-event />
+              </el-tab-pane>
 							<el-tab-pane label="历史工单" name="history">
-								<el-form :model="state.queryParams" ref="queryParamsRef" :inline="true" @submit.native.prevent>
-									<el-form-item label="关键词" prop="Keyword">
-										<el-input v-model="state.queryParams.Keyword" placeholder="工单标题/工单编码" clearable @keyup.enter="handleQuery" />
-									</el-form-item>
-									<el-form-item>
-										<el-button type="primary" @click="handleQuery" :loading="state.historyOrderLoading">
-											<SvgIcon name="ele-Search" class="mr5" />查询
-										</el-button>
-										<el-button @click="resetQuery(queryParamsRef)" :loading="state.historyOrderLoading" class="default-button">
-											<SvgIcon name="ele-Refresh" class="mr5" />重置
-										</el-button>
-									</el-form-item>
-								</el-form>
-								<el-table
-									:data="state.tableData"
-									v-loading="state.historyOrderLoading"
-									row-key="id"
-									@selection-change="handleSelectionChange"
-									max-height="300"
-									ref="multipleTableRef"
-								>
-									<el-table-column type="selection" label="重复件" width="80" :reserve-selection="true" v-if="state.ruleForm.isRepeat === 'true'" />
-									<el-table-column prop="phoneNo" label="工单标题" show-overflow-tooltip width="180">
-										<template #default="{ row }">
-											{{ row.title }}
-										</template>
-									</el-table-column>
-									<el-table-column prop="hotspotName" label="热点分类" show-overflow-tooltip> </el-table-column>
-									<el-table-column prop="no" label="工单编码" show-overflow-tooltip> </el-table-column>
-									<el-table-column prop="currentStepName" label="当前环节" show-overflow-tooltip></el-table-column>
-									<el-table-column prop="statusText" label="状态" width="70" fixed="right" align="center">
-										<template #default="{ row }">
-											<!-- 草稿 -->
-											<span class="color-info" v-if="row.status === 0">{{ row.statusText }}</span>
-											<!-- 待签收 -->
-											<span class="color-success" v-if="row.status === 10">{{ row.statusText }}</span>
-											<!-- 办理中 -->
-											<span class="color-primary" v-if="row.status === 20">{{ row.statusText }}</span>
-											<!-- 会签中 -->
-											<span class="color-primary" v-if="row.status === 30">{{ row.statusText }}</span>
-											<!-- 退回 -->
-											<span class="color-danger" v-if="row.status === 40">{{ row.statusText }}</span>
-											<!-- 办理完成 -->
-											<span class="color-success" v-if="row.status === 50">{{ row.statusText }}</span>
-											<!-- 已归档 -->
-											<span class="color-info" v-if="row.status === 60">{{ row.statusText }}</span>
-										</template>
-									</el-table-column>
-									<el-table-column prop="statusText" label="操作" width="170" fixed="right" align="center">
-										<template #default="{ row }">
-											<el-button @click="onSupply(row)" link type="primary" v-auth="'business:order:supply'"> 补充 </el-button>
-											<el-button @click="onRevoke(row)" link type="primary" v-auth="'business:order:revoke'"> 撤销 </el-button>
-											<el-button @click="onSupervise(row)" link type="primary"> 督办 </el-button>
-										</template>
-									</el-table-column>
-								</el-table>
-								<pagination
-									:total="state.total"
-									v-model:page="state.queryParams.PageIndex"
-									v-model:limit="state.queryParams.PageSize"
-									@pagination="searchHistory"
-								/>
+                <History :formData="state.ruleForm" :orderId="state.orderId" @handleSelectionChange="handleSelectionChange" ref="historyRef"/>
 							</el-tab-pane>
 						</el-tabs>
 					</el-card>
 					<el-card shadow="never">
 						<el-tabs v-model="rightBottomActive" @tab-change="handleRightBottom">
-							<el-tab-pane label="语音助手" name="voice"> </el-tab-pane>
-							<el-tab-pane label="市民画像" name="draw"> </el-tab-pane>
+							<el-tab-pane label="语音助手" name="voice">
+                <voice-assistant />
+              </el-tab-pane>
+							<el-tab-pane label="市民画像" name="draw">
+                <citizen-portrait />
+              </el-tab-pane>
 						</el-tabs>
 					</el-card>
 				</el-scrollbar>
@@ -653,15 +482,13 @@
 		<!-- 拓展表单 -->
 		<order-expand-form ref="ExpandFormRef" @saveExpandForm="saveExpandForm" :orderDetail="orderDetailInfo" :extra="extra" />
 		<!-- 历史工单 -->
-		<order-history ref="HistoryOrderRef" @saveSelect="saveSelect"> </order-history>
-		<!-- 补充信息 -->
-		<order-supply ref="SupplyRef" @onSupplySuccess="onSupplySuccess" />
-		<!-- 工单撤销 -->
-		<order-revoke ref="orderRevokeRef" @onRevokeSuccess="onRevokeSuccess" />
-		<!-- 工单督办 -->
-		<order-super-vise ref="orderSuperviseRef" @onSuperviseSuccess="onSuperviseSuccess" />
+		<order-history ref="HistoryOrderRef" @saveSelect="saveSelect" />
+    <!-- 重复事件列表 -->
+    <repeat-event-dialog ref="repeatEventDialogRef" />
 		<!--  流程审批  -->
-		<process-approval ref="processApprovalRef" @orderProcessSuccess="orderProcessSuccess"> </process-approval>
+		<process-approval ref="processApprovalRef" @orderProcessSuccess="orderProcessSuccess" />
+    <!-- 地图选点 -->
+    <map-dialog ref="mapDialogRef" @confirm="selectMap"/>
 	</div>
 </template>
 
@@ -674,22 +501,24 @@ import { useRoute, useRouter } from 'vue-router';
 import { useTelStatus } from '/@/stores/telStatus';
 import { throttle } from '/@/utils/tools';
 import { commonEnum } from '/@/utils/constants';
-import { auth } from '/@/utils/authFunction';
-import { orderBaseDataAdd, orderAdd, hotSpotType, historyOrder, orderEdit, orderDetail, orderBaseExt } from '/@/api/business/order';
+import { orderBaseDataAdd, orderAdd, hotSpotType, orderEdit, orderDetail, orderBaseExt } from '/@/api/business/order';
 import { useUserInfo } from '/@/stores/userInfo';
 import { treeArea } from '/@/api/system/area';
-import { knowPopScreen, getKeyWord } from '/@/api/knowledge';
 import mittBus from '/@/utils/mitt';
 
 // 引入组件
+const Knowledge = defineAsyncComponent(() => import('/@/views/business/order/accept/Knowledge.vue')); // 知识库
+const History = defineAsyncComponent(() => import('/@/views/business/order/accept/History.vue')); // 历史工单
+const RepeatEvent = defineAsyncComponent(() => import('/@/views/business/order/accept/Repeat-event.vue')); // 重复事件
+const VoiceAssistant = defineAsyncComponent(() => import('/@/views/business/order/accept/Voice-assistant.vue')); // 重复事件
+const CitizenPortrait = defineAsyncComponent(() => import('/@/views/business/order/accept/Citizen-portrait.vue')); // 市民坏画像
+const RepeatEventDialog = defineAsyncComponent(() => import('/@/views/business/order/components/Order-repeat-event.vue')); // 重复事件弹窗列表
 const OrderExpandForm = defineAsyncComponent(() => import('/@/views/business/order/components/Order-expand-form.vue')); // 拓展表单
-const OrderHistory = defineAsyncComponent(() => import('/@/views/business/order/components/Order-history.vue')); // 历史工单
+const OrderHistory = defineAsyncComponent(() => import('/@/views/business/order/components/Order-history.vue')); // 历史工单弹窗列表
 const CommonAdvice = defineAsyncComponent(() => import('/@/components/CommonAdvice/index.vue')); // 常用意见
-const OrderSupply = defineAsyncComponent(() => import('/@/views/business/order/components/Order-supply.vue')); // 补充信息
 const AnnexList = defineAsyncComponent(() => import('/@/components/AnnexList/index.vue')); // 附件列表
-const OrderRevoke = defineAsyncComponent(() => import('/@/views/business/order/components/Order-revoke.vue')); // 撤销组件
-const OrderSuperVise = defineAsyncComponent(() => import('/@/views/business/supervise/components/Order-supervise.vue')); // 工单督办
 const ProcessApproval = defineAsyncComponent(() => import('/@/components/ProcessApproval/index.vue')); // 流程审批
+const MapDialog = defineAsyncComponent(() => import('/@/views/business/order/components/Map-Dialog.vue')); // 地图定位
 // 定义变量内容
 const state = reactive<any>({
 	createBy: 'manual', // 工单创建方式 默认手动创建  tel:来电弹单  letter:互联网来信 默认表示手动创建
@@ -731,8 +560,7 @@ const state = reactive<any>({
 		callAddress: '', // 来电归属地
 	},
 	formLoading: false, // 表单加载状态
-	historyOrderLoading: false, // 历史工单加载状态
-	loading: false, // 知识检索加载状态
+
 	acceptTypeOptions: [], // 受理类型
 	channelOptions: [], // 来源频道
 	emergencyLevelOptions: [], // 紧急程度
@@ -755,28 +583,8 @@ const state = reactive<any>({
 		},
 	],
 	orgData: [], // 机构数据
-	tableData: [], // 历史工单
-	total: 0, // 历史工单总条数
-	queryParams: {
-		PageIndex: 1, // 当前页
-		PageSize: 10, // 每页条数
-		Keyword: '', // 关键字
-	},
-	KnowledgeKeyword: '', //知识检索内容
-	hotWords: [], // 知识检索热点
-	knowledgeList: [], //知识检索列表
-	external: [], // 知识检索展开
-	hotspotExternal: [], // 热点分类展开
-	knowledgeQuery: {
-		// 知识库查询
-		PageIndex: 1, // 当前页
-		PageSize: 5, // 每页条数
-		Keyword: '', // 关键字
-	},
-	knowledgeTotal: 0, // 知识库总条数
 	orderId: '', // 工单id
 });
-const queryParamsRef = ref<RefType>(); // 历史工单查询参数
 const useTelStatusStore = useTelStatus(); // 来电弹屏
 const { telStatusInfo } = storeToRefs(useTelStatusStore); // 来电弹屏信息
 const storesUserInfo = useUserInfo(); // 用户信息
@@ -814,7 +622,7 @@ const createFilter = (queryString: string) => {
 	};
 };
 links.value = loadAll();
-
+// 选择企业
 const handleSelect = (item: Record<string, any>) => {
 	console.log(item);
 };
@@ -840,32 +648,15 @@ const load = async (node: any, resolve: any) => {
 	resolve(res.result);
 };
 // 选择热点分类
+const knowledgeActiveRef = ref<RefType>()
 const hotSpotChange = (val: any, e: any) => {
 	state.hotspotExternal = [];
 	state.external = [];
 	state.hotspotExternal = getParentId(e, state.external);
 	state.ruleForm.hotspotSpliceName = val.hotSpotFullName;
 	state.ruleForm.hotspotName = val.hotSpotName;
-	knowledgeRetrievalPaged(val.hotSpotName);
+  knowledgeActiveRef.value.knowledgeRetrievalPaged(val.hotSpotName);
 };
-//  知识检索
-const knowledgeRetrievalPaged = async (val?: string) => {
-	state.knowledgeQuery.Keyword = val ?? '';
-	state.KnowledgeKeyword = val ?? '';
-	try {
-		state.loading = true;
-		const res: any = await knowPopScreen(state.knowledgeQuery);
-		state.knowledgeList = res.result?.items ?? [];
-		state.knowledgeTotal = res.result?.total ?? 0;
-		state.loading = false;
-	} catch (error) {
-		state.loading = false;
-	}
-};
-// 手机号码脱敏处理
-// const phoneNumber = computed(() => {
-// 	return desensitizationPhone(telStatusInfo.value.onCallArr[0]?.from);
-// });
 // 递归查找父级Id
 const getParentId = (val: any, arr: string[]) => {
 	if (val.data.parentId) {
@@ -889,11 +680,33 @@ const selectOrderType = (val: any) => {
 	});
 };
 const areaRef = ref<RefType>();
+const showRepeatEvent = ref<boolean>(false); //是否展示重复性事件
 // 获取事发地址
 const changeArea = () => {
 	const currentNode = areaRef.value.getCheckedNodes();
 	state.ruleForm.address = currentNode[0].pathLabels.join(''); // 事发地址
+  showRepeatEvent.value = true;
+  rightActive.value = 'repeat';
 };
+// 地图选点
+const mapDialogRef = ref<RefType>();
+const selectLocation = ()=>{
+  const location = {
+    longitude: state.ruleForm.longitude,
+    latitude: state.ruleForm.latitude,
+    adcode: state.ruleForm.areaCode,
+    street: state.ruleForm.street
+  }
+  mapDialogRef.value.openDialog(location);
+}
+// 地图选点
+const selectMap = (location:any)=>{
+    ruleFormRef.value.resetFields('areaCode');
+    state.ruleForm.longitude = location.longitude;
+    state.ruleForm.latitude = location.latitude;
+    state.ruleForm.areaCode = location.adcode;
+    state.ruleForm.street = location.street;
+}
 const ExpandFormRef = ref<RefType>();
 // 打开拓展表单
 const showExpandForm = () => {
@@ -997,12 +810,23 @@ const submit = throttle((formEl: FormInstance | undefined) => {
 		handleForm(orderDetail);
 	});
 }, 300);
+// 选中常用意见
+const chooseAdvice = (item: any) => {
+  state.ruleForm.content += item.content;
+};
+// 流程提交成功
+const orderProcessSuccess = () => {
+  // 关闭当前 tagsView
+  mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
+  mittBus.emit('clearCache', 'order');
+  router.push({
+    path: '/business/order/index',
+  });
+};
 // 选择是否重复
 const isRepeatChange = (val: string) => {
 	if (val === 'false') clearRepeat();
 };
-const multipleSelection = ref<any[]>([]); // 重复件表格选中项
-const multipleTableRef = ref<RefType>(); // 重复件表格ref
 // 清除重复件
 const clearRepeat = () => {
 	ElMessageBox.confirm(`确认要清除选择的重复工单?`, '提示', {
@@ -1014,7 +838,7 @@ const clearRepeat = () => {
 		autofocus: false,
 	})
 		.then(() => {
-			multipleTableRef.value!.clearSelection();
+      historyRef.value.clearRepeat();
 			setTimeout(() => {
 				state.ruleForm.duplicateTitle = '';
 				state.ruleForm.duplicateIds = [];
@@ -1031,140 +855,38 @@ const selectRepeat = () => {
 };
 // 弹窗确定选择重复件
 const saveSelect = (row: any) => {
-	multipleTableRef.value!.clearSelection();
+  historyRef.value.clearRepeat();
 	state.ruleForm.duplicateIds = row.map((item: any) => item.id);
 	state.ruleForm.duplicateTitle = '已选择';
-	multipleSelection.value = row;
-	for (let i of multipleSelection.value) {
-		for (let j of state.tableData) {
-			if (i.id === j.id) {
-				setTimeout(() => {
-					multipleTableRef.value!.toggleRowSelection(j, true);
-				}, 0);
-			}
-		}
-	}
+  historyRef.value.dialogConfirmRepeat(row)
 	HistoryOrderRef.value.closeDialog();
 };
-// 右边表格选中重复件
+// 右侧选择历史工单
 const handleSelectionChange = (row: any) => {
-	if (row && row.length) {
-		state.ruleForm.duplicateIds = row.map((item: any) => item.id);
-		state.ruleForm.duplicateTitle = '已选择';
-		multipleSelection.value = row;
-	} else {
-		state.ruleForm.duplicateIds = [];
-		state.ruleForm.duplicateTitle = '';
-		multipleSelection.value = [];
-	}
-};
-// 选中常用意见
-const chooseAdvice = (item: any) => {
-	state.ruleForm.content += item.content;
-};
-// 流程提交成功
-const orderProcessSuccess = () => {
-	// 关闭当前 tagsView
-	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
-	mittBus.emit('clearCache', 'order');
-	router.push({
-		path: '/business/order/index',
-	});
-};
-/** 搜索按钮操作 */
-const handleQuery = throttle(() => {
-	state.queryParams.PageIndex = 1;
-	searchHistory();
-}, 500);
-/** 重置按钮操作 */
-const resetQuery = throttle((formEl: FormInstance | undefined) => {
-	if (!formEl) return;
-	formEl.resetFields();
-	handleQuery();
-}, 300);
-/** 获取历史工单 */
-const searchHistory = throttle(async (orderDetail?: any) => {
-	if (!auth('business:order:history')) ElMessage.error('抱歉,您没有权限查询历史工单!');
-	else {
-		state.historyOrderLoading = true;
-		let request = {
-			...state.queryParams,
-			PhoneNo: state.ruleForm.contact,
-			OrderId: state.orderId, //传入id 排除重复工单选择自己
-		};
-		try {
-			const response = await historyOrder(request);
-			state.tableData = response?.result.items ?? [];
-			state.total = response?.result.total;
-			state.historyOrderLoading = false;
-			if (orderDetail) {
-				if (orderDetail.result.duplicateIds && orderDetail.result.duplicateIds.length) {
-					// 是否重复
-					state.ruleForm.isRepeat = 'true';
-					state.ruleForm.duplicateTitle = '已选择';
-					multipleSelection.value = orderDetail.result.duplicateIds;
-					for (let i of multipleSelection.value) {
-						for (let j of state.tableData) {
-							if (i === j.id) {
-								setTimeout(() => {
-									multipleTableRef.value!.toggleRowSelection(j, true);
-								}, 0);
-							}
-						}
-					}
-				} else {
-					state.ruleForm.isRepeat = 'false';
-				}
-			}
-		} catch (error) {
-			state.historyOrderLoading = false;
-		}
-	}
-}, 300);
-// 补充信息
-const SupplyRef = ref<RefType>();
-const onSupply = (val: any) => {
-	SupplyRef.value.openDialog(val);
-};
-// 补充意见提交成功
-const onSupplySuccess = () => {
-	searchHistory();
-};
-// 撤销
-const orderRevokeRef = ref<RefType>();
-const onRevoke = (row: any) => {
-	orderRevokeRef.value.openDialog(row);
-};
-// 撤销提交成功
-const onRevokeSuccess = () => {
-	searchHistory();
-};
-// 督办
-const orderSuperviseRef = ref<RefType>(); // 工单督办
-const onSupervise = () => {
-	orderSuperviseRef.value.openDialog(state.ruleForm);
-};
-// 督办提交成功
-const onSuperviseSuccess = () => {
-	// 刷新列表
-	searchHistory();
-};
-// 预览知识
-const onPreview = (row: any) => {
-	router.push({
-		name: 'knowledgePreview',
-		params: {
-			id: row.id,
-			tagsViewName: '知识预览',
-		},
-	});
+  if (row && row.length) {
+    state.ruleForm.duplicateIds = row.map((item: any) => item.id);
+    state.ruleForm.duplicateTitle = '已选择';
+  } else {
+    state.ruleForm.duplicateIds = [];
+    state.ruleForm.duplicateTitle = '';
+  }
 };
+const historyRef = ref<RefType>();// 历史工单组件
+const searchHistory = (val?:any)=>{
+  historyRef.value.searchHistory(val);
+  rightActive.value = 'history';
+}
 const rightActive = ref<string>('knowledge'); // 右侧顶部Tab
 const handleRight = (val: string) => {};
 const knowledgeActive = ref<string>('center'); // 知识库顶部Tab
 const handleKnowledge = (val: string) => {};
 const rightBottomActive = ref<string>('voice'); // 右侧底部Tab
 const handleRightBottom = (val: string) => {};
+// 查看重复事件
+const repeatEventDialogRef = ref<RefType>();
+const onRepeatEvent = ()=>{
+  repeatEventDialogRef.value.openDialog();
+}
 const extra = ref<any>({
 	ext: {},
 	area: {},
@@ -1172,10 +894,8 @@ const extra = ref<any>({
 const orderDetailInfo = ref({});
 onBeforeMount(async () => {
 	state.formLoading = true;
-	state.historyOrderLoading = true;
-	state.loading = true;
 	try {
-		const [area, res, hotspot] = await Promise.all([treeArea(), orderBaseDataAdd(), getKeyWord()]);
+		const [area, res] = await Promise.all([treeArea(), orderBaseDataAdd()]);
 		state.acceptTypeOptions = res.result?.acceptTypeOptions ?? [];
 		state.channelOptions = res.result?.channelOptions ?? [];
 		state.emergencyLevelOptions = res.result?.emergencyLevelOptions ?? [];
@@ -1188,7 +908,6 @@ onBeforeMount(async () => {
 		state.ruleForm.seats = `${userInfos.value.name} [${userInfos.value.staffNo}]`;
 
 		state.areaOptions = area.result ?? []; //省市区数据
-		state.hotWords = hotspot.result ?? []; // 知识库热词
 		//  historyParams.createBy  createBy 代表来源  tel:来电弹单  letter:互联网来信 默认表示手动创建
 		console.log(historyParams, route.params);
 		if (historyParams.createBy) {
@@ -1206,7 +925,6 @@ onBeforeMount(async () => {
 					dicDataValue: state.ruleForm.sourceChannelCode,
 					dicDataName: state.ruleForm.sourceChannel,
 				};
-				searchHistory(); // 查询历史订单
 			}
 		}
 		if (route.params.id) {
@@ -1216,7 +934,13 @@ onBeforeMount(async () => {
 			// 如果获取到id 调用查询详情
 			state.ruleForm = response.result;
 			orderDetailInfo.value = response.result;
-			searchHistory(response);
+      if (response.result.duplicateIds && response.result.duplicateIds.length) {
+        // 是否重复
+        state.ruleForm.isRepeat = 'true';
+        state.ruleForm.duplicateTitle = '已选择';
+      } else {
+        state.ruleForm.isRepeat = 'false';
+      }
 			if (state.ruleForm.orderType === 1) {
 				// 工单类型 选择了12315市场监管受理单
 				state.acceptTypeOptions = state.acceptTypeOptions.map((item: any) => {
@@ -1271,19 +995,13 @@ onBeforeMount(async () => {
 				dicDataValue: state.ruleForm.pushTypeCode,
 				dicDataName: state.ruleForm.pushType,
 			};
-			knowledgeRetrievalPaged(state.ruleForm.hotspotName);
+      knowledgeActiveRef.value.knowledgeRetrievalPaged(state.ruleForm.hotspotName);
 			state.formLoading = false;
-			state.historyOrderLoading = false;
-			state.loading = false;
 		}
 	} catch (error) {
 		state.formLoading = false;
-		state.historyOrderLoading = false;
-		state.loading = false;
 	} finally {
-		state.formLoading = false;
-		state.historyOrderLoading = false;
-		state.loading = false;
+		state.formLoading = false
 	}
 });
 onMounted(async () => {
@@ -1293,54 +1011,12 @@ onMounted(async () => {
 </script>
 
 <style scoped lang="scss">
-.box {
-	background-color: var(--el-color-white);
-	border-radius: 8px;
-}
-
 :deep(.el-divider--horizontal) {
 	margin-top: 0;
 }
 
 .order-add-container {
 	color: var(--hotline-color-text-main);
-	.right-content {
-		.knowledge-container {
-			position: relative;
 
-			.knowledge-input {
-				:deep(.el-input__wrapper) {
-					border-radius: 20px;
-					background: var(--hotline-bg-main-color);
-				}
-			}
-
-			.knowledge-search-button {
-				height: calc(100% - 6px);
-			}
-
-			.knowledge-item {
-				&:last-child {
-					margin-bottom: 0;
-				}
-
-				cursor: pointer;
-
-				&:hover {
-					color: var(--el-color-primary);
-				}
-
-				.indent {
-					text-indent: 1em;
-					color: var(--hotline-color-text-main-light);
-					line-height: 20px;
-
-					&:hover {
-						color: var(--el-color-primary);
-					}
-				}
-			}
-		}
-	}
 }
 </style>

+ 49 - 0
src/views/business/order/components/Map-Dialog.vue

@@ -0,0 +1,49 @@
+
+
+<template>
+  <el-dialog v-model="state.dialogVisible" title="地图选点" draggable ref="dialogRef" width="60%" append-to-body destroy-on-close>
+    <Amap v-model="location" ref="AmapRef"/>
+    <template #footer>
+				<span class="dialog-footer">
+					<el-button @click="closeDialog" class="default-button">取 消</el-button>
+					<el-button type="primary" @click="confirm" :loading="state.loading" :disabled="disabled">确定</el-button>
+				</span>
+    </template>
+  </el-dialog>
+</template>
+<script setup lang="ts">
+import {reactive, defineAsyncComponent, ref, computed} from "vue";
+const Amap = defineAsyncComponent(() => import('/@/views/business/order/components/amap-select.vue')); //地图组件
+// 定义变量内容
+const state = reactive<any>({
+  dialogVisible: false,
+});
+const location = ref({});
+// 打开弹窗
+const openDialog = (val: any) => {
+  location.value = val;
+  state.dialogVisible = true;
+};
+// 关闭弹窗
+const closeDialog = () => {
+  state.dialogVisible = false;
+};
+const disabled = computed(()=>{
+  return !AmapRef.value?.location?.longitude
+})
+// 确定
+const AmapRef = ref<RefType>();
+const emit = defineEmits(['confirm']);
+const confirm = ()=>{
+  const location = AmapRef.value?.location;
+  emit('confirm',location);
+  closeDialog();
+}
+defineExpose({
+  openDialog,
+  closeDialog
+})
+</script>
+<style scoped lang="scss">
+
+</style>

+ 3 - 20
src/views/business/order/components/Order-history.vue

@@ -19,24 +19,7 @@
 					<el-table-column prop="hotspotName" label="热点分类" show-overflow-tooltip> </el-table-column>
 					<el-table-column prop="no" label="工单编码" show-overflow-tooltip> </el-table-column>
 					<el-table-column prop="currentStepName" label="当前环节" show-overflow-tooltip></el-table-column>
-					<el-table-column prop="statusText" label="状态" width="70" fixed="right" align="center">
-						<template #default="{row}">
-              <!-- 草稿 -->
-              <span class="color-info" v-if="row.status === 0">{{ row.statusText }}</span>
-              <!-- 待签收 -->
-              <span class="color-success" v-if="row.status === 10">{{ row.statusText }}</span>
-              <!-- 办理中 -->
-              <span class="color-primary" v-if="row.status === 20">{{ row.statusText }}</span>
-              <!-- 会签中 -->
-              <span class="color-primary" v-if="row.status === 30">{{ row.statusText }}</span>
-              <!-- 退回 -->
-              <span class="color-danger" v-if="row.status === 40">{{ row.statusText }}</span>
-              <!-- 办理完成 -->
-              <span class="color-success" v-if="row.status === 50">{{ row.statusText }}</span>
-              <!-- 已归档 -->
-              <span class="color-info" v-if="row.status === 60">{{ row.statusText }}</span>
-						</template>
-					</el-table-column>
+					<el-table-column prop="statusText" label="状态" width="70" fixed="right" align="center"></el-table-column>
           <el-table-column label="操作" width="150" fixed="right" align="center">
             <template #default="{ row }">
               <el-button type="primary" link @click="onSupply(row)" :loading="state.loading"  v-auth="'business:order:supply'">补充</el-button>
@@ -121,11 +104,11 @@ const resetQuery = (formEl: FormInstance | undefined) => {
 };
 /** 获取历史工单 */
 const getList = () => {
-	if (!state.ruleForm.fromPhone) return;
+	if (!state.ruleForm.contact) return;
 	state.loading = true;
 	let request = {
 		...state.queryParams,
-		PhoneNo: state.ruleForm.fromPhone,
+		PhoneNo: state.ruleForm.contact,
 		OrderId: route.params.id ?? '', //传入id 排除重复工单选择自己
 	};
 	historyOrder(request)

+ 123 - 0
src/views/business/order/components/Order-repeat-event.vue

@@ -0,0 +1,123 @@
+<template>
+  <el-dialog v-model="state.dialogVisible" draggable title="重复性事件" ref="dialogRef" width="60%" append-to-body>
+    <el-form :model="state.queryParams" ref="queryParamsRef" :inline="true" @submit.native.prevent>
+      <el-form-item label="关键词" prop="Keyword">
+        <el-input v-model="state.queryParams.Keyword" placeholder="事件标题/关键词" clearable @keyup.enter="handleQuery" />
+      </el-form-item>
+      <el-form-item label="创建时间" prop="exTime">
+        <el-date-picker
+            v-model="state.queryParams.exTime"
+            type="datetimerange"
+            unlink-panels
+            range-separator="至"
+            start-placeholder="开始时间"
+            end-placeholder="结束时间"
+            :shortcuts="shortcuts"
+            @change="timeStartChangeCr"
+            value-format="YYYY-MM-DD[T]HH:mm:ss"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="handleQuery" :loading="state.loading">
+          <SvgIcon name="ele-Search" class="mr5" />查询
+        </el-button>
+        <el-button @click="resetQuery(queryParamsRef)" :loading="state.loading" class="default-button">
+          <SvgIcon name="ele-Refresh" class="mr5" />重置
+        </el-button>
+      </el-form-item>
+    </el-form>
+    <el-table
+        :data="state.tableData"
+        v-loading="state.loading"
+        max-height="300"
+    >
+      <el-table-column prop="phoneNo" label="标题" show-overflow-tooltip width="180">
+        <template #default="{ row }">
+          {{ row.title }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="hotspotName" label="关键词" show-overflow-tooltip> </el-table-column>
+      <el-table-column prop="no" label="创建时间" show-overflow-tooltip width="170">
+        <template #default="{ row }">
+
+        </template>
+      </el-table-column>
+      <el-table-column prop="currentStepName" label="创建人" show-overflow-tooltip></el-table-column>
+      <el-table-column prop="statusText" label="事件工单数" width="100" fixed="right" align="center"></el-table-column>
+    </el-table>
+    <template #footer>
+				<span class="dialog-footer">
+					<el-button class="default-button" @click="state.dialogVisible = false">关 闭</el-button>
+				</span>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts" name="orderRepeatEvent">
+import {reactive, ref} from 'vue';
+import type { FormInstance } from 'element-plus';
+import {shortcuts} from "/@/utils/constants";
+import {ElButton, ElMessage} from "element-plus";
+import {throttle} from "/@/utils/tools";
+import {auth} from "/@/utils/authFunction";
+// 引入组件
+// 定义变量内容
+const state = reactive<any>({
+  dialogVisible: false, // 弹窗显示隐藏
+  queryParams: {
+    PageIndex: 1, // 当前页
+    PageSize: 10, // 每页条数
+    Keyword: '',  // 关键字
+  },
+  tableData: [], // 表格数据
+  total: 0,   // 总条数
+  loading: false, // 加载状态
+  ruleForm: {}, // 表单数据
+});
+const queryParamsRef = ref<RefType>(); // 查询参数
+const handleTimeChange = (val: string[], startKey: string, endKey: string) => {
+  if (val) {
+    state.queryParams[startKey] = val[0];
+    state.queryParams[endKey] = val[1];
+  } else {
+    state.queryParams[startKey] = '';
+    state.queryParams[endKey] = '';
+  }
+};
+// 时间
+const timeStartChangeCr = (val: string[]) => {
+  handleTimeChange(val, 'CreationTimeStart', 'CreationTimeEnd');
+};
+/** 搜索按钮操作 */
+const handleQuery = throttle(() => {
+  state.queryParams.PageIndex = 1;
+  queryList();
+}, 500);
+/** 重置按钮操作 */
+const resetQuery = throttle((formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+  handleQuery();
+}, 300);
+const queryList = ()=>{
+  if (!auth('business:order:history')) ElMessage.error('抱歉,您没有权限查询历史工单!');
+  else {
+
+  }
+}
+// 打开弹窗
+const openDialog = (row: any) => {
+  queryList();
+  state.dialogVisible = true;
+};
+const dialogRef = ref<RefType>();
+// 关闭弹窗
+const closeDialog = () => {
+  state.dialogVisible = false;
+};
+// 暴露变量
+defineExpose({
+  openDialog,
+  closeDialog,
+});
+</script>

+ 190 - 0
src/views/business/order/components/amap-select.vue

@@ -0,0 +1,190 @@
+<template>
+	<div class="map-wrapper">
+		<div id="map-container"></div>
+		<div class="search-box">
+			<el-autocomplete
+				v-model="keyword"
+				:fetch-suggestions="handleSearch"
+				:trigger-on-focus="false"
+				clearable
+				placeholder="输入城市+关键字搜索"
+				@select="handleSelect"
+				style="width: 300px"
+			/>
+			<el-input v-model="location.longitude" placeholder="点击地图选择经度" maxlength="15" readonly style="width: 150px; margin: 0 5px"></el-input>
+			<el-input v-model="location.latitude" placeholder="点击地图选择纬度" maxlength="15" readonly style="width: 150px"></el-input>
+		</div>
+	</div>
+</template>
+
+<script setup>
+import AMapLoader from '@amap/amap-jsapi-loader';
+import {computed, onMounted, ref, shallowRef, watch} from 'vue';
+window._AMapSecurityConfig = {
+	securityJsCode: import.meta.env.VITE_AMAP_SECURITYJSCODE,
+};
+const props = defineProps({
+	modelValue: {
+		type: Object,
+		default() {
+			return {};
+		},
+	},
+});
+const emit = defineEmits(['update:modelValue']);
+const map = shallowRef(null);
+// 地点
+// const location = computed({
+//   get() {
+//     return props.modelValue;
+//   },
+//   set(val) {
+//     emit('update:modelValue', val);
+//   },
+// });
+const location = ref(props.modelValue);
+watch(location, (val) => {
+	if (val.longitude && val.latitude) {
+		drawMarker();
+	}
+});
+const keyword = ref('');
+let placeSearch, AMapObj, marker, geocoder;
+const initMap = () => {
+	AMapLoader.load({
+		key: import.meta.env.VITE_AMAP_KEY, // 申请好的Web端Key,首次调用 load 时必填
+		version: '2.0',
+	}).then((AMap) => {
+		AMapObj = AMap;
+		map.value = new AMap.Map('map-container');
+		// 添加点击事件
+		map.value.on('click', onMapClick);
+		if (location.value.longitude) {
+			drawMarker();
+		}
+		AMap.plugin(['AMap.ToolBar', 'AMap.Scale', 'AMap.Geolocation', 'AMap.PlaceSearch', 'AMap.Geocoder'], () => {
+			// 缩放条
+			const toolbar = new AMap.ToolBar();
+			// 比例尺
+			const scale = new AMap.Scale();
+			// 定位
+			const geolocation = new AMap.Geolocation({
+				enableHighAccuracy: true, //是否使用高精度定位,默认:true
+				timeout: 10000, //超过10秒后停止定位,默认:5s
+				position: 'RT', //定位按钮的停靠位置
+				buttonOffset: new AMap.Pixel(10, 20), //定位按钮与设置的停靠位置的偏移量,默认:Pixel(10, 20)
+				zoomToAccuracy: true, //定位成功后是否自动调整地图视野到定位点
+			});
+			geocoder = new AMap.Geocoder({
+				city: '全国',
+			});
+			map.value.addControl(geolocation);
+			map.value.addControl(toolbar);
+			map.value.addControl(scale);
+			placeSearch = new AMap.PlaceSearch({
+				map: map.value,
+				city: '',
+				pageSize: 30, // 单页显示结果条数
+				pageIndex: 1, // 页码
+				citylimit: false, // 是否强制限制在设置的城市内搜索
+				autoFitView: true,
+			});
+		});
+	});
+};
+onMounted(() => {
+	initMap();
+});
+// 搜索地图
+const handleSearch = (queryString, cb) => {
+	placeSearch.search(queryString, (status, result) => {
+		if (result && typeof result === 'object' && result.poiList) {
+			const list = result.poiList.pois;
+			list.forEach((item) => {
+				item.value = item.name;
+				item.label = item.name;
+			});
+			cb(list);
+		} else {
+			cb([]);
+		}
+	});
+};
+// 点击地图
+const onMapClick = (e) => {
+	const { lng, lat } = e.lnglat;
+	// 逆地理编码
+	geocoder.getAddress([lng, lat], (status, result) => {
+		if (status === 'complete' && result.info === 'OK') {
+			const { addressComponent, formattedAddress } = result.regeocode;
+      let { city, province, district,township,adcode } = addressComponent;
+      if (!city) {
+        // 直辖市
+        city = province;
+      }
+      const allAddress = province+city+district+township;
+      const street = formattedAddress.substring(allAddress.length);
+			location.value = {
+				longitude: lng,
+				latitude: lat,
+        formattedAddress,
+        street,
+				zone: [province, city, district,township],
+        adcode
+			};
+      emit('update:modelValue', location.value);
+		}
+	});
+};
+// 点击搜索项
+const handleSelect = (item) => {
+	const { pname, cityname, adname, address, name } = item;
+	const { lng, lat } = item.location;
+	location.value = {
+		longitude: lng,
+		latitude: lat,
+		address,
+		zone: [pname, cityname, adname],
+		name,
+	};
+
+  emit('update:modelValue', location.value);
+	map.value.setZoomAndCenter(16, [lng, lat]);
+};
+// 绘制地点marker
+const drawMarker = (val) => {
+	const { longitude, latitude } = location.value || val;
+	if (marker) {
+		marker.setMap(null);
+	}
+	marker = new AMapObj.Marker({
+		position: new AMapObj.LngLat(longitude, latitude),
+		anchor: 'bottom-center',
+	});
+	map.value.add(marker);
+	// map.value.setZoomAndCenter(16, [longitude, latitude]);
+};
+defineExpose({
+  location,
+});
+</script>
+
+<style lang="scss" scoped>
+.map-wrapper {
+	position: relative;
+	width: 100%;
+	height: 400px;
+	#map-container {
+		width: 100%;
+		height: 100%;
+	}
+	.search-box {
+		position: absolute;
+		top: 10px;
+		left: 10px;
+		z-index: 1;
+		display: flex;
+		align-items: center;
+	}
+}
+</style>

+ 4 - 0
src/views/business/supervise/components/Order-supervise.vue

@@ -116,6 +116,10 @@ const getOrgList = async (workflowId: string) => {
 };
 // 打开弹窗
 const openDialog = (val: any) => {
+  if(!val.workflow){
+    ElMessage.warning('该工单未配置流程')
+    return;
+  }
 	state.orderDetail = val;
 	getOrgList(val.workflow.id);
 	state.dialogVisible = true;