Browse Source

reactor:表格重构,;

zhangchong 5 months ago
parent
commit
35716e39ac

+ 1 - 1
.env.luzhou

@@ -7,7 +7,7 @@ VITE_API_URL=http://125.65.135.71:50100/hl
 # 业务系统socket请求地址
 VITE_API_SOCKET_URL=http://125.65.135.71:50100/hlws/hubs/hotline
 # 业务系统文件上传上传请求地址
-VITE_API_UPLOAD_URL=http://125.65.135.71:50120/hlfs
+VITE_API_UPLOAD_URL=http://125.65.135.71:50100/hlfs
 # 数据共享平台请求地址
 VITE_DATASHARE_API_YRL=http://125.65.135.71:50100/hlds
 # 高德地图安全密钥

+ 5 - 0
package.json

@@ -23,12 +23,14 @@
 		"@microsoft/signalr": "^7.0.0",
 		"@originjs/vite-plugin-commonjs": "^1.0.3",
 		"@vueuse/motion": "^2.0.0",
+		"@vxe-ui/plugin-export-xlsx": "4.0.7",
 		"@wangeditor-next/editor": "^5.6.2",
 		"@wangeditor-next/editor-for-vue": "^5.1.14",
 		"axios": "^1.4.0",
 		"dayjs": "^1.11.9",
 		"echarts": "^5.5.0",
 		"element-plus": "^2.7.7",
+		"exceljs": "4.2.1",
 		"file-saver": "^2.0.5",
 		"html-docx-js-typescript": "^0.1.5",
 		"html2canvas": "^1.4.1",
@@ -51,6 +53,8 @@
 		"vue3-puzzle-vcode": "^1.1.7",
 		"vue3-seamless-scroll": "^2.0.1",
 		"vuedraggable": "^4.1.0",
+		"vxe-pc-ui": "4.3.1",
+		"vxe-table": "4.9.1",
 		"webpack": "^5.0.0"
 	},
 	"devDependencies": {
@@ -74,6 +78,7 @@
 		"typescript": "~5.2.2",
 		"vite": "^4.4.11",
 		"vite-plugin-compression": "^0.5.1",
+		"vite-plugin-lazy-import": "^1.0.7",
 		"vite-plugin-vue-setup-extend-plus": "^0.1.0",
 		"vue-eslint-parser": "^9.1.0"
 	},

+ 3 - 0
src/layout/navBars/breadcrumb/setings.vue

@@ -416,6 +416,7 @@ import other from '@/utils/other';
 import mittBus from '@/utils/mitt';
 import {useUserInfo} from "@/stores/userInfo";
 import { useDark } from '@vueuse/core';
+import { VxeUI } from 'vxe-pc-ui';
 
 const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
