| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- 员工打卡区 --> |
| | | <el-card shadow="never" |
| | | <!-- <el-card shadow="never" |
| | | class="mb16"> |
| | | <div class="attendance-header"> |
| | | <div> |
| | |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | </el-card> |
| | | </el-card> --> |
| | | <div class="attendance-operation"> |
| | | <el-button @click="handleBack" |
| | | type="default" |
| | | size="small" |
| | | style="margin-right: 16px"> |
| | | <el-icon> |
| | | <ArrowLeft /> |
| | | </el-icon> |
| | | 返回排班管理 |
| | | </el-button> |
| | | <!-- 查询条件(管理员考勤日报) --> |
| | | <el-form :model="searchForm" |
| | | :inline="true" |
| | |
| | | label="备注" |
| | | show-overflow-tooltip /> |
| | | </el-table> |
| | | <pagination :total="total" |
| | | <pagination :total="page.total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :page="page.current" |
| | | :limit="page.size" |
| | |
| | | |
| | | <script setup> |
| | | import { ref, reactive, computed, onMounted, onBeforeUnmount } from "vue"; |
| | | import { useRouter } from "vue-router"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { |
| | | createPersonalAttendanceRecord, |
| | |
| | | } from "@/api/personnelManagement/personalAttendanceRecords.js"; |
| | | import Pagination from "@/components/Pagination/index.vue"; |
| | | import { deptTreeSelect } from "@/api/system/user.js"; |
| | | import { Refresh, Search } from "@element-plus/icons-vue"; |
| | | import { Refresh, Search, ArrowLeft } from "@element-plus/icons-vue"; |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const router = useRouter(); |
| | | const tableLoading = ref(false); |
| | | // 分页参数 |
| | | const page = reactive({ |
| | |
| | | findPersonalAttendanceRecords({ ...page, ...searchForm }) |
| | | .then(res => { |
| | | tableData.value = res.data.records; |
| | | page.value.total = res.data.total; |
| | | page.total = res.data.total; |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | |
| | | |
| | | // 查询今日打卡信息 |
| | | const fetchTodayData = () => { |
| | | findTodayPersonalAttendanceRecord({}).then(res => { |
| | | todayRecord.value = res.data; |
| | | }); |
| | | // findTodayPersonalAttendanceRecord({}).then(res => { |
| | | // todayRecord.value = res.data; |
| | | // }); |
| | | }; |
| | | |
| | | const paginationChange = pagination => { |
| | |
| | | }); |
| | | }; |
| | | |
| | | // 获取当前位置 |
| | | const getCurrentLocation = () => { |
| | | return new Promise((resolve, reject) => { |
| | | if (!navigator.geolocation) { |
| | | reject(new Error("浏览器不支持地理定位")); |
| | | return; |
| | | } |
| | | |
| | | // 检查是否使用HTTPS |
| | | const isSecureContext = |
| | | window.isSecureContext || window.location.protocol === "https:"; |
| | | console.log( |
| | | "当前协议:", |
| | | window.location.protocol, |
| | | "是否安全上下文:", |
| | | isSecureContext |
| | | ); |
| | | |
| | | if (!isSecureContext) { |
| | | console.warn("当前不是HTTPS协议,地理位置API可能受限"); |
| | | } |
| | | |
| | | navigator.geolocation.getCurrentPosition( |
| | | position => { |
| | | const { longitude, latitude } = position.coords; |
| | | console.log("获取位置成功:", longitude, latitude); |
| | | resolve({ longitude, latitude }); |
| | | }, |
| | | error => { |
| | | console.log("获取位置失败:", error); |
| | | let errorMessage = "获取位置失败"; |
| | | |
| | | // 根据错误类型提供更具体的提示 |
| | | switch (error.code) { |
| | | case error.PERMISSION_DENIED: |
| | | errorMessage = |
| | | "用户拒绝了位置权限请求,请在浏览器设置中允许位置访问"; |
| | | break; |
| | | case error.POSITION_UNAVAILABLE: |
| | | errorMessage = "位置信息不可用,请检查设备定位功能"; |
| | | break; |
| | | case error.TIMEOUT: |
| | | errorMessage = "获取位置超时,请重试"; |
| | | break; |
| | | case error.UNKNOWN_ERROR: |
| | | errorMessage = "获取位置时发生未知错误"; |
| | | break; |
| | | default: |
| | | errorMessage = `获取位置失败: ${error.message}`; |
| | | } |
| | | |
| | | // 检查是否是HTTPS问题 |
| | | if (error.code === error.PERMISSION_DENIED && !isSecureContext) { |
| | | errorMessage += "(注意:生产环境需要使用HTTPS协议才能获取位置)"; |
| | | } |
| | | |
| | | reject(new Error(errorMessage)); |
| | | }, |
| | | { |
| | | enableHighAccuracy: true, |
| | | timeout: 10000, |
| | | maximumAge: 0, |
| | | } |
| | | ); |
| | | }); |
| | | }; |
| | | |
| | | // 打卡 |
| | | const handleCheckInOut = () => { |
| | | createPersonalAttendanceRecord({}).then(res => { |
| | | fetchData(); |
| | | fetchTodayData(); |
| | | ElMessage.success("打卡成功!"); |
| | | }); |
| | | getCurrentLocation() |
| | | .then(location => { |
| | | console.log("位置成功"); |
| | | createPersonalAttendanceRecord(location).then(res => { |
| | | fetchData(); |
| | | fetchTodayData(); |
| | | ElMessage.success("打卡成功!"); |
| | | }); |
| | | }) |
| | | .catch(error => { |
| | | // 获取位置失败时,仍允许打卡 |
| | | ElMessage.warning("获取位置失败,将使用默认位置打卡"); |
| | | createPersonalAttendanceRecord({}).then(res => { |
| | | fetchData(); |
| | | fetchTodayData(); |
| | | ElMessage.success("打卡成功!"); |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | |
| | | fetchDeptOptions(); |
| | | }); |
| | | |
| | | // 返回排班管理页面 |
| | | const handleBack = () => { |
| | | router.push({ |
| | | path: "/personnelManagement/classsSheduling/index", |
| | | }); |
| | | }; |
| | | |
| | | onBeforeUnmount(() => { |
| | | if (timer) { |
| | | clearInterval(timer); |