From 83946cf045cc431dcbf66b9e192eacd329da1148 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期三, 11 二月 2026 14:12:26 +0800
Subject: [PATCH] 打卡规则配置
---
src/api/personnelManagement/attendanceRules.js | 45 +++
index.html | 4
src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue | 293 ++++++++++++++++++++
src/views/personnelManagement/attendanceCheckin/index.vue | 3
src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue | 461 ++++++++++++++++++++++++++++++++
5 files changed, 805 insertions(+), 1 deletions(-)
diff --git a/index.html b/index.html
index a684690..274352d 100644
--- a/index.html
+++ b/index.html
@@ -10,6 +10,10 @@
/>
<link rel="icon" href="/favicon.ico" />
<title>%VITE_APP_TITLE%</title>
+ <!-- 楂樺痉鍦板浘API -->
+ <script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=6af5d2639adbbabf95eddfbf2bae5739"></script>
+ <!-- 楂樺痉鍦板浘鎼滅储鎻掍欢 -->
+ <script type="text/javascript" src="https://webapi.amap.com/loca?v=2.0.0&key=6af5d2639adbbabf95eddfbf2bae5739"></script>
<!--[if lt IE 11
]><script>
window.location.href = "/html/ie.html";
diff --git a/src/api/personnelManagement/attendanceRules.js b/src/api/personnelManagement/attendanceRules.js
new file mode 100644
index 0000000..021442e
--- /dev/null
+++ b/src/api/personnelManagement/attendanceRules.js
@@ -0,0 +1,45 @@
+import request from "@/utils/request";
+
+// 鑾峰彇鎵撳崱瑙勫垯鍒楄〃
+export function getAttendanceRules(query) {
+ return request({
+ url: "/personalAttendanceLocationConfig/listPage",
+ method: "get",
+ params: query,
+ });
+}
+
+// 鏂板鎵撳崱瑙勫垯
+export function addAttendanceRule(data) {
+ return request({
+ url: "/personalAttendanceLocationConfig/add",
+ method: "post",
+ data,
+ });
+}
+
+// 鏇存柊鎵撳崱瑙勫垯
+export function updateAttendanceRule(data) {
+ return request({
+ url: "/attendanceRules/update",
+ method: "put",
+ data,
+ });
+}
+
+// 鍒犻櫎鎵撳崱瑙勫垯
+export function deleteAttendanceRule(ids) {
+ return request({
+ url: `/personalAttendanceLocationConfig/del`,
+ method: "delete",
+ data: ids,
+ });
+}
+
+// 鑾峰彇鍗曚釜鎵撳崱瑙勫垯璇︽儏
+export function getAttendanceRuleDetail(id) {
+ return request({
+ url: `/attendanceRules/detail/${id}`,
+ method: "get",
+ });
+}
diff --git a/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue b/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue
new file mode 100644
index 0000000..39eacda
--- /dev/null
+++ b/src/views/personnelManagement/attendanceCheckin/checkinRules/components/form.vue
@@ -0,0 +1,461 @@
+<template>
+ <el-dialog v-model="dialogVisible"
+ :title="dialogTitle"
+ width="700px"
+ :close-on-click-modal="false">
+ <el-form ref="formRef"
+ :model="form"
+ :rules="rules"
+ label-width="120px"
+ class="mt8">
+ <!-- 閮ㄩ棬閫夋嫨 -->
+ <el-form-item label="閮ㄩ棬"
+ prop="sysDeptId">
+ <el-tree-select v-model="form.sysDeptId"
+ :data="deptOptions"
+ :props="{ value: 'id', label: 'label', children: 'children' }"
+ value-key="id"
+ placeholder="璇烽�夋嫨閮ㄩ棬"
+ check-strictly
+ style="width: 100%"
+ :disabled="operationType === 'view'" />
+ </el-form-item>
+ <!-- 鍦扮偣淇℃伅 -->
+ <!-- <el-form-item label="鍦扮偣鍚嶇О"
+ prop="locationName">
+ <el-input v-model="form.locationName"
+ placeholder="璇疯緭鍏ュ湴鐐瑰悕绉�"
+ :disabled="operationType === 'view'" />
+ </el-form-item> -->
+ <!-- 鎵撳崱鑼冨洿 -->
+ <el-form-item label="鎵撳崱鑼冨洿(m)"
+ prop="radius">
+ <el-input-number v-model="form.radius"
+ :min="10"
+ :max="1000"
+ :step="10"
+ placeholder="璇疯緭鍏ユ墦鍗¤寖鍥�"
+ :disabled="operationType === 'view'" />
+ </el-form-item>
+ <!-- 楂樺痉鍦板浘閫夋嫨 -->
+ <el-form-item label="鎵撳崱浣嶇疆"
+ prop="longitude">
+ <div class="map-container">
+ <div class="map-header"
+ style="margin-bottom: 10px">
+ <el-button @click="getCurrentLocation">
+ <el-icon>
+ <Position />
+ </el-icon>
+ 褰撳墠浣嶇疆
+ </el-button>
+ <span style="margin-left: 10px; color: #909399;font-size: 12px;">鐐瑰嚮鍦板浘閫夋嫨浣嶇疆</span>
+ </div>
+ <div id="map-container"
+ class="map"
+ ref="mapContainer"></div>
+ <div class="coordinates-info mt10">
+ <el-input v-model="form.longitude"
+ readonly
+ placeholder="缁忓害"
+ style="width: 140px; margin-right: 10px" />
+ <el-input v-model="form.latitude"
+ readonly
+ placeholder="绾害"
+ style="width: 140px; margin-right: 10px" />
+ <!-- <el-input v-model="form.locationName"
+ placeholder="鍦扮偣鍚嶇О"
+ style="width: calc(100% - 290px)" /> -->
+ </div>
+ </div>
+ </el-form-item>
+ <el-form-item label="鍦扮偣鍚嶇О"
+ prop="locationName">
+ <el-input v-model="form.locationName"
+ :disabled="operationType === 'view'"
+ placeholder="璇疯緭鍏ュ湴鐐瑰悕绉�" />
+ </el-form-item>
+ <!-- 涓婁笅鐝椂闂� -->
+ <el-form-item label="涓婄彮鏃堕棿"
+ prop="startAt">
+ <el-time-picker v-model="form.startAt"
+ format="HH:mm"
+ value-format="HH:mm"
+ placeholder="璇烽�夋嫨涓婄彮鏃堕棿"
+ :disabled="operationType === 'view'" />
+ </el-form-item>
+ <el-form-item label="涓嬬彮鏃堕棿"
+ prop="endAt">
+ <el-time-picker v-model="form.endAt"
+ format="HH:mm"
+ value-format="HH:mm"
+ placeholder="璇烽�夋嫨涓嬬彮鏃堕棿"
+ :disabled="operationType === 'view'" />
+ </el-form-item>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary"
+ @click="submitForm"
+ v-if="operationType !== 'view'">
+ 纭畾
+ </el-button>
+ </span>
+ </template>
+ </el-dialog>
+</template>
+
+<script setup>
+ import { ref, reactive, computed, watch, onMounted, nextTick } from "vue";
+ import { ElMessage } from "element-plus";
+ import { Position } from "@element-plus/icons-vue";
+ import { deptTreeSelect } from "@/api/system/user.js";
+ import { addAttendanceRule } from "@/api/personnelManagement/attendanceRules.js";
+
+ const props = defineProps({
+ modelValue: {
+ type: Boolean,
+ default: false,
+ },
+ operationType: {
+ type: String,
+ default: "add",
+ },
+ row: {
+ type: Object,
+ default: () => ({}),
+ },
+ });
+
+ const emit = defineEmits(["update:modelValue", "close"]);
+
+ const dialogVisible = computed({
+ get: () => props.modelValue,
+ set: val => emit("update:modelValue", val),
+ });
+
+ const dialogTitle = computed(() => {
+ if (props.operationType === "add") return "鏂板鎵撳崱瑙勫垯";
+ if (props.operationType === "edit") return "缂栬緫鎵撳崱瑙勫垯";
+ return "鏌ョ湅鎵撳崱瑙勫垯";
+ });
+
+ // 琛ㄥ崟鏁版嵁
+ const formRef = ref();
+ const form = reactive({
+ id: "",
+ sysDeptId: "",
+ locationName: "",
+ longitude: "",
+ latitude: "",
+ radius: 100,
+ startAt: "09:00",
+ endAt: "18:00",
+ });
+
+ // 琛ㄥ崟楠岃瘉瑙勫垯
+ 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" }],
+ radius: [{ required: true, message: "璇疯緭鍏ユ墦鍗¤寖鍥�", trigger: "blur" }],
+ startAt: [{ required: true, message: "璇烽�夋嫨涓婄彮鏃堕棿", trigger: "change" }],
+ endAt: [{ required: true, message: "璇烽�夋嫨涓嬬彮鏃堕棿", trigger: "change" }],
+ };
+
+ // 閮ㄩ棬閫夐」
+ const deptOptions = ref([]);
+
+ // 鍦板浘鐩稿叧
+ const mapContainer = ref(null);
+ let map = null;
+ let marker = null;
+ let circle = null;
+
+ // 鑾峰彇閮ㄩ棬鍒楄〃
+ const fetchDeptOptions = () => {
+ deptTreeSelect().then(response => {
+ deptOptions.value = filterDisabledDept(
+ JSON.parse(JSON.stringify(response.data))
+ );
+ });
+ };
+
+ // 杩囨护绂佺敤鐨勯儴闂�
+ const filterDisabledDept = deptList => {
+ return deptList.filter(dept => {
+ if (dept.disabled) {
+ return false;
+ }
+ if (dept.children && dept.children.length) {
+ dept.children = filterDisabledDept(dept.children);
+ }
+ return true;
+ });
+ };
+
+ // 鍒濆鍖栧湴鍥�
+ const initMap = () => {
+ nextTick(() => {
+ if (window.AMap && mapContainer.value) {
+ // 鍒濆鍖栧湴鍥�
+ map = new window.AMap.Map(mapContainer.value, {
+ zoom: 16,
+ center: [116.397428, 39.90923], // 榛樿鍖椾含
+ });
+
+ // 娣诲姞鎺т欢
+ window.AMap.plugin(["AMap.ToolBar", "AMap.Scale"], function () {
+ map.addControl(new window.AMap.ToolBar());
+ map.addControl(new window.AMap.Scale());
+ });
+
+ // 娣诲姞鏍囪
+ marker = new window.AMap.Marker({
+ position: [116.397428, 39.90923],
+ draggable: true,
+ cursor: "move",
+ title: "鎷栨嫿瀹氫綅",
+ });
+ map.add(marker);
+
+ // 娣诲姞鍦嗗舰鑼冨洿
+ circle = new window.AMap.Circle({
+ center: [116.397428, 39.90923],
+ radius: form.radius,
+ strokeColor: "#3366FF",
+ strokeOpacity: 0.8,
+ strokeWeight: 2,
+ fillColor: "#3366FF",
+ fillOpacity: 0.2,
+ });
+ map.add(circle);
+
+ // 鐩戝惉鏍囪鎷栨嫿
+ marker.on("dragend", e => {
+ const position = e.lnglat;
+ const lng = position.getLng();
+ const lat = position.getLat();
+ form.longitude = lng;
+ form.latitude = lat;
+ updateCircle(position);
+ });
+
+ // 鐩戝惉鏍囪鎷栨嫿寮�濮�
+ marker.on("dragstart", () => {
+ map.setDefaultCursor("move");
+ });
+
+ // 鐩戝惉鏍囪鎷栨嫿缁撴潫
+ marker.on("dragend", () => {
+ map.setDefaultCursor("default");
+ });
+
+ // 鐩戝惉鍦板浘鐐瑰嚮
+ map.on("click", e => {
+ const position = e.lnglat;
+ const lng = position.getLng();
+ const lat = position.getLat();
+ form.longitude = lng;
+ form.latitude = lat;
+ updateMarker(position);
+ updateCircle(position);
+ });
+
+ // 灏濊瘯鑾峰彇褰撳墠浣嶇疆骞惰缃负鍦板浘涓績
+ if (navigator.geolocation && !form.longitude && !form.latitude) {
+ navigator.geolocation.getCurrentPosition(
+ position => {
+ console.log("鑾峰彇鍒板綋鍓嶄綅缃�:", position);
+ const { longitude, latitude } = position.coords;
+ const currentPosition = [longitude, latitude];
+ map.setCenter(currentPosition);
+ updateMarker(currentPosition);
+ updateCircle(currentPosition);
+ form.longitude = longitude;
+ form.latitude = latitude;
+ },
+ error => {
+ console.log("鑾峰彇浣嶇疆澶辫触锛屼娇鐢ㄩ粯璁や綅缃�");
+ }
+ );
+ } else if (form.longitude && form.latitude) {
+ // 濡傛灉鏈夋暟鎹紝璁剧疆鍒板湴鍥�
+ const position = [form.longitude, form.latitude];
+ map.setCenter(position);
+ updateMarker(position);
+ updateCircle(position);
+ }
+ }
+ });
+ };
+
+ // 鏇存柊鏍囪浣嶇疆
+ const updateMarker = position => {
+ if (marker) {
+ marker.setPosition(position);
+ }
+ };
+
+ // 鏇存柊鍦嗗舰鑼冨洿
+ const updateCircle = position => {
+ if (circle) {
+ circle.setCenter(position);
+ circle.setRadius(form.radius);
+ }
+ };
+
+ // 鑾峰彇褰撳墠浣嶇疆
+ const getCurrentLocation = () => {
+ if (navigator.geolocation) {
+ navigator.geolocation.getCurrentPosition(
+ position => {
+ const { longitude, latitude } = position.coords;
+ form.longitude = longitude;
+ form.latitude = latitude;
+ if (map) {
+ map.setCenter([longitude, latitude]);
+ updateMarker([longitude, latitude]);
+ updateCircle([longitude, latitude]);
+ }
+
+ // 閫嗗湴鐞嗙紪鐮佽幏鍙栧湴鍧�
+ if (window.AMap) {
+ // 鍔犺浇Geocoder鎻掍欢
+ window.AMap.plugin("AMap.Geocoder", function () {
+ const geocoder = new window.AMap.Geocoder();
+ geocoder.getAddress([longitude, latitude], (status, result) => {
+ if (status === "complete" && result.regeocode) {
+ form.locationName = result.regeocode.formattedAddress;
+ }
+ });
+ });
+ }
+ },
+ error => {
+ ElMessage.error("鑾峰彇浣嶇疆澶辫触锛岃鎵嬪姩閫夋嫨");
+ }
+ );
+ } else {
+ ElMessage.error("娴忚鍣ㄤ笉鏀寔鍦扮悊瀹氫綅");
+ }
+ };
+
+ // 鐩戝惉鍗婂緞鍙樺寲
+ watch(
+ () => form.radius,
+ newValue => {
+ if (circle) {
+ circle.setRadius(newValue);
+ }
+ }
+ );
+
+ // 鐩戝惉寮圭獥鏄剧ず
+ watch(
+ () => dialogVisible.value,
+ newValue => {
+ if (newValue) {
+ // 閲嶇疆琛ㄥ崟
+ Object.assign(form, {
+ id: "",
+ sysDeptId: "",
+ locationName: "",
+ longitude: "",
+ latitude: "",
+ radius: 100,
+ startAt: "09:00",
+ endAt: "18:00",
+ });
+
+ // 濡傛灉鏄紪杈戞垨鏌ョ湅锛屽~鍏呮暟鎹�
+ if (props.operationType !== "add" && props.row.id) {
+ // 澶勭悊鏃堕棿鏍煎紡锛岀‘淇濇槸HH:mm鏍煎紡
+ const rowData = { ...props.row };
+ if (rowData.startAt && rowData.startAt.includes(":")) {
+ rowData.startAt = rowData.startAt.split(":").slice(0, 2).join(":");
+ }
+ if (rowData.endAt && rowData.endAt.includes(":")) {
+ rowData.endAt = rowData.endAt.split(":").slice(0, 2).join(":");
+ }
+ Object.assign(form, rowData);
+ }
+
+ // 鍒濆鍖栧湴鍥�
+ setTimeout(() => {
+ initMap();
+ }, 100);
+ }
+ }
+ );
+
+ // 鎻愪氦琛ㄥ崟
+ const submitForm = () => {
+ formRef.value.validate(valid => {
+ if (valid) {
+ const submitData = {
+ ...form,
+ // 杞崲鏃堕棿鏍煎紡锛岀‘淇濆彧淇濈暀鏃跺垎閮ㄥ垎
+ startAt: form.startAt
+ ? `${form.startAt.split(":").slice(0, 2).join(":")}`
+ : null,
+ endAt: form.endAt
+ ? `${form.endAt.split(":").slice(0, 2).join(":")}`
+ : null,
+ };
+
+ if (props.operationType === "add") {
+ addAttendanceRule(submitData).then(() => {
+ ElMessage.success("鏂板鎴愬姛");
+ emit("close");
+ });
+ } else if (props.operationType === "edit") {
+ addAttendanceRule(submitData).then(() => {
+ ElMessage.success("鏇存柊鎴愬姛");
+ emit("close");
+ });
+ }
+ }
+ });
+ };
+
+ // 鍒濆鍖�
+ onMounted(() => {
+ fetchDeptOptions();
+ });
+</script>
+
+<style scoped lang="scss">
+ .map-container {
+ width: 100%;
+ }
+
+ .map {
+ width: 100%;
+ height: 400px;
+ border: 1px solid #e4e7ed;
+ }
+
+ .coordinates-info {
+ display: flex;
+ gap: 10px;
+ }
+
+ .coordinates-display {
+ padding: 10px;
+ background-color: #f5f7fa;
+ border-radius: 4px;
+ }
+
+ .mt10 {
+ margin-top: 10px;
+ }
+
+ .mt8 {
+ margin-top: 8px;
+ }
+</style>
\ No newline at end of file
diff --git a/src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue b/src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue
new file mode 100644
index 0000000..1fd19f3
--- /dev/null
+++ b/src/views/personnelManagement/attendanceCheckin/checkinRules/index.vue
@@ -0,0 +1,293 @@
+<template>
+ <div class="app-container">
+ <!-- 椤甸潰鏍囬鍜屾搷浣滄寜閽� -->
+ <div class="page-header">
+ <div class="title">鎵撳崱瑙勫垯閰嶇疆</div>
+ <div class="actions">
+ <el-button type="primary"
+ @click="openForm('add')">
+ <el-icon>
+ <Plus />
+ </el-icon>
+ 鏂板瑙勫垯
+ </el-button>
+ </div>
+ </div>
+ <!-- 鏌ヨ鏉′欢 -->
+ <!-- <el-form :model="searchForm"
+ :inline="true"
+ class="search-form mb16">
+ <el-form-item label="閮ㄩ棬锛�"
+ prop="countId">
+ <el-tree-select v-model="searchForm.countId"
+ :data="deptOptions"
+ :props="{ value: 'id', label: 'label', children: 'children' }"
+ value-key="id"
+ placeholder="璇烽�夋嫨閮ㄩ棬"
+ check-strictly
+ style="width: 200px" />
+ </el-form-item>
+ <el-form-item label="鍦扮偣锛�"
+ prop="locationName">
+ <el-input v-model="searchForm.locationName"
+ placeholder="璇疯緭鍏ュ湴鐐瑰悕绉�"
+ clearable
+ style="width: 200px" />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary"
+ @click="fetchData">
+ <el-icon>
+ <Search />
+ </el-icon>
+ 鎼滅储
+ </el-button>
+ <el-button @click="resetSearch">
+ <el-icon>
+ <Refresh />
+ </el-icon>
+ 閲嶇疆
+ </el-button>
+ </el-form-item>
+ </el-form> -->
+ <!-- 瑙勫垯鍒楄〃 -->
+ <el-card shadow="never"
+ class="mb16">
+ <el-table :data="tableData"
+ border
+ v-loading="tableLoading"
+ style="width: 100%"
+ row-key="id">
+ <el-table-column type="index"
+ label="搴忓彿"
+ width="60"
+ align="center" />
+ <el-table-column label="閮ㄩ棬">
+ <template #default="scope">
+ {{ getDeptNameById(scope.row.sysDeptId) }}
+ </template>
+ </el-table-column>
+ <el-table-column prop="locationName"
+ label="鍦扮偣鍚嶇О" />
+ <el-table-column prop="longitude"
+ label="缁忓害" />
+ <el-table-column prop="latitude"
+ label="绾害" />
+ <el-table-column prop="radius"
+ label="鎵撳崱鑼冨洿(m)" />
+ <el-table-column prop="startAt"
+ label="涓婄彮鏃堕棿">
+ <template #default="scope">
+ {{ scope.row.startAt }}
+ </template>
+ </el-table-column>
+ <el-table-column prop="endAt"
+ label="涓嬬彮鏃堕棿">
+ <template #default="scope">
+ {{ scope.row.endAt }}
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔"
+ width="180"
+ fixed="right"
+ align="center">
+ <template #default="scope">
+ <el-button type="primary"
+ size="small"
+ link
+ @click="openForm('edit', scope.row)">缂栬緫</el-button>
+ <el-button type="danger"
+ size="small"
+ link
+ @click="handleDelete(scope.row.id)">鍒犻櫎</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <pagination :total="page.total"
+ layout="total, sizes, prev, pager, next, jumper"
+ :page="page.current"
+ :limit="page.size"
+ @pagination="paginationChange"
+ class="mt10" />
+ </el-card>
+ <!-- 鏂板/缂栬緫瑙勫垯寮圭獥 -->
+ <rule-form ref="ruleFormRef"
+ v-model="dialogVisible"
+ :operation-type="operationType"
+ :row="currentRow"
+ @close="dialogVisible = false; fetchData()" />
+ </div>
+</template>
+
+<script setup>
+ import { ref, reactive, onMounted } from "vue";
+ import { ElMessage, ElMessageBox } from "element-plus";
+ import { Plus, Edit, Delete, Search, Refresh } from "@element-plus/icons-vue";
+ import Pagination from "@/components/Pagination/index.vue";
+ import RuleForm from "./components/form.vue";
+ import { deptTreeSelect } from "@/api/system/user.js";
+ import {
+ getAttendanceRules,
+ deleteAttendanceRule,
+ } from "@/api/personnelManagement/attendanceRules.js";
+
+ const { proxy } = getCurrentInstance();
+
+ // 琛ㄦ牸鏁版嵁
+ const tableData = ref([]);
+ const tableLoading = ref(false);
+
+ // 鍒嗛〉鍙傛暟
+ const page = reactive({
+ current: 1,
+ size: 10,
+ total: 0,
+ });
+
+ // 鏌ヨ琛ㄥ崟
+ const searchForm = reactive({
+ countId: "",
+ locationName: "",
+ });
+
+ // 閮ㄩ棬閫夐」
+ const deptOptions = ref([]);
+
+ // 寮圭獥鎺у埗
+ const dialogVisible = ref(false);
+ const operationType = ref("add");
+ const currentRow = ref({});
+ const ruleFormRef = ref();
+
+ // 鏍煎紡鍖栨椂闂�
+ const formatTime = timestamp => {
+ if (!timestamp) return "";
+ const date = new Date(timestamp);
+ return `${String(date.getHours()).padStart(2, "0")}:${String(
+ date.getMinutes()
+ ).padStart(2, "0")}`;
+ };
+
+ // 鑾峰彇閮ㄩ棬鍒楄〃
+ const fetchDeptOptions = () => {
+ deptTreeSelect().then(response => {
+ deptOptions.value = filterDisabledDept(
+ JSON.parse(JSON.stringify(response.data))
+ );
+ });
+ };
+
+ // 杩囨护绂佺敤鐨勯儴闂�
+ const filterDisabledDept = deptList => {
+ return deptList.filter(dept => {
+ if (dept.disabled) {
+ return false;
+ }
+ if (dept.children && dept.children.length) {
+ dept.children = filterDisabledDept(dept.children);
+ }
+ return true;
+ });
+ };
+
+ // 鏍规嵁閮ㄩ棬ID鏌ユ壘閮ㄩ棬鍚嶇О
+ const getDeptNameById = (deptId, deptList = deptOptions.value) => {
+ for (const dept of deptList) {
+ if (dept.id === deptId) {
+ return dept.label;
+ }
+ if (dept.children && dept.children.length) {
+ const name = getDeptNameById(deptId, dept.children);
+ if (name) {
+ return name;
+ }
+ }
+ }
+ return "";
+ };
+
+ // 鏌ヨ瑙勫垯鍒楄〃
+ const fetchData = () => {
+ tableLoading.value = true;
+ getAttendanceRules({ ...page, ...searchForm })
+ .then(res => {
+ tableData.value = res.data.records;
+ page.total = res.data.total;
+ })
+ .finally(() => {
+ tableLoading.value = false;
+ });
+ };
+
+ // 鍒嗛〉鍙樻洿
+ const paginationChange = pagination => {
+ page.current = pagination.page;
+ page.size = pagination.limit;
+ fetchData();
+ };
+
+ // 閲嶇疆鎼滅储
+ const resetSearch = () => {
+ searchForm.countId = "";
+ searchForm.locationName = "";
+ fetchData();
+ };
+
+ // 鎵撳紑琛ㄥ崟
+ const openForm = (type, row = {}) => {
+ operationType.value = type;
+ currentRow.value = row;
+ dialogVisible.value = true;
+ };
+
+ // 鍒犻櫎瑙勫垯
+ const handleDelete = id => {
+ ElMessageBox.confirm("纭畾瑕佸垹闄よ繖鏉¤鍒欏悧锛�", "鍒犻櫎纭", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ })
+ .then(() => {
+ deleteAttendanceRule([id]).then(() => {
+ ElMessage.success("鍒犻櫎鎴愬姛");
+ fetchData();
+ });
+ })
+ .catch(() => {
+ // 鍙栨秷鍒犻櫎
+ });
+ };
+
+ // 鍒濆鍖�
+ onMounted(() => {
+ fetchDeptOptions();
+ fetchData();
+ });
+</script>
+
+<style scoped lang="scss">
+ .page-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20px;
+
+ .title {
+ font-size: 18px;
+ font-weight: 600;
+ }
+
+ .actions {
+ display: flex;
+ gap: 10px;
+ }
+ }
+
+ .mb16 {
+ margin-bottom: 16px;
+ }
+
+ .mt10 {
+ margin-top: 10px;
+ }
+</style>
\ No newline at end of file
diff --git a/src/views/personnelManagement/attendanceCheckin/index.vue b/src/views/personnelManagement/attendanceCheckin/index.vue
index 05949ef..7ce645b 100644
--- a/src/views/personnelManagement/attendanceCheckin/index.vue
+++ b/src/views/personnelManagement/attendanceCheckin/index.vue
@@ -5,7 +5,8 @@
class="mb16">
<div class="attendance-header">
<div>
- <div class="title">鎵撳崱绛惧埌</div>
+ <div class="title">鎵撳崱绛惧埌
+ </div>
<div class="sub-title">鏀寔涓�閿墦鍗★紝鑷姩璁板綍涓婁笅鐝椂闂�</div>
</div>
<div class="attendance-actions">
--
Gitblit v1.9.3