| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565 |
- <template>
- <view class="container">
- <!-- 时间日期信息 -->
- <view class="header">
- <text class="day">{{ currentDay }}</text>
- <text class="date">{{ currentDate }}</text>
- <text class="nowTime">{{ nowTime }}</text>
- </view>
- <!-- 打卡记录 -->
- <view class="record">
- <view class="record-item">
- <text class="ygoa-icon icon-goToWork"></text>
- <text class="title">上班</text>
- <text class="time">{{ signInTime || '未打卡' }}</text>
- <text class="signStatus" v-if="!isSignInStatusDisabled">({{signInStatusName}})</text>
- </view>
- <view class="record-item">
- <text class="ygoa-icon icon-afterWork"></text>
- <text class="title">下班</text>
- <text class="time">{{ signOutTime || '未打卡' }}</text>
- <text class="signStatus" v-if="!isSignOutStatusDisabled"
- style="color: #e64340;">({{signOutStatusName}})</text>
- </view>
- <view class="record-item" @click="getAddress">
- <text class="ygoa-icon icon-location"></text>
- <text class="title">当前位置</text>
- <text class="time">{{ address || '点击获取定位' }}</text>
- </view>
- </view>
- <!-- 地图 -->
- <atl-map :mapKey="config.mapKey" :mapType="mapType" :marker="marker" :polygons="polygons" :isPolygons="true">
- <template v-slot:content>
- </template>
- </atl-map>
- <!-- 打卡按钮 -->
- <view class="footer">
- <button type="default" @click="signInOrOut" style="background-color: #3c9cff; color: #fcfcfc;"
- v-if="signName=='上班签到'">上班签到</button>
- <button type="default" @click="signInOrOut" style="background-color: #1aad19; color: #fcfcfc;"
- v-else-if="signName=='下班签退'">下班签退</button>
- </view>
- </view>
- </template>
- <script setup>
- import {
- onBeforeUnmount,
- onMounted,
- reactive,
- ref
- } from 'vue';
- // 导入地理位置相关函数
- import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
- import {
- point,
- polygon
- } from "@turf/helpers";
- import {
- useUserStore
- } from '@/store/user';
- import $modal from '@/plugins/modal.js'
- import $tab from '@/plugins/tab.js';
- import config from '@/config.js';
- import {
- createAttendance,
- tranAddress,
- checkAttendance
- } from '@/api/mine.js'
- const userStore = useUserStore();
- const thisUser = userStore.user;
- const intervalId = ref(null); // 定时器ID
- onBeforeUnmount(() => {
- clearInterval(intervalId.value);
- })
- // 组件挂载后初始化当前日期与位置
- onMounted(() => {
- dateInit();
- // getlocation();
- });
- function showNowTime() {
- // let nowMilliseconds=Date.now();
- // intervalId.value = setInterval(() => {
- // nowMilliseconds+=1000;
- // nowTime.value = new Date(nowMilliseconds).toLocaleString('zh-CN', {
- // year: 'numeric',
- // month: '2-digit',
- // day: '2-digit',
- // hour: '2-digit',
- // minute: '2-digit',
- // second: '2-digit',
- // hour12: false // 24小时制
- // });
- // }, 1000); // 每1秒更新一次
- intervalId.value = setInterval(() => {
- nowTime.value = getNowTime()
- }, 1000); // 每1秒更新一次
- }
- // 当前日期和时间相关信息
- const currentDate = ref('2023-04-01');
- const currentDay = ref('星期三');
- const nowTime = ref(''); // 当前时间
- const weekArr = reactive(['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']); // 星期数组
- // 初始化日期
- function dateInit() {
- const nowDate = new Date();
- const year = nowDate.getFullYear(); // 获取年份
- const month = nowDate.getMonth() + 1; // 获取月份
- const day = nowDate.getDate(); // 获取日期
- // 格式化月份和日期为两位数
- const formattedMonth = month < 10 ? '0' + month : month;
- const formattedDay = day < 10 ? '0' + day : day;
- currentDate.value = `${year}-${formattedMonth}-${formattedDay}`; // 设置当前日期
- const dayOfWeek = nowDate.getDay(); // 获取当前星期
- currentDay.value = weekArr[dayOfWeek]; // 设置当前星期
- showNowTime();
- getTodayAtt();
- }
- const signInTime = ref(''); // 上班签到时间
- const signOutTime = ref(''); // 下班签到时间
- //打卡按钮文字显示
- const signName = ref('')
- //迟到早退状态,默认隐藏
- const signInStatusName = ref('迟到')
- const signOutStatusName = ref('早退')
- const isSignInStatusDisabled = ref(true)
- const isSignOutStatusDisabled = ref(true)
- //获取今天考勤状态
- function getTodayAtt() {
- const params = {
- universalid: thisUser.useId,
- rizi: currentDate.value
- }
- checkAttendance(params).then(res => {
- if ("success" == res.returnMsg) {
- // console.log("kaoqin",res);
- const attList = res.returnParams.list;
- const time1 = attList.find(item => item.att_type_id === '1');
- //拿到所有签退数据后,用pop取最后一个
- const time2 = attList.filter(item => item.att_type_id === '2').pop();
- console.log('time2', time2);
- if (time1 !== undefined) {
- // console.log('getTime1',time1);
- signInTime.value = time1.att_time.split(' ')[1];
- signName.value = '下班签退';
- if (Array.isArray(config.lateTimeRange) && isTimeInRange(signInTime.value, config
- .lateTimeRange[0], '23:59:59')) {
- isSignInStatusDisabled.value = false; //迟到
- }
- } else {
- signName.value = '上班签到';
- }
- if (time2 !== undefined) {
- signOutTime.value = time2.att_time.split(' ')[1];
- if (Array.isArray(config.signOutTimeRange) && isTimeInRange(signOutTime.value, "00:00:00",
- config.signOutTimeRange[0])) {
- isSignOutStatusDisabled.value = false; //早退
- } else {
- isSignOutStatusDisabled.value = true; //隐藏早退状态
- }
- }
- }
- })
- }
- //上班卡或下班卡
- function signInOrOut() {
- if ('上班签到' == signName.value) {
- signIn();
- } else {
- signOut();
- }
- }
- function signIn() {
- const now = getNowTime();
- //判断打卡时间是否符合
- if (!isTimeInRange(now, ...config.signInTimeRange)) {
- $modal.msg('不在签到时间8:30--9:30内,请前往补卡')
- return;
- }
- // attType.value=1;
- const signIn = 1;
- getAddress().then(() => {
- clockIn(signIn);
- });
- };
- // 下班签退
- function signOut() {
- const now = getNowTime();
- const signOut = 2;
- //判断打卡时间是否符合
- console.log('now', now);
- if (!isTimeInRange(now, ...config.signOutTimeRange)) {
- $modal.confirm('当前非正常签退时间,是否继续?').then(res => {
- if (res) {
- getAddress().then(() => {
- clockIn(signOut); // 执行打卡并获取结果
- });
- }
- })
- } else {
- getAddress().then(() => {
- clockIn(signOut);
- });
- }
- };
- //获取当前时间
- function getNowTime() {
- return new Date().toLocaleTimeString('en-US', {
- hour12: false
- }).substring(0, 8)
- }
- //判断时间是否在区间内
- function isTimeInRange(time, startTime, endTime) {
- // 将时间字符串转换为Date对象
- const timeObj = new Date('1970-01-01T' + time + 'Z');
- const startObj = new Date('1970-01-01T' + startTime + 'Z');
- const endObj = new Date('1970-01-01T' + endTime + 'Z');
- // 比较时间
- return timeObj >= startObj && timeObj <= endObj;
- }
- // 地图配置信息
- // const mapKey = config.mapKey; // 地图API密钥
- const mapType = ref('tmap'); // 地图类型
- const address = ref(''); // 初始化地址
- // 打卡定位信息
- const longitude = ref(0); // 经度
- const latitude = ref(0); // 纬度
- // 标记信息
- const marker = reactive({
- id: 1,
- latitude: 25.958812,
- longitude: 119.213036,
- width: 50, // 标记宽度
- height: 50, // 标记高度
- title: '宇光同行' // 标记标题
- });
- // 获取当前定位经纬度
- function getlocation() {
- return new Promise((resolve, reject) => {
- //判断用户是否打开位置权限
- uni.getSetting({
- success(res) {
- // 如果用户未授权
- if (!res.authSetting['scope.userLocation']) {
- $modal.confirm('需要您授权获取地理位置信息').then(res => {
- if (res) {
- // 打开权限设置页面
- uni.openSetting({
- success: (settingData) => {
- if (settingData.authSetting[
- 'scope.userLocation']) {
- $modal.msg('授权后请重新打开此页面')
- // reject("用户未授权");
- }
- }
- });
- }
- })
- .catch(err => {
- //用户点击取消
- if (!err) {
- uni.showToast({
- title: '获取地理位置授权失败',
- icon: 'none',
- success: () => {
- // 返回上一页
- setTimeout(() => {
- $tab.navigateBack()
- }, 1000);
- }
- });
- // reject("用户未授权");
- }
- })
- } else {
- // 已授权,获取位置
- fetchLocation(resolve, reject);
- }
- },
- fail(err) {
- reject(err); // 拒绝 Promise
- }
- });
- });
- }
- // 封装获取位置的函数
- function fetchLocation(resolve, reject) {
- wx.getLocation({
- success: (res) => {
- longitude.value = res.longitude; // 保存经度
- latitude.value = res.latitude; // 保存纬度
- resolve(); // 解析 Promise
- },
- fail: (err) => {
- if (err.errMsg.includes("频繁调用")) {
- $modal.msg('请勿频繁调用');
- // reject("频繁调用错误");
- return;
- }
- console.log('getLocationErr', err);
- reject(err); // 拒绝 Promise
- },
- });
- }
- // 获取当前位置地址
- function getAddress() {
- // getlocation()
- // .then(() => {
- // tranLocationToAddress(); // 执行地址转换
- // })
- // .catch(err => {
- // console.error('获取地址失败', err);
- // });
- return new Promise((resolve, reject) => {
- getlocation()
- .then(() => {
- tranLocationToAddress(); // 执行地址转换
- resolve(); // 地址获取成功
- })
- .catch(err => {
- // console.error('获取地址失败', err);
- reject(err); // 地址获取失败
- });
- });
- }
- // 经纬度转地址
- function tranLocationToAddress() {
- let locationStr = latitude.value + ',' + longitude.value; // 组合经纬度
- tranAddress(locationStr).then(res => {
- // console.log('地址转换请求成功', res);
- address.value = res.result.address; // 保存地址
- })
- .catch(err => {
- console('地址转换请求失败', err); // 请求错误处理
- })
- }
- // 多边形区域设置
- const polygons = reactive([{
- points: [{
- latitude: 25.9591401,
- longitude: 119.21292356
- },
- {
- latitude: 25.95828592,
- longitude: 119.21261955
- },
- {
- latitude: 25.9576709,
- longitude: 119.21458294
- },
- {
- latitude: 25.95845106,
- longitude: 119.21486162
- },
- {
- latitude: 25.9591401,
- longitude: 119.21292356
- }
- ],
- strokeWidth: 1, // 边框宽度
- strokeColor: "#ff000066", // 边框颜色
- fillColor: "#ff000016", // 填充颜色
- }]);
- // 打卡
- function clockIn(attType) {
- // 发起打卡请求相关业务逻辑
- //判断是否已经打过卡
- if (isClockIn(attType)) {
- return;
- }
- var now = new Date();
- // 使用toISOString()获取一个ISO格式的字符串,然后替换T为空格,并去除最后的Z(表示UTC时间)
- var formatted = now.toISOString().replace('T', ' ').replace('Z', '');
- var localString = new Date(formatted + '-08:00').toISOString().replace('T', ' ').replace('Z', '');
- // console.log('nowtime',formatted,localString);
- const params = {
- user_name: thisUser.userName,
- user_id: thisUser.useId,
- kaoqin_type: attType,
- now_date: localString,
- longitude: longitude.value,
- latitude: latitude.value,
- address: address.value,
- unitId: thisUser.unitId
- };
- createAttendance(params).then(res => {
- // console.log('createAttendance',res);
- if ("success" == res.returnMsg) {
- uni.showToast({
- title: "打卡成功",
- icon: 'none'
- });
- getTodayAtt(); //更新今日考勤数据
- return true;
- } else {
- uni.showToast({
- title: "未在指定范围,打卡失败",
- icon: 'none'
- });
- return false;
- }
- })
- // const _polygons = polygons.map((polygon) => {
- // return polygon.points.map((i) => [
- // Number(i.longitude),
- // Number(i.latitude),
- // ]);
- // });
- // const _point = point([longitude.value, latitude.value]); // 用当前坐标创建点
- // const _polygon = polygon(_polygons); // 创建多边形
- // const f = booleanPointInPolygon(_point, _polygon); // 判断点是否在多边形内
- }
- //判断是否已经打卡
- function isClockIn(attType) {
- var attTypeData = '';
- switch (attType) {
- case 1:
- attTypeData = signInTime.value;
- break;
- case 2:
- break;
- }
- console.log('attTypeData', attTypeData);
- if ('' !== attTypeData) {
- uni.showToast({
- title: "请勿重复打卡",
- icon: 'none'
- });
- return true;
- }
- return false;
- }
- </script>
- <style>
- @import "@/static/font/ygoa/iconfont.css";
- .ygoa-icon {
- margin-right: 20rpx;
- font-size: 50rpx;
- }
- .container {
- display: flex;
- flex-direction: column;
- align-items: center;
- padding: 20rpx;
- }
- .header {
- width: 100%;
- height: 200rpx;
- background-color: #f8f8f8;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- }
- .day {
- font-size: 24px;
- color: #333;
- /* font-weight: bold; */
- }
- .date {
- font-size: 16px;
- color: #666;
- }
- .nowTime {
- font-size: 16px;
- color: #666;
- }
- .record {
- width: 100%;
- margin-top: 20rpx;
- border-top: 1px solid #ddd;
- border-bottom: 1px solid #ddd;
- padding: 0 15rpx;
- }
- .record-item {
- display: flex;
- align-items: center;
- height: 100rpx;
- border-bottom: 1px solid #eee;
- }
- .icon {
- width: 50rpx;
- height: 50rpx;
- margin-right: 10rpx;
- }
- .title {
- font-size: 28rpx;
- }
- .time {
- font-size: 24rpx;
- color: #999;
- margin-left: auto;
- }
- .signStatus {
- font-size: 24rpx;
- color: orange;
- /* margin-left: auto; */
- }
- .map {
- width: 100%;
- height: 500rpx;
- margin-top: 20rpx;
- }
- .footer {
- width: 100%;
- margin-top: 20rpx;
- display: flex;
- justify-content: space-around;
- }
- .footer button {
- width: 100%;
- }
- </style>
|