From 59e4906ad374bb44b481012b4b2a7d3d077b8677 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期一, 06 七月 2026 17:00:00 +0800
Subject: [PATCH] 排班模块逻辑修改
---
src/views/personnelManagement/classsSheduling/index.vue | 151 +++++++++++++++++++++++--
src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue | 31 ++++-
src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue | 151 +++++++++++++++++-------
3 files changed, 269 insertions(+), 64 deletions(-)
diff --git a/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue b/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue
index cbbb8af..0ddea67 100644
--- a/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue
+++ b/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue
@@ -37,11 +37,17 @@
<el-option v-for="item in shifts_list"
:key="item.value"
:label="item.label"
- :value="item.value" />
+ :value="item.value"
+ :disabled="
+ operationType === 'add' &&
+ (String(item.label || '').includes('鍋�') ||
+ String(item.label || '').includes('浼�'))
+ " />
</el-select>
</el-form-item>
<el-form-item label="鎵撳崱鑼冨洿(m)"
- prop="radius">
+ prop="radius"
+ v-show="!hideClockFields">
<el-input-number v-model="form.radius"
:min="10"
:max="1000"
@@ -51,7 +57,8 @@
</el-form-item>
<!-- 楂樺痉鍦板浘閫夋嫨 -->
<el-form-item label="鎵撳崱浣嶇疆"
- prop="longitude">
+ prop="longitude"
+ v-show="!hideClockFields">
<div class="map-container">
<div class="map-header"
style="margin-bottom: 10px">
@@ -82,14 +89,16 @@
</div>
</el-form-item>
<el-form-item label="鍦扮偣鍚嶇О"
- prop="locationName">
+ prop="locationName"
+ v-show="!hideClockFields">
<el-input v-model="form.locationName"
:disabled="operationType === 'view'"
placeholder="璇疯緭鍏ュ湴鐐瑰悕绉�" />
</el-form-item>
<!-- 涓婁笅鐝椂闂� -->
<el-form-item label="涓婄彮鏃堕棿"
- prop="startAt">
+ prop="startAt"
+ v-show="!hideClockFields">
<el-time-picker v-model="form.startAt"
format="HH:mm"
value-format="HH:mm"
@@ -97,7 +106,8 @@
:disabled="operationType === 'view'" />
</el-form-item>
<el-form-item label="涓嬬彮鏃堕棿"
- prop="endAt">
+ prop="endAt"
+ v-show="!hideClockFields">
<el-time-picker v-model="form.endAt"
format="HH:mm"
value-format="HH:mm"
@@ -110,7 +120,9 @@
</el-form>
<template #footer>
<span class="dialog-footer">
- <el-button type="primary" @click="submitForm" v-if="operationType !== 'view'">纭畾</el-button>
+ <el-button type="primary"
+ @click="submitForm"
+ v-if="operationType !== 'view'">纭畾</el-button>
<el-button @click="dialogVisible = false">鍙栨秷</el-button>
</span>
</template>
@@ -157,6 +169,21 @@
// 鑾峰彇鐝瀛楀吀鍊�
const { shifts_list } = useDict("shifts_list");
+ const selectedShiftLabel = computed(() => {
+ const item = shifts_list.value?.find(
+ s => String(s.value) === String(form.shift)
+ );
+ return item?.label || "";
+ });
+
+ const hideClockFields = computed(() => {
+ if (props.operationType === "view") return false;
+ return (
+ selectedShiftLabel.value.includes("鍋�") ||
+ selectedShiftLabel.value.includes("浼�")
+ );
+ });
+
// 琛ㄥ崟鏁版嵁
const formRef = ref();
const form = reactive({
@@ -172,44 +199,53 @@
});
// 琛ㄥ崟楠岃瘉瑙勫垯
- const rules = {
- sysDeptId: [{ required: true, message: "璇烽�夋嫨閮ㄩ棬", trigger: "change" }],
- locationName: [
- { required: true, message: "璇疯緭鍏ュ湴鐐瑰悕绉�", trigger: "blur" },
- ],
- longitude: [{ required: true, message: "璇烽�夋嫨鎵撳崱浣嶇疆", trigger: "blur" }],
- latitude: [{ required: true, message: "璇烽�夋嫨鎵撳崱浣嶇疆", trigger: "blur" }],
- shift: [{ required: true, message: "璇烽�夋嫨鐝", trigger: "change" }],
- radius: [{ required: true, message: "璇疯緭鍏ユ墦鍗¤寖鍥�", trigger: "blur" }],
- startAt: [{ required: true, message: "璇烽�夋嫨涓婄彮鏃堕棿", trigger: "change" }],
- endAt: [
- { required: true, message: "璇烽�夋嫨涓嬬彮鏃堕棿", trigger: "change" },
- {
- validator: (rule, value, callback) => {
- // 濡傛灉鏄鐝紝涓嶉檺鍒舵椂闂撮『搴�
- if (form.shift && ['澶滅彮', '澶�'].includes(form.shift)) {
- callback();
- return;
- }
- if (form.startAt && value) {
- const startParts = form.startAt.split(":");
- const endParts = value.split(":");
- const startTime =
- parseInt(startParts[0]) * 60 + parseInt(startParts[1]);
- const endTime = parseInt(endParts[0]) * 60 + parseInt(endParts[1]);
- if (endTime <= startTime) {
- callback(new Error("涓嬬彮鏃堕棿涓嶈兘鏃╀簬涓婄彮鏃堕棿"));
+ const rules = computed(() => {
+ const base = {
+ sysDeptId: [{ required: true, message: "璇烽�夋嫨閮ㄩ棬", trigger: "change" }],
+ shift: [{ required: true, message: "璇烽�夋嫨鐝", trigger: "change" }],
+ };
+
+ if (hideClockFields.value) {
+ return base;
+ }
+
+ return {
+ ...base,
+ locationName: [
+ { required: true, message: "璇疯緭鍏ュ湴鐐瑰悕绉�", trigger: "blur" },
+ ],
+ longitude: [{ required: true, message: "璇烽�夋嫨鎵撳崱浣嶇疆", trigger: "blur" }],
+ latitude: [{ required: true, message: "璇烽�夋嫨鎵撳崱浣嶇疆", trigger: "blur" }],
+ radius: [{ required: true, message: "璇疯緭鍏ユ墦鍗¤寖鍥�", trigger: "blur" }],
+ startAt: [{ required: true, message: "璇烽�夋嫨涓婄彮鏃堕棿", trigger: "change" }],
+ endAt: [
+ { required: true, message: "璇烽�夋嫨涓嬬彮鏃堕棿", trigger: "change" },
+ {
+ validator: (rule, value, callback) => {
+ if (form.shift && ["澶滅彮", "澶�"].includes(form.shift)) {
+ callback();
+ return;
+ }
+ if (form.startAt && value) {
+ const startParts = form.startAt.split(":");
+ const endParts = value.split(":");
+ const startTime =
+ parseInt(startParts[0]) * 60 + parseInt(startParts[1]);
+ const endTime = parseInt(endParts[0]) * 60 + parseInt(endParts[1]);
+ if (endTime <= startTime) {
+ callback(new Error("涓嬬彮鏃堕棿涓嶈兘鏃╀簬涓婄彮鏃堕棿"));
+ } else {
+ callback();
+ }
} else {
callback();
}
- } else {
- callback();
- }
+ },
+ trigger: "change",
},
- trigger: "change",
- },
- ],
- };
+ ],
+ };
+ });
// 閮ㄩ棬閫夐」
const deptOptions = ref([]);
@@ -393,8 +429,8 @@
watch(
() => form.radius,
newValue => {
- if (circle) {
- circle.setRadius(newValue);
+ if (circle && newValue != null && newValue !== "") {
+ circle.setRadius(Number(newValue));
}
}
);
@@ -405,6 +441,29 @@
() => {
if (formRef.value && form.endAt) {
formRef.value.validateField("endAt");
+ }
+ }
+ );
+
+ watch(
+ () => hideClockFields.value,
+ val => {
+ if (!val) return;
+ form.radius = null;
+ form.longitude = "";
+ form.latitude = "";
+ form.locationName = "";
+ form.startAt = "";
+ form.endAt = "";
+ if (formRef.value) {
+ formRef.value.clearValidate([
+ "radius",
+ "longitude",
+ "latitude",
+ "locationName",
+ "startAt",
+ "endAt",
+ ]);
}
}
);
@@ -442,7 +501,9 @@
// 鍒濆鍖栧湴鍥�
setTimeout(() => {
- initMap();
+ if (!hideClockFields.value) {
+ initMap();
+ }
}, 100);
}
}
@@ -513,4 +574,4 @@
.mt8 {
margin-top: 8px;
}
-</style>
\ No newline at end of file
+</style>
diff --git a/src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue b/src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue
index c47dd2e..d09329b 100644
--- a/src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue
+++ b/src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue
@@ -74,23 +74,39 @@
</template>
</el-table-column>
<el-table-column prop="locationName"
- label="鍦扮偣鍚嶇О" />
+ label="鍦扮偣鍚嶇О">
+ <template #default="scope">
+ {{ scope.row.locationName || "-" }}
+ </template>
+ </el-table-column>
<el-table-column prop="longitude"
- label="缁忓害" />
+ label="缁忓害">
+ <template #default="scope">
+ {{ scope.row.longitude ?? "-" }}
+ </template>
+ </el-table-column>
<el-table-column prop="latitude"
- label="绾害" />
+ label="绾害">
+ <template #default="scope">
+ {{ scope.row.latitude ?? "-" }}
+ </template>
+ </el-table-column>
<el-table-column prop="radius"
- label="鎵撳崱鑼冨洿(m)" />
+ label="鎵撳崱鑼冨洿(m)">
+ <template #default="scope">
+ {{ scope.row.radius ?? "-" }}
+ </template>
+ </el-table-column>
<el-table-column prop="startAt"
label="涓婄彮鏃堕棿">
<template #default="scope">
- {{ scope.row.startAt }}
+ {{ scope.row.startAt || "-" }}
</template>
</el-table-column>
<el-table-column prop="endAt"
label="涓嬬彮鏃堕棿">
<template #default="scope">
- {{ scope.row.endAt }}
+ {{ scope.row.endAt || "-" }}
</template>
</el-table-column>
<el-table-column label="鎿嶄綔"
@@ -232,7 +248,8 @@
tableLoading.value = true;
getAttendanceRules({ ...page, ...searchForm })
.then(res => {
- tableData.value = res.data.records;
+ const records = Array.isArray(res?.data?.records) ? res.data.records : [];
+ tableData.value = records.filter(r => String(r?.id) !== "999");
page.total = res.data.total;
})
.finally(() => {
diff --git a/src/views/personnelManagement/classsSheduling/index.vue b/src/views/personnelManagement/classsSheduling/index.vue
index 140ffba..8228be9 100644
--- a/src/views/personnelManagement/classsSheduling/index.vue
+++ b/src/views/personnelManagement/classsSheduling/index.vue
@@ -149,12 +149,12 @@
'shift-box-early': m.shift === '鏃╃彮',
'shift-box-mid': m.shift === '涓彮',
'shift-box-night': m.shift === '澶滅彮',
- 'shift-box-rest': m.shift === '浼戞伅',
+ 'shift-box-rest': !m.shift || m.shift === '浼戞伅',
'shift-box-leave': m.shift === '璇峰亣',
'shift-box-other': m.shift === '澶�11',
'shift-box-business': m.shift === '澶�12',
}">
- <span class="shift-text">{{ getShiftNameByValue(m.shift) || '鈥�' }}</span>
+ <span class="shift-text">{{ getShiftNameByValue(m.shift) || '浼戞伅' }}</span>
</div>
<template #dropdown>
<el-dropdown-menu>
@@ -199,7 +199,7 @@
</div> -->
<div class="user-total">
<span class="total-label">鍚堣鍑哄嫟:</span>
- <span class="total-value">{{ item.work_time }}澶�</span>
+ <span class="total-value">{{ item.year.totalYearAttendance }}澶�</span>
</div>
</div>
</div>
@@ -271,6 +271,23 @@
<div class="search_thing">
<div class="search_label"
style="width: 90px">
+ <span style="color: red; margin-right: 4px">*</span>閮ㄩ棬锛�
+ </div>
+ <div class="search_input">
+ <el-tree-select v-model="schedulingQuery.deptId"
+ :data="deptOptions"
+ :props="{ value: 'id', label: 'label', children: 'children' }"
+ value-key="id"
+ placeholder="璇烽�夋嫨閮ㄩ棬"
+ check-strictly
+ clearable
+ @change="onSchedulingDeptChange"
+ style="width: 100%" />
+ </div>
+ </div>
+ <div class="search_thing">
+ <div class="search_label"
+ style="width: 90px">
<span style="color: red; margin-right: 4px">*</span>浜哄憳鍚嶇О锛�
</div>
<div class="search_input">
@@ -279,7 +296,8 @@
style="width: 100%"
multiple
clearable
- collapse-tags>
+ collapse-tags
+ :disabled="!schedulingQuery.deptId">
<el-option v-for="item in personList"
:key="item.id"
:label="item.staffName"
@@ -296,8 +314,9 @@
<div class="search_input">
<el-select v-model="schedulingQuery.shift"
placeholder="璇烽�夋嫨"
- style="width: 100%">
- <el-option v-for="item in classType"
+ style="width: 100%"
+ :disabled="!schedulingQuery.deptId">
+ <el-option v-for="item in schedulingClassType"
:key="item.id"
:label="getShiftNameByValue(item.shift)"
:value="item.id">
@@ -318,7 +337,14 @@
</template>
<script setup>
- import { ref, reactive, onMounted, getCurrentInstance } from "vue";
+ import {
+ ref,
+ reactive,
+ computed,
+ watch,
+ onMounted,
+ getCurrentInstance,
+ } from "vue";
import { useRouter } from "vue-router";
import {
page,
@@ -376,6 +402,7 @@
// 浜哄憳鍒楄〃
const personList = ref([]);
+ const personListAll = ref([]);
// 鍔犺浇鐘舵��
const loading = ref(false);
@@ -383,8 +410,18 @@
// 鎺掔彮鏌ヨ鏉′欢
const schedulingQuery = reactive({
week: "",
+ deptId: "",
userId: null,
shift: "",
+ });
+
+ const schedulingClassType = computed(() => {
+ if (!schedulingQuery.deptId) return classType.value || [];
+ return (classType.value || []).filter(item => {
+ if (["998", "999"].includes(String(item?.id))) return true;
+ const itemDeptId = item.deptId ?? item.sysDeptId ?? item.dept_id;
+ return String(itemDeptId) === String(schedulingQuery.deptId);
+ });
});
// 鍒楄〃鏁版嵁
@@ -593,6 +630,10 @@
proxy.$modal.msgError("璇烽�夋嫨鍛ㄦ");
return;
}
+ if (!schedulingQuery.deptId) {
+ proxy.$modal.msgError("璇烽�夋嫨閮ㄩ棬");
+ return;
+ }
let time = schedulingQuery.week.getTime();
// 鏍煎紡鍖栨棩鏈熶负 YYYY-MM-DD 鏍煎紡
@@ -628,8 +669,10 @@
proxy.$modal.msgSuccess("鎿嶄綔鎴愬姛");
schedulingVisible.value = false;
schedulingQuery.week = "";
+ schedulingQuery.deptId = "";
schedulingQuery.userId = null;
schedulingQuery.shift = "";
+ personList.value = [];
refresh();
})
.catch(err => {
@@ -683,8 +726,7 @@
}
proxy.$download.saveAs(blob, fileName + ".xlsx");
})
- .catch(err => {
- })
+ .catch(err => {})
.finally(() => {
downLoading.value = false;
});
@@ -709,7 +751,18 @@
// 鏌ヨ瑙勫垯鍒楄〃
const fetchData = () => {
getAttendanceRules({ current: -1, size: -1 }).then(res => {
- classType.value = res.data.records;
+ const records = Array.isArray(res?.data?.records) ? res.data.records : [];
+ const appendList = [
+ { id: 998, shift: "浼戞伅" },
+ { id: 999, shift: "璇峰亣" },
+ ];
+ const exists = new Set(records.map(r => String(r?.id)));
+ appendList.forEach(item => {
+ if (!exists.has(String(item.id))) {
+ records.push(item);
+ }
+ });
+ classType.value = records;
});
};
// 鑾峰彇鐢ㄦ埛
@@ -724,8 +777,61 @@
staffState: 1,
}).then(res => {
let arr = res.data.records;
- personList.value = arr;
+ personListAll.value = arr;
+ updatePersonListByDept();
});
+ };
+
+ const findDeptNodeById = (deptId, deptList = deptOptions.value) => {
+ const list = Array.isArray(deptList) ? deptList : [];
+ for (const node of list) {
+ if (String(node.id) === String(deptId)) return node;
+ if (node.children && node.children.length) {
+ const found = findDeptNodeById(deptId, node.children);
+ if (found) return found;
+ }
+ }
+ return null;
+ };
+
+ const collectDeptIds = node => {
+ const ids = [];
+ if (!node) return ids;
+ ids.push(String(node.id));
+ if (node.children && node.children.length) {
+ node.children.forEach(child => {
+ ids.push(...collectDeptIds(child));
+ });
+ }
+ return ids;
+ };
+
+ const updatePersonListByDept = () => {
+ if (!schedulingQuery.deptId) {
+ personList.value = [];
+ return;
+ }
+ const node = findDeptNodeById(schedulingQuery.deptId);
+ const deptIds = new Set(collectDeptIds(node));
+ personList.value = (personListAll.value || []).filter(item => {
+ const itemDeptId = item.deptId ?? item.sysDeptId ?? item.dept_id;
+ return deptIds.has(String(itemDeptId));
+ });
+ };
+
+ const setDefaultShiftByDept = () => {
+ if (!schedulingQuery.deptId) {
+ schedulingQuery.shift = "";
+ return;
+ }
+ const first = schedulingClassType.value?.[0];
+ schedulingQuery.shift = first ? first.id : "";
+ };
+
+ const onSchedulingDeptChange = () => {
+ schedulingQuery.userId = null;
+ updatePersonListByDept();
+ setDefaultShiftByDept();
};
// 鏍规嵁瀛楀吀鑾峰彇鏃ユ湡
@@ -761,6 +867,27 @@
}
monthList.value.reverse();
});
+
+ watch(
+ () => classType.value,
+ () => {
+ if (schedulingVisible.value && schedulingQuery.deptId) {
+ setDefaultShiftByDept();
+ }
+ }
+ );
+
+ watch(
+ () => schedulingVisible.value,
+ val => {
+ if (!val) return;
+ schedulingQuery.week = "";
+ schedulingQuery.deptId = "";
+ schedulingQuery.userId = null;
+ schedulingQuery.shift = "";
+ personList.value = [];
+ }
+ );
</script>
<style scoped>
@@ -973,7 +1100,7 @@
.user-stats {
/* display: flex; */
/* flex-wrap: wrap;
- gap: 10px; */
+ gap: 10px; */
margin-bottom: 4px;
}
--
Gitblit v1.9.3