Browse Source

Merge branch 'dev'

zhangchong 10 months ago
parent
commit
913d5ed61b

+ 0 - 106
src/components/Pagination/index.vue

@@ -1,106 +0,0 @@
-<template>
-  <div :class="{ hidden: hidden }" class="pagination-container">
-    <el-pagination :background="background" v-model:current-page="currentPage" v-model:page-size="pageSize"
-      :layout="layout" :page-sizes="pageSizes" :pager-count="pagerCount" :total="total" :small="small"
-      @size-change="handleSizeChange" @current-change="handleCurrentChange" />
-  </div>
-</template>
-
-<script lang="ts" name="pagination" setup>
-import {computed, onMounted, ref, watch} from 'vue';
-import mittBus from '@/utils/mitt';
-// 定义父组件传过来的值
-const props = defineProps({
-  total: {
-    required: true,
-    type: Number,
-  },
-  page: {
-    type: Number,
-    default: 1,
-  },
-  limit: {
-    type: Number,
-    default: 20,
-  },
-  pageSizes: {
-    type: Array,
-    default() {
-      return [10, 20, 30, 50, 100]
-    },
-  },
-  // 移动端页码按钮的数量端默认值5
-  pagerCount: {
-    type: Number,
-    default: document.body.clientWidth < 992 ? 5 : 7,
-  },
-  layout: {
-    type: String,
-    default: 'total, sizes, prev, pager, next, jumper',
-  },
-  background: {
-    type: Boolean,
-    default: false,
-  },
-  autoScroll: {
-    type: Boolean,
-    default: true,
-  },
-  hidden: {
-    type: Boolean,
-    default: false,
-  },
-})
-
-// 定义子组件向父组件传值/事件
-const emit = defineEmits(['update:page', 'update:limit', 'pagination']);
-
-// 定义变量内容
-const small = ref(false);
-const currentPage = computed({
-  get() {
-    return props.page
-  },
-  set(val) {
-    emit('update:page', val)
-  },
-})
-const pageSize = computed({
-  get() {
-    return props.limit
-  },
-  set(val) {
-    emit('update:limit', val)
-  },
-})
-const handleSizeChange = (val: any) => {
-  /**
-   * 场景:API返回总数为25条,按照10条每页,一共有3页。选了2的页数之后,然后把size选择成30条,
-   * 这个时候,分页就会同时触发size选择函数以及current选择函数。{page: 2, size: 30},{page: 1, size: 30}请求两次,会导致列表会有暂无数据的情况
-   * 解决办法:用setTimeout(函数,0),用延迟,虽然还是两次请求,但是每次都是{page: 1, size: 30}
-   */
-  setTimeout(() => {
-    emit('pagination', { page: currentPage.value, limit: val })
-  }, 0)
-  mittBus.emit('scrollTopEmit', { top: 0 });// 分页发送监听事件 滚动到页面顶部
-}
-const handleCurrentChange = (val: any) => {
-  emit('pagination', { page: val, limit: pageSize.value })
-  mittBus.emit('scrollTopEmit', { top: 0 });// 分页发送监听事件 滚动到页面顶部
-}
-onMounted(() => {
-  // 监听布局大小 改变分页的大小
-  // let themeConfig = Local.get('themeConfig');
-  // small.value = themeConfig.globalComponentSize == 'small';
-})
-</script>
-<style scoped>
-.pagination-container {
-  padding-top: 20px;
-  display: flex;
-  justify-content: flex-end;
-}
-.pagination-container.hidden {
-  display: none;
-}
-</style>

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

@@ -48,7 +48,7 @@ let isShow = ref<boolean>(true);
 const contentRef = ref();
 const isShowTooltip = function (): void {
 	// 计算span标签的offsetWidth与盒子元素的offsetWidth,给isShow赋值
-	isShow.value = contentRef.value.parentNode.offsetWidth >= contentRef.value.offsetWidth;
+	isShow.value = contentRef.value.parentNode?.offsetWidth >= contentRef.value?.offsetWidth;
 };
 </script>
 <style>

+ 41 - 32
src/layout/navBars/breadcrumb/telControl.vue

@@ -444,15 +444,15 @@
 			<el-form-item label="转接号码" prop="telNo" :rules="[{ required: true, message: '请选择转接分机或填写外部电话', trigger: 'blur' }]">
 				<el-select-v2
 					v-model="state.transferForm.telNo"
-					:options="state.telsList"
+					:options="state.threeWayAndTransfer"
 					placeholder="请选择转接分机或填写外部电话"
 					filterable
 					class="w100"
 					allow-create
 					default-first-option
 					:props="{
-						label: 'telNo',
-						value: 'telNo',
+						label: 'dicDataName',
+						value: 'dicDataValue',
 					}"
 				/>
 			</el-form-item>
@@ -498,15 +498,15 @@
 			<el-form-item label="三方通话号码" prop="telNo" :rules="[{ required: true, message: '请选择或填写三方通话号码', trigger: 'blur' }]">
 				<el-select-v2
 					v-model="state.threeWayForm.telNo"
-					:options="state.telsList"
+					:options="state.threeWayAndTransfer"
 					placeholder="请选择或填写三方通话号码"
 					filterable
 					class="w100"
 					allow-create
 					default-first-option
 					:props="{
-						label: 'telNo',
-						value: 'telNo',
+						label: 'dicDataName',
+						value: 'dicDataValue',
 					}"
 				/>
 			</el-form-item>
@@ -521,7 +521,7 @@
 </template>
 
 <script setup lang="ts" name="telControl">
-import { reactive, ref, computed, defineAsyncComponent, onMounted, onBeforeUnmount } from 'vue';
+import { reactive, ref, computed, defineAsyncComponent, onMounted, onBeforeUnmount, watch } from 'vue';
 import { ElMessageBox, ElNotification, ElMessage, FormInstance } from 'element-plus';
 import { storeToRefs } from 'pinia';
 import { useTelStatus, TelStates, RestStates } from '@/stores/telStatus';
@@ -557,6 +557,7 @@ import mittBus from '@/utils/mitt';
 import { voiceAssistant } from '@/api/todo/voiceAssistant';
 import { submitLog } from '@/api/public/log';
 import { B } from '@vueuse/motion/dist/shared/motion.5ee44005';
+import { getDataByCode } from '@/api/system/dict';
 // 引入组件
 const CommonAdvice = defineAsyncComponent(() => import('@/components/CommonAdvice/index.vue')); // 常用意见
 const AnnexList = defineAsyncComponent(() => import('@/components/AnnexList/index.vue'));
