Browse Source

reactor:更换验证码验证方式;

zhangchong 1 year ago
parent
commit
ac78864747

+ 1 - 0
package.json

@@ -40,6 +40,7 @@
 		"splitpanes": "^3.1.5",
 		"vue": "^3.2.45",
 		"vue-router": "^4.1.6",
+		"vue3-puzzle-vcode": "^1.1.7",
 		"vue3-seamless-scroll": "^2.0.1",
 		"vuedraggable": "^4.1.0",
 		"webpack": "^5.0.0"

BIN
src/assets/images/login/code1.png


BIN
src/assets/images/login/code2.png


BIN
src/assets/images/login/code3.png


BIN
src/assets/images/login/code4.png


BIN
src/assets/images/login/code5.png


+ 0 - 82
src/components/ImgVerify/hooks.ts

@@ -1,82 +0,0 @@
-import { onMounted, ref } from 'vue';
-
-/**
- * 绘制图形验证码
- * @param width - 图形宽度
- * @param height - 图形高度
- */
-export const useImageVerify = (width = 120, height = 32) => {
-	const domRef = ref<HTMLCanvasElement>();
-	const imgCode = ref('');
-
-	function setImgCode(code: string) {
-		imgCode.value = code;
-	}
-
-	function getImgCode() {
-		if (!domRef.value) return;
-		imgCode.value = draw(domRef.value, width, height);
-	}
-
-	onMounted(() => {
-		getImgCode();
-	});
-
-	return {
-		domRef,
-		imgCode,
-		setImgCode,
-		getImgCode,
-	};
-};
-
-function randomNum(min: number, max: number) {
-	return Math.floor(Math.random() * (max - min) + min);
-}
-
-function randomColor(min: number, max: number) {
-	const r = randomNum(min, max);
-	const g = randomNum(min, max);
-	const b = randomNum(min, max);
-	return `rgb(${r},${g},${b})`;
-}
-
-function draw(dom: HTMLCanvasElement, width: number, height: number) {
-	let imgCode = '';
-	const Random_STRING: string = '23456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
-	const ctx = dom.getContext('2d');
-	if (!ctx) return imgCode;
-
-	ctx.fillStyle = randomColor(255, 255);
-	ctx.fillRect(2, 0, width, height);
-	for (let i = 0; i < 4; i += 1) {
-		const text = Random_STRING[randomNum(0, Random_STRING.length)];
-		imgCode += text;
-		const fontSize = randomNum(18, 41);
-		const deg = randomNum(-30, 30);
-		ctx.font = `${fontSize}px Simhei`;
-		ctx.textBaseline = 'top';
-		ctx.fillStyle = randomColor(80, 150);
-		ctx.save();
-		ctx.translate(30 * i + 15, 15);
-		ctx.rotate((deg * Math.PI) / 180);
-		ctx.fillText(text, -15 + 5, -15);
-		ctx.restore();
-	}
-	for (let i = 0; i < 5; i += 1) {
-		ctx.beginPath();
-		ctx.moveTo(randomNum(0, width), randomNum(0, height));
-		ctx.lineTo(randomNum(0, width), randomNum(0, height));
-		ctx.strokeStyle = randomColor(180, 230);
-		ctx.closePath();
-		ctx.stroke();
-	}
-	for (let i = 0; i < 41; i += 1) {
-		ctx.beginPath();
-		ctx.arc(randomNum(0, width), randomNum(0, height), 1, 0, 2 * Math.PI);
-		ctx.closePath();
-		ctx.fillStyle = randomColor(150, 200);
-		ctx.fill();
-	}
-	return imgCode;
-}

+ 0 - 35
src/components/ImgVerify/index.vue

@@ -1,35 +0,0 @@
-<template>
-	<canvas ref="domRef" width="120" height="32" class="cursor-pointer" @click="getImgCode" />
-</template>
-<script setup lang="ts" name="ReImageVerify">
-import { watch } from 'vue';
-import { useImageVerify } from './hooks';
-interface Props {
-	code?: string;
-}
-
-interface Emits {
-	(e: 'update:code', code: string): void;
-}
-
-const props = withDefaults(defineProps<Props>(), {
-	code: '',
-});
-
-const emit = defineEmits<Emits>();
-
-const { domRef, imgCode, setImgCode, getImgCode } = useImageVerify();
-
-watch(
-	() => props.code,
-	(newValue) => {
-		setImgCode(newValue);
-	}
-);
-watch(imgCode, (newValue) => {
-	// 不区分大小写
-	emit('update:code', newValue.toUpperCase());
-});
-
-defineExpose({ getImgCode });
-</script>

+ 11 - 2
src/views/business/discern/apply/index.vue → src/views/business/discern/apply.vue