@@ -543,6 +544,8 @@ const onAddDarkChange = () => {
 	else body.setAttribute('data-theme', '');
 	const isDark = useDark();
 	isDark.value = themeConfig.value.isIsDark; // 更改暗黑模式
+	if(isDark.value) VxeUI.setTheme('dark');
+	else VxeUI.setTheme('default');
 };
 // 布局切换
 const onSetLayout = (layout: string) => {

+ 194 - 1
src/main.ts

@@ -12,6 +12,199 @@ import '@/theme/index.scss';
 import ProTable from '@/components/ProTable/index.vue';
 import { MotionPlugin } from '@vueuse/motion';
 
+import {
+	VxeUI,
+	VxeAlert,
+	VxeAnchor,
+	VxeAnchorLink,
+	VxeAvatar,
+	VxeBadge,
+	VxeBreadcrumb,
+	VxeBreadcrumbItem,
+	VxeButton,
+	VxeButtonGroup,
+	VxeCalendar,
+	VxeCard,
+	VxeCarousel,
+	VxeCarouselItem,
+	VxeCheckbox,
+	VxeCheckboxGroup,
+	VxeCol,
+	VxeCollapse,
+	VxeCollapsePane,
+	VxeColorPicker,
+	VxeCountdown,
+	VxeDatePicker,
+	VxeDrawer,
+	VxeEmpty,
+	VxeForm,
+	VxeFormDesign,
+	VxeFormGroup,
+	VxeFormItem,
+	VxeFormView,
+	VxeIcon,
+	VxeIconPicker,
+	VxeImage,
+	VxeImageGroup,
+	VxeImagePreview,
+	VxeInput,
+	VxeLayoutAside,
+	VxeLayoutBody,
+	VxeLayoutContainer,
+	VxeLayoutFooter,
+	VxeLayoutHeader,
+	VxeLink,
+	VxeListDesign,
+	VxeListView,
+	VxeList,
+	VxeLoading,
+	VxeMenu,
+	VxeModal,
+	VxeNoticeBar,
+	VxeNumberInput,
+	VxeOptgroup,
+	VxeOption,
+	VxePager,
+	VxePasswordInput,
+	VxePrintPageBreak,
+	VxePrint,
+	VxePulldown,
+	VxeRadio,
+	VxeRadioButton,
+	VxeRadioGroup,
+	VxeRate,
+	VxeResult,
+	VxeRow,
+	VxeSelect,
+	VxeSlider,
+	VxeSteps,
+	VxeSwitch,
+	VxeTabPane,
+	VxeTableSelect,
+	VxeTabs,
+	VxeTag,
+	VxeTextEllipsis,
+	VxeText,
+	VxeTextarea,
+	VxeTip,
+	VxeTooltip,
+	VxeTree,
+	VxeTreeSelect,
+	VxeUpload,
+	VxeWatermark
+} from 'vxe-pc-ui'
+
+import {
+	VxeTable,
+	VxeColumn,
+	VxeColgroup,
+	VxeGrid,
+	VxeToolbar
+} from 'vxe-table'
+
+// 导入主题变量,也可以重写主题变量
+import 'vxe-table/styles/cssvar.scss'
+import 'vxe-pc-ui/styles/cssvar.scss'
+import VxeUIPluginExportXLSX from '@vxe-ui/plugin-export-xlsx';
+import ExcelJS from 'exceljs'
+// 导入默认的语言
+import zhCN from 'vxe-pc-ui/lib/language/zh-CN'
+
+VxeUI.setI18n('zh-CN', zhCN)
+VxeUI.setLanguage('zh-CN')
+VxeUI.use(VxeUIPluginExportXLSX, {
+	ExcelJS
+})
+
+function lazyVxeUI (app:any) {
+	app.use(VxeAlert)
+	app.use(VxeAnchor)
+	app.use(VxeAnchorLink)
+	app.use(VxeAvatar)
+	app.use(VxeBadge)
+	app.use(VxeBreadcrumb)
+	app.use(VxeBreadcrumbItem)
+	app.use(VxeButton)
+	app.use(VxeButtonGroup)
+	app.use(VxeCalendar)
+	app.use(VxeCard)
+	app.use(VxeCarousel)
+	app.use(VxeCarouselItem)
+	app.use(VxeCheckbox)
+	app.use(VxeCheckboxGroup)
+	app.use(VxeCol)
+	app.use(VxeCollapse)
+	app.use(VxeCollapsePane)
+	app.use(VxeColorPicker)
+	app.use(VxeCountdown)
+	app.use(VxeDatePicker)
+	app.use(VxeDrawer)
+	app.use(VxeEmpty)
+	app.use(VxeForm)
+	app.use(VxeFormDesign)
+	app.use(VxeFormGroup)
+	app.use(VxeFormItem)
+	app.use(VxeFormView)
+	app.use(VxeIcon)
+	app.use(VxeIconPicker)
+	app.use(VxeImage)
+	app.use(VxeImageGroup)
+	app.use(VxeImagePreview)
+	app.use(VxeInput)
+	app.use(VxeLayoutAside)
+	app.use(VxeLayoutBody)
+	app.use(VxeLayoutContainer)
+	app.use(VxeLayoutFooter)
+	app.use(VxeLayoutHeader)
+	app.use(VxeLink)
+	app.use(VxeListDesign)
+	app.use(VxeListView)
+	app.use(VxeList)
+	app.use(VxeLoading)
+	app.use(VxeMenu)
+	app.use(VxeModal)
+	app.use(VxeNoticeBar)
+	app.use(VxeNumberInput)
+	app.use(VxeOptgroup)
+	app.use(VxeOption)
+	app.use(VxePager)
+	app.use(VxePasswordInput)
+	app.use(VxePrintPageBreak)
+	app.use(VxePrint)
+	app.use(VxePulldown)
+	app.use(VxeRadio)
+	app.use(VxeRadioButton)
+	app.use(VxeRadioGroup)
+	app.use(VxeRate)
+	app.use(VxeResult)
+	app.use(VxeRow)
+	app.use(VxeSelect)
+	app.use(VxeSlider)
+	app.use(VxeSteps)
+	app.use(VxeSwitch)
+	app.use(VxeTabPane)
+	app.use(VxeTableSelect)
+	app.use(VxeTabs)
+	app.use(VxeTag)
+	app.use(VxeTextEllipsis)
+	app.use(VxeText)
+	app.use(VxeTextarea)
+	app.use(VxeTip)
+	app.use(VxeTooltip)
+	app.use(VxeTree)
+	app.use(VxeTreeSelect)
+	app.use(VxeUpload)
+	app.use(VxeWatermark)
+}
+
+function lazyVxeTable (app:any) {
+	app.use(VxeTable)
+	app.use(VxeColumn)
+	app.use(VxeColgroup)
+	app.use(VxeGrid)
+	app.use(VxeToolbar)
+}
+
 // 注册echarts
 import { registerEcharts } from '@/utils/echarts';
 const app = createApp(App);
@@ -22,4 +215,4 @@ other.elSvg(app);
 // 全局组件挂载
 app.component('ProTable', ProTable);
 registerEcharts(app);
-app.use(pinia).use(router).use(ElementPlus).use(MotionPlugin).mount('#app');
+app.use(pinia).use(router).use(ElementPlus).use(MotionPlugin).use(lazyVxeUI).use(lazyVxeTable).mount('#app');

+ 1 - 0
src/theme/index.scss

@@ -8,3 +8,4 @@
 @import './dark.scss';
 @import "./iconfont/iconfont.css";
 @import "./splitpanes.scss";
+@import "./vxe.scss";

+ 19 - 0
src/theme/vxe.scss

@@ -0,0 +1,19 @@
+.vxe-table--render-default.border--default .vxe-table--header-wrapper,
+.vxe-table--render-default.border--full .vxe-table--header-wrapper,
+.vxe-table--render-default.border--outer .vxe-table--header-wrapper {
+	background-color: var(--hotline-bg-main-color) !important;
+}
+.vxe-table--render-default .vxe-header--column:not(.col--ellipsis), .vxe-table--render-default .vxe-footer--column:not(.col--ellipsis){
+	padding: 8px 0 !important;
+	font-size: var(--el-font-size-base) !important;
+}
+.vxe-table--render-default.is--padding .vxe-body--column:not(.col--ellipsis){
+	padding: 5px 0 !important;
+}
+.vxe-pager{
+	height: 40px !important;
+}
+/*
+.vxe-table--render-default .vxe-body--row.row--current{
+	background-color: var(--hotline-bg-main-color) !important;
+}*/

+ 1 - 0
src/types/global.d.ts

@@ -9,6 +9,7 @@ declare module 'vuedraggable';
 declare module 'vue-json-viewer';
 declare module '@wangeditor-next/editor-for-vue';
 declare module '@wangeditor-next/editor';
+declare module 'vxe-table';
 // 声明一个模块,防止引入文件时报错
 declare module '*.json';
 declare module '*.png';

+ 42 - 0
src/views/business/delay/index.vue

@@ -14,6 +14,48 @@
 			>
 				<template #table-search>
 					<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
+						<el-form-item label="数据范围" prop="DataScope" v-auth="'business:delay:DataScope'">
+							<el-segmented
+								:options="[
+									{
+										value: 1,
+										label: '我的',
+									},
+									{
+										value: 0,
+										label: '全部',
+									},
+								]"
+								v-model="state.queryParams.DataScope"
+								@change="handleQuery"
+								:disabled="state.loading"
+							/>
+						</el-form-item>
+						<el-form-item label="快捷查询" prop="QueryDelayState">
+							<el-segmented
+								:options="[
+									{
+										value: 0,
+										label: '全部',
+									},
+									{
+										value: 1,
+										label: '待审批',
+									},
+									{
+										value: 2,
+										label: '审批通过',
+									},
+									{
+										value: -1,
+										label: '审批拒绝',
+									},
+								]"
+								v-model="state.queryParams.QueryDelayState"
+								@change="handleQuery"
+								:disabled="state.loading"
+							/>
+						</el-form-item>
 						<el-form-item label="关键字" prop="Keyword">
 							<el-input
 								v-model.trim="state.queryParams.Keyword"

+ 56 - 135
src/views/home/components/Todo-center.vue

@@ -71,24 +71,43 @@
 			/></el-button>
 		</div>
 		<div style="height: calc(100vh - 330px); overflow: hidden">
-			<el-auto-resizer>
-				<template #default="{ height, width }">
-					<el-table-v2
-						:columns="columns"
-						:data="state.tableData"
-						:width="width"
-						:height="height"
-						:header-height="0"
-						:row-height="32"
-						:scrollbar-always-on="true"
-						v-loading="state.tableLoading"
-						fixed
-						ref="table"
-						row-key="key"
-					/>
-					<template> </template>
-				</template>
-			</el-auto-resizer>
+			<vxe-table
+				:loading="state.tableLoading"
+				:data="state.tableData"
+				:row-config="{ isCurrent: true, isHover: true, height: 30,useKey:true }"
+				ref="tableRef"
+				height="auto"
+				auto-resize
+				show-overflow
+				:scrollY="{ enabled: true, gt: 0 }"
+				:show-header="false"
+			>
+				<vxe-column field="no" title="工单编码" width="200">
+					<template #default="{ row }">
+						<span v-if="row.type === 'Waited'"><SvgIcon name="iconfont icon-daiban" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'WaitedExpired'"><SvgIcon name="iconfont icon-chaoqi1" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'Visit'"><SvgIcon name="iconfont icon-outbound" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'Sign'"><SvgIcon name="iconfont icon-huiqian" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'Delay'"><SvgIcon name="iconfont icon-yanqi" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'NearlyExpired'"><SvgIcon name="iconfont icon-chaoqi" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'Screen'"><SvgIcon name="iconfont icon-zhenbiechaxun" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'ScreenApply'"><SvgIcon name="iconfont icon-chaoqigongdan" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'SendBackAudit'"><SvgIcon name="iconfont icon-wj-thwj" />【{{ row.no }}】</span>
+					</template>
+				</vxe-column>
+				<vxe-column field="title" title="工单标题" min-width="200">
+					<template #default="{ row }">
+						<order-detail :order="{ id: row.orderId, ...row }">{{ row.title }}</order-detail>
+					</template>
+				</vxe-column>
+				<vxe-column field="acceptType" title="受理类型" width="100"></vxe-column>
+				<vxe-column field="hotspotName" title="热点分类" min-width="150"></vxe-column>
+				<vxe-column field="expiredTime" title="工单期满时间" width="160">
+					<template #default="{ row }">
+						{{ formatDate(row.time, 'YYYY-mm-dd HH:MM:SS') }}
+					</template>
+				</vxe-column>
+			</vxe-table>
 		</div>
 	</el-card>
 </template>