@@ -570,6 +571,7 @@ const state = reactive<any>({
 		telNo: null, //分机号
 	},
 	telsList: <EmptyArrayType>[], // 分机列表
+	threeWayAndTransfer: <EmptyArrayType>[], // 三方通话和转接
 	loading: false,
 	showHangupList: false, //是否展示挂断列表
 	restDialogVisible: false, //小休弹窗
@@ -736,8 +738,8 @@ const RestApplyPassFn = (data: any) => {
 const getTelsLists = async () => {
 	state.loading = true;
 	try {
-		const res: any = await getTelList();
-		state.telsList = res?.result ?? [];
+		const { result } = await getTelList();
+		state.telsList = result ?? [];
 		state.loading = false;
 		return state.telsList;
 	} catch (err) {
@@ -745,6 +747,15 @@ const getTelsLists = async () => {
 		state.loading = false;
 	}
 };
+// 查询三方会议和转接的号码
+const getThreeWayAndTransfer = async () => {
+	try {
+		const { result } = await getDataByCode('TransferNumber');
+		state.threeWayAndTransfer = result ?? [];
+	} catch (err) {
+		console.log(err);
+	}
+};
 // 鼠标移入移出改变图标
 const onHover = (val: string, path: string) => {
 	state[val] = getImageUrl(path);
@@ -845,7 +856,6 @@ const onConnect = () => {
 		// 普通模式才链接语音助手
 		connectVoiceAssistant(currentTel.value.telNo); // 坐席助手开启
 	}
-	// isReconnect.value = true;
 };
 // 业务系统发送消息
 const sendMsg = (msg: any) => {
@@ -1251,31 +1261,22 @@ const onClose = async (event: any) => {
 	await submitLogFn(event);
 };
 // 重新链接呼叫中心
-let reconnectAttempts = 0; // 重连次数
-let maxReconnectAttempts = 99; // 最大重连次数
-let reconnectInterval = 2; // 重连间隔
 const reconnectTimeout = ref(); // 重连定时器
+// 避免重复连接
+let lockReconnect = false;
 const reConnect = async () => {
-	/*	ElNotification({
-		title: '重连提示',
-		message: `检测到与呼叫中心链接断开,${reconnectInterval}秒后将重新链接`,
-		type: 'warning',
-		duration: reconnectInterval * 1000,
-	});*/
-	console.log('开始重连', `已重连${reconnectAttempts}次,最大重连次数${maxReconnectAttempts}次,重连间隔${reconnectInterval}秒`);
-	if (reconnectAttempts < maxReconnectAttempts) {
-		reconnectTimeout.value = setTimeout(() => {
-			reconnectAttempts++;
-			websocket_connect();
-		}, reconnectInterval * 1000);
-	} else {
-		ElNotification({
-			title: '呼叫中心重连失败',
-			message: '已到达重连次数最高,请手动刷新重连',
-			type: 'warning',
-		});
-		console.error('已到达重连次数最高,请手动刷新重连');
+	console.log(`是否锁定重连: ${lockReconnect}`);
+	if (lockReconnect) {
+		return;
 	}
+	lockReconnect = true;
+	//没连接上会一直重连,设置延迟避免请求过多
+	reconnectTimeout.value && clearTimeout(reconnectTimeout.value);
+	console.log('开始重连');
+	reconnectTimeout.value = setTimeout(() => {
+		websocket_connect();
+		lockReconnect = false;
+	}, 4 * 1000);
 };
 // 链接成功 停止重连
 const stopReconnect = () => {
@@ -2002,10 +2003,18 @@ onMounted(async () => {
 	await signalRStart(); //开启消息监听
 	await resetState(); // 先重置状态
 	await getTelsLists(); // 查询所有分机
+	await getThreeWayAndTransfer(); // 查询转接和三方
 	await callCenterConnect(); // 呼叫中心链接
 	// 加入分组
 	await signalR.joinGroup('CallCenter');
 });
+watch(
+	() => isReconnect.value,
+	(val: boolean) => {
+		console.log(`是否需要重连:${isReconnect.value}`);
+	},
+	{ immediate: true }
+);
 onBeforeUnmount(() => {
 	mittBus.off('RestApplyPass');
 	if (ola.ws) ola.close();

+ 5 - 0
src/utils/constants.ts

@@ -154,3 +154,8 @@ export const defaultDateThree = [
   dayjs().startOf('day').subtract(3, 'month').format('YYYY-MM-DD[T]HH:mm:ss'),
   dayjs().endOf('day').format('YYYY-MM-DD[T]HH:mm:ss'),
 ];
+// 默认选择日期(近一个月)
+export const defaultDateOne = [
+  dayjs().startOf('day').subtract(1, 'month').format('YYYY-MM-DD[T]HH:mm:ss'),
+  dayjs().endOf('day').format('YYYY-MM-DD[T]HH:mm:ss'),
+];

+ 0 - 1
src/views/business/discern/todo.vue

@@ -225,7 +225,6 @@ const handleQuery = () => {
 };
 /** 获取列表 */
 const queryList = () => {
-	const index = columns.value.findIndex((item) => item.prop === 'title');
 	let request = other.deepClone(state.queryParams);
 	Reflect.deleteProperty(request, 'exTime'); // 删除无用的参数
 	state.loading = true;

+ 34 - 53
src/views/business/order/index.vue

@@ -13,7 +13,7 @@
 				</el-checkbox-group>
 			</div>
 			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent label-width="100px">
-				<el-row :gutter="10">
+				<el-row :gutter="0">
 					<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
 						<el-form-item label="工单标题" prop="Keyword">
 							<el-input v-model="state.queryParams.Keyword" placeholder="工单标题" clearable @keyup.enter="handleQuery" />
@@ -25,8 +25,18 @@
 						</el-form-item>
 					</el-col>
 					<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
-						<el-form-item label="省本地编号" prop="ProvinceNo">
-							<el-input v-model="state.queryParams.ProvinceNo" placeholder="省本地编号" clearable @keyup.enter="handleQuery" />
+						<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"
+							/>
 						</el-form-item>
 					</el-col>
 					<transition name="el-zoom-in-top">
@@ -162,18 +172,8 @@
 					</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="timeStartChangeCr"
-									value-format="YYYY-MM-DD[T]HH:mm:ss"
-								/>
+							<el-form-item label="省本地编号" prop="ProvinceNo">
+								<el-input v-model="state.queryParams.ProvinceNo" placeholder="省本地编号" clearable @keyup.enter="handleQuery" />
 							</el-form-item>
 						</el-col>
 					</transition>
@@ -211,7 +211,7 @@
 					</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="exTime">
+							<el-form-item label="期时间" prop="exTime">
 								<el-date-picker
 									v-model="state.queryParams.exTime"
 									type="datetimerange"
@@ -220,7 +220,7 @@
 									start-placeholder="开始时间"
 									end-placeholder="结束时间"
 									:shortcuts="shortcuts"
-									@change="timeStartChangeEx"
+									@change="handleQuery"
 									value-format="YYYY-MM-DD[T]HH:mm:ss"
 								/>
 							</el-form-item>
@@ -263,7 +263,7 @@
 									start-placeholder="开始时间"
 									end-placeholder="结束时间"
 									:shortcuts="shortcuts"
-									@change="timeStartChangeDone"
+									@change="handleQuery"
 									value-format="YYYY-MM-DD[T]HH:mm:ss"
 								/>
 							</el-form-item>
@@ -382,7 +382,7 @@
 import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
 import type { FormInstance } from 'element-plus';
 import { ElMessage, ElMessageBox, ElNotification } from 'element-plus';
-import { shortcuts } from '@/utils/constants';
+import { defaultDateOne, shortcuts } from "@/utils/constants";
 import other from '@/utils/other';
 import { useRoute, useRouter } from 'vue-router';
 import { formatDate } from '@/utils/formatTime';
@@ -392,6 +392,7 @@ import { addEnd } from '@/api/query/end';
 import { treeArea } from '@/api/auxiliary/area';
 import { orderSign } from '@/api/todo/order';
 import { downloadFileByStream, downloadZip } from '@/utils/tools';
+import Other from "@/utils/other";
 
 // 引入组件
 const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
@@ -423,7 +424,7 @@ const state = reactive<any>({
 		HotspotIds: [], // 热点
 		OrgCodes: [], // 机构
 		NameOrNo: null, // 受理坐席
-		crTime: [], // 创建时间
+		crTime: defaultDateOne, // 生成时间
 		CreationTimeStart: null, // 创建时间 开始
 		CreationTimeEnd: null, // 创建时间 结束
 		TransferPhone: null, // 转派人
@@ -555,28 +556,6 @@ const changeArea = () => {
 	const area = areaRef.value?.getCheckedNodes() ?? [];
 	state.queryParams.AreaCodes = area.map((item: any) => item.value);
 };
-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] = '';
-	}
-	handleQuery();
-};
-// 受理时间
-const timeStartChangeCr = (val: string[]) => {
-	handleTimeChange(val, 'CreationTimeStart', 'CreationTimeEnd');
-};
-// 过期时间
-const timeStartChangeEx = (val: string[]) => {
-	handleTimeChange(val, 'ExpiredTimeStart', 'ExpiredTimeEnd');
-};
-// 办结时间
-const timeStartChangeDone = (val: string[]) => {
-	handleTimeChange(val, 'ActualHandleTimeStart', 'ActualHandleTimeEnd');
-};
 // 获取查询条件基础信息
 const getBaseData = async () => {
 	try {
@@ -607,11 +586,19 @@ const handleQuery = () => {
 };
 /** 获取列表 */
 const queryList = () => {
-	let request = other.deepClone(state.queryParams);
-	Reflect.deleteProperty(request, 'crTime'); // 删除无用的参数
-	Reflect.deleteProperty(request, 'exTime'); // 删除无用的参数
-	Reflect.deleteProperty(request, 'doneTime'); // 删除无用的参数
-	Reflect.deleteProperty(request, 'AreaCode'); // 删除无用的参数
+
+  let request = Other.deepClone(state.queryParams);
+  request.CreationTimeStart = state.queryParams.crTime === null ? null : state.queryParams.crTime[0]; // 生成时间
+  request.CreationTimeEnd = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
+  request.ExpiredTimeStart = state.queryParams.exTime === null ? null : state.queryParams.exTime[0]; // 期满时间
+  request.ExpiredTimeEnd = state.queryParams.exTime === null ? null : state.queryParams.exTime[1];
+  request.ActualHandleTimeStart = state.queryParams.doneTime === null ? null : state.queryParams.doneTime[0]; // 期满时间
+  request.ActualHandleTimeEnd = state.queryParams.doneTime === null ? null : state.queryParams.doneTime[1];
+  Reflect.deleteProperty(request, 'crTime'); // 删除无用的参数
+  Reflect.deleteProperty(request, 'exTime'); // 删除无用的参数
+  Reflect.deleteProperty(request, 'doneTime'); // 删除无用的参数
+  Reflect.deleteProperty(request, 'AreaCode'); // 删除无用的参数
+
 	state.loading = true;
 	orderList(request)
 		.then((response: any) => {
@@ -629,12 +616,6 @@ const hotSpotRef = ref<RefType>();
 const resetQuery = (formEl: FormInstance | undefined) => {
 	if (!formEl) return;
 	formEl.resetFields();
-	state.queryParams.CreationTimeStart = null;
-	state.queryParams.CreationTimeEnd = null;
-	state.queryParams.ExpiredTimeStart = null;
-	state.queryParams.ExpiredTimeEnd = null;
-	state.queryParams.ActualHandleTimeStart = null;
-	state.queryParams.ActualHandleTimeEnd = null;
 	state.queryParams.IsSensitiveWord = null;
 	state.queryParams.IsProvinceOrder = null;
 	fastSearch.value = 'all';

+ 55 - 10
src/views/knowledge/config/type/component/Knowledge-type-add.vue

@@ -1,14 +1,14 @@
 <template>
 	<div class="knowledge-type-add-container">
-		<el-dialog title="新增类型" v-model="state.dialogVisible" width="500px" draggable>
-			<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="80px">
-				<el-row :gutter="35">
-					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+		<el-dialog title="新增类型" v-model="state.dialogVisible" draggable append-to-body destroy-on-close @close="close">
+			<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="80px" v-loading="state.loading">
+				<el-row :gutter="10">
+					<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
 						<el-form-item label="类型名称" prop="name" :rules="[{ required: true, message: '请填写类型名称', trigger: 'blur' }]">
 							<el-input v-model="state.ruleForm.name" placeholder="请填写类型名称" clearable></el-input>
 						</el-form-item>
 					</el-col>
-					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
 						<el-form-item label="上级类型" prop="parentId" :rules="[{ required: false, message: '请选择上级类型', trigger: 'change' }]">
 							<el-cascader
 								:options="state.treeData"
@@ -24,7 +24,23 @@
 							</el-cascader>
 						</el-form-item>
 					</el-col>
-					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
+						<el-form-item label="适用部门" prop="orgArray" :rules="[{ required: true, message: '请选择适用部门', trigger: 'change' }]">
+							<el-cascader
+								:options="orgData"
+								filterable
+								:props="{ checkStrictly: true, value: 'id', label: 'name', emitPath: false, multiple: true }"
+								placeholder="请选择适用部门"
+								clearable
+								class="w100"
+								v-model="state.ruleForm.orgArray"
+								ref="orgRef"
+								@change="changeOrgData"
+							>
+							</el-cascader>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
 						<el-form-item label="排序" prop="sort" :rules="[{ required: false, message: '请填写排序', trigger: 'blur' }]">
 							<el-input-number v-model="state.ruleForm.sort" :min="0" :precision="0" class="w100" placeholder="请填写排序" />
 						</el-form-item>
@@ -34,7 +50,7 @@
 			<template #footer>
 				<span class="dialog-footer">
 					<el-button @click="closeDialog" class="default-button">取 消</el-button>
-					<el-button type="primary" @click="onSubmit(ruleFormRef)" v-waves="'light'" :loading="state.loading">确 定 </el-button>
+					<el-button type="primary" @click="onSubmit(ruleFormRef)" :loading="state.loading">确 定 </el-button>
 				</span>
 			</template>
 		</el-dialog>
@@ -45,6 +61,7 @@
 import { reactive, ref } from 'vue';
 import { ElMessage, FormInstance } from 'element-plus';
 import { addType } from '@/api/knowledge/type';
+import { getCanUseOrg } from '@/api/system/user';
 
 // 定义子组件向父组件传值/事件
 const emit = defineEmits(['updateList']);
@@ -54,19 +71,36 @@ const state = reactive<any>({
 	dialogVisible: false, // 弹窗
 	ruleForm: {
 		name: '', // 类型名称
-		sort: 0,  // 排序
+		sort: 0, // 排序
 		parentId: '', // 上级类型
+    orgArray:[]
 	},
 	treeData: [], // 上级
 	loading: false, // 加载
 });
+// 获取机构数据
+const orgData = ref<any[]>([]);
+const getOrgData = async () => {
+	state.loading = true;
+	getCanUseOrg()
+		.then((res: any) => {
+			orgData.value = res?.result ?? [];
+			state.loading = false;
+		})
+		.catch(() => {
+			state.loading = false;
+		});
+};
 // 打开弹窗
 const ruleFormRef = ref<any>(); // 表单ref
-const openDialog = (treeData: any) => {
+const openDialog = (treeData: any[], orgData: any[]) => {
 	state.treeData = treeData ?? [];
+	getOrgData();
+	state.dialogVisible = true;
+};
+const close = () => {
 	ruleFormRef.value?.clearValidate();
 	ruleFormRef.value?.resetFields();
-	state.dialogVisible = true;
 };
 // 关闭弹窗
 const closeDialog = () => {
@@ -78,6 +112,17 @@ const getKnowledgeList = () => {
 	let currentNode = cascadeRef.value.getCheckedNodes();
 	state.ruleForm.parentName = currentNode[0]?.label ?? '';
 };
+// 选择适用部门
+const orgRef = ref<RefType>();
+const changeOrgData = () => {
+	let currentNode = orgRef.value.getCheckedNodes();
+  state.ruleForm.typeOrgDtos = currentNode.map((item: any) => {
+    return {
+      orgId: item.value,
+      orgName: item.label
+    }
+  });
+};
 // 新增
 const onSubmit = async (formEl: FormInstance | undefined) => {
 	if (!formEl) return;

+ 62 - 11
src/views/knowledge/config/type/component/Knowledge-type-edit.vue

@@ -1,14 +1,14 @@
 <template>
 	<div class="knowledge-type-edit-container">
-		<el-dialog title="修改类型" v-model="state.dialogVisible" width="500px" draggable>
-			<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="80px">
-				<el-row :gutter="35">
-					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+		<el-dialog title="修改类型" v-model="state.dialogVisible" draggable append-to-body destroy-on-close @close="close">
+			<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="80px" v-loading="state.loading">
+				<el-row :gutter="10">
+					<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
 						<el-form-item label="类型名称" prop="name" :rules="[{ required: true, message: '请填写类型名称', trigger: 'blur' }]">
 							<el-input v-model="state.ruleForm.name" placeholder="请填写类型名称" clearable></el-input>
 						</el-form-item>
 					</el-col>
-					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
 						<el-form-item label="上级类型" prop="parentId" :rules="[{ required: false, message: '请选择上级类型', trigger: 'change' }]">
 							<el-cascader
 								:options="state.treeData"
@@ -24,7 +24,26 @@
 							</el-cascader>
 						</el-form-item>
 					</el-col>
-					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
+						<el-form-item label="适用部门" prop="orgArray" :rules="[{ required: true, message: '请选择适用部门', trigger: 'change' }]">
+							<el-cascader
+								:options="orgData"
+								filterable
+								:props="{ checkStrictly: true, value: 'id', label: 'name', emitPath: false, multiple: true }"
+								placeholder="请选择适用部门"
+								clearable
+								class="w100"
+								v-model="state.ruleForm.orgArray"
+								ref="orgRef"
+								@change="changeOrgData"
+								collapse-tags
+								collapse-tags-tooltip
+								:max-collapse-tags="3"
+							>
+							</el-cascader>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
 						<el-form-item label="排序" prop="sort" :rules="[{ required: false, message: '请填写排序', trigger: 'blur' }]">
 							<el-input-number v-model="state.ruleForm.sort" :min="0" :precision="0" class="w100" placeholder="请填写排序" />
 						</el-form-item>
@@ -34,7 +53,7 @@
 			<template #footer>
 				<span class="dialog-footer">
 					<el-button @click="closeDialog" class="default-button">取 消</el-button>
-					<el-button type="primary" @click="onSubmit(ruleFormRef)" v-waves="'light'" :loading="state.loading">确 定 </el-button>
+					<el-button type="primary" @click="onSubmit(ruleFormRef)" :loading="state.loading">确 定 </el-button>
 				</span>
 			</template>
 		</el-dialog>
@@ -47,6 +66,7 @@ import { ElMessage, FormInstance } from 'element-plus';
 import { excludeSelfById } from '@/utils/tools';
 import other from '@/utils/other';
 import { updateType, typeDetail } from '@/api/knowledge/type';
+import { getCanUseOrg } from '@/api/system/user';
 
 // 定义子组件向父组件传值/事件
 const emit = defineEmits(['updateList']);
@@ -56,26 +76,46 @@ const state = reactive<any>({
 	dialogVisible: false, // 弹窗
 	ruleForm: {
 		name: '', // 类型名称
-		sort: 0,  // 排序
+		sort: 0, // 排序
 		parentId: '', // 上级类型
+		orgArray: [],
 	},
 	treeData: [], // 上级
 	loading: false, // 加载
 });
+// 获取机构数据
+const orgData = ref<any[]>([]);
+const getOrgData = async () => {
+	state.loading = true;
+	getCanUseOrg()
+		.then((res: any) => {
+			orgData.value = res?.result ?? [];
+			state.loading = false;
+		})
+		.catch(() => {
+			state.loading = false;
+		});
+};
 // 打开弹窗
 const ruleFormRef = ref<any>(); // 表单ref
 const openDialog = async (row: any, treeData: any) => {
 	try {
-		const res: any = await typeDetail(row.id);
-		state.ruleForm = res.result;
+		await getOrgData();
+		const { result } = await typeDetail(row.id);
+		state.ruleForm = result;
 		state.treeData = other.deepClone(treeData);
 		state.treeData = excludeSelfById(state.treeData, row.id);
+		state.ruleForm.orgArray = result.knowledgeTypeOrgs.map((item: any) => item.orgId);
 		state.dialogVisible = true;
 	} catch (error) {
 		// 打印错误信息
 		console.error(error);
 	}
 };
+const close = () => {
+	ruleFormRef.value?.clearValidate();
+	ruleFormRef.value?.resetFields();
+};
 // 关闭弹窗
 const closeDialog = () => {
 	state.dialogVisible = false;
@@ -86,7 +126,18 @@ const getKnowledgeList = () => {
 	let currentNode = cascadeRef.value.getCheckedNodes();
 	state.ruleForm.parentName = currentNode[0]?.label ?? '';
 };
-// 新增
+// 选择适用部门
+const orgRef = ref<RefType>();
+const changeOrgData = () => {
+	let currentNode = orgRef.value.getCheckedNodes();
+	state.ruleForm.typeOrgDtos = currentNode.map((item: any) => {
+		return {
+			orgId: item.value,
+			orgName: item.label,
+		};
+	});
+};
+// 保存
 const onSubmit = async (formEl: FormInstance | undefined) => {
 	if (!formEl) return;
 	await formEl.validate((valid: boolean) => {

+ 10 - 0
src/views/knowledge/config/type/index.vue

@@ -62,6 +62,7 @@ import { formatDate } from '@/utils/formatTime';
 import { delType, treeList } from '@/api/knowledge/type';
 import { throttle } from '@/utils/tools';
 import other from '@/utils/other';
+import { getCanUseOrg } from "@/api/system/user";
 // 引入组件
 const KnowledgeTypeAdd = defineAsyncComponent(() => import('@/views/knowledge/config/type/component/Knowledge-type-add.vue')); // 新增组件
 const KnowledgeTypeEdit = defineAsyncComponent(() => import('@/views/knowledge/config/type/component/Knowledge-type-edit.vue')); // 修改组件
@@ -89,6 +90,15 @@ const state = reactive<any>({
         return <TextTooltip content={data.rowData.name} effect="dark" placement="top"></TextTooltip>;
       },
 		},
+    {
+      key: 'name',
+      dataKey: 'name',
+      title: '所属部门',
+      width: 300,
+      cellRenderer: (data: any) => {
+        return <TextTooltip content={data.rowData.name} effect="dark" placement="top"></TextTooltip>;
+      },
+    },
 		{
 			key: 'sort',
 			dataKey: 'sort',

+ 4 - 4
src/views/knowledge/index/edit.vue

@@ -114,7 +114,7 @@
 							</template>
 						</el-skeleton>
 					</el-col>
-					<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
+<!--					<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
 						<el-skeleton :loading="state.loading" animated>
 							<template #template>
 								<el-form-item label="来源部门" prop="sourceOrganizeId" :rules="[{ required: true, message: '请选择来源部门', trigger: 'change' }]">
@@ -136,7 +136,7 @@
 								</el-form-item>
 							</template>
 						</el-skeleton>
-					</el-col>
+					</el-col>-->
 					<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
 						<el-skeleton :loading="state.loading" animated>
 							<template #template>
@@ -423,7 +423,7 @@ const cascadeRef = ref<RefType>();
 const getKnowledgeList = () => {
 	let currentNode = cascadeRef.value.getCheckedNodes();
 	state.ruleForm.knowledgeType = currentNode.map((item: any) => {
-		return { value: item.label, key: item.value, splice: item.data.spliceName };
+		return { KnowledgeTypeName: item.label, KnowledgeTypeId: item.value, KnowledgeTypeSpliceName : item.data.spliceName };
 	});
 };
 // 添加关键词
@@ -604,7 +604,7 @@ const getDetail = async () => {
 		if (state.ruleForm.keywordsDto && state.ruleForm.keywordsDto.length) {
 			state.ruleForm.keywordsName = state.ruleForm.keywordsDto.map((item: any) => item.tag).join(',');
 		}
-		state.ruleForm.knowledgeTypeId = state.ruleForm.knowledgeType.map((item: any) => item.key);
+		state.ruleForm.knowledgeTypeId = state.ruleForm.knowledgeType.map((item: any) => item.knowledgeTypeId);
 	}
 };
 onMounted(() => {

+ 130 - 100
src/views/knowledge/index/index.vue

@@ -3,110 +3,137 @@
 		<el-card shadow="never" class="h100">
 			<splitpanes class="h100" :horizontal="horizontal">
 				<pane min-size="16" max-size="25" size="16">
-					<el-tabs v-model="state.activeName" stretch @tab-change="resetNode">
-						<el-tab-pane label="部门" name="0">
-							<el-input v-model="filterOrg" placeholder="请填写部门名称" class="input-with-select mb10" clearable @input="onQueryChanged"> </el-input>
-						</el-tab-pane>
-						<el-tab-pane label="知识分类" name="1">
-							<el-input v-model="filterType" placeholder="请填写知识分类名称" class="input-with-select mb10" clearable> </el-input>
-						</el-tab-pane>
-						<el-tab-pane label="热点" name="2">
-							<el-input v-model="filterHot" placeholder="请填写热点名称" class="input-with-select mb10" clearable> </el-input>
-						</el-tab-pane>
-					</el-tabs>
-					<el-scrollbar style="height: calc(100% - 100px);'" ref="scrollBarRef" noresize>
-						<el-skeleton
-							:loading="state.loading"
-							animated
-							:rows="10"
-							:style="state.activeName === '0' ? 'min-width: 100%; display: inline-block' : 'display:none'"
-						>
-							<template #default>
-								<el-tree-v2
-									:data="state.orgData"
-									highlight-current
-									:expand-on-click-node="false"
-									:props="{ children: 'children', label: 'name' }"
-									@node-click="handleNodeClick"
-									ref="orgRef"
-									:filter-method="filterNode"
-									:item-size="40"
-									:height="treeHeight"
-									empty-text="暂无组织数据"
-									:style="state.activeName === '0' ? 'min-width: 100%; display: inline-block' : 'display:none'"
-								>
-									<template #default="{ node }">
-										<span :title="node.label">{{ node.label }}</span>
-									</template>
-								</el-tree-v2>
-							</template>
-						</el-skeleton>
-						<el-skeleton
-							:loading="state.typeLoading"
-							animated
-							:rows="10"
-							:style="state.activeName === '1' ? 'min-width: 100%; display: inline-block' : 'display:none'"
-						>
-							<template #default>
-								<el-tree
-									:data="state.knowledgeOptions"
-									highlight-current
-									:expand-on-click-node="false"
-									:props="{ children: 'children', label: 'name' }"
-									@node-click="handleNodeClick"
-									ref="typeRef"
-									:filter-node-method="filterNodeType"
-									node-key="id"
-									:style="state.activeName === '1' ? 'min-width: 100%; display: inline-block' : 'display:none'"
-								>
-								</el-tree>
-							</template>
-						</el-skeleton>
-						<el-skeleton
-							:loading="state.loading"
-							animated
-							:rows="10"
-							:style="state.activeName === '2' ? 'min-width: 100%; display: inline-block' : 'display:none'"
-						>
-							<template #default>
-								<el-tree
-									node-key="id"
-									:load="loadNode"
-									lazy
-									v-if="lazyShow"
-									:props="{
+          <template v-if="userInfos.isCenter">
+            <el-tabs v-model="state.activeName" stretch @tab-change="resetNode">
+              <el-tab-pane label="部门" name="0">
+                <el-input v-model="filterOrg" placeholder="请填写部门名称" class="input-with-select mb10" clearable @input="onQueryChanged"> </el-input>
+              </el-tab-pane>
+              <el-tab-pane label="知识分类" name="1">
+                <el-input v-model="filterType" placeholder="请填写知识分类名称" class="input-with-select mb10" clearable> </el-input>
+              </el-tab-pane>
+              <el-tab-pane label="热点" name="2">
+                <el-input v-model="filterHot" placeholder="请填写热点名称" class="input-with-select mb10" clearable> </el-input>
+              </el-tab-pane>
+            </el-tabs>
+            <el-scrollbar style="height: calc(100% - 100px);'" ref="scrollBarRef" noresize>
+              <el-skeleton
+                :loading="state.loading"
+                animated
+                :rows="10"
+                :style="state.activeName === '0' ? 'min-width: 100%; display: inline-block' : 'display:none'"
+              >
+                <template #default>
+                  <el-tree-v2
+                    :data="state.orgData"
+                    highlight-current
+                    :expand-on-click-node="false"
+                    :props="{ children: 'children', label: 'name' }"
+                    @node-click="handleNodeClick"
+                    ref="orgRef"
+                    :filter-method="filterNode"
+                    :item-size="40"
+                    :height="treeHeight"
+                    empty-text="暂无组织数据"
+                    :style="state.activeName === '0' ? 'min-width: 100%; display: inline-block' : 'display:none'"
+                  >
+                    <template #default="{ node }">
+                      <span :title="node.label">{{ node.label }}</span>
+                    </template>
+                  </el-tree-v2>
+                </template>
+              </el-skeleton>
+              <el-skeleton
+                :loading="state.typeLoading"
+                animated
+                :rows="10"
+                :style="state.activeName === '1' ? 'min-width: 100%; display: inline-block' : 'display:none'"
+              >
+                <template #default>
+                  <el-tree
+                    :data="state.knowledgeOptions"
+                    highlight-current
+                    :expand-on-click-node="false"
+                    :props="{ children: 'children', label: 'name' }"
+                    @node-click="handleNodeClick"
+                    ref="typeRef"
+                    :filter-node-method="filterNodeType"
+                    node-key="id"
+                    :style="state.activeName === '1' ? 'min-width: 100%; display: inline-block' : 'display:none'"
+                  >
+                  </el-tree>
+                </template>
+              </el-skeleton>
+              <el-skeleton
+                :loading="state.loading"
+                animated
+                :rows="10"
+                :style="state.activeName === '2' ? 'min-width: 100%; display: inline-block' : 'display:none'"
+              >
+                <template #default>
+                  <el-tree
+                    node-key="id"
+                    :load="loadNode"
+                    lazy
+                    v-if="lazyShow"
+                    :props="{
 										label: 'hotSpotFullName',
 										children: 'children',
 										isLeaf: 'hasChild',
 									}"
-									:filter-node-method="filterNodeHot"
-									@node-click="handleNodeClick"
-									highlight-current
-									check-strictly
-									:expand-on-click-node="false"
-									ref="hotRef"
-									:style="state.activeName === '2' ? 'min-width: 100%; display: inline-block' : 'display:none'"
-								/>
-								<el-tree
-									ref="hotRef"
-									:data="state.hotSpotData"
-									node-key="id"
-									v-else
-									default-expand-all
-									highlight-current
-									:props="{
+                    :filter-node-method="filterNodeHot"
+                    @node-click="handleNodeClick"
+                    highlight-current
+                    check-strictly
+                    :expand-on-click-node="false"
+                    ref="hotRef"
+                    :style="state.activeName === '2' ? 'min-width: 100%; display: inline-block' : 'display:none'"
+                  />
+                  <el-tree
+                    ref="hotRef"
+                    :data="state.hotSpotData"
+                    node-key="id"
+                    v-else
+                    default-expand-all
+                    highlight-current
+                    :props="{
 										label: 'hotSpotFullName',
 										children: 'children',
 									}"
-									:filter-node-method="filterNodeHot"
-									@node-click="handleNodeClick"
-									:expand-on-click-node="false"
-									check-strictly
-									:style="state.activeName === '2' ? 'min-width: 100%; display: inline-block' : 'display:none'"
-								/>
-							</template>
-						</el-skeleton>
-					</el-scrollbar>
+                    :filter-node-method="filterNodeHot"
+                    @node-click="handleNodeClick"
+                    :expand-on-click-node="false"
+                    check-strictly
+                    :style="state.activeName === '2' ? 'min-width: 100%; display: inline-block' : 'display:none'"
+                  />
+                </template>
+              </el-skeleton>
+            </el-scrollbar>
+          </template>
+				  <template v-else>
+            <el-input v-model="filterType" placeholder="请填写知识分类名称" class="input-with-select mb10" clearable> </el-input>
+            <el-scrollbar ref="scrollBarRef" noresiz style="height: calc(100% - 50px);'">
+              <el-skeleton
+                :loading="state.typeLoading"
+                animated
+                :rows="10"
+              >
+                <template #default>
+                  <el-tree
+                    :data="state.knowledgeOptions"
+                    highlight-current
+                    :expand-on-click-node="false"
+                    :props="{ children: 'children', label: 'name' }"
+                    @node-click="handleNodeClick"
+                    ref="typeRef"
+                    :filter-node-method="filterNodeType"
+                    node-key="id"
+                    style="min-width: 100%; display: inline-block"
+                  >
+                  </el-tree>
+                </template>
+              </el-skeleton>
+            </el-scrollbar>
+          </template>
 				</pane>
 				<pane>
 					<el-scrollbar class="pr10 scrollbar__view">
@@ -159,7 +186,7 @@
 							:key="Math.random()"
 						>
 							<template #tableHeader="scope">
-								<el-button type="primary" @click="onOpenAddUser" v-auth="'knowledge:index:add'">
+								<el-button type="primary" @click="onOpenAddUser" v-auth="'knowledge:index:add'" :loading="state.loading">
 									<SvgIcon name="ele-Plus" class="mr5" />创建知识
 								</el-button>
 							</template>
@@ -251,6 +278,8 @@ import { treeList } from '@/api/knowledge/type';
 import { hotSpotSearch, hotSpotType } from '@/api/business/order';
 import { Splitpanes, Pane } from 'splitpanes';
 import 'splitpanes/dist/splitpanes.css';
+import { useUserInfo } from "@/stores/userInfo";
+import { storeToRefs } from "pinia";
 
 // 引入组件
 const ProcessAudit = defineAsyncComponent(() => import('@/components/ProcessAudit/index.vue')); // 流程审批
@@ -287,7 +316,8 @@ const state = reactive<any>({
 const router = useRouter(); //路由
 const ruleFormRef = ref<FormInstance>(); //表单ref
 const horizontal = ref(false);
-
+const storesUserInfo = useUserInfo();
+const { userInfos } = storeToRefs(storesUserInfo); // 用户信息
 // 热点分类懒加载
 const lazyShow = ref(true);
 const loading = ref(false);
@@ -387,7 +417,7 @@ const getKnowledgeType = async () => {
 };
 const staticColumns = [
 	{ prop: 'title', label: '标题', width: 300 },
-	{ prop: 'knowledgeType', label: '知识分类', width: 200 },
+	{ prop: 'knowledgeTypeText', label: '知识分类', width: 200 },
 	{ prop: 'statusName', label: '知识状态' },
 	{ prop: 'attribution', label: '知识归属', width: 120 },
 	{ prop: 'sourceOrganize.name', label: '来源部门', width: 120 },

+ 123 - 92
src/views/knowledge/retrieval/index.vue

@@ -8,105 +8,132 @@
 			</el-tabs>
 			<splitpanes class="h100" Vertical>
 				<pane min-size="16" max-size="25" size="16" class="left-container">
-					<el-tabs v-model="state.activeName" stretch @tab-change="resetNode">
-						<el-tab-pane label="部门" name="0">
-							<el-input v-model="filterOrg" placeholder="请填写部门名称" class="input-with-select mb10" clearable @input="onQueryChanged"> </el-input>
-						</el-tab-pane>
-						<el-tab-pane label="知识分类" name="1">
-							<el-input v-model="filterType" placeholder="请填写知识分类名称" class="input-with-select mb10" clearable> </el-input>
-						</el-tab-pane>
-						<el-tab-pane label="热点" name="2">
-							<el-input v-model="filterHot" placeholder="请填写热点名称" class="input-with-select mb10" clearable> </el-input>
-						</el-tab-pane>
-					</el-tabs>
-					<el-scrollbar style="height: calc(100% - 140px);'" ref="scrollBarRef">
-            <el-skeleton :loading="state.loading" animated :rows="10" :style="state.activeName === '0' ? 'min-width: 100%; display: inline-block' : 'display:none'">
-              <template #default>
-                <el-tree-v2
-                  :data="state.orgData"
-                  highlight-current
-                  :expand-on-click-node="false"
-                  :props="{ children: 'children', label: 'name' }"
-                  @node-click="handleNodeClick"
-                  ref="orgRef"
-                  :filter-method="filterNode"
-                  :item-size="40"
-                  :height="treeHeight"
-                  empty-text="暂无组织数据"
-                  :style="state.activeName === '0' ? 'min-width: 100%; display: inline-block' : 'display:none'"
-                >
-                  <template #default="{ node }">
-                    <span :title="node.label">{{ node.label }}</span>
-                  </template>
-                </el-tree-v2>
-              </template>
-            </el-skeleton>
-            <el-skeleton
-              :loading="state.typeLoading"
-              animated
-              :rows="10"
-              :style="state.activeName === '1' ? 'min-width: 100%; display: inline-block' : 'display:none'"
-            >
-              <template #default>
-                <el-tree
-                  :data="state.knowledgeOptions"
-                  highlight-current
-                  :expand-on-click-node="false"
-                  :props="{ children: 'children', label: 'name' }"
-                  @node-click="handleNodeClick"
-                  ref="typeRef"
-                  :filter-node-method="filterNodeType"
-                  node-key="id"
-                  :style="state.activeName === '1' ? 'min-width: 100%; display: inline-block' : 'display:none'"
-                >
-                </el-tree>
-              </template>
-            </el-skeleton>
-            <el-skeleton
-              :loading="state.loading"
-              animated
-              :rows="10"
-              :style="state.activeName === '2' ? 'min-width: 100%; display: inline-block' : 'display:none'"
-            >
-              <template #default>
-                <el-tree
-                  node-key="id"
-                  :load="loadNode"
-                  lazy
-                  v-if="lazyShow"
-                  :props="{
+          <template v-if="userInfos.isCenter">
+            <el-tabs v-model="state.activeName" stretch @tab-change="resetNode">
+              <el-tab-pane label="部门" name="0">
+                <el-input v-model="filterOrg" placeholder="请填写部门名称" class="input-with-select mb10" clearable @input="onQueryChanged"> </el-input>
+              </el-tab-pane>
+              <el-tab-pane label="知识分类" name="1">
+                <el-input v-model="filterType" placeholder="请填写知识分类名称" class="input-with-select mb10" clearable> </el-input>
+              </el-tab-pane>
+              <el-tab-pane label="热点" name="2">
+                <el-input v-model="filterHot" placeholder="请填写热点名称" class="input-with-select mb10" clearable> </el-input>
+              </el-tab-pane>
+            </el-tabs>
+            <el-scrollbar style="height: calc(100% - 140px);'" ref="scrollBarRef" noresize>
+              <el-skeleton :loading="state.loading" animated :rows="10" :style="state.activeName === '0' ? 'min-width: 100%; display: inline-block' : 'display:none'">
+                <template #default>
+                  <el-tree-v2
+                    :data="state.orgData"
+                    highlight-current
+                    :expand-on-click-node="false"
+                    :props="{ children: 'children', label: 'name' }"
+                    @node-click="handleNodeClick"
+                    ref="orgRef"
+                    :filter-method="filterNode"
+                    :item-size="40"
+                    :height="treeHeight"
+                    empty-text="暂无组织数据"
+                    :style="state.activeName === '0' ? 'min-width: 100%; display: inline-block' : 'display:none'"
+                  >
+                    <template #default="{ node }">
+                      <span :title="node.label">{{ node.label }}</span>
+                    </template>
+                  </el-tree-v2>
+                </template>
+              </el-skeleton>
+              <el-skeleton
+                :loading="state.typeLoading"
+                animated
+                :rows="10"
+                :style="state.activeName === '1' ? 'min-width: 100%; display: inline-block' : 'display:none'"
+              >
+                <template #default>
+                  <el-tree
+                    :data="state.knowledgeOptions"
+                    highlight-current
+                    :expand-on-click-node="false"
+                    :props="{ children: 'children', label: 'name' }"
+                    @node-click="handleNodeClick"
+                    ref="typeRef"
+                    :filter-node-method="filterNodeType"
+                    node-key="id"
+                    :style="state.activeName === '1' ? 'min-width: 100%; display: inline-block' : 'display:none'"
+                  >
+                  </el-tree>
+                </template>
+              </el-skeleton>
+              <el-skeleton
+                :loading="state.loading"
+                animated
+                :rows="10"
+                :style="state.activeName === '2' ? 'min-width: 100%; display: inline-block' : 'display:none'"
+              >
+                <template #default>
+                  <el-tree
+                    node-key="id"
+                    :load="loadNode"
+                    lazy
+                    v-if="lazyShow"
+                    :props="{
 										label: 'hotSpotFullName',
 										children: 'children',
 										isLeaf: 'hasChild',
 									}"
-                  :filter-node-method="filterNodeHot"
-                  @node-click="handleNodeClick"
-                  highlight-current
-                  check-strictly
-                  :expand-on-click-node="false"
-                  ref="hotRef"
-                  :style="state.activeName === '2' ? 'min-width: 100%; display: inline-block' : 'display:none'"
-                />
-                <el-tree
-                  ref="hotRef"
-                  :data="state.hotSpotData"
-                  node-key="id"
-                  v-else
-                  default-expand-all
-                  highlight-current
-                  :props="{
+                    :filter-node-method="filterNodeHot"
+                    @node-click="handleNodeClick"
+                    highlight-current
+                    check-strictly
+                    :expand-on-click-node="false"
+                    ref="hotRef"
+                    :style="state.activeName === '2' ? 'min-width: 100%; display: inline-block' : 'display:none'"
+                  />
+                  <el-tree
+                    ref="hotRef"
+                    :data="state.hotSpotData"
+                    node-key="id"
+                    v-else
+                    default-expand-all
+                    highlight-current
+                    :props="{
 										label: 'hotSpotFullName',
 										children: 'children',
 									}"
-                  :filter-node-method="filterNodeHot"
-                  @node-click="handleNodeClick"
-                  :expand-on-click-node="false"
-                  check-strictly
-                  :style="state.activeName === '2' ? 'min-width: 100%; display: inline-block' : 'display:none'"
-                />
-              </template>
-            </el-skeleton>
-					</el-scrollbar>
+                    :filter-node-method="filterNodeHot"
+                    @node-click="handleNodeClick"
+                    :expand-on-click-node="false"
+                    check-strictly
+                    :style="state.activeName === '2' ? 'min-width: 100%; display: inline-block' : 'display:none'"
+                  />
+                </template>
+              </el-skeleton>
+            </el-scrollbar>
+          </template>
+          <template v-else>
+            <el-input v-model="filterType" placeholder="请填写知识分类名称" class="input-with-select mb10" clearable> </el-input>
+            <el-scrollbar ref="scrollBarRef" noresize style="height: calc(100% - 90px);'">
+              <el-skeleton
+                :loading="state.typeLoading"
+                animated
+                :rows="10"
+              >
+                <template #default>
+                  <el-tree
+                    :data="state.knowledgeOptions"
+                    highlight-current
+                    :expand-on-click-node="false"
+                    :props="{ children: 'children', label: 'name' }"
+                    @node-click="handleNodeClick"
+                    ref="typeRef"
+                    :filter-node-method="filterNodeType"
+                    node-key="id"
+                    style="min-width: 100%; display: inline-block"
+                  >
+                  </el-tree>
+                </template>
+              </el-skeleton>
+            </el-scrollbar>
+          </template>
 				</pane>
 				<pane class="center-container">
 					<div class="input-box">
@@ -239,6 +266,8 @@ import { formatDate } from '@/utils/formatTime';
 import { throttle } from '@/utils/tools';
 import { Splitpanes, Pane } from 'splitpanes';
 import 'splitpanes/dist/splitpanes.css';
+import { useUserInfo } from "@/stores/userInfo";
+import { storeToRefs } from "pinia";
 
 
 const pagination = defineAsyncComponent(() => import('@/components/ProTable/components/Pagination.vue')); // 分页
@@ -263,6 +292,8 @@ const state = reactive<any>({
   typeLoading: false, // 知识类型loading
 });
 const router = useRouter(); // 路由
+const storesUserInfo = useUserInfo();
+const { userInfos } = storeToRefs(storesUserInfo); // 用户信息
 const topList = ref<EmptyArrayType>([]); // 常用知识前10
 const handleClick = () => {
   handleQuery();

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

@@ -185,7 +185,7 @@ const setOption = (data: any) => {
 			left: 'center',
 		},
 		tooltip: {
-			formatter: '{b}:{d}%',
+      formatter: '{b0}: {c0} ({d}%)',
 		},
 		legend: [
 			{

+ 352 - 39
src/views/statistics/order/detailSource.vue

@@ -4,12 +4,12 @@
 		<el-card shadow="never">
 			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
 				<el-form-item label="来电人身份" prop="IdentityType">
-					<el-select v-model="state.queryParams.IdentityType" placeholder="请选择来电人身份" clearable @change="handleQuery">
+					<el-select v-model="state.queryParams.IdentityType" placeholder="请选择来电人身份" @change="handleQuery">
 						<el-option v-for="item in identityTypeOptions" :value="item.value" :key="item.value" :label="item.key" />
 					</el-select>
 				</el-form-item>
 				<el-form-item label="时间段" prop="crTime">
-          <el-date-picker
+					<el-date-picker
 						v-model="state.queryParams.crTime"
 						type="daterange"
 						unlink-panels
@@ -50,62 +50,373 @@
 <script setup lang="tsx" name="statisticsOrderDetailSource">
 import { onMounted, reactive, ref } from 'vue';
 import { FormInstance } from 'element-plus';
-import { orderSourceList, orderSourceListExport } from "@/api/statistics/order";
+import { orderSourceList, orderSourceListExport } from '@/api/statistics/order';
 import { defaultDate, shortcuts } from '@/utils/constants';
 import { useRouter } from 'vue-router';
-import { downloadFileByStream, guid } from "@/utils/tools";
-import Other from "@/utils/other";
+import { downloadFileByStream, guid } from '@/utils/tools';
+import Other from '@/utils/other';
 
 // 表格配置项
 const columns = ref<any[]>([
-	{ type: 'index', fixed: 'left', width: 55, label: '序号', align: 'center' },
-	{ prop: 'userName', label: '派单人员', align: 'center' },
+	{ prop: 'time', label: '日期', align: 'center', minWidth: 100, fixed: 'left' },
 	{
-		prop: 'sendOrderNum',
-		label: '派单量',
+		prop: 'subtotal',
+		label: '小计',
 		align: 'center',
-		sortable: true,
 		render: (scope) => {
 			return (
-				<el-button type="primary" link onClick={() => linkDetail(scope)}>
-					{scope.row.sendOrderNum}
-				</el-button>
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.subtotal}
+						</el-button>
+					) : (
+						<span>{scope.row.subtotal}</span>
+					)}
+				</>
 			);
 		},
 	},
 	{
-		prop: 'noSendOrderNum',
-		label: '待派单件',
+		prop: 'phone',
+		label: '电话',
 		align: 'center',
-		sortable: true,
 		render: (scope) => {
 			return (
-				<el-button type="primary" link onClick={() => linkDetail(scope)}>
-					{scope.row.noSendOrderNum}
-				</el-button>
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.phone}
+						</el-button>
+					) : (
+						<span>{scope.row.phone}</span>
+					)}
+				</>
 			);
 		},
 	},
 	{
-		prop: 'reSendOrderNum',
-		label: '重办信件',
+		prop: 'web',
+		label: '因特网',
 		align: 'center',
-		sortable: true,
 		render: (scope) => {
 			return (
-				<el-button type="primary" link onClick={() => linkDetail(scope)}>
-					{scope.row.reSendOrderNum}
-				</el-button>
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.web}
+						</el-button>
+					) : (
+						<span>{scope.row.web}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'rests',
+		label: '其他',
+		align: 'center',
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.rests}
+						</el-button>
+					) : (
+						<span>{scope.row.rests}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'created',
+		label: '自建',
+		align: 'center',
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.created}
+						</el-button>
+					) : (
+						<span>{scope.row.created}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'weChat',
+		label: '微信',
+		align: 'center',
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.weChat}
+						</el-button>
+					) : (
+						<span>{scope.row.weChat}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'app',
+		label: 'APP',
+		align: 'center',
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.app}
+						</el-button>
+					) : (
+						<span>{scope.row.app}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'wisdomYB',
+		label: '智慧宜宾',
+		align: 'center',
+		minWidth: 120,
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.wisdomYB}
+						</el-button>
+					) : (
+						<span>{scope.row.wisdomYB}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'platform',
+		label: '综治平台',
+		align: 'center',
+		minWidth: 120,
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.platform}
+						</el-button>
+					) : (
+						<span>{scope.row.platform}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'platform12328',
+		label: '省12328平台',
+		align: 'center',
+		minWidth: 120,
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.platform12328}
+						</el-button>
+					) : (
+						<span>{scope.row.platform12328}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'mayorAndNetizens',
+		label: '市长和网民',
+		align: 'center',
+		minWidth: 120,
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.mayorAndNetizens}
+						</el-button>
+					) : (
+						<span>{scope.row.mayorAndNetizens}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'mediaYB',
+		label: '宜宾融媒体',
+		align: 'center',
+		minWidth: 120,
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.mediaYB}
+						</el-button>
+					) : (
+						<span>{scope.row.mediaYB}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'platform12345',
+		label: '省12345平台',
+		align: 'center',
+		minWidth: 120,
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.platform12345}
+						</el-button>
+					) : (
+						<span>{scope.row.platform12345}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'interaction',
+		label: '省政民互动',
+		minWidth: 120,
+		align: 'center',
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.interaction}
+						</el-button>
+					) : (
+						<span>{scope.row.interaction}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'serviceYB',
+		label: '宜办事',
+		align: 'center',
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.serviceYB}
+						</el-button>
+					) : (
+						<span>{scope.row.serviceYB}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'cityTransfer',
+		label: '市州互转',
+		align: 'center',
+		minWidth: 120,
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.cityTransfer}
+						</el-button>
+					) : (
+						<span>{scope.row.serviceYB}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'platform110',
+		label: '宜宾110平台',
+		align: 'center',
+		minWidth: 120,
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.platform110}
+						</el-button>
+					) : (
+						<span>{scope.row.platform110}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'noService',
+		label: '办不成事反映窗口',
+		align: 'center',
+		minWidth: 150,
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.noService}
+						</el-button>
+					) : (
+						<span>{scope.row.noService}</span>
+					)}
+				</>
+			);
+		},
+	},
+	{
+		prop: 'iyb',
+		label: 'i宜宾',
+		align: 'center',
+		render: (scope) => {
+			return (
+				<>
+					{scope.row.time !== '合计' ? (
+						<el-button type="primary" link onClick={() => linkDetail(scope)}>
+							{scope.row.iyb}
+						</el-button>
+					) : (
+						<span>{scope.row.iyb}</span>
+					)}
+				</>
 			);
 		},
 	},
-	{ prop: 'chainRate', label: '派单准确率', align: 'center' },
 ]);
 // 定义变量内容
 const ruleFormRef = ref<RefType>(); // 表单ref
 const state = reactive<any>({
 	queryParams: {
-    IdentityType: null,
+		IdentityType: null,
 		// 查询条件
 		crTime: defaultDate,
 	},
@@ -125,13 +436,13 @@ const handleQuery = () => {
 /** 获取列表 */
 const queryList = () => {
 	state.loading = true;
-  let request = Other.deepClone(state.queryParams);
-  request.StartTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
-  request.EndTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
-  Reflect.deleteProperty(request, 'crTime');
-  orderSourceList(request)
+	let request = Other.deepClone(state.queryParams);
+	request.StartTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
+	request.EndTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
+	Reflect.deleteProperty(request, 'crTime');
+	orderSourceList(request)
 		.then((res: any) => {
-			// state.tableData = res.result ?? [];
+			state.tableData = res.result ?? [];
 			state.loading = false;
 		})
 		.catch(() => {
@@ -153,18 +464,20 @@ const linkDetail = (scope: any) => {
 			id: guid(),
 		},
 		state: {
-      IdentityType: scope.row.IdentityType,
+			IdentityType: scope.row.IdentityType,
 			startTime: state.queryParams.crTime[0],
 			endTime: state.queryParams.crTime[1],
+      Time: scope.row.time,
+      SourceChannel:scope.column.label
 		},
 	});
 };
 // 表格导出
 const exportTable = (val: any, isExportAll = false) => {
-  let request = Other.deepClone(state.queryParams);
-  request.StartTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
-  request.EndTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
-  Reflect.deleteProperty(request, 'crTime');
+	let request = Other.deepClone(state.queryParams);
+	request.StartTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
+	request.EndTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
+	Reflect.deleteProperty(request, 'crTime');
 	const columnInfos = val.map((item: any) => {
 		return {
 			prop: item.prop,
@@ -177,7 +490,7 @@ const exportTable = (val: any, isExportAll = false) => {
 		isExportAll,
 	};
 	state.loading = true;
-  orderSourceListExport(req)
+	orderSourceListExport(req)
 		.then((res: any) => {
 			state.loading = false;
 			downloadFileByStream(res);

+ 40 - 16
src/views/statistics/order/detailSourceOrder.vue

@@ -11,9 +11,10 @@
         :total="state.total"
         v-model:page-index="state.queryParams.PageIndex"
         v-model:page-size="state.queryParams.PageSize"
-        @export-current="exportCurrent"
-        @export-all="exportAll"
         :key="Math.random()"
+        :toolButton="['refresh', 'setting', 'exportCurrent', 'exportAll']"
+        @export-current="exportTable($event)"
+        @export-all="exportTable($event, true)"
       >
         <template #expiredStatusText="{ row }">
           <span :class="'overdue-status-' + row.expiredStatus" :title="row.expiredStatusText"></span>
@@ -31,7 +32,8 @@ import type { FormInstance } from 'element-plus';
 import other from '@/utils/other';
 import { useRoute, useRouter } from 'vue-router';
 import { formatDate } from '@/utils/formatTime';
-import { departmentAcceptTypeDetail } from '@/api/statistics/order';
+import {  orderSourceListDetail, orderSourceListDetailExport } from "@/api/statistics/order";
+import { downloadFileByStream } from "@/utils/tools";
 
 // 引入组件
 const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
@@ -105,17 +107,15 @@ const historyParams = history.state;
 /** 获取列表 */
 const queryList = () => {
   let request = other.deepClone(state.queryParams);
-  request.StartDate = historyParams.StartDate;
-  request.EndDate = historyParams.EndDate;
-  request.OrgCode = historyParams.OrgCode;
-  request.AcceptTypeCode = historyParams.AcceptTypeCode;
-  request.TypeCode = historyParams.TypeCode;
+  request.startTime = historyParams.startTime;
+  request.endTime = historyParams.endTime;
+  request.Time = historyParams.Time;
+  request.IdentityType = historyParams.IdentityType;
+  request.SourceChannel = historyParams.SourceChannel;
   state.loading = true;
-  console.log(historyParams)
-  departmentAcceptTypeDetail(request)
+  orderSourceListDetail(request)
     .then((response: any) => {
       state.tableData = response?.result.items ?? [];
-
       state.total = response?.result.total;
       state.loading = false;
     })
@@ -129,11 +129,35 @@ const resetQuery = (formEl: FormInstance | undefined) => {
   formEl.resetFields();
   queryList();
 };
-const exportCurrent = () => {
-  console.log('导出当前页', proTableRef.value);
-};
-const exportAll = () => {
-  console.log('导出全部', proTableRef.value);
+// 表格导出
+const exportTable = (val: any, isExportAll = false) => {
+  let request = other.deepClone(state.queryParams);
+  request.startTime = historyParams.startTime;
+  request.endTime = historyParams.endTime;
+  request.Time = historyParams.Time;
+  request.IdentityType = historyParams.IdentityType;
+  request.SourceChannel = historyParams.SourceChannel;
+  state.loading = true;
+  const columnInfos = val.map((item: any) => {
+    return {
+      prop: item.prop,
+      name: item.label,
+    };
+  });
+  const req = {
+    queryDto: request,
+    columnInfos,
+    isExportAll,
+  };
+  state.loading = true;
+  orderSourceListDetailExport(req)
+    .then((res: any) => {
+      state.loading = false;
+      downloadFileByStream(res);
+    })
+    .catch(() => {
+      state.loading = false;
+    });
 };
 onMounted(() => {
   queryList();

+ 12 - 11
src/views/statistics/order/source.vue

@@ -33,10 +33,13 @@
 		</el-card>
 		<el-card shadow="never">
 			<el-row :gutter="20">
-				<el-col :xs="24" :sm="12" :md="18" :lg="18" :xl="18">
-					<v-chart class="chart" :option="option" :loading="state.loading" autoresize />
+				<el-col :xs="24" :sm="24" :md="24" :lg="18" :xl="18">
+          <template v-if="dataTable.length">
+            <v-chart class="chart" :option="option" :loading="state.loading" autoresize />
+          </template>
+          <Empty v-else />
 				</el-col>
-				<el-col :xs="24" :sm="12" :md="6" :lg="6" :xl="6">
+				<el-col :xs="24" :sm="24" :md="24" :lg="6" :xl="6">
 					<ProTable
 						ref="proTableRef"
 						:columns="columns"
@@ -57,14 +60,14 @@
 	</div>
 </template>
 <script setup lang="tsx" name="statisticsOrderSource">
-import { onMounted, reactive, ref } from 'vue';
+import { computed, onMounted, reactive, ref } from "vue";
 import { FormInstance } from 'element-plus';
-import { callPeriodBase } from '@/api/statistics/call';
 import { defaultDate, shortcuts } from '@/utils/constants';
 import Other from '@/utils/other';
 import { orderSource, orderSourceExport } from '@/api/statistics/order';
 import { downloadFileByStream } from '@/utils/tools';
 import { useRouter } from 'vue-router';
+import Empty from "@/components/Empty/index.vue";
 
 const proTableRef = ref<RefType>(); // 表格ref
 // 表格配置项
@@ -97,6 +100,7 @@ const handleQuery = () => {
 	queryList();
 };
 /** 获取列表 */
+const dataTable = ref([]);
 const queryList = () => {
 	state.loading = true;
 	let request = Other.deepClone(state.queryParams);
@@ -111,7 +115,7 @@ const queryList = () => {
 					return item.source;
 				})
 				.filter((item: any) => item !== '合计');
-			const dataTable = state.tableData
+      dataTable.value = state.tableData
 				.map((item: any) => {
 					return {
 						name: item.source,
@@ -120,7 +124,7 @@ const queryList = () => {
 					};
 				})
 				.filter((item: any) => item.name !== '合计');
-			setOption(legendData, dataTable);
+			setOption(legendData, dataTable.value);
 			state.loading = false;
 		})
 		.catch(() => {
@@ -142,7 +146,7 @@ const setOption = (legendData: string[], data: any) => {
 			left: 'center',
 		},
 		tooltip: {
-			formatter: '{b}:{d}%',
+			formatter: '{b0}: {c0} ({d}%)',
 		},
 		legend: [
 			{
@@ -152,9 +156,6 @@ const setOption = (legendData: string[], data: any) => {
 				data: legendData,
 			},
 		],
-		grid: {
-			containLabel: true,
-		},
 		series: [
 			{
 				type: 'pie',

+ 501 - 182
src/views/statistics/order/timeSource.vue

@@ -1,65 +1,64 @@
 <template>
-  <div class="statistics-order-time-source-container layout-pd">
-    <!-- 搜索  -->
-    <el-card shadow="never">
-      <el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
-        <el-form-item label="来电人身份" prop="IdentityType">
-          <el-select v-model="state.queryParams.IdentityType" placeholder="请选择来电人身份" clearable @change="handleQuery">
-            <el-option v-for="item in identityTypeOptions" :value="item.value" :key="item.value" :label="item.key" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="时间段" prop="crTime">
-          <el-date-picker
-            v-model="state.queryParams.crTime"
-            type="daterange"
-            unlink-panels
-            range-separator="至"
-            start-placeholder="开始时间"
-            end-placeholder="结束时间"
-            :shortcuts="shortcuts"
-            @change="handleQuery"
-            value-format="YYYY-MM-DD"
-            :clearable="false"
-          />
-        </el-form-item>
-        <el-form-item label-width="0">
-          <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 type="info" @click="onDetail" :loading="state.loading"> <SvgIcon name="ele-List" class="mr5" /> 列表明细 </el-button>
-        </el-form-item>
-      </el-form>
-    </el-card>
-    <el-card shadow="never">
-      <el-row :gutter="20">
-        <el-col :xs="24" :sm="12" :md="18" :lg="18" :xl="18">
-          <v-chart class="chart" :option="option" :loading="state.loading" autoresize />
-        </el-col>
-        <el-col :xs="24" :sm="12" :md="6" :lg="6" :xl="6">
-          <ProTable
-            ref="proTableRef"
-            :columns="columns"
-            :data="state.tableData"
-            @updateTable="queryList"
-            :loading="state.loading"
-            :pagination="false"
-            border
-            :tool-button="false"
-            max-height="60vh"
-            :toolButton="['refresh', 'setting', 'exportAll']"
-            @export-all="exportTable($event, true)"
-          >
-          </ProTable>
-        </el-col>
-      </el-row>
-    </el-card>
-  </div>
+	<div class="statistics-order-time-source-container layout-pd">
+		<!-- 搜索  -->
+		<el-card shadow="never">
+			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
+				<el-form-item label="来电人身份" prop="IdentityType">
+					<el-select v-model="state.queryParams.IdentityType" placeholder="请选择来电人身份" clearable @change="handleQuery">
+						<el-option v-for="item in identityTypeOptions" :value="item.value" :key="item.value" :label="item.key" />
+					</el-select>
+				</el-form-item>
+				<el-form-item label="时间段" prop="crTime">
+					<el-date-picker
+						v-model="state.queryParams.crTime"
+						type="daterange"
+						unlink-panels
+						range-separator="至"
+						start-placeholder="开始时间"
+						end-placeholder="结束时间"
+						:shortcuts="shortcuts"
+						@change="handleQuery"
+						value-format="YYYY-MM-DD"
+						:clearable="false"
+					/>
+				</el-form-item>
+				<el-form-item label-width="0">
+					<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 type="info" @click="onDetail" :loading="state.loading"> <SvgIcon name="ele-List" class="mr5" /> 列表明细 </el-button>
+				</el-form-item>
+			</el-form>
+		</el-card>
+		<el-card shadow="never">
+			<el-row :gutter="20">
+				<el-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16">
+					<v-chart class="chart" :option="option" :loading="state.loading" autoresize />
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="8" :xl="8">
+					<ProTable
+						ref="proTableRef"
+						:columns="columns"
+						:data="state.tableData"
+						@updateTable="queryList"
+						:loading="state.loading"
+						:pagination="false"
+						border
+						:tool-button="false"
+						max-height="60vh"
+						:toolButton="['refresh', 'setting', 'exportAll']"
+						@export-all="exportTable($event, true)"
+					>
+					</ProTable>
+				</el-col>
+			</el-row>
+		</el-card>
+	</div>
 </template>
 <script setup lang="tsx" name="statisticsOrderTimeSource">
 import { onMounted, reactive, ref } from 'vue';
 import { FormInstance } from 'element-plus';
-import { callList, callPeriodBase } from '@/api/statistics/call';
 import { defaultDate, shortcuts } from '@/utils/constants';
 import Other from '@/utils/other';
 import { orderSource, orderSourceExport } from '@/api/statistics/order';
@@ -69,162 +68,482 @@ import { useRouter } from 'vue-router';
 const proTableRef = ref<RefType>(); // 表格ref
 // 表格配置项
 const columns = ref<any[]>([
-  { prop: 'source', label: '时间段', align: 'center' },
-  { prop: 'num', label: '数量', align: 'center' },
-  { prop: 'rateText', label: '占比', align: 'center' },
+  { prop: 'time', label: '时间段', align: 'center', minWidth: 100, fixed: 'left' },
+  {
+    prop: 'subtotal',
+    label: '小计',
+    align: 'center',
+  },
+  {
+    prop: 'phone',
+    label: '电话',
+    align: 'center',
+  },
+  {
+    prop: 'web',
+    label: '因特网',
+    align: 'center',
+  },
+  {
+    prop: 'rests',
+    label: '其他',
+    align: 'center',
+  },
+  {
+    prop: 'created',
+    label: '自建',
+    align: 'center',
+  },
+  {
+    prop: 'weChat',
+    label: '微信',
+    align: 'center',
+  },
+  {
+    prop: 'app',
+    label: 'APP',
+    align: 'center',
+  },
+  {
+    prop: 'wisdomYB',
+    label: '智慧宜宾',
+    align: 'center',
+    minWidth: 120,
+  },
+  {
+    prop: 'platform',
+    label: '综治平台',
+    align: 'center',
+    minWidth: 120,
+  },
+  {
+    prop: 'platform12328',
+    label: '省12328平台',
+    align: 'center',
+    minWidth: 120,
+  },
+  {
+    prop: 'mayorAndNetizens',
+    label: '市长和网民',
+    align: 'center',
+    minWidth: 120,
+  },
+  {
+    prop: 'mediaYB',
+    label: '宜宾融媒体',
+    align: 'center',
+    minWidth: 120,
+  },
+  {
+    prop: 'platform12345',
+    label: '省12345平台',
+    align: 'center',
+    minWidth: 120,
+  },
+  {
+    prop: 'interaction',
+    label: '省政民互动',
+    minWidth: 120,
+    align: 'center',
+  },
+  {
+    prop: 'serviceYB',
+    label: '宜办事',
+    align: 'center',
+  },
+  {
+    prop: 'cityTransfer',
+    label: '市州互转',
+    align: 'center',
+    minWidth: 120,
+  },
+  {
+    prop: 'platform110',
+    label: '宜宾110平台',
+    align: 'center',
+    minWidth: 120,
+  },
+  {
+    prop: 'noService',
+    label: '办不成事反映窗口',
+    align: 'center',
+    minWidth: 150,
+  },
+  {
+    prop: 'iyb',
+    label: 'i宜宾',
+    align: 'center',
+  },
 ]);
 // 定义变量内容
 const ruleFormRef = ref<RefType>(); // 表单ref
 const state = reactive<any>({
-  queryParams: {
-    // 查询条件
-    IdentityType: null, // 关键词
-    crTime: defaultDate, //
-    StartTime: null,
-    EndTime: null,
-  },
-  tableData: [], //表单
-  loading: false, // 加载
-  total: 0, // 总数
-  callForwardingSource: [],
+	queryParams: {
+		// 查询条件
+		IdentityType: null, // 关键词
+		crTime: defaultDate, //
+		StartTime: null,
+		EndTime: null,
+	},
+	tableData: [], //表单
+	loading: false, // 加载
+	total: 0, // 总数
+	callForwardingSource: [],
 });
 const identityTypeOptions = [
-  { key: '市民', value: 1 },
-  { key: '企业', value: 2 },
+	{ key: '市民', value: 1 },
+	{ key: '企业', value: 2 },
 ];
 /** 搜索按钮操作 */
 const handleQuery = () => {
-  // state.queryParams.PageIndex = 1;
-  queryList();
+	// state.queryParams.PageIndex = 1;
+	queryList();
 };
 /** 获取列表 */
 const queryList = () => {
-  state.loading = true;
-  let request = Other.deepClone(state.queryParams);
-  request.StartTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
-  request.EndTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
-  Reflect.deleteProperty(request, 'crTime');
-  orderSource(request)
-    .then((res: any) => {
-      state.tableData = res.result;
-      const legendData = state.tableData
-        .map((item: any) => {
-          return item.source;
-        })
-        .filter((item: any) => item !== '合计');
-      const dataTable = state.tableData
-        .map((item: any) => {
-          return {
-            name: item.source,
-            value: item.num,
-            ...item,
-          };
-        })
-        .filter((item: any) => item.name !== '合计');
-      setOption(legendData, dataTable);
-      state.loading = false;
-    })
-    .catch(() => {
-      state.loading = false;
-    });
+	state.loading = true;
+	let request = Other.deepClone(state.queryParams);
+	request.StartTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
+	request.EndTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
+	Reflect.deleteProperty(request, 'crTime');
+	orderSource(request)
+		.then((res: any) => {
+			setOption([], []);
+			state.loading = false;
+		})
+		.catch(() => {
+			state.loading = false;
+		});
 };
 /** 重置按钮操作 */
 const resetQuery = (formEl: FormInstance | undefined) => {
-  if (!formEl) return;
-  formEl.resetFields();
-  queryList();
+	if (!formEl) return;
+	formEl.resetFields();
+	queryList();
 };
 const option = ref<any>({});
 // 信件来源统计
 const setOption = (legendData: string[], data: any) => {
-  option.value = {
-    title: {
-      text: '信件来源统计',
-      left: 'center',
-    },
-    tooltip: {
-      formatter: '{b}:{d}%',
-    },
-    legend: [
-      {
-        left: 'left',
-        top: '40',
-        orient: 'vertical',
-        data: legendData,
-      },
-    ],
-    grid: {
-      containLabel: true,
-    },
-    series: [
-      {
-        type: 'pie',
-        radius: ['0%', '80%'],
-        label: {
-          show: true,
-          overflow: 'none',
-          formatter: function (params) {
-            if (params.name !== '') {
-              return `${params.name}:${params.data.value}(${params.percent}%)`;
-            }
-          },
-        },
-        data: data,
+	option.value = {
+		title: {
+			text: '信件来源分时统计',
+			left: 'center',
+			top: '0',
+		},
+		tooltip: {
+			trigger: 'axis',
+			axisPointer: {
+				type: 'shadow',
+			},
+			confine: true,
+		},
+		legend: {
+			top: '7%',
+			data: [
+				'自建',
+				'string',
+				'市长与网民',
+				'宜宾110平台',
+				'智慧宜宾',
+				'微信',
+				'小程序',
+				'网站',
+				'其他',
+				'App',
+				'因特网',
+				'综治平台',
+				'省政民互动',
+				'市州互转',
+				'微博',
+				'电话',
+				'i宜宾',
+				'省12345平台',
+				'宜宾融媒体',
+			],
+		},
+		grid: {
+			left: '0',
+			right: '1%',
+			bottom: '0%',
+			top: '20%',
+			containLabel: true,
+		},
+		xAxis: {
+      axisLabel: {
+        rotate:45   //设置的值大于0向右倾斜,小于0向左
       },
-    ],
-  };
-};
-// 获取基础信息
-const getBaseInfo = async () => {
-  try {
-    const { result } = await callPeriodBase();
-    state.callForwardingSource = result.callForwardingSource ?? [];
-  } catch (e) {
-    console.log(e);
-  }
+      data: [
+				'00:00~00:59',
+				'01:00~01:59',
+				'02:00~02:59',
+				'03:00~03:59',
+				'04:00~04:59',
+				'05:00~05:59',
+				'06:00~06:59',
+				'07:00~07:59',
+				'08:00~08:59',
+				'09:00~09:59',
+				'10:00~10:59',
+				'11:00~11:59',
+				'12:00~12:59',
+				'13:00~13:59',
+				'14:00~14:59',
+				'15:00~15:59',
+				'16:00~16:59',
+				'17:00~17:59',
+				'18:00~18:59',
+				'19:00~19:59',
+				'20:00~20:59',
+				'21:00~21:59',
+				'22:00~22:59',
+				'23:00~23:59',
+			],
+		},
+		yAxis: {
+			type: 'value',
+		},
+		series: [
+			{
+				name: '自建',
+				type: 'bar',
+				stack: 'total',
+
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: 'string',
+				type: 'bar',
+				stack: 'total',
+
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '市长与网民',
+				type: 'bar',
+				stack: 'total',
+
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '宜宾110平台',
+				type: 'bar',
+				stack: 'total',
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '智慧宜宾',
+				type: 'bar',
+				stack: 'total',
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '微信',
+				type: 'bar',
+				stack: 'total',
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '小程序',
+				type: 'bar',
+				stack: 'total',
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '网站',
+				type: 'bar',
+				stack: 'total',
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '其他',
+				type: 'bar',
+				stack: 'total',
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: 'App',
+				type: 'bar',
+				stack: 'total',
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '因特网',
+				type: 'bar',
+				stack: 'total',
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '综治平台',
+				type: 'bar',
+				stack: 'total',
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '省政民互动',
+				type: 'bar',
+				stack: 'total',
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '市州互转',
+				type: 'bar',
+				stack: 'total',
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '微博',
+				type: 'bar',
+				stack: 'total',
+
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '电话',
+				type: 'bar',
+				stack: 'total',
+
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: 'i宜宾',
+				type: 'bar',
+				stack: 'total',
+
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '省12345平台',
+				type: 'bar',
+				stack: 'total',
+
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '宜宾融媒体',
+				type: 'bar',
+				stack: 'total',
+				animationDelay: function (idx) {
+					return idx * 50 + 1000;
+				},
+				data: [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210],
+			},
+			{
+				name: '合计',
+				type: 'bar',
+				stack: 'total',
+				data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], //默认数据
+				label: {
+					show: true,
+					position: 'top',
+					formatter: function (params) {
+						//合计数据
+						let total = [120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90, 230, 210, 101, 134, 90, 230, 210];
+						return total[params.dataIndex];
+					},
+					fontWeight: 'bold',
+					color: '#000',
+				},
+			},
+		],
+		animationEasing: 'elasticOut',
+		animationDuration: 2000,
+	};
 };
 // 表格导出
 const exportTable = (val: any, isExportAll = false) => {
-  let request = Other.deepClone(state.queryParams);
-  request.StartTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
-  request.EndTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
-  Reflect.deleteProperty(request, 'crTime');
-  const columnInfos = val.map((item: any) => {
-    return {
-      prop: item.prop,
-      name: item.label,
-    };
-  });
-  const req = {
-    queryDto: request,
-    columnInfos,
-    isExportAll,
-  };
-  state.loading = true;
-  orderSourceExport(req)
-    .then((res: any) => {
-      state.loading = false;
-      downloadFileByStream(res);
-    })
-    .catch(() => {
-      state.loading = false;
-    });
+	let request = Other.deepClone(state.queryParams);
+	request.StartTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[0];
+	request.EndTime = state.queryParams.crTime === null ? null : state.queryParams.crTime[1];
+	Reflect.deleteProperty(request, 'crTime');
+	const columnInfos = val.map((item: any) => {
+		return {
+			prop: item.prop,
+			name: item.label,
+		};
+	});
+	const req = {
+		queryDto: request,
+		columnInfos,
+		isExportAll,
+	};
+	state.loading = true;
+	orderSourceExport(req)
+		.then((res: any) => {
+			state.loading = false;
+			downloadFileByStream(res);
+		})
+		.catch(() => {
+			state.loading = false;
+		});
 };
 // 查看列表明细
 const router = useRouter();
 const onDetail = () => {
-  router.push({
-    name: 'statisticsOrderDetailSource',
-  });
+	router.push({
+		name: 'statisticsOrderDetailSource',
+	});
 };
 onMounted(() => {
-  getBaseInfo();
-  queryList();
+	queryList();
 });
 </script>
 <style lang="scss" scoped>
-.chart{
-  height: 60vh;
-  margin-top: 10px;
+.chart {
+	height: 60vh;
+	margin-top: 10px;
 }
 </style>

+ 0 - 1
src/views/todo/order/index.vue

@@ -246,7 +246,6 @@ const handleQuery = () => {
 const queryList = async () => {
 	try {
 		state.loading = true;
-		const index = columns.value.findIndex((item) => item.prop === 'acceptType');
 		if (state.queryParams.IsHandled === 'true') {
 			columns.value = columnsDone;
 		} else {

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

@@ -232,7 +232,6 @@ const queryList = async () => {
 			columns.value = columnsTodo;
 		}
 		let request = Other.deepClone(state.queryParams);
-
 		request.StartTime = state.queryParams.scTime === null ? null : state.queryParams.scTime[0];
 		request.EndTime = state.queryParams.scTime === null ? null : state.queryParams.scTime[1];
 		Reflect.deleteProperty(request, 'scTime');