@@ -163,8 +163,9 @@ const queryList = throttle(() => {
 const resetQuery = throttle((formEl: FormInstance | undefined) => {
 	if (!formEl) return;
 	formEl.resetFields();
-	state.queryParams.CreationTimeStart = '';
-	state.queryParams.CreationTimeEnd = '';
+	state.queryParams.CreationTimeStart = null;
+	state.queryParams.CreationTimeEnd = null;
+  state.queryParams.IsHomePage = null;
 	queryList();
 }, 300);
 // 表格多选
@@ -193,7 +194,15 @@ const submitDiscern = (row: any) => {
 	};
 	processAuditRef.value.openDialog(params);
 };
+const historyParams = history.state;
 onMounted(async () => {
+	console.log(historyParams);
+	if (historyParams.IsHomePage) {
+		// 会签待办
+		// 先重置其他查询条件
+		ruleFormRef.value.resetFields();
+		state.queryParams = { ...state.queryParams, IsHomePage: historyParams.IsHomePage };
+	}
 	await getBaseData();
 	queryList();
 });

+ 6 - 6
src/views/business/visit/component/Visit-detail.vue

@@ -195,7 +195,7 @@
 												<el-form-item
 													label="话务员评价"
 													:prop="`visitDetails.${index}.seatEvaluate`"
-													:rules="[{ required: notGetThrough, message: '请选择话务员评价', trigger: 'change' }]"
+													:rules="[{ required: true, message: '请选择话务员评价', trigger: 'change' }]"
 												>
 													<el-radio-group v-model="item.seatEvaluate">
 														<el-radio :label="item.key" v-for="item in seatEvaluate" :key="item.key">{{ item.value }}</el-radio>
@@ -206,7 +206,7 @@
 												<el-form-item
 													label="话务员回访内容"
 													:prop="`visitDetails.${index}.visitContent`"
-													:rules="[{ required: notGetThrough, message: '请填写话务员回访内容', trigger: 'blur' }]"
+													:rules="[{ required: true, message: '请填写话务员回访内容', trigger: 'blur' }]"
 												>
 													<common-advice
 														@chooseAdvice="chooseAdvice($event, index)"
@@ -230,7 +230,7 @@
 												<el-form-item
 													label="部门办件结果"
 													:prop="`visitDetails.${index}.orgProcessingResults`"
-													:rules="[{ required: notGetThrough, message: '请选择部门办件结果', trigger: 'change' }]"
+													:rules="[{ required: true, message: '请选择部门办件结果', trigger: 'change' }]"
 												>
 													<el-select
 														v-model="item.orgProcessingResults"
@@ -253,7 +253,7 @@
 												<el-form-item
 													label="不满意原因"
 													:prop="`visitDetails.${index}.orgNoSatisfiedReason`"
-													:rules="[{ required: notGetThrough, message: '请选择不满意原因', trigger: 'change' }]"
+													:rules="[{ required: true, message: '请选择不满意原因', trigger: 'change' }]"
 												>
 													<el-select
 														v-model="item.orgNoSatisfiedReason"
@@ -273,7 +273,7 @@
 												<el-form-item
 													label="部门办件态度"
 													:prop="`visitDetails.${index}.orgHandledAttitude`"
-													:rules="[{ required: notGetThrough, message: '请选择部门办件态度', trigger: 'change' }]"
+													:rules="[{ required: true, message: '请选择部门办件态度', trigger: 'change' }]"
 												>
 													<el-select
 														v-model="item.orgHandledAttitude"
@@ -295,7 +295,7 @@
 												<el-form-item
 													label="部门回访内容"
 													:prop="`visitDetails.${index}.visitContent`"
-													:rules="[{ required: notGetThrough, message: '请填写部门回访内容', trigger: 'blur' }]"
+													:rules="[{ required: true, message: '请填写部门回访内容', trigger: 'blur' }]"
 												>
 													<common-advice
 														@chooseAdvice="chooseAdvice($event, index)"

+ 15 - 16
src/views/home/component/Numbers.vue → src/views/home/component/Numbers-center.vue

@@ -4,20 +4,20 @@
 			<el-card shadow="never" v-loading="loading" class="statistics-item">
 				<div class="statistics-title">
 					<img v-lazy="getImageUrl('home/Call.png')" alt="" src="" />
-					{{ userInfos.isCenter ? '今日来电' : '今日待办' }}
+					今日来电
 				</div>
 				<div class="statistics-number">
 					<div class="statistics-number-item">
 						<p class="statistics-number-item-number">
-							<b> {{ userInfos.isCenter ? state.data.callNum : state.data.handleNum }} </b>
+							<b> {{ state.data.callNum }} </b>
 						</p>
-						<p class="statistics-number-item-tips">{{ userInfos.isCenter ? '全部' : '我的' }}</p>
+						<p class="statistics-number-item-tips">全部</p>
 					</div>
 					<div class="statistics-number-item">
 						<p class="statistics-number-item-number">
-							<b>{{ userInfos.isCenter ? state.data.validCallNum : state.data.handleOrgNum }}</b>
+							<b>{{ state.data.validCallNum }}</b>
 						</p>
-						<p class="statistics-number-item-tips">{{ userInfos.isCenter ? '有效' : '部门' }}</p>
+						<p class="statistics-number-item-tips">有效</p>
 					</div>
 				</div>
 			</el-card>
@@ -26,21 +26,20 @@
 			<el-card shadow="never" v-loading="loading" class="statistics-item">
 				<div class="statistics-title">
 					<img v-lazy="getImageUrl('home/connectionRate.png')" alt="" src="" />
-					{{ userInfos.isCenter ? '今日接通率' : '已办' }}
+					今日接通率
 				</div>
 				<div class="statistics-number">
 					<div class="statistics-number-item">
 						<p class="statistics-number-item-number">
-							<b>{{ userInfos.isCenter ? state.data.answeredNum : state.data.tasksOkNum }}</b>
+							<b>{{ state.data.answeredNum }}</b>
 						</p>
-						<p class="statistics-number-item-tips">{{ userInfos.isCenter ? '接通' : '我的' }}</p>
+						<p class="statistics-number-item-tips">接通</p>
 					</div>
 					<div class="statistics-number-item">
 						<p class="statistics-number-item-number">
-
-							<b>{{ userInfos.isCenter ? state.data.answeredRate : state.data.tasksOkOrgNum }}</b>
+							<b>{{ state.data.answeredRate }}</b>
 						</p>
-						<p class="statistics-number-item-tips">{{ userInfos.isCenter ? '接通率' : '部门' }}</p>
+						<p class="statistics-number-item-tips">接通率</p>
 					</div>
 				</div>
 			</el-card>
@@ -49,20 +48,20 @@
 			<el-card shadow="never" v-loading="loading" class="statistics-item">
 				<div class="statistics-title">
 					<img v-lazy="getImageUrl('home/workOrder.png')" alt="" src="" />
-					{{ userInfos.isCenter ? '今日受理工单' : '部门超期工单' }}
+					今日受理工单
 				</div>
 				<div class="statistics-number">
 					<div class="statistics-number-item">
 						<p class="statistics-number-item-number">
-							<b>{{ userInfos.isCenter ? state.data.orderNum : state.data.exceedTasksOkNum }}</b>
+							<b>{{ state.data.orderNum }}</b>
 						</p>
-						<p class="statistics-number-item-tips">{{ userInfos.isCenter ? '受理工单量' : '待办超期' }}</p>
+						<p class="statistics-number-item-tips">受理工单量</p>
 					</div>
 					<div class="statistics-number-item">
 						<p class="statistics-number-item-number">
-							<b>{{ userInfos.isCenter ? state.data.directlyNum : state.data.exceedHandleNum }}</b>
+							<b>{{ state.data.directlyNum }}</b>
 						</p>
-						<p class="statistics-number-item-tips">{{ userInfos.isCenter ? '今日直办工单量' : '已办超期' }}</p>
+						<p class="statistics-number-item-tips">今日直办工单量</p>
 					</div>
 				</div>
 			</el-card>

+ 226 - 0
src/views/home/component/Numbers-department.vue

@@ -0,0 +1,226 @@
+<template>
+	<el-row :gutter="20">
+		<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
+			<el-card shadow="never" v-loading="loading" class="statistics-item">
+				<el-statistic :value="state.data.answeredNum" @click="linkTo('0')">
+					<template #title>
+						<div class="flex-center-align">
+							<span class="color-info font14">即将超期</span>
+							<el-tooltip effect="dark" content="工单当前办理人该登录用户,但工单超期状态处于即将超期" placement="top">
+								<SvgIcon name="ele-Warning" class="ml4" size="14px" />
+							</el-tooltip>
+						</div>
+					</template>
+				</el-statistic>
+			</el-card>
+		</el-col>
+		<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
+			<el-card shadow="never" v-loading="loading" class="statistics-item">
+				<el-statistic :value="state.data.answeredNum" @click="linkTo('1')">
+					<template #title>
+						<div class="flex-center-align">
+							<span class="color-info font14">已超期</span>
+							<el-tooltip effect="dark" content="工单当前办理人该登录用户,但工单超期状态处于已超期" placement="top">
+								<SvgIcon name="ele-Warning" class="ml4" size="14px" />
+							</el-tooltip>
+						</div>
+					</template>
+				</el-statistic>
+			</el-card>
+		</el-col>
+		<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
+			<el-card shadow="never" v-loading="loading" class="statistics-item">
+				<el-statistic :value="state.data.answeredNum" @click="linkTo('2')">
+					<template #title>
+						<div class="flex-center-align">
+							<span class="color-info font14">会签待办</span>
+							<el-tooltip effect="dark" content="当前登录用户待办的会签件" placement="top">
+								<SvgIcon name="ele-Warning" class="ml4" size="14px" />
+							</el-tooltip>
+						</div>
+					</template>
+				</el-statistic>
+			</el-card>
+		</el-col>
+		<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
+			<el-card shadow="never" v-loading="loading" class="statistics-item">
+				<el-statistic :value="state.data.answeredNum" @click="linkTo('3')">
+					<template #title>
+						<div class="flex-center-align">
+							<span class="color-info font14">甄别待审批</span>
+							<el-tooltip effect="dark" content="当前登录用户待审批的甄别件" placement="top">
+								<SvgIcon name="ele-Warning" class="ml4" size="14px" />
+							</el-tooltip>
+						</div>
+					</template>
+				</el-statistic>
+			</el-card>
+		</el-col>
+		<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
+			<el-card shadow="never" v-loading="loading" class="statistics-item">
+				<el-statistic :value="state.data.answeredNum" @click="linkTo('4')">
+					<template #title>
+						<div class="flex-center-align">
+							<span class="color-info font14">延期待审批</span>
+							<el-tooltip effect="dark" content="当前登录用户待审批的延期件" placement="top">
+								<SvgIcon name="ele-Warning" class="ml4" size="14px" />
+							</el-tooltip>
+						</div>
+					</template>
+				</el-statistic>
+			</el-card>
+		</el-col>
+		<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
+			<el-card shadow="never" v-loading="loading" class="statistics-item">
+				<el-statistic :value="state.data.answeredNum" @click="linkTo('5')">
+					<template #title>
+						<div class="flex-center-align">
+							<span class="color-info font14">甄别待处理</span>
+							<el-tooltip effect="dark" content="当前登录用户可以提交甄别申请的工单数" placement="top">
+								<SvgIcon name="ele-Warning" class="ml4" size="14px" />
+							</el-tooltip>
+						</div>
+					</template>
+				</el-statistic>
+			</el-card>
+		</el-col>
+	</el-row>
+</template>
+<script setup lang="ts">
+import { reactive, ref } from 'vue';
+import { storeToRefs } from 'pinia';
+import { useUserInfo } from '@/stores/userInfo';
+import { getHomeData } from '@/api/home';
+import { useRouter } from 'vue-router';
+import { ElMessage } from 'element-plus';
+import mitt from 'mitt';
+import mittBus from '@/utils/mitt';
+const stores = useUserInfo(); // 用户信息
+const { userInfos } = storeToRefs(stores); // 用户信息
+const state = reactive({
+	data: {
+		answeredNum: 0, // 今日来电
+		answeredRate: 0, // 今日接通率
+		callNum: 0, // 今日来电
+		directlyNum: 0, // 今日直办
+		orderNum: 0, // 今日受理工单
+		validCallNum: 0, // 今日有效来电
+		exceedHandleNum: 0, // 超期办理工单
+		exceedTasksOkNum: 0, // 超期办结工单
+		handleNum: 0, // 已办工单
+		handleOrgNum: 0, // 部门已办工单
+		tasksOkNum: 0, // 已办结工单
+		tasksOkOrgNum: 0, // 部门已办结工单
+	},
+});
+const loading = ref(false);
+// 获取首页数据
+const getHomeDataFn = async () => {
+	loading.value = true;
+	try {
+		const { result } = await getHomeData();
+		state.data = result;
+	} catch (error) {
+		console.log(error);
+	} finally {
+		loading.value = false;
+	}
+};
+// 点击跳转
+const router = useRouter();
+const linkTo = (type: string) => {
+	switch (type) {
+		case '0': // 即将超期
+			if (!router.hasRoute('todoOrder')) {
+				ElMessage.warning('当前用户未配置工单待办页面');
+				return;
+			}
+			mittBus.emit('clearCache', 'todoOrder');
+			router.push({
+				name: 'todoOrder',
+				state: {
+					ExpiredOrAlmostOverdue: 'false', // 即将超期
+				},
+			});
+			// const historyParams = history.state;
+			break;
+		case '1': // 已超期
+			if (!router.hasRoute('todoOrder')) {
+				ElMessage.warning('当前用户未配置工单待办页面');
+				return;
+			}
+      mittBus.emit('clearCache', 'todoOrder');
+			router.push({
+				name: 'todoOrder',
+				state: {
+					ExpiredOrAlmostOverdue: 'true', // 已超期
+				},
+			});
+			break;
+		case '2': // 会签待办
+			if (!router.hasRoute('todoOrder')) {
+				ElMessage.warning('当前用户未配置工单待办页面');
+				return;
+			}
+			mittBus.emit('clearCache', 'todoOrder');
+			router.push({
+				name: 'todoOrder',
+				state: {
+					IsCountersign: 'true',
+				},
+			});
+			break;
+		case '3': // 甄别待审批
+			if (!router.hasRoute('businessDiscernTodo')) {
+				ElMessage.warning('当前用户未配置甄别待审批页面');
+				return;
+			}
+      mittBus.emit('clearCache', 'businessDiscernTodo');
+			router.push({
+				name: 'businessDiscernTodo',
+			});
+			break;
+		case '4': // 延期待审批
+			if (!router.hasRoute('businessDelayAudit')) {
+				ElMessage.warning('当前用户未配置延期待审批页面');
+				return;
+			}
+      mittBus.emit('clearCache', 'businessDelayAudit');
+			router.push({
+				name: 'businessDelayAudit',
+			});
+			break;
+		case '5': // 甄别待处理
+			if (!router.hasRoute('businessDiscernApply')) {
+				ElMessage.warning('当前用户未配置甄别待处理页面');
+				return;
+			}
+      mittBus.emit('clearCache', 'businessDiscernApply');
+			router.push({
+				name: 'businessDiscernApply',
+				state: {
+          IsHomePage: 'true', // 默认查5个工作日内的数据
+				},
+			});
+			break;
+		default:
+			break;
+	}
+};
+getHomeDataFn();
+</script>
+<style scoped lang="scss">
+:deep(.el-statistic__content) {
+	font-size: 32px;
+	font-weight: bold;
+	margin-top: 15px;
+}
+.statistics {
+	display: flex;
+	justify-content: space-between;
+	&-item {
+		margin-bottom: 15px;
+		cursor: pointer;
+	}
+}
+</style>

+ 36 - 36
src/views/home/component/ToDo.vue

@@ -10,8 +10,20 @@
 			更多<SvgIcon name="ele-ArrowRight" />
 		</el-button>
 		<el-tabs v-model="activeName" @tab-change="handleChange" v-if="auths(['home:orderTodo', 'home:orderSeatTodo'])">
-			<el-tab-pane name="0" label="工单待办" v-if="auth('home:orderTodo')"></el-tab-pane>
-			<el-tab-pane name="1" label="工单坐席待办" v-if="auth('home:orderSeatTodo')"></el-tab-pane>
+			<el-tab-pane name="0" v-if="auth('home:orderTodo')">
+				<template #label>
+					<div>
+						工单待办 <span>({{ state.total }})</span>
+					</div>
+				</template>
+			</el-tab-pane>
+			<el-tab-pane name="1" v-if="auth('home:orderSeatTodo')">
+				<template #label>
+					<div>
+						工单坐席待办 <span>({{ state.total1 }})</span>
+					</div>
+				</template>
+			</el-tab-pane>
 		</el-tabs>
 		<template v-if="auths(['home:orderTodo', 'home:orderSeatTodo'])">
 			<ProTable
@@ -62,6 +74,8 @@ const state = reactive({
 		PageIndex: 1,
 		PageSize: 10,
 	},
+	total: 0,
+	total1: 0,
 });
 const activeName = ref('0');
 watchEffect(() => {
@@ -154,6 +168,7 @@ const handleChange = async (tab: any) => {
 				const res: any = await orderListTodo({ ...state.queryParams, IsHandled: 'false' });
 				state.tableData = res.result?.items ?? [];
 				columns.value = todoColumns;
+				state.total = res.result?.total ?? 0;
 				state.tableLoading = false;
 			} catch (error) {
 				state.tableLoading = false;
@@ -163,6 +178,7 @@ const handleChange = async (tab: any) => {
 			try {
 				const res: any = await seatsListTodo({ ...state.queryParams, IsHandled: 'false' });
 				state.tableData = res.result?.items ?? [];
+				state.total1 = res.result?.total ?? 0;
 				columns.value = seatsColumns;
 				state.tableLoading = false;
 			} catch (error) {
@@ -174,6 +190,23 @@ const handleChange = async (tab: any) => {
 			break;
 	}
 };
+// 获取列表和总数
+const getTableAndNum = async () => {
+	state.tableLoading = true;
+	try {
+		const [todo, seats] = await Promise.all([
+			orderListTodo({ ...state.queryParams, IsHandled: 'false' }),
+			seatsListTodo({ ...state.queryParams, IsHandled: 'false' }),
+		]);
+		state.tableData = todo.result?.items ?? [];
+		columns.value = todoColumns;
+		state.total = todo.result?.total ?? 0;
+		state.total1 = seats.result?.total ?? 0;
+		state.tableLoading = false;
+	} catch (error) {
+		state.tableLoading = false;
+	}
+};
 // 跳转
 const router = useRouter();
 // 列表入口
@@ -187,40 +220,7 @@ const linkList = () => {
 			break;
 	}
 };
-// 编辑工单
-const onOrderEdit = (row: any) => {
-	if (!router.hasRoute('orderAccept')) {
-		ElMessage.warning('当前用户未配置工单受理页面');
-		return;
-	}
-	router.push({
-		name: 'orderAccept',
-		params: {
-			tagsViewName: '工单受理-' + row.no,
-			id: row.id,
-			callId: '0',
-		},
-	});
-};
-// 签收工单
-const onSign = (row: any) => {
-	ElMessageBox.confirm(`您确定要要签收【${row.title}】,是否继续?`, '提示', {
-		confirmButtonText: '确认',
-		cancelButtonText: '取消',
-		type: 'warning',
-		draggable: true,
-		cancelButtonClass: 'default-button',
-		autofocus: false,
-	})
-		.then(() => {
-			orderSign(row.id).then(() => {
-				ElMessage.success('签收成功');
-				handleChange(activeName.value);
-			});
-		})
-		.catch(() => {});
-};
 onMounted(() => {
-	handleChange(activeName.value);
+	getTableAndNum();
 });
 </script>

+ 14 - 9
src/views/home/index.vue

@@ -2,14 +2,13 @@
 	<div class="home-container layout-pd">
 		<el-row :gutter="20">
 			<el-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16">
-        <!-- 统计 -->
-        <numbers />
-        <!-- 待办工作台 -->
-				<to-do/>
+				<component :is="userInfos.isCenter ? NumbersCenter : NumbersDepartment" />
+				<!-- 待办工作台 -->
+				<to-do />
 			</el-col>
 			<el-col :xs="24" :sm="24" :md="24" :lg="8" :xl="8">
-        <!-- 常用入口 -->
-        <entrance />
+				<!-- 常用入口 -->
+				<entrance />
 				<!-- 通知公告 -->
 				<notice />
 			</el-col>
@@ -18,10 +17,16 @@
 </template>
 
 <script lang="ts" setup name="home">
-import { defineAsyncComponent} from 'vue';
+import { defineAsyncComponent } from 'vue';
+import { useUserInfo } from '@/stores/userInfo';
+import { storeToRefs } from 'pinia';
 // 引入组件
-const Numbers = defineAsyncComponent(() => import('@/views/home/component/Numbers.vue'));
+const NumbersCenter = defineAsyncComponent(() => import('@/views/home/component/Numbers-center.vue'));
+const NumbersDepartment = defineAsyncComponent(() => import('@/views/home/component/Numbers-department.vue'));
 const Entrance = defineAsyncComponent(() => import('@/views/home/component/Entrance.vue'));
 const ToDo = defineAsyncComponent(() => import('@/views/home/component/ToDo.vue'));
 const Notice = defineAsyncComponent(() => import('@/views/home/component/Notice.vue'));
-</script>
+
+const stores = useUserInfo(); // 用户信息
+const { userInfos } = storeToRefs(stores); // 用户信息
+</script>

+ 0 - 12
src/views/knowledge/index/edit.vue

@@ -362,18 +362,6 @@ const state = reactive<any>({
 	knowledgeOptions: [], //关联知识
 });
 const ruleFormRef = ref<any>(); // 表单ref
-// 热点分类远程搜索
-const HotspotProps = {
-	label: 'hotSpotFullName',
-	children: 'children',
-	isLeaf: 'isLeaf',
-};
-// 热点分类懒加载
-const load = async (node: any, resolve: any) => {
-	if (node.isLeaf) return resolve([]);
-	const res: any = await hotSpotType({ id: node.data.id ? node.data.id : '' });
-	resolve(res.result);
-};
 // 选择热点分类
 const chooseHotSpot = (val: any, e: any) => {
   state.ruleForm.hotspotSpliceName = val.hotSpotFullName; // 热点分类拼接名称

+ 54 - 95
src/views/login/component/Account.vue

@@ -34,39 +34,6 @@
 				</el-input>
 			</el-form-item>
 		</motion>
-		<motion :delay="300">
-			<el-form-item
-				prop="verifyCode"
-				class="mb30"
-				:rules="[
-					{ required: true, message: '请输入验证码', trigger: 'blur' },
-					{
-						validator: validatePass,
-						trigger: 'blur',
-					},
-				]"
-			>
-				<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>
-		</motion>
 		<motion :delay="400" v-if="themeConfig.isLoginMessageCode">
 			<el-form-item prop="msgCode" class="mb30" :rules="[{ required: msgCodeRequired, message: '请输入短信验证码', trigger: 'blur' }]">
 				<el-col :span="11">
@@ -95,6 +62,7 @@
 		<motion :delay="400">
 			<el-form-item>
 				<el-button type="primary" class="login-content-submit" round @click="onSignIn(ruleFormRef)" :loading="state.loading">登录</el-button>
+				<puzzle-Code :show="showCode" @success="success" @close="close" @fail="fail" :imgs="imgList"></puzzle-Code>
 			</el-form-item>
 		</motion>
 		<motion :delay="500"> 运营管理系统 <span class="color-danger font-bold">v5.0</span> </motion>
@@ -108,7 +76,7 @@
 </template>
 
 <script setup lang="ts" name="loginAccount">
-import { reactive, computed, ref, defineAsyncComponent } from 'vue';
+import { reactive, computed, ref } from 'vue';
 import { useRoute, useRouter } from 'vue-router';
 import { ElMessage, ElNotification } from 'element-plus';
 import { storeToRefs } from 'pinia';
@@ -121,11 +89,11 @@ import { NextLoading } from '@/utils/loading';
 import type { FormInstance } from 'element-plus';
 import { sendCode, signIn } from '@/api/login';
 import { JSEncrypt } from 'jsencrypt'; // rsa加密
-import { throttle } from '@/utils/tools';
+import { getImageUrl, throttle } from '@/utils/tools';
 import Motion from '@/utils/motion';
-
-const ReImageVerify = defineAsyncComponent(() => import('@/components/ImgVerify/index.vue'));
-
+//引入'vue3-puzzle-vcode'插件
+import puzzleCode from 'vue3-puzzle-vcode';
+import Img from '@/assets/images/login/code1.png';
 // 定义变量内容
 const storesThemeConfig = useThemeConfig(); // 主题配置
 const { themeConfig } = storeToRefs(storesThemeConfig); // 主题配置
@@ -135,7 +103,6 @@ const state = reactive<any>({
 	ruleForm: {
 		username: '', // 账号
 		password: '', // 密码
-		verifyCode: '', // 验证码
 		msgCode: '', // 短信验证码
 	},
 	loading: false, // 加载
@@ -145,20 +112,6 @@ const ruleFormRef = ref<FormInstance>(); // 表单ref
 const currentTime = computed(() => {
 	return formatAxis(new Date());
 });
-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 verifyCode = ref<string>(''); // 验证码
 const count = ref(300); // 倒计时
 const countText = ref('s后重新获取'); // 倒计时文本
 const click = ref('获取验证码'); // 点击
@@ -169,15 +122,6 @@ const getIdentifyCodeBtn = () => {
 		ruleFormRef.value?.validateField('username');
 		return;
 	}
-	if (!state.ruleForm.verifyCode) {
-		ruleFormRef.value?.validateField('verifyCode');
-		return;
-	}
-	// 验证码错误
-	if (state.ruleForm.verifyCode.toUpperCase() !== verifyCode.value.toUpperCase()) {
-		ruleFormRef.value?.validateField('verifyCode');
-		return;
-	}
 	// state.loading = true;
 	// 获取短信验证码
 	sendCode(state.ruleForm.username)
@@ -217,44 +161,59 @@ const countDown = () => {
 		}, 1000);
 	}
 };
+console.log(getImageUrl('home/Call.png'));
+const imgList = [getImageUrl('login/code1.png'), getImageUrl('login/code2.png'), getImageUrl('login/code3.png'), getImageUrl('login/code4.png')];
+const showCode = ref(false); // 是否展示验证码
+const success = () => {
+	// 验证成功
+	showCode.value = false;
+	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),
+		msgCode: encryptor.encrypt(state.ruleForm.msgCode),
+	};
+	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;
+		});
+};
+const close = () => {
+	// 关闭验证码
+	showCode.value = false;
+};
+const fail = () => {
+	// 验证失败
+};
 // 登录
 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),