@@ -118,104 +137,6 @@ const state = reactive({
 const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
 const activeName = ref('all');
-const columns = ref<any[]>([
-	{
-		key: 'no',
-		title: '工单编码',
-		dataKey: 'no',
-		width: 180,
-		cellRenderer: (data: any) => {
-			switch (data.rowData.type) {
-				case 'Waited':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-daiban" />【{data.rowData.no}】
-						</span>
-					);
-				case 'WaitedExpired':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-chaoqi1" />【{data.rowData.no}】
-						</span>
-					);
-				case 'Visit':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-outbound" />【{data.rowData.no}】
-						</span>
-					);
-				case 'Sign':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-huiqian" />【{data.rowData.no}】
-						</span>
-					);
-				case 'Delay':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-yanqi" />【{data.rowData.no}】
-						</span>
-					);
-				case 'NearlyExpired':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-chaoqi" />【{data.rowData.no}】
-						</span>
-					);
-				case 'Screen':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-zhenbiechaxun" />【{data.rowData.no}】
-						</span>
-					);
-				case 'ScreenApply':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-chaoqigongdan" />【{data.rowData.no}】
-						</span>
-					);
-				case 'SendBackAudit':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-wj-thwj" />【{data.rowData.no}】
-						</span>
-					);
-				default:
-					return <span>【{data.rowData.no}】</span>;
-			}
-		},
-	},
-	{
-		key: 'title',
-		title: '工单标题',
-		dataKey: 'title',
-		width: 200,
-		align: 'center',
-		cellRenderer: (data: any) => <OrderDetail order={{ id: data.rowData.orderId, ...data.rowData }}>{data.rowData.title}</OrderDetail>,
-	},
-	{
-		key: 'acceptType',
-		title: '受理类型',
-		dataKey: 'acceptType',
-		width: 150,
-		align: 'center',
-	},
-	{
-		key: 'hotspotName',
-		title: '热点分类',
-		dataKey: 'hotspotName',
-		width: 200,
-		align: 'center',
-	},
-	{
-		key: 'time',
-		title: '工单期满时间',
-		dataKey: 'time',
-		width: 160,
-		align: 'center',
-		cellRenderer: (data: any) => <span>{formatDate(data.rowData.time, 'YYYY-mm-dd HH:MM:SS')}</span>,
-	},
-]);
 // 获取列表和总数
 const resultData = ref<EmptyObjectType>({});
 const getTableAndNum = async () => {
@@ -226,21 +147,21 @@ const getTableAndNum = async () => {
 		if (['ZiGong'].includes(themeConfig.value.appScope)) {
 			// state.tableData = result?.waitedList ?? []; // 待办列表
 			// 判断这几个有权限的路由 如果有就按照顺序取第一个
-			if (waited.value){
+			if (waited.value) {
 				state.tableData = result?.waitedList ?? []; // 待办列表
-			}else if(waitedExpired.value){
+			} else if (waitedExpired.value) {
 				state.tableData = result?.waitedExpired ?? []; // 已超期
-			}else if(visit.value){
+			} else if (visit.value) {
 				state.tableData = result?.visitList ?? []; // 回访列表
-			}else if(sign.value){
+			} else if (sign.value) {
 				state.tableData = result?.signData ?? []; // 会签列表
-			}else if(delay.value){
+			} else if (delay.value) {
 				state.tableData = result?.delayList ?? []; // 延期列表
-			}else if(nearlyExpired.value) {
+			} else if (nearlyExpired.value) {
 				state.tableData = result?.nearlyExpiredList ?? []; // 部门即将超期列表
-			} else if(screen.value){
+			} else if (screen.value) {
 				state.tableData = result?.screenList ?? []; // 甄别待审批列表
-			}else if(sendBackAudit.value){
+			} else if (sendBackAudit.value) {
 				state.tableData = result?.sendBackAuditList ?? []; // 退回待审批列表
 			}
 		} else {
@@ -269,55 +190,55 @@ const handleChange = async (tab: any) => {
 				setTimeout(() => {
 					state.tableData = allList.value;
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'waited': // 工单待办
 				setTimeout(() => {
 					state.tableData = resultData.value?.waitedList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'waitedExpired': // 已超期
 				setTimeout(() => {
 					state.tableData = resultData.value?.waitedExpiredList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'visit': // 回访
 				setTimeout(() => {
 					state.tableData = resultData.value?.visitList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'sign': // 会签
 				setTimeout(() => {
 					state.tableData = resultData.value?.signDataList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'delay': // 延期
 				setTimeout(() => {
 					state.tableData = resultData.value?.delayDataList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'nearlyExpired': // 部门即将超期
 				setTimeout(() => {
 					state.tableData = resultData.value?.nearlyExpiredList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'screen': // 甄别待审批
 				setTimeout(() => {
 					state.tableData = resultData.value?.screenList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'sendBackAudit': // 退回待审批
 				setTimeout(() => {
 					state.tableData = resultData.value?.sendBackAuditList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			default:
 				state.tableLoading = false;
@@ -422,14 +343,14 @@ const allList = computed(() => {
 onMounted(() => {
 	getTableAndNum();
 	// 判断这几个有权限的路由 如果有就按照顺序取第一个
-	if(['ZiGong','LuZhou'].includes(themeConfig.value.appScope)){
+	if (['ZiGong', 'LuZhou'].includes(themeConfig.value.appScope)) {
 		if (waited.value) activeName.value = 'waited';
 		else if (waitedExpired.value) activeName.value = 'waitedExpired';
 		else if (visit.value) activeName.value = 'visit';
 		else if (sign.value) activeName.value = 'sign';
 		else if (delay.value) activeName.value = 'delay';
 		else if (nearlyExpired.value) activeName.value = 'nearlyExpired';
-		else if (screen.value)activeName.value = 'screen';
+		else if (screen.value) activeName.value = 'screen';
 		else if (sendBackAudit.value) activeName.value = 'sendBackAudit';
 	}
 });

+ 47 - 127
src/views/home/components/Todo-department.vue

@@ -71,24 +71,43 @@
 			/></el-button>
 		</div>
 		<div style="height: calc(100vh - 330px); overflow: hidden">
-			<el-auto-resizer>
-				<template #default="{ height, width }">
-					<el-table-v2
-						:columns="columns"
-						:data="state.tableData"
-						:width="width"
-						:height="height"
-						:header-height="0"
-						:row-height="32"
-						:scrollbar-always-on="true"
-						v-loading="state.tableLoading"
-						fixed
-						ref="table"
-						row-key="key"
-					/>
-					<template> </template>
-				</template>
-			</el-auto-resizer>
+			<vxe-table
+				:loading="state.tableLoading"
+				:data="state.tableData"
+				:row-config="{ isCurrent: true, isHover: true, height: 30, useKey: true }"
+				ref="tableRef"
+				height="auto"
+				auto-resize
+				show-overflow
+				:scrollY="{ enabled: true, gt: 0 }"
+				:show-header="false"
+			>
+				<vxe-column field="no" title="工单编码" width="200">
+					<template #default="{ row }">
+						<span v-if="row.type === 'Waited'"><SvgIcon name="iconfont icon-daiban" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'WaitedExpired'"><SvgIcon name="iconfont icon-chaoqi1" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'Visit'"><SvgIcon name="iconfont icon-outbound" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'Sign'"><SvgIcon name="iconfont icon-huiqian" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'Delay'"><SvgIcon name="iconfont icon-yanqi" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'NearlyExpired'"><SvgIcon name="iconfont icon-chaoqi" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'Screen'"><SvgIcon name="iconfont icon-zhenbiechaxun" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'ScreenApply'"><SvgIcon name="iconfont icon-chaoqigongdan" />【{{ row.no }}】</span>
+						<span v-if="row.type === 'SendBackAudit'"><SvgIcon name="iconfont icon-wj-thwj" />【{{ row.no }}】</span>
+					</template>
+				</vxe-column>
+				<vxe-column field="title" title="工单标题" min-width="200">
+					<template #default="{ row }">
+						<order-detail :order="{ id: row.orderId, ...row }">{{ row.title }}</order-detail>
+					</template>
+				</vxe-column>
+				<vxe-column field="acceptType" title="受理类型" width="100"></vxe-column>
+				<vxe-column field="hotspotName" title="热点分类" min-width="150"></vxe-column>
+				<vxe-column field="expiredTime" title="工单期满时间" width="160">
+					<template #default="{ row }">
+						{{ formatDate(row.time, 'YYYY-mm-dd HH:MM:SS') }}
+					</template>
+				</vxe-column>
+			</vxe-table>
 		</div>
 	</el-card>
 </template>
@@ -119,105 +138,6 @@ const state = reactive({
 const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
 const activeName = ref('all');
-// 表格配置项
-const columns = ref<any[]>([
-	{
-		key: 'no',
-		title: '工单编码',
-		dataKey: 'no',
-		width: 180,
-		cellRenderer: (data: any) => {
-			switch (data.rowData.type) {
-				case 'Waited':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-daiban" />【{data.rowData.no}】
-						</span>
-					);
-				case 'WaitedExpired':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-chaoqi1" />【{data.rowData.no}】
-						</span>
-					);
-				case 'Visit':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-outbound" />【{data.rowData.no}】
-						</span>
-					);
-				case 'Sign':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-huiqian" />【{data.rowData.no}】
-						</span>
-					);
-				case 'Delay':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-yanqi" />【{data.rowData.no}】
-						</span>
-					);
-				case 'NearlyExpired':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-chaoqi" />【{data.rowData.no}】
-						</span>
-					);
-				case 'Screen':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-zhenbiechaxun" />【{data.rowData.no}】
-						</span>
-					);
-				case 'ScreenApply':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-chaoqigongdan" />【{data.rowData.no}】
-						</span>
-					);
-				case 'SendBackAudit':
-					return (
-						<span>
-							<SvgIcon name="iconfont icon-wj-thwj" />【{data.rowData.no}】
-						</span>
-					);
-				default:
-					return <span>【{data.rowData.no}】</span>;
-			}
-		},
-	},
-	{
-		key: 'title',
-		title: '工单标题',
-		dataKey: 'title',
-		width: 200,
-		align: 'center',
-		cellRenderer: (data: any) => <OrderDetail order={{ id: data.rowData.orderId, ...data.rowData }}>{data.rowData.title}</OrderDetail>,
-	},
-	{
-		key: 'acceptType',
-		title: '受理类型',
-		dataKey: 'acceptType',
-		width: 150,
-		align: 'center',
-	},
-	{
-		key: 'hotspotName',
-		title: '热点分类',
-		dataKey: 'hotspotName',
-		width: 200,
-		align: 'center',
-	},
-	{
-		key: 'time',
-		title: '工单期满时间',
-		dataKey: 'time',
-		width: 160,
-		align: 'center',
-		cellRenderer: (data: any) => <span>{formatDate(data.rowData.time, 'YYYY-mm-dd HH:MM:SS')}</span>,
-	},
-]);
 // 获取列表和总数
 const resultData = ref<EmptyObjectType>({});
 const getTableAndNum = async () => {
@@ -272,61 +192,61 @@ const handleChange = async (tab: any) => {
 				setTimeout(() => {
 					state.tableData = allList.value ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'waited': // 工单待办
 				setTimeout(() => {
 					state.tableData = resultData.value?.waitedList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'waitedExpired': // 已超期
 				setTimeout(() => {
 					state.tableData = resultData.value?.waitedExpiredList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'visit': // 回访
 				setTimeout(() => {
 					state.tableData = resultData.value?.visitList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'sign': // 会签
 				setTimeout(() => {
 					state.tableData = resultData.value?.signDataList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'delay': // 延期
 				setTimeout(() => {
 					state.tableData = resultData.value?.delayDataList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'nearlyExpired': // 部门即将超期
 				setTimeout(() => {
 					state.tableData = resultData.value?.nearlyExpiredList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'screenApply': // 甄别待申请
 				setTimeout(() => {
 					state.tableData = resultData.value?.screenApplyList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'screen': // 甄别待审批
 				setTimeout(() => {
 					state.tableData = resultData.value?.screenList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			case 'sendBackAudit': // 退回待审批
 				setTimeout(() => {
 					state.tableData = resultData.value?.sendBackAuditList ?? [];
 					state.tableLoading = false;
-				}, 300);
+				}, 10);
 				break;
 			default:
 				state.tableLoading = false;

+ 103 - 2
src/views/tels/smartRecord/index.vue

@@ -106,6 +106,48 @@
 					</el-col>
 				</el-row>
 			</el-form>
+
+			<vxe-toolbar ref="toolbarRef" custom>
+				<template #buttons>
+					<vxe-button status="primary">新增</vxe-button>
+					<vxe-button>删除</vxe-button>
+					<vxe-button>保存</vxe-button>
+					<el-button>测试</el-button>
+					<el-button>测试</el-button>
+				</template>
+				<template #tools>
+					<vxe-button icon="vxe-icon-upload"></vxe-button>
+					<vxe-button icon="vxe-icon-setting"></vxe-button>
+					<vxe-button icon="vxe-icon-ellipsis-h"></vxe-button>
+				</template>
+			</vxe-toolbar>
+			<vxe-table
+				border
+				:loading="loading"
+				:data="tableData"
+				:sort-config="sortConfig"
+				auto-resize
+				:column-config="{ resizable: true }"
+				:row-config="{ isCurrent: true, isHover: true }"
+				ref="tableRef"
+				@sort-change="sortChangeEvent"
+			>
+				<vxe-column type="seq" width="70"></vxe-column>
+				<vxe-column field="name" title="Name"></vxe-column>
+				<vxe-column field="role" title="Role" sortable></vxe-column>
+				<vxe-column field="sex" title="Sex" sortable></vxe-column>
+				<vxe-column field="age" title="Age" sortable></vxe-column>
+				<vxe-column field="address" title="Address" sortable>
+					<template #default="{ row }">
+						<el-switch v-model="row.flag1" disabled size="small"></el-switch>
+					</template>
+				</vxe-column>
+				<vxe-column field="operation" title="操作" fixed="right">
+					<template #default="{ row }">
+						<el-switch v-model="row.flag1" disabled size="small"></el-switch>
+					</template>
+				</vxe-column>
+			</vxe-table>
 		</el-card>
 	</div>
 </template>
@@ -116,7 +158,8 @@ import type { FormInstance } from 'element-plus';
 import { ElMessage } from 'element-plus';
 import { formatDate } from '@/utils/formatTime';
 import { olaFn } from '@/utils/olaFn';
-
+import { VxeTablePropTypes, VxeTableEvents, VxeColumnPropTypes } from 'vxe-table';
+import XEUtils from 'xe-utils';
 
 // 表格配置项
 const columns = ref<any[]>([
@@ -182,7 +225,6 @@ const handleQuery = () => {
 const queryList = async () => {
 	state.loading = true;
 	try {
-
 	} catch (e) {
 		state.loading = false;
 		console.log(e);
@@ -197,8 +239,15 @@ const resetQuery = (formEl: FormInstance | undefined) => {
 	queryList();
 };
 // 播放录音
+const toolbarRef = ref<RefType>();
+const tableRef = ref<RefType>();
 onMounted(() => {
 	// queryList();
+	const $table = tableRef.value;
+	const $toolbar = toolbarRef.value;
+	if ($table && $toolbar) {
+		$table.connect($toolbar);
+	}
 });
 const wsStatus = ref('Disconnected');
 const jsonData = ref('');
@@ -312,4 +361,56 @@ const unHold = () => {
 const hangup = () => {
 	olaRef.value.hangup();
 };
+
+interface RowVO {
+	id: number;
+	name: string;
+	role: string;
+	sex: string;
+	age: number;
+	num: string;
+	num2: string;
+	address: string;
+}
+
+const loading = ref(false);
+const tableData = ref<RowVO[]>();
+
+const sortConfig = ref<VxeTablePropTypes.SortConfig<RowVO>>({
+	remote: true,
+});
+
+const findList = (field?: VxeColumnPropTypes.Field, order?: VxeTablePropTypes.SortOrder) => {
+	loading.value = true;
+	// 模拟接口
+	return new Promise<RowVO[]>((resolve) => {
+		setTimeout(() => {
+			loading.value = false;
+			const mockList = [
+				{ id: 10001, name: 'Test1', role: 'Develop', sex: 'Man', age: 28, num: '3.8', num2: '3.8', address: 'test abc' },
+				{ id: 10002, name: 'Test2', role: 'Test', sex: 'Women', age: 22, num: '511', num2: '511', address: 'Guangzhou' },
+				{ id: 10003, name: 'Test3', role: 'PM', sex: 'Man', age: 32, num: '12.8', num2: '12.8', address: 'Shanghai' },
+				{ id: 10004, name: 'Test4', role: 'Designer', sex: 'Women', age: 23, num: '103', num2: '103', address: 'test abc' },
+				{ id: 10005, name: 'Test5', role: 'Develop', sex: 'Women', age: 30, num: '56', num2: '56', address: 'Shanghai' },
+				{ id: 10006, name: 'Test6', role: 'Designer', sex: 'Women', age: 21, num: '49', num2: '49', address: 'test abc' },
+				{ id: 10007, name: 'Test7', role: 'Test', sex: 'Man', age: 29, num: '400.9', num2: '400.9', address: 'test abc' },
+				{ id: 10008, name: 'Test8', role: 'Develop', sex: 'Man', age: 35, num: '5000', num2: '5000', address: 'test abc' },
+			];
+			if (field && order) {
+				const rest = XEUtils.orderBy(mockList, { field, order });
+				tableData.value = rest;
+				resolve(rest);
+			} else {
+				tableData.value = mockList;
+				resolve(mockList);
+			}
+		}, 300);
+	});
+};
+
+const sortChangeEvent: VxeTableEvents.SortChange<RowVO> = ({ field, order }) => {
+	findList(field, order);
+};
+
+findList();
 </script>

+ 163 - 16
src/views/todo/center/index.vue

@@ -1,7 +1,7 @@
 <template>
 	<div class="todo-center-container layout-padding">
-		<div class="layout-padding-auto layout-padding-view pd20">
-			<ProTable
+		<div class="layout-padding-auto layout-padding-view pd15">
+			<!--						<ProTable
 				ref="proTableRef"
 				:columns="columns"
 				:data="state.tableData"
@@ -41,13 +41,129 @@
 				<template #title="{ row }">
 					<order-detail :order="row" @updateList="queryList">{{ row.title }}</order-detail>
 				</template>
-				<!-- 表格操作 -->
+				&lt;!&ndash; 表格操作 &ndash;&gt;
 				<template #operation="{ row }">
 					<el-button link type="primary" @click="onSign(row)" title="签收工单" v-if="row.canSign" v-auth="'todo:center:sign'"> 签收 </el-button>
 					<el-button link type="success" @click="onOrderEdit(row)" title="编辑工单" v-if="row.canEdit" v-auth="'todo:center:edit'"> 修改 </el-button>
 					<el-button link type="primary" @click="onMigration(row)" title="平级移动" v-auth="'todo:center:migration'"> 平级移动 </el-button>
 				</template>
-			</ProTable>
+			</ProTable>-->
+			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent class="mb10" inline>
+				<el-form-item label="工单标题" prop="Title">
+					<el-input v-model.trim="state.queryParams.Title" placeholder="工单标题" clearable @keyup.enter="handleQuery" class="keyword-input" />
+				</el-form-item>
+				<el-form-item label="工单编码" prop="No">
+					<el-input v-model.trim="state.queryParams.No" placeholder="工单编码" clearable @keyup.enter="handleQuery" class="keyword-input" />
+				</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="drawer = true" class="default-button"> <SvgIcon name="ele-Search" class="mr5" />更多查询</el-button>
+				</el-form-item>
+			</el-form>
+			<vxe-toolbar
+				ref="toolbarRef"
+				:loading="state.loading"
+				custom
+				:refresh="{
+					queryMethod: handleQuery,
+				}"
+			>
+				<template #buttons>
+					<el-button type="primary" @click="onJbExport" :loading="state.loading" :disabled="isChecked" v-auth="'todo:center:jbdExport'"
+						><SvgIcon name="iconfont icon-daochu" class="mr5" />交办单导出
+					</el-button>
+					<el-button type="primary" @click="onAssignOrders" :loading="state.loading" v-auth="'todo:center:assignOrders'"
+						><SvgIcon name="ele-List" class="mr5" />分配工单
+					</el-button>
+				</template>
+				<template #tools> </template>
+			</vxe-toolbar>
+			<div style="overflow: hidden; width: 100%; height: 100%; flex: 1">
+				<!--				:export-config="{modes: ['current', 'all'],types:['xlsx'],filename:'测试'}"-->
+				<vxe-table
+					border
+					:loading="state.loading"
+					:data="state.tableData"
+					:sort-config="{ remote: true }"
+					:column-config="{ resizable: true }"
+					:row-config="{ isCurrent: true, isHover: true, height: 30 }"
+					ref="tableRef"
+					@sort-change="sortChange"
+					@checkbox-all="selectAllChangeEvent"
+					@checkbox-change="selectChangeEvent"
+					height="auto"
+					auto-resize
+					show-overflow
+					:print-config="{}"
+					:scrollY="{ enabled: true, gt: 0 }"
+					id="todoCenter"
+					:custom-config="{ storage: true }"
+				>
+					<vxe-column type="checkbox" width="60" align="center"></vxe-column>
+					<vxe-column field="expiredStatusText" title="超期状态" width="90" align="center">
+						<template #default="{ row }">
+							<span :class="'overdue-status-' + row.expiredStatus" :title="row.expiredStatusText"></span>
+						</template>
+					</vxe-column>
+					<vxe-column field="no" title="工单编码" width="140"></vxe-column>
+					<vxe-column field="isProvinceText" title="省/市工单" width="90"></vxe-column>
+					<vxe-column field="isUrgentText" title="是否紧急" width="90">
+						<template #default="{ row }">
+							<span class="color-danger font-bold">{{ row.isUrgentText }}</span>
+						</template>
+					</vxe-column>
+					<vxe-column field="currentStepName" title="当前节点" width="100"></vxe-column>
+					<vxe-column field="statusText" title="工单状态" width="100"></vxe-column>
+					<vxe-column field="title" title="工单标题" width="200">
+						<template #default="{ row }">
+							<order-detail :order="row" @updateList="queryList">{{ row.title }}</order-detail>
+						</template>
+					</vxe-column>
+					<vxe-column field="centerToOrgHandlerName" title="派单员" width="120"></vxe-column>
+					<vxe-column field="startTime" title="受理时间" sortable width="160">
+						<template #default="{ row }">
+							{{ formatDate(row.startTime, 'YYYY-mm-dd HH:MM:SS') }}
+						</template>
+					</vxe-column>
+					<vxe-column field="expiredTime" title="工单期满时间" sortable width="160">
+						<template #default="{ row }">
+							{{ formatDate(row.expiredTime, 'YYYY-mm-dd HH:MM:SS') }}
+						</template>
+					</vxe-column>
+					<vxe-column field="filedTime" title="办结时间" sortable width="160">
+						<template #default="{ row }">
+							{{ formatDate(row.filedTime, 'YYYY-mm-dd HH:MM:SS') }}
+						</template>
+					</vxe-column>
+					<vxe-column field="orgLevelOneName" title="一级部门" width="140"></vxe-column>
+					<vxe-column field="actualHandleOrgName" title="接办部门" width="140"></vxe-column>
+					<vxe-column field="acceptType" title="受理类型" width="100"></vxe-column>
+					<vxe-column field="counterSignTypeText" title="是否会签" width="90"></vxe-column>
+					<vxe-column field="sourceChannel" title="来源渠道" width="100"></vxe-column>
+					<vxe-column field="hotspotName" title="热点分类" width="150"></vxe-column>
+					<vxe-column field="sensitive" title="敏感词" width="150"></vxe-column>
+					<vxe-column field="acceptorName" title="受理人" width="120"></vxe-column>
+					<vxe-column field="reTransactNum" title="重办次数" width="90"></vxe-column>
+					<vxe-column title="操作" fixed="right" width="130" align="center">
+						<template #default="{ row }">
+							<el-button link type="primary" @click="onSign(row)" title="签收工单" v-if="row.canSign" v-auth="'todo:center:sign'"> 签收 </el-button>
+							<el-button link type="success" @click="onOrderEdit(row)" title="编辑工单" v-if="row.canEdit" v-auth="'todo:center:edit'">
+								修改
+							</el-button>
+							<el-button link type="primary" @click="onMigration(row)" title="平级移动" v-auth="'todo:center:migration'"> 平级移动 </el-button>
+						</template>
+					</vxe-column>
+				</vxe-table>
+			</div>
+			<vxe-pager
+				v-model:currentPage="state.queryParams.PageIndex"
+				v-model:pageSize="state.queryParams.PageSize"
+				:total="state.total"
+				@page-change="queryList"
+				:layouts="['PrevPage', 'Number', 'NextPage', 'Sizes', 'FullJump', 'Total']"
+			>
+			</vxe-pager>
 		</div>
 		<!-- 工单平移 -->
 		<order-migration ref="orderMigrationRef" @updateList="queryList" />
@@ -121,7 +237,7 @@
 	</div>
 </template>
 <script setup lang="tsx" name="todoCenter">
-import { defineAsyncComponent, onActivated, onBeforeUnmount, onMounted, reactive, ref } from 'vue';
+import { computed, defineAsyncComponent, onActivated, onBeforeUnmount, onMounted, reactive, ref } from 'vue';
 import type { FormInstance } from 'element-plus';
 import { ElMessage, ElMessageBox } from 'element-plus';
 import { defaultTimeStartEnd, shortcuts } from '@/utils/constants';
@@ -158,8 +274,8 @@ const state = reactive<any>({
 		StepName: null, // 当前节点名称
 		IsUrgent: null,
 		CenterToOrgHandlerName: null, // 派单员
-		SortField:null,
-		SortRule:null,
+		SortField: null,
+		SortRule: null,
 	},
 	tableData: [], //表单
 	loading: false, // 加载
@@ -179,7 +295,7 @@ const columns = ref<any[]>([
 	{
 		prop: 'isUrgentText',
 		label: '是否紧急',
-		render: (scope:any) => {
+		render: (scope: any) => {
 			return <span class="color-danger font-bold">{scope.row.isUrgentText}</span>;
 		},
 	},
@@ -191,7 +307,7 @@ const columns = ref<any[]>([
 		prop: 'startTime',
 		label: '受理时间',
 		minWidth: 160,
-		render: (scope:any) => {
+		render: (scope: any) => {
 			return <span>{formatDate(scope.row.startTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
 		},
 		sortable: 'custom',
@@ -200,7 +316,7 @@ const columns = ref<any[]>([
 		prop: 'expiredTime',
 		label: '工单期满时间',
 		minWidth: 160,
-		render: (scope:any) => {
+		render: (scope: any) => {
 			return <span>{formatDate(scope.row.expiredTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
 		},
 		sortable: 'custom',
@@ -209,7 +325,7 @@ const columns = ref<any[]>([
 		prop: 'filedTime',
 		label: '办结时间',
 		minWidth: 160,
-		render: (scope:any) => {
+		render: (scope: any) => {
 			return <span>{formatDate(scope.row.filedTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
 		},
 		sortable: 'custom',
@@ -250,9 +366,9 @@ const getBaseData = async () => {
 };
 // 排序
 const sortChange = (val: any) => {
-	state.queryParams.SortField = val.order ? val.prop : null;
+	state.queryParams.SortField = val.order ? val.field : null;
 	// 0 升序 1 降序
-	state.queryParams.SortRule = val.order ? (val.order == 'descending' ? 1 : 0) : null;
+	state.queryParams.SortRule = val.order ? (val.order == 'desc' ? 1 : 0) : null;
 	handleQuery();
 };
 // 手动查询,将页码设置为1
@@ -322,8 +438,8 @@ const onOrderEdit = (row: any) => {
 };
 // 交办单导出
 const onJbExport = () => {
-	const ids = proTableRef.value.selectedList.map((item: any) => item.id);
-	ElMessageBox.confirm(`您确定导出选中的${proTableRef.value.selectedList.length}个工单交办单,是否继续?`, '提示', {
+	const ids = checkTable.value.map((item: any) => item.id);
+	ElMessageBox.confirm(`您确定导出选中的工单交办单,是否继续?`, '提示', {
 		confirmButtonText: '确认',
 		cancelButtonText: '取消',
 		type: 'warning',
@@ -374,9 +490,33 @@ const onAssignOrders = () => {
 		})
 		.catch(() => {});
 };
+const tableRef = ref<RefType>();
+const checkTable = ref<EmptyArrayType>([]);
+const selectAllChangeEvent = ({ checked }) => {
+	if (tableRef.value) {
+		const records = tableRef.value.getCheckboxRecords();
+		checkTable.value = records;
+		console.log(checked ? '所有勾选事件' : '所有取消事件', records);
+	}
+};
+
+const selectChangeEvent = ({ checked }) => {
+	if (tableRef.value) {
+		const records = tableRef.value.getCheckboxRecords();
+		checkTable.value = records;
+		console.log(checked ? '勾选事件' : '取消事件', records);
+	}
+};
+const isChecked = computed(() => {
+	return !Boolean(checkTable.value.length);
+});
+const toolbarRef = ref<RefType>();
 onMounted(() => {
 	getBaseData();
 	queryList();
+	if (tableRef.value && toolbarRef.value) {
+		tableRef.value.connect(toolbarRef.value);
+	}
 });
 onActivated(() => {
 	mittBus.on('clearCachePage', () => {
@@ -387,4 +527,11 @@ onActivated(() => {
 onBeforeUnmount(() => {
 	mittBus.off('clearCachePage');
 });
-</script>
+</script>
+<style lang="scss" scoped>
+.todo-center-container {
+	.table {
+		flex: 1;
+	}
+}
+</style>

+ 165 - 9
src/views/todo/order/index.vue

@@ -5,7 +5,139 @@
 				<el-tab-pane name="false" label="工单待办" :disabled="state.loading"></el-tab-pane>
 				<el-tab-pane name="true" label="工单已办" :disabled="state.loading"></el-tab-pane>
 			</el-tabs>
-			<ProTable
+			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
+				<el-form-item label="快捷查询" prop="QueryType" v-if="['ZiGong'].includes(themeConfig.appScope)" v-auth="'todo:seats:fastSearch'">
+					<el-segmented
+						:options="[
+							{
+								value: 1,
+								label: '中心办理件',
+							},
+							{
+								value: 2,
+								label: '转单件',
+							},
+							{
+								value: 3,
+								label: '二次派发',
+							},
+						]"
+						v-model="state.queryParams.QueryType"
+						@change="handleQuery"
+						:disabled="state.loading"
+					/>
+				</el-form-item>
+				<el-form-item label="工单标题" prop="Keyword">
+					<el-input v-model.trim="state.queryParams.Keyword" placeholder="工单标题" clearable @keyup.enter="handleQuery" class="keyword-input" />
+				</el-form-item>
+				<el-form-item label="工单编码" prop="No">
+					<el-input v-model.trim="state.queryParams.No" placeholder="工单编码" clearable @keyup.enter="handleQuery" class="keyword-input" />
+				</el-form-item>
+				<el-form-item label="">
+					<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+					<el-button @click="drawer = true" class="default-button"> <SvgIcon name="ele-Search" class="mr5" />更多查询</el-button>
+				</el-form-item>
+			</el-form>
+			<vxe-toolbar
+				ref="toolbarRef"
+				:loading="state.loading"
+				custom
+				:refresh="{
+					queryMethod: handleQuery,
+				}"
+			>
+				<template #buttons>
+					<el-button type="primary" @click="onJbExport" :disabled="isChecked" :loading="state.loading" v-auth="'todo:order:jbdExport'"
+						><SvgIcon name="iconfont icon-daochu" class="mr5" />交办单导出
+					</el-button>
+					<el-button
+						type="primary"
+						@click="onToEnd"
+						:disabled="isChecked"
+						:loading="state.loading"
+						v-auth-all="['todo:seats:fastSearch', 'todo:order:toEnd:multiple']"
+						><SvgIcon name="ele-List" class="mr5" />批量归档
+					</el-button>
+					<el-button type="primary" @click="onAssignOrders" :loading="state.loading" v-auth="'todo:order:assignOrders'"
+						><SvgIcon name="ele-List" class="mr5" />分配工单
+					</el-button>
+				</template>
+				<template #tools> </template>
+			</vxe-toolbar>
+			<div style="overflow: hidden; width: 100%; height: 100%; flex: 1">
+				<vxe-table
+					border
+					:loading="state.loading"
+					:data="state.tableData"
+					:sort-config="{ remote: true }"
+					:column-config="{ resizable: true }"
+					:row-config="{ isCurrent: true, isHover: true, height: 30 }"
+					ref="tableRef"
+					@sort-change="sortChange"
+					@checkbox-all="selectAllChangeEvent"
+					@checkbox-change="selectChangeEvent"
+					height="auto"
+					auto-resize
+					show-overflow
+					:print-config="{}"
+					:scrollY="{ enabled: true, gt: 0 }"
+					id="todoOrder"
+					:custom-config="{ storage: true }"
+				>
+					<vxe-column type="checkbox" width="50" align="center"></vxe-column>
+					<vxe-column field="expiredStatusText" title="超期状态" width="90" align="center">
+						<template #default="{ row }">
+							<span :class="'overdue-status-' + row.expiredStatus" :title="row.expiredStatusText"></span>
+						</template>
+					</vxe-column>
+					<vxe-column field="no" title="工单编码" width="140"></vxe-column>
+					<vxe-column field="isProvinceText" title="省/市工单" width="90"></vxe-column>
+					<vxe-column field="isUrgentText" title="是否紧急" width="90">
+						<template #default="{ row }">
+							<span class="color-danger font-bold">{{ row.isUrgentText }}</span>
+						</template>
+					</vxe-column>
+					<vxe-column field="currentStepName" title="当前节点" width="100"></vxe-column>
+					<vxe-column field="statusText" title="工单状态" width="100"></vxe-column>
+					<vxe-column field="title" title="工单标题" width="200">
+						<template #default="{ row }">
+							<order-detail :order="row" @updateList="queryList">{{ row.title }}</order-detail>
+						</template>
+					</vxe-column>
+					<vxe-column field="creationTime" title="生成时间" sortable width="160">
+						<template #default="{ row }">
+							{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}
+						</template>
+					</vxe-column>
+					<vxe-column field="startTime" title="受理时间" sortable width="160">
+						<template #default="{ row }">
+							{{ formatDate(row.startTime, 'YYYY-mm-dd HH:MM:SS') }}
+						</template>
+					</vxe-column>
+					<vxe-column field="expiredTime" title="工单期满时间" sortable width="160">
+						<template #default="{ row }">
+							{{ formatDate(row.expiredTime, 'YYYY-mm-dd HH:MM:SS') }}
+						</template>
+					</vxe-column>
+					<vxe-column field="counterSignTypeText" title="是否会签" width="90"></vxe-column>
+					<vxe-column field="orgLevelOneName" title="一级部门" width="140" :visible="state.queryParams.IsHandled === 'true'"></vxe-column>
+					<vxe-column field="actualHandleOrgName" title="接办部门" width="140" :visible="state.queryParams.IsHandled === 'true'"></vxe-column>
+					<vxe-column field="acceptType" title="受理类型" width="100"></vxe-column>
+					<vxe-column field="sourceChannel" title="来源渠道" width="100"></vxe-column>
+					<vxe-column field="hotspotName" title="热点分类" width="150"></vxe-column>
+					<vxe-column field="acceptorName" title="受理人" width="120"></vxe-column>
+					<vxe-column field="reTransactNum" title="重办次数" width="90"></vxe-column>
+				</vxe-table>
+			</div>
+			<vxe-pager
+				v-model:currentPage="state.queryParams.PageIndex"
+				v-model:pageSize="state.queryParams.PageSize"
+				:total="state.total"
+				@page-change="queryList"
+				:layouts="['PrevPage', 'Number', 'NextPage', 'Sizes', 'FullJump', 'Total']"
+			>
+			</vxe-pager>
+			<!--			<ProTable
 				ref="proTableRef"
 				:columns="columnsTodo"
 				:data="state.tableData"
@@ -119,7 +251,7 @@
 				<template #title="{ row }">
 					<order-detail :order="row" @updateList="queryList">{{ row.title }}</order-detail>
 				</template>
-			</ProTable>
+			</ProTable>-->
 		</div>
 		<!--	更多查询	-->
 		<el-drawer v-model="drawer" title="更多查询" size="500px">
@@ -184,7 +316,7 @@
 	</div>
 </template>
 <script setup lang="tsx" name="todoOrder">
-import { defineAsyncComponent, onMounted, reactive, ref, onActivated, onBeforeUnmount } from 'vue';
+import { defineAsyncComponent, onMounted, reactive, ref, onActivated, onBeforeUnmount, computed } from 'vue';
 import { ElMessage, ElMessageBox, ElNotification, FormInstance } from 'element-plus';
 import { formatDate } from '@/utils/formatTime';
 import { orderAverage, orderBatchArchive, orderListTodo } from '@/api/todo/order';
@@ -197,6 +329,7 @@ import { treeArea } from '@/api/auxiliary/area';
 import { useThemeConfig } from '@/stores/themeConfig';
 import { storeToRefs } from 'pinia';
 import { auth } from '@/utils/authFunction';
+import { VxeTableEvents } from 'vxe-table';
 // 引入组件
 const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
 // 定义变量内容
@@ -336,9 +469,9 @@ const columnsDone = ref<any[]>([
 ]);
 // 排序
 const sortChange = (val: any) => {
-	state.queryParams.SortField = val.order ? val.prop : null;
+	state.queryParams.SortField = val.order ? val.field : null;
 	// 0 升序 1 降序
-	state.queryParams.SortRule = val.order ? (val.order == 'descending' ? 1 : 0) : null;
+	state.queryParams.SortRule = val.order ? (val.order == 'desc' ? 1 : 0) : null;
 	handleQuery();
 };
 // 手动查询,将页码设置为1
@@ -350,7 +483,6 @@ const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
 /** 获取列表 */
 const requestParams = ref<EmptyObjectType>({});
-
 const queryList = async () => {
 	state.loading = true;
 	if (['ZiGong'].includes(themeConfig.value.appScope) && auth('todo:seats:fastSearch') && state.queryParams.IsHandled === 'false') {
@@ -383,8 +515,8 @@ const resetQuery = (formEl: FormInstance | undefined) => {
 };
 // 交办单导出
 const onJbExport = () => {
-	const ids = proTableRef.value.selectedList.map((item: any) => item.id);
-	ElMessageBox.confirm(`您确定导出选中的${proTableRef.value.selectedList.length}个工单交办单,是否继续?`, '提示', {
+	const ids = checkTable.value.map((item: any) => item.id);
+	ElMessageBox.confirm(`您确定导出选中的工单交办单,是否继续?`, '提示', {
 		confirmButtonText: '确认',
 		cancelButtonText: '取消',
 		type: 'warning',
@@ -441,7 +573,7 @@ const onAssignOrders = () => {
 };
 // 批量归档
 const onToEnd = () => {
-	const ids = proTableRef.value.selectedList.map((item: any) => item.id);
+	const ids = checkTable.value.map((item: any) => item.id);
 	ElMessageBox.confirm(`您确定要批量归档选中的工单,是否继续?`, '提示', {
 		confirmButtonText: '确认',
 		cancelButtonText: '取消',
@@ -468,9 +600,33 @@ const onToEnd = () => {
 		})
 		.catch(() => {});
 };
+const tableRef = ref<RefType>();
+const checkTable = ref<EmptyArrayType>([]);
+const selectAllChangeEvent = ({ checked }) => {
+	if (tableRef.value) {
+		const records = tableRef.value.getCheckboxRecords();
+		checkTable.value = records;
+		console.log(checked ? '所有勾选事件' : '所有取消事件', records);
+	}
+};
+
+const selectChangeEvent = ({ checked }) => {
+	if (tableRef.value) {
+		const records = tableRef.value.getCheckboxRecords();
+		checkTable.value = records;
+		console.log(checked ? '勾选事件' : '取消事件', records);
+	}
+};
+const isChecked = computed(() => {
+	return !Boolean(checkTable.value.length);
+});
+const toolbarRef = ref<RefType>();
 onMounted(() => {
 	getBaseData();
 	queryList();
+	if (tableRef.value && toolbarRef.value) {
+		tableRef.value.connect(toolbarRef.value);
+	}
 });
 onActivated(() => {
 	mittBus.on('clearCachePage', () => {

+ 11 - 0
vite.config.ts

@@ -6,6 +6,7 @@ import viteCompression from 'vite-plugin-compression'; //开启gzip打包压缩
 import vueJsx from '@vitejs/plugin-vue-jsx'; // jsx
 import { viteCommonjs } from '@originjs/vite-plugin-commonjs';
 import { visualizer } from "rollup-plugin-visualizer";
+import { lazyImport, VxeResolver } from 'vite-plugin-lazy-import'
 // @ts-ignore
 export default defineConfig((mode: ConfigEnv) => {
 	return {
@@ -23,6 +24,16 @@ export default defineConfig((mode: ConfigEnv) => {
 				gzipSize: true, // 是否统计并显示gzip
 				brotliSize: true, // 是否统计并显示brotli
 			}),
+			lazyImport({
+				resolvers: [
+					VxeResolver({
+						libraryName: 'vxe-table'
+					}),
+					VxeResolver({
+						libraryName: 'vxe-pc-ui'
+					})
+				]
+			})
 		],
 		root: process.cwd(),
 		resolve: { alias: { '@': resolve(__dirname, './src') } },

File diff suppressed because it is too large
+ 498 - 189
yarn.lock


Some files were not shown because too many files changed in this diff