Browse Source

feat:新增会签待办页面;新增回访待办查询条件;新增登录页通过短信登录方式;

zhangchong 1 year ago
parent
commit
01ed240eb7

+ 1 - 1
src/components/ImgVerify/hooks.ts

@@ -43,7 +43,7 @@ function randomColor(min: number, max: number) {
 
 function draw(dom: HTMLCanvasElement, width: number, height: number) {
 	let imgCode = '';
-	const Random_STRING: string = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+	const Random_STRING: string = '23456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
 	const ctx = dom.getContext('2d');
 	if (!ctx) return imgCode;
 

+ 0 - 2
src/components/ProcessTimeLine/index.vue

@@ -1,5 +1,4 @@
 <template>
-	<div>
 		<el-timeline class="time-line">
 			<el-timeline-item v-for="(item, index) in props.data" :key="index" :type="item.type" size="large" hollow hide-timestamp>
 				<!-- 左侧展示 -->
@@ -93,7 +92,6 @@
 				</el-collapse-transition>
 			</el-timeline-item>
 		</el-timeline>
-	</div>
 </template>
 
 <script setup lang="ts" name="processTimeLine">

+ 1 - 1
src/utils/toolsValidate.ts

@@ -188,7 +188,7 @@ export function verifyNumberCnUppercase(val: any, unit = '仟佰拾亿仟佰拾
  */
 export function verifyPhone(val: string) {
 	// false: 手机号码不正确
-	return /^((12[0-9])|(13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0|1,5-9]))\d{8}$/.test(val);
+	return /^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(val);
 }
 
 /**

+ 4 - 15
src/views/login/component/Account.vue

@@ -37,6 +37,7 @@
 		<motion :delay="300">
 			<el-form-item
 				prop="verifyCode"
+        class="mb30"
 				:rules="[
 					{ required: true, message: '请输入验证码', trigger: 'blur' },
 					{
@@ -72,9 +73,7 @@
 			</el-form-item>
 		</motion>
     <motion :delay="500">
-       <div class="mt10">
         运营管理系统 <span class="color-danger font-bold">v5.0</span>
-      </div>
     </motion>
 		<motion :delay="500">
 			<div class="login-msg">
@@ -231,24 +230,14 @@ const signInSuccess = (isNoPower: boolean | undefined) => {
 
 .login-content-form {
 	margin-top: 20px;
-	font-size: 16px;
+  font-size: var(--el-font-size-medium);
 
 	:deep(.el-input--large) {
-		font-size: 16px;
+    font-size: var(--el-font-size-medium);
 	}
 
 	:deep(.el-form-item__error) {
-		font-size: 14px;
-	}
-
-	.login-content-password {
-		display: inline-block;
-		width: 20px;
-		cursor: pointer;
-
-		&:hover {
-			color: #909399;
-		}
+    font-size: var(--el-font-size-medium);
 	}
 
 	.login-content-code {

+ 273 - 36
src/views/login/component/Mobile.vue

@@ -1,69 +1,290 @@
 <template>
-	<el-form size="large" class="login-content-form">
-		<el-form-item class="login-animation1">
-			<el-input type="text" placeholder="请输入手机号" v-model="state.ruleForm.userName" clearable autocomplete="off">
+	<el-form size="large" class="login-content-form" ref="ruleFormRef" :model="state.ruleForm" @submit.native.prevent>
+		<el-form-item
+			prop="userName"
+			class="mb30"
+			:rules="[
+				{ required: true, message: '请输入手机号', trigger: 'blur' },
+				{ validator: checkPhone, trigger: 'blur' },
+			]"
+		>
+			<el-input placeholder="请输入手机号" v-model="state.ruleForm.userName" clearable autocomplete="off" class="inputDeep">
 				<template #prefix>
-					<i class="iconfont icon-dianhua el-input__icon"></i>
+					<SvgIcon name="ele-Phone" class="el-input__icon" />
 				</template>
 			</el-input>
 		</el-form-item>
-		<el-form-item class="login-animation2">
+		<el-form-item prop="password" class="mb30" :rules="[{ required: true, message: '请输入短信验证码', trigger: 'blur' }]">
 			<el-col :span="15">
-				<el-input type="text" maxlength="4" placeholder="请输入验证码" v-model="state.ruleForm.code" clearable autocomplete="off">
+				<el-input
+					type="text"
+					maxlength="4"
+					placeholder="请输入短信验证码"
+					v-model="state.ruleForm.code"
+					clearable
+					autocomplete="off"
+					class="inputDeep"
+				>
 					<template #prefix>
-						<el-icon class="el-input__icon"><ele-Position /></el-icon>
+						<SvgIcon name="ele-ChatDotSquare" class="el-input__icon" />
 					</template>
 				</el-input>
 			</el-col>
 			<el-col :span="1"></el-col>
 			<el-col :span="8">
-				<el-button class="login-content-code">获取验证码</el-button>
+				<el-button class="login-content-code" :disabled="isDisabled" @click="getIdentifyCodeBtn">{{
+					isDisabled ? count + 's后重新获取' : click
+				}}</el-button>
 			</el-col>
 		</el-form-item>
-		<el-form-item class="login-animation3">
-			<el-button round type="primary" class="login-content-submit">
-				<span>登 录</span>
-			</el-button>
+		<el-form-item
+			prop="verifyCode"
+			:rules="[
+				{ required: true, message: '请输入验证码', trigger: 'blur' },
+				{
+					validator: validatePass,
+					trigger: 'blur',
+				},
+			]"
+      class="mb30"
+		>
+			<el-col :span="15">
+				<el-input
+					type="text"
+					maxlength="4"
+					class="inputDeep"
+					placeholder="验证码不区分大小写"
+					v-model="state.ruleForm.verifyCode"
+					@keyup.enter="onSignIn(ruleFormRef)"
+					clearable
+					autocomplete="off"
+				>
+					<template #prefix>
+						<SvgIcon name="iconfont icon-quanxian" class="el-input__icon" />
+					</template>
+				</el-input>
+			</el-col>
+			<el-col :span="8" :offset="1" class="flex">
+				<ReImageVerify v-model:code="verifyCode" />
+			</el-col>
+		</el-form-item>
+		<el-form-item>
+			<el-button type="primary" class="login-content-submit" round @click="onSignIn(ruleFormRef)" :loading="state.loading">登录</el-button>
 		</el-form-item>
-		<div class="font12 mt30 login-animation4 login-msg">
-			* 温馨提示:建议使用谷歌、Microsoft Edge,版本 79.0.1072.62 及以上浏览器,360浏览器请使用极速模式
-		</div>
+    <motion :delay="500">
+      <div>
+        运营管理系统 <span class="color-danger font-bold">v5.0</span>
+      </div>
+    </motion>
+    <motion :delay="500">
+      <div class="login-msg">
+        <div>联系管理员<b>重置密码</b></div>
+        <!-- <el-button link type="primary" class="font16" @click="forgetPwd">忘记密码</el-button> -->
+      </div>
+    </motion>
 	</el-form>
 </template>
 
 <script setup lang="ts" name="loginMobile">
-import { reactive } from 'vue';
-// 定义接口来定义对象的类型
-interface LoginMobileState {
-	userName: any;
-	code: string | number | undefined;
-}
+import { reactive, defineAsyncComponent, ref, computed } from 'vue';
+import { ElNotification, FormInstance } from 'element-plus';
+import { throttle } from '@/utils/tools';
+import { JSEncrypt } from 'jsencrypt';
+import { signIn } from '@/api/login';
+import { Cookie, Local, Session } from '@/utils/storage';
+import { storeToRefs } from 'pinia';
+import { useThemeConfig } from '@/stores/themeConfig';
+import { useRoute, useRouter } from 'vue-router';
+import { initFrontEndControlRoutes } from '@/router/frontEnd';
+import { initBackEndControlRoutes } from '@/router/backEnd';
+import { formatAxis } from '@/utils/formatTime';
+import { NextLoading } from '@/utils/loading';
+import { verifyPhone } from '@/utils/toolsValidate';
+import Motion from "@/utils/motion";
 
-// 定义对象与类型
-const ruleForm: LoginMobileState = {
-	userName: '',
-	code: '',
-};
+const ReImageVerify = defineAsyncComponent(() => import('@/components/ImgVerify/index.vue'));
 
 // 定义变量内容
 const state = reactive({
-	ruleForm
+	ruleForm: {
+		userName: '',
+		code: '',
+		verifyCode: '',
+	},
+	loading: false,
 });
 
+// 验证码
+const verifyCode = ref<string>(''); // 验证码
+// 验证手机号
+const validatePass = (rule: any, value: any, callback: any) => {
+	if (value === '') {
+		callback(new Error('请输入验证码'));
+	} else {
+		if (state.ruleForm.verifyCode !== '') {
+			if (state.ruleForm.verifyCode.toUpperCase() !== verifyCode.value.toUpperCase()) {
+				callback(new Error('验证码错误,请重新输入'));
+			}
+		}
+		callback();
+	}
+};
+const count = ref(60);
+const click = ref('获取验证码');
+const isDisabled = ref(false);
+const checkPhone = (rule, value, callback) => {
+	if (!value) {
+		return callback(new Error('手机号不能为空'));
+	} else {
+		if (verifyPhone(value)) {
+			callback();
+		} else {
+			return callback(new Error('请输入正确的手机号'));
+		}
+	}
+};
+const getIdentifyCodeBtn = () => {
+  if(!state.ruleForm.userName) {
+    ruleFormRef.value?.validateField('userName');
+    return;
+  }
+  if (!verifyPhone(state.ruleForm.userName)) {
+    ruleFormRef.value?.validateField('userName');
+    return;
+  }
+  // state.loading = true;
+	countDown();
+};
+// 倒计时
+const countDown = () => {
+	if (count.value === 0) {
+		isDisabled.value = false;
+		click.value = '获取验证码';
+		count.value = 60;
+		return;
+	} else {
+		count.value--;
+		click.value = count.value + 's后重新获取';
+		isDisabled.value = true;
+		setTimeout(() => {
+			countDown();
+		}, 1000);
+	}
+};
+
+const ruleFormRef = ref<FormInstance>(); // 表单ref
+const storesThemeConfig = useThemeConfig(); // 主题配置
+const { themeConfig } = storeToRefs(storesThemeConfig); // 主题配置
+const route = useRoute(); // 路由
+const router = useRouter(); // 路由
+// 登录
+const onSignIn = throttle(async (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	await formEl.validate((valid: boolean) => {
+		if (!valid) return;
+		state.loading = true;
+		// 新建一个JSEncrypt对象
+		const encryptor = new JSEncrypt({ default_key_size: '2048' });
+		// 设置公钥
+		const publicKey =
+			'-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgw+/x6IQPkH0A4eoF63jkLThsOXWyNBdcL9LATGy/G1yTHOr1RyKJB//iNug+V8DIoIHuFTlhgLHDbSqxvRWMONxIIF289riS6bDI4Ox/pFmOfmElFRk0lKGihaTE2Aefd6g/N+RfLLaHWztY+/voVeDTiOIw9y3tokIxjKwuJ/mQ66MkKh78AqQjjSD/3jcBP8ZhMyCJOK9XQcqvhD6WBFWkxlAqKOWggDU7YohfrbNkg3bd0oGE6zCE2EHhkcQbzGCh3lu1zf4TfKMXD+PPrr5JWDNYQTXFQklqgae+Puge7xxZGYRoi5YpIUnkQGm6zpPxhIOdxlz+Yb5geSJUQIDAQAB-----END PUBLIC KEY-----';
+		encryptor.setPublicKey(publicKey); // publicKey为公钥
+		// 加密数据
+		const submitObj = {
+			username: encryptor.encrypt(state.ruleForm.username),
+			password: encryptor.encrypt(state.ruleForm.password),
+		};
+		signIn(submitObj)
+			.then(async (res: any) => {
+				//登录
+				// 存储 token 到浏览器缓存
+				Cookie.set('token', res.result);
+				if (!themeConfig.value.isRequestRoutes) {
+					// 前端控制路由,2、请注意执行顺序
+					const isNoPower = await initFrontEndControlRoutes();
+					signInSuccess(isNoPower);
+				} else {
+					// 模拟后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
+					// 添加完动态路由,再进行 router 跳转,否则可能报错 No match found for location with path "/"
+					const isNoPower = await initBackEndControlRoutes();
+					// 执行完 initBackEndControlRoutes,再执行 signInSuccess
+					signInSuccess(isNoPower);
+				}
+			})
+			.catch(() => {
+				state.loading = false;
+			});
+	});
+}, 1000);
+// 登录成功后的跳转
+// 时间获取
+const currentTime = computed(() => {
+	return formatAxis(new Date());
+});
+const signInSuccess = (isNoPower: boolean | undefined) => {
+	if (isNoPower) {
+		state.loading = false;
+		ElNotification({
+			title: '提示',
+			message: '抱歉,您没有登录权限,请联系管理员',
+			type: 'warning',
+		});
+		Session.clear();
+		Cookie.clear();
+		Local.clear();
+	} else {
+		// 初始化登录成功时间问候语
+		let currentTimeInfo = currentTime.value;
+		// 登录成功,跳到转首页
+		/*// 如果是复制粘贴的路径,非首页/登录页,那么登录成功后重定向到对应的路径中
+    if (route.query?.redirect) {
+      router.push({
+        path: <string>route.query?.redirect,
+        query: Object.keys(<string>route.query?.params).length > 0 ? JSON.parse(<string>route.query?.params) : '',
+      });
+    } else {
+      router.push('/');
+    }*/
+		router.push('/');
+		// 设置登录成功后的时间问候语
+		Cookie.set('userName', state.ruleForm.username);
+		// 登录成功提示
+		// 关闭 loading
+		state.loading = true;
+		const signInText = '欢迎回来!';
+		ElNotification({
+			type: 'success',
+			title: `${currentTimeInfo}`,
+			message: `${signInText}`,
+		});
+		NextLoading.start();
+	}
+};
 </script>
 
 <style scoped lang="scss">
+.inputDeep {
+	:deep(.el-input__wrapper) {
+		box-shadow: 0 0 0 0 var(--el-input-border-color, var(--el-border-color)) inset;
+		border-radius: 0;
+		border-bottom: 1px solid var(--el-input-border-color, var(--el-border-color));
+	}
+	:deep(.el-form-item.is-error .el-input__wrapper.is-focus) {
+		box-shadow: 0 0 0 0 var(--el-input-border-color, var(--el-border-color)) inset;
+	}
+}
 .login-content-form {
+	font-size: var(--el-font-size-medium);
 	margin-top: 20px;
-	@for $i from 1 through 4 {
-		.login-animation#{$i} {
-			opacity: 0;
-			animation-name: error-num;
-			animation-duration: 0.5s;
-			animation-fill-mode: forwards;
-			animation-delay: calc($i/10) + s;
-		}
+
+	:deep(.el-input--large) {
+		font-size: var(--el-font-size-medium);
+	}
+
+	:deep(.el-form-item__error) {
+		font-size: var(--el-font-size-medium);
 	}
+
 	.login-content-code {
 		width: 100%;
 		padding: 0;
@@ -74,8 +295,24 @@ const state = reactive({
 		font-weight: 300;
 		margin-top: 15px;
 	}
+	.login-content-submit {
+		width: 100%;
+		margin-top: 45px;
+		height: 50px;
+		border-radius: 30px;
+		font-size: 16px;
+		letter-spacing: 5px;
+	}
 	.login-msg {
-		color: var(--el-text-color-placeholder);
+    margin-top: 10px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    color: var(--el-color-primary);
+    b {
+      color: #999;
+      padding-left: 4px;
+    }
 	}
 }
 </style>

+ 21 - 16
src/views/login/index.vue

@@ -6,21 +6,23 @@
 				<Motion>
 					<h4 class="login-content-title">{{ getThemeConfig.globalViceTitle }}</h4>
 				</Motion>
-				<div v-if="!state.isScan">
-					<el-tabs v-model="state.tabsActiveName">
-						<!-- <el-tab-pane label="账号密码登录" name="account"> -->
-						<account />
-						<!-- </el-tab-pane> -->
-						<!-- <el-tab-pane label="手机号登录" name="mobile">
-							<Mobile />
-						</el-tab-pane> -->
-					</el-tabs>
-				</div>
-				<!-- <Scan v-if="isScan" />
-				<div class="login-content-main-scan" @click="isScan = !isScan">
-					<i class="iconfont" :class="isScan ? 'icon-diannao1' : 'icon-barcode-qr'"></i>
+        <Motion>
+<!--          <div v-if="!state.isScan">-->
+            <el-tabs v-model="state.tabsActiveName">
+              <el-tab-pane label="账号登录" name="account">
+                <account />
+              </el-tab-pane>
+              <el-tab-pane label="手机号登录" name="mobile">
+                <Mobile />
+              </el-tab-pane>
+            </el-tabs>
+<!--          </div>-->
+        </Motion>
+<!--				<Scan v-if="state.isScan" />
+				<div class="login-content-main-scan" @click="state.isScan = !state.isScan">
+					<i class="iconfont" :class="state.isScan ? 'icon-diannao1' : 'icon-barcode-qr'"></i>
 					<div class="login-content-main-scan-delta"></div>
-				</div> -->
+				</div>-->
 			</div>
 		</div>
 	</div>
@@ -41,8 +43,8 @@ interface LoginState {
 
 // 引入组件
 const Account = defineAsyncComponent(() => import('@/views/login/component/Account.vue'));
-// const Mobile = defineAsyncComponent(() => import('@/views/login/component/Mobile.vue'));
-// const Scan = defineAsyncComponent(() => import('@/views/login/component/Scan.vue'));
+const Mobile = defineAsyncComponent(() => import('@/views/login/component/Mobile.vue'));
+const Scan = defineAsyncComponent(() => import('@/views/login/component/Scan.vue'));
 
 const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
@@ -62,6 +64,9 @@ onMounted(async () => {
 </script>
 
 <style scoped lang="scss">
+:deep(.el-tabs__item){
+  font-size: var(--el-font-size-medium);
+}
 .login-container {
 	position: relative;
 	background-image: v-bind(bgImg);

+ 155 - 0
src/views/todo/countersign/index.vue

@@ -0,0 +1,155 @@
+<template>
+  <div class="todo-countersign-container layout-pd">
+    <!-- 搜索  -->
+    <el-card shadow="never">
+      <el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent  inline>
+        <el-form-item label="关键词" prop="Keyword">
+          <el-input v-model="state.queryParams.Keyword" placeholder="工单编码/标题" clearable @keyup.enter="queryList" class="keyword-input"/>
+        </el-form-item>
+        <el-form-item label="是否省工单" prop="IsProvince">
+          <el-select v-model="state.queryParams.IsProvince" placeholder="请选择是否省工单" class="w100">
+            <el-option label="是" value="true" />
+            <el-option label="否" value="false" />
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="queryList" :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-form-item>
+      </el-form>
+    </el-card>
+    <el-card shadow="never">
+      <!-- 表格 -->
+      <el-table :data="state.tableData" v-loading="state.loading">
+        <el-table-column label="超期状态" width="80" align="center">
+          <template #default="{ row }">
+            <span :class="'overdue-status-'+row.order?.expiredStatus" :title="row.order?.expiredStatusText"></span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="id" label="会签编码" show-overflow-tooltip width="300"></el-table-column>
+        <el-table-column prop="order.no" label="工单编码" show-overflow-tooltip width="150"></el-table-column>
+        <el-table-column prop="order.sourceChannel" label="来源方式" show-overflow-tooltip></el-table-column>
+        <el-table-column width="100" label="省/市工单" prop="isProvince">
+          <template #default="{ row }">
+            <span>{{ row.order?.isProvince ? '省工单' : '市工单' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="工单标题" prop="no" show-overflow-tooltip width="300">
+          <template #default="{ row }">
+            <order-detail :order="row.order" @updateList="queryList">{{ row.order?.title }}</order-detail>
+          </template>
+        </el-table-column>
+        <el-table-column label="工单期满时间" show-overflow-tooltip width="170">
+          <template #default="{ row }">
+            <span>{{ formatDate(row.order?.expiredTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="startTime" label="受理时间" show-overflow-tooltip width="170">
+          <template #default="{ row }">
+            <span>{{ formatDate(row.order?.startTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="order.acceptType" label="受理类型" show-overflow-tooltip width="150"></el-table-column>
+        <el-table-column label="工单状态" show-overflow-tooltip width="100" prop="order.statusText"></el-table-column>
+        <el-table-column prop="order.actualHandleOrgName" label="接办部门" show-overflow-tooltip width="170"></el-table-column>
+        <el-table-column label="接办时间" show-overflow-tooltip width="170">
+          <template #default="{ row }">
+            <span>{{ formatDate(row.order?.actualHandleTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="order.hotspotName" label="热点分类" show-overflow-tooltip width="150"></el-table-column>
+        <el-table-column prop="starterOrgName" label="会签发起部门" show-overflow-tooltip width="150"></el-table-column>
+        <el-table-column prop="starterName" label="会签发起人" show-overflow-tooltip width="120"></el-table-column>
+        <el-table-column label="会签发起时间" show-overflow-tooltip width="170">
+          <template #default="{ row }">
+            <span>{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="100" fixed="right" align="center">
+          <template #default="{ row }">
+            <!--						<el-button link type="primary" @click="onCountersignDetail(row)" title="查看会签明细" v-auth="'query:countersign:detail'">
+              会签明细
+            </el-button>-->
+            <order-detail :order="row.order" @updateList="queryList" />
+          </template>
+        </el-table-column>
+        <template #empty>
+          <Empty />
+        </template>
+      </el-table>
+      <!-- 分页 -->
+      <pagination
+        :total="state.total"
+        v-model:page="state.queryParams.PageIndex"
+        v-model:limit="state.queryParams.PageSize"
+        @pagination="queryList"
+      />
+    </el-card>
+    <!-- 会签明细 -->
+    <countersign-detail ref="countersignDetailRef" @updateList="queryList" />
+  </div>
+</template>
+<script setup lang="ts" name="todoCountersign">
+import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
+import { ElButton, ElMessage, FormInstance } from 'element-plus';
+import { auth } from '@/utils/authFunction';
+import { throttle } from '@/utils/tools';
+import { formatDate } from '@/utils/formatTime';
+import { useRouter } from 'vue-router';
+import { countersignList } from '@/api/query/countersign';
+import { storeToRefs } from 'pinia';
+import { useUserInfo } from '@/stores/userInfo';
+// 引入组件
+const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
+const CountersignDetail = defineAsyncComponent(() => import('@/views/query/countersign/detail/index.vue')); // 会签明细
+// 定义变量内容
+const ruleFormRef = ref<RefType>(); // 表单ref
+const router = useRouter(); // 路由
+const state = reactive(<any>{
+  queryParams: {
+    // 查询条件
+    PageIndex: 1,
+    PageSize: 10,
+    Keyword: null, // 关键字
+  },
+  tableData: [], //表单
+  loading: false, // 加载
+  total: 0, // 总数
+});
+const storesUserInfo = useUserInfo();
+const { userInfos } = storeToRefs(storesUserInfo); // 用户信息
+/** 获取列表 */
+const queryList = throttle(() => {
+  if (!auth('query:Countersign:query')) ElMessage.error('抱歉,您没有权限查看会签查询!');
+  else {
+    state.loading = true;
+    state.queryParams.IsOnlyStarter = userInfos.value.isCenter;
+    countersignList(state.queryParams)
+      .then((res) => {
+        state.tableData = res.result?.items ?? [];
+        state.total = res.result?.totalCount ?? 0;
+      })
+      .catch(() => {})
+      .finally(() => {
+        state.loading = false;
+      });
+  }
+}, 300);
+
+/** 重置按钮操作 */
+const resetQuery = throttle((formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+  queryList();
+}, 300);
+// 会签明细
+const countersignDetailRef = ref<RefType>(); // 会签明细ref
+const onCountersignDetail = (row: any) => {
+  countersignDetailRef.value.openDialog(row);
+};
+onMounted(() => {
+  queryList();
+});
+</script>

+ 12 - 0
src/views/todo/visit/index.vue

@@ -6,6 +6,18 @@
 				<el-form-item label="关键字" prop="Keyword">
 					<el-input v-model="state.queryParams.Keyword" placeholder="工单编码/标题" clearable @keyup.enter="queryList" class="keyword-input" />
 				</el-form-item>
+        <el-form-item label="归档类型" prop="FiledType">
+          <el-select v-model="state.queryParams.FiledType" placeholder="请选择归档类型">
+            <el-option label="中心归档" value="10" />
+            <el-option label="部门归档" value="20" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="是否会签" prop="IsCountersign">
+          <el-select v-model="state.queryParams.IsCountersign" placeholder="请选择是否会签">
+            <el-option label="是" value="true" />
+            <el-option label="否" value="false" />
+          </el-select>
+        </el-form-item>
 				<el-form-item>
 					<el-button type="primary" @click="queryList" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
 					<el-button @click="resetQuery(ruleFormRef)" v-waves class="default-button" :loading="state.loading">