-			msgCode: encryptor.encrypt(state.ruleForm.msgCode),
-		};
-		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;
-			});
+		showCode.value = true;
 	});
 }, 1000);
 // 登录成功后的跳转

+ 31 - 14
src/views/system/workforce/scheduling.vue

@@ -55,7 +55,7 @@ const columns = ref<any[]>([{ prop: 'schedulingUserName', label: '姓名', width
 const numberList = ref<any[]>([]); // 班次列表
 /** 通话记录列表 */
 const queryList = async () => {
-	state.loading = true;
+	/*state.loading = true;
 	try {
 		columns.value = [{ prop: 'schedulingUserName', label: '姓名', width: 120, fixed: 'left', align: 'center' }];
 		const days = dayjs(month.value).daysInMonth(); // 获取当月有多少天
@@ -66,22 +66,30 @@ const queryList = async () => {
 				label: `${num}日`,
 				align: 'center',
 				render: (scope) => {
+					/!* {scope.row?.schedulingTime === `${dayjs(month.value).format('YYYY-MM')}-${num}`
+            ? `${scope.row[dayjs(month.value).format(`YYYY-MM-${num}`)]}`
+            : ''}*!/
+					const value = `${scope.row[dayjs(month.value).format(`YYYY-MM-${num}`)]}`;
 					return (
-						<el-button
-							type="primary"
-							link
-							title={'点击修改' + scope.row?.schedulingUserName + dayjs(month.value).format('YYYY-MM') + '-' + num + '排班'}
-							onClick={() => changeScheduling(scope)}
-						>
-							{scope.row?.schedulingTime === `${dayjs(month.value).format('YYYY-MM')}-${num}`
-								? `${scope.row[dayjs(month.value).format(`YYYY-MM-${num}`)]}`
-								: ''}
-						</el-button>
+						<>
+							{value !== 'undefined' && value ? (
+								<el-button
+									type="primary"
+									link
+									title={'点击修改' + scope.row?.schedulingUserName + dayjs(month.value).format('YYYY-MM') + '-' + num + '排班'}
+									onClick={() => changeScheduling(scope)}
+								>
+									{`${scope.row[dayjs(month.value).format(`YYYY-MM-${num}`)]}`}
+								</el-button>
+							) : (
+								''
+							)}
+						</>
 					);
 				},
 			});
 		}
-		const request = {
+		/!*const request = {
 			...state.queryParams,
 			StartTime: `${month.value}-01`,
 			EndTime: `${month.value}-${days}`,
@@ -95,12 +103,21 @@ const queryList = async () => {
 				[`${dayjs(item.schedulingTime).format('YYYY-MM-DD')}`]: item.schedulingShift?.name,
 			};
 		});
-		state.total = response.result?.total ?? 0;
+		state.total = response.result?.total ?? 0;*!/
+		state.tableData = [
+			{
+				schedulingUserName: '张冲',
+				'2024-03-01': '班次1',
+				'2024-03-02': '班次2',
+				'2024-03-03': '班次3',
+				'2024-03-04': '',
+			},
+		];
 		state.loading = false;
 	} catch (e) {
 		state.loading = false;
 		console.log(e);
-	}
+	}*/
 };
 // 批量排班
 const multipleSchedulingRef = ref<RefType>(); // 批量排班ref

+ 18 - 2
src/views/todo/order/index.vue

@@ -21,6 +21,12 @@
 						<el-option label="否" value="false" />
 					</el-select>
 				</el-form-item>
+        <el-form-item label="超期状态" prop="ExpiredOrAlmostOverdue">
+          <el-select v-model="state.queryParams.ExpiredOrAlmostOverdue" 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">
@@ -63,7 +69,7 @@
 	</div>
 </template>
 <script setup lang="tsx" name="todoOrder">
-import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
+import { defineAsyncComponent, onActivated, onMounted, reactive, ref } from 'vue';
 import { ElButton, FormInstance } from 'element-plus';
 import { throttle } from '@/utils/tools';
 import { formatDate } from '@/utils/formatTime';
@@ -130,7 +136,6 @@ const columns = ref<any[]>([
 	{ prop: 'employeeName', label: '受理人', width: 120 },
 	{ prop: 'operation', label: '操作', fixed: 'right', width: 100, align: 'center' },
 ]);
-// 获取查询条件基础信息
 /** 获取列表 */
 const queryList = throttle(async () => {
 	try {
@@ -164,7 +169,18 @@ const resetQuery = throttle((formEl: FormInstance | undefined) => {
 	formEl.resetFields();
 	queryList();
 }, 300);
+const historyParams = history.state;
 onMounted(() => {
+  if (historyParams.IsCountersign) { // 会签待办
+    // 先重置其他查询条件
+    ruleFormRef.value.resetFields();
+    state.queryParams = { ...state.queryParams, IsCountersign: historyParams.IsCountersign };
+  }
+  if(historyParams.ExpiredOrAlmostOverdue) { // 即将超期 已超期
+    ruleFormRef.value.resetFields();
+    state.queryParams = { ...state.queryParams, ExpiredOrAlmostOverdue: historyParams.ExpiredOrAlmostOverdue };
+  }
+  console.log(historyParams)
 	queryList();
 });
 </script>

+ 5 - 0
yarn.lock

@@ -5307,6 +5307,11 @@ vue-router@^4.1.6:
   dependencies:
     "@vue/devtools-api" "^6.5.0"
 
+vue3-puzzle-vcode@^1.1.7:
+  version "1.1.7"
+  resolved "https://registry.npmmirror.com/vue3-puzzle-vcode/-/vue3-puzzle-vcode-1.1.7.tgz#954e577fbbd4085d37dde08f98636b313c9f0f80"
+  integrity sha512-mW780dz7HKjrElnE60CeYSeHGidKBKHoMjTDYfqF21330rTkFOsfDK1FQKZ22MktgMtTEoS/imfpEDlM1cxY/g==
+
 vue3-seamless-scroll@^2.0.1:
   version "2.0.1"
   resolved "https://registry.npmmirror.com/vue3-seamless-scroll/-/vue3-seamless-scroll-2.0.1.tgz"