移动端考勤管理

dev_xd
lj7788@126.com 2025-09-02 17:55:02 +08:00
parent 6fce3ed81b
commit 7b8ee3dc75
14 changed files with 231 additions and 50 deletions

View File

@ -2058,4 +2058,10 @@ swiper-item video {
.txtb {
font-weight: 600;
}
.txt-blue{
color: #728ce3;
}
.inline-block{
display: inline-block;
}

View File

@ -0,0 +1 @@
<svg class="icon" style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11345"><path d="M512 512m-512 0a512 512 0 1 0 1024 0 512 512 0 1 0-1024 0Z" fill="#07C160" p-id="11346"></path><path d="M234.549 484.627l161.554 125.136 402.358-360.365s27.008-23.954 50.566-5.27c6.999 5.653 15.081 21.559-3.154 46.567L425.871 769.106s-32.232 42.83-70.477-0.479L174.126 530.619s-21.488-32.194 5.421-51.549c9.069-6.42 29.768-16.481 55.002 5.557z" fill="#FFFFFF" p-id="11347"></path></svg>

After

Width:  |  Height:  |  Size: 590 B

View File

@ -0,0 +1 @@
<svg class="icon" style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8413"><path d="M893.44 341.12c-1.28-6.4-3.84-12.16-8.96-17.28l-185.6-184.96c-14.08-13.44-35.84-13.44-49.92 0-14.08 13.44-14.08 35.84 0 49.92l133.76 133.12L158.72 321.92C142.08 321.92 128 336 128 353.28S142.08 384 158.72 384l624 0-133.76 133.12c-14.08 13.44-14.08 35.84 0 49.92 14.08 13.44 35.84 13.44 49.92 0l185.6-184.96c5.12-5.12 7.68-10.88 8.96-17.28C895.36 361.6 896 357.12 896 353.28S895.36 344.32 893.44 341.12zM801.28 704 177.28 704l133.76-133.12c14.08-13.44 14.08-35.84 0-49.92-14.08-13.44-35.84-13.44-49.92 0l-185.6 184.96C70.4 710.4 67.84 716.8 66.56 722.56 64.64 726.4 64 730.88 64 734.72s0.64 8.32 2.56 12.16c1.28 6.4 3.84 12.16 8.96 17.28l185.6 184.96c14.08 13.44 35.84 13.44 49.92 0 14.08-13.44 14.08-35.84 0-49.92l-133.76-133.12 624 0c17.28 0 30.72-14.08 30.72-30.72S817.92 704 801.28 704z" p-id="8414" fill="#ccc"></path></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -14,6 +14,7 @@ Page({
initData: {},
type: "",
cfgData: null,
arrSel: "in",
},
/**
@ -26,6 +27,11 @@ Page({
});
}
const proUserInfo = getUserInfo();
// 根据当前时间设置arrSel的值14点前为in14点后为out
const now = new Date();
const arrSel = now.getHours() < 14 ? "in" : "out";
this.setData({
projectUserInfo: proUserInfo.projectUserInfo,
projectId: app.globalData.useProjectId,
@ -35,6 +41,7 @@ Page({
text: app.globalData.useProjectName,
},
type: options.type,
arrSel: arrSel,
});
if (options.id) {
this.loadData(options.id);
@ -42,53 +49,25 @@ Page({
app.toast("参数错误!");
this.returnToPage();
}
//todo 14点前 arrSel=in,之后arrSel=out
},
loadData(id) {
getMobileAttendanceConfigById(id).then((res) => {
if (res.code == 200) {
try {
let cfgData = wx.getStorageSync("editAttCfg");
if (cfgData) {
this.setData({
cfgData: res.data,
cfgData: cfgData,
});
} else {
app.toast("参数错误!");
this.returnToPage();
}
});
} catch (e) {
app.toast("参数错误!");
this.returnToPage();
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {},
/**
* 生命周期函数--监听页面显示
*/
onShow() {},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {},
onProjectSelect(e) {
let projectId = e.detail.id;
let projectName = e.detail.text;

View File

@ -1,5 +1,7 @@
{
"usingComponents": {},
"usingComponents": {
"svg-icon": "/pageage/components/svg-icon/index"
},
"navigationStyle": "custom",
"styleIsolation": "apply-shared",
"backgroundColor": "#191d28"

View File

@ -9,11 +9,28 @@
</view>
</van-col>
<van-col span="15">
<view class="header_name">移动考勤配置详情</view>
<view class="header_name">创建移动考勤</view>
</van-col>
</van-row>
</view>
</view>
<scroll-view class="max_content_scroll" type="list" scroll-y bindscrolltolower="onScrollToLower">
<project-select init="{{ initData }}" bindchange="onProjectSelect" id="projectSel"></project-select>
<view class="content_box">
<view class="content_box_title">
<svg-icon src="switch" color="#9966CC" size="40" class="inline-block"/>
<text class="txt-blue">请选择考勤方向</text>
</view>
<view class="content_box_content arrow_content">
<view class="arrow_box {{arrSel=='in'?'is-active':''}}" bindtap="doSelectArr('in')">
<svg-icon src="select" wx:if="{{arrSel=='in'}}" colors="{{['#07C160','#fff']}}" size="40" class="img-sel"/>
<view>上班考勤打卡</view>
</view>
<view class="arrow_box {{arrSel=='out'?'is-active':''}}" bindtap="doSelectArr('out')">
<svg-icon src="select" wx:if="{{arrSel=='out'}}" colors="{{['#07C160','#fff']}}" size="40" class="img-sel"/>
<view>下班考勤打卡</view>
</view>
</view>
</view>
</scroll-view>

View File

@ -1 +1,31 @@
/* pageage/mobile_attendance/attendance_config/info/index.wxss */
.content_box{
padding:20rpx 40rpx;
}
.content_box_title{
display: flex;
align-items: center;
}
.arrow_content{
display: flex;
}
.arrow_box{
background-color: #ccc;
width:45%;
margin:0 5%;
position: relative;
display: flex;
align-items: center;
}
.arrow_box .img-sel{
position: absolute;
left: 50%;
margin-left:-20rpx;
top: 20rpx;
}
.arrow_box view{
height: 120rpx;
line-height: 120rpx;
}

View File

@ -1,5 +1,6 @@
import { getToken, getUserInfo } from "../../../../utils/auth.js";
import { getMobileAttendanceConfig } from "../../../../api/project.js";
import { calculateDistance } from "../../../../utils/location.js";
const app = getApp();
@ -8,13 +9,16 @@ Page({
* 页面的初始数据
*/
data: {
projectUserInfo: {},
projectUserInfo: {},
projectId: "",
projectName: "",
initData: {},
total: 0,
listData: [],
userLongitude: undefined,
userLatitude: undefined,
pageNum: 1,
pageSize: 10,
},
/**
@ -36,8 +40,31 @@ Page({
text: app.globalData.useProjectName,
},
});
this.getListData();
// 先获取用户位置,再获取列表数据
this.getUserLocation();
},
/**
* 获取用户当前位置
*/
getUserLocation() {
wx.getLocation({
type: "gcj02", // 使用国测局坐标
success: (res) => {
this.setData({
userLongitude: res.longitude,
userLatitude: res.latitude,
});
this.getListData();
},
fail: (err) => {
console.error("获取位置失败", err);
// 即使获取位置失败,也继续加载列表数据
this.getListData();
},
});
},
getListData() {
let postData = {
pageNum: this.data.pageNum,
@ -47,30 +74,63 @@ Page({
};
getMobileAttendanceConfig(postData).then((res) => {
if (res.code == 200) {
let tmps = (res.rows || []).map((it) => {
// 如果有用户位置信息,则计算距离,否则设置为-1
if (
this.data.userLongitude !== undefined &&
this.data.userLatitude !== undefined
) {
it.distance = calculateDistance(
this.data.userLongitude,
this.data.userLatitude,
it.longitude,
it.latitude
);
} else {
it.distance = -1; // 无法计算距离
}
return it;
});
this.setData({
total: res.total,
listData: this.data.listData.concat(res.rows),
listData: this.data.listData.concat(tmps),
});
}
});
},
getInfo(e) {
let cfgData = e.currentTarget.dataset.set;
wx.setStorageSync("editAttCfg", cfgData);
wx.redirectTo({
url: `../add/index?type=att&id=${cfgData.id}`,
});
},
getDistance(longitude, latitude) {
// 现在这个方法不再需要因为距离计算已经在getListData中完成
// 但为了保持接口兼容性,如果需要可以返回已计算的距离
const item = this.data.listData.find(
(it) => it.longitude === longitude && it.latitude === latitude
);
return item ? item.distance : -1;
},
//项目切换 返回值
onProjectSelect(e) {
let projectId = e.detail.id;
let projectName = e.detail.text;
app.globalData.useProjectId = projectId;
app.globalData.useProjectName = projectName;
this.onLoad();
// 项目切换后重新获取用户位置和列表数据
this.getUserLocation();
},
returnToPage: function () {
/*关闭当前页面,跳转到其它页面。*/
if (wx.getStorageSync("nav-menu") == "xmgl") {
wx.redirectTo({
url: "../../project_more/index",
url: "../../../project_more/index",
});
} else {
wx.redirectTo({
url: "../../project_quality/index",
url: "../../../project_quality/index",
});
}
},

View File

@ -1,4 +1,5 @@
<wxs module="format" src="/utils/format.wxs"></wxs>
<wxs module="distance" src="/utils/distance.wxs"></wxs>
<view class="header_title">
<view class="header_title_row">
@ -15,7 +16,7 @@
</view>
</view>
<scroll-view class="max_content_scroll" type="list" scroll-y bindscrolltolower="onScrollToLower">
<scroll-view class="max_content_scroll" type="list" scroll-y bindscrolltolower="onScrollToLower">
<project-select init="{{ initData }}" bindchange="onProjectSelect" id="projectSel"></project-select>
<view class="modify_video_nav" style="margin-top: 5rpx;">
@ -39,12 +40,16 @@
<view class="inspect_list_title_number">{{
index < 10 ? "0" + (index + 1) : index + 1 }}</view>
<view class="module_title">
<view class="content-distance">
距离:
<view class="inline-block"><rich-text nodes="{{distance.formatDistance(item.distance)}}"></rich-text>
</view>
</view>
</view>
</view>
<view class="inspect_list_content">
<svg-icon src="position" color="#45affb" size="120" class="left-img"/>
<svg-icon src="position" color="#45affb" size="120" class="left-img" />
<view class="content-right">
<view class="content-row first">
考勤标题:
@ -62,6 +67,11 @@
考勤位置:
{{item.address}}
</view>
<view class="content-row">
距离:
<view class="inline-block"><rich-text nodes="{{distance.formatDistance(item.distance)}}"></rich-text>
</view>
</view>
</view>
</view>

View File

@ -25,4 +25,8 @@
.left-img{
position: relative;
top:36rpx;
}
.module_title{
flex-grow: 1;
text-align: right;
}

View File

@ -108,6 +108,9 @@ Page({
cfgData: cfgData,
form: form,
});
} else {
app.toast("参数错误!");
this.returnToPage();
}
} catch (e) {
app.toast("参数错误!");
@ -560,6 +563,8 @@ Page({
ajax.then((res) => {
if (res.code == 200) {
app.toast("保存成功!");
// 清除editAttCfg
wx.removeStorageSync("editAttCfg");
this.doBack(true);
} else {
app.toast("保存失败,请重试");
@ -665,4 +670,12 @@ Page({
});
}
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
// 页面卸载时清除editAttCfg
wx.removeStorageSync("editAttCfg");
},
});

View File

@ -64,7 +64,7 @@
<view class="inspect_info_title">指定考勤班组</view>
<view class="inspect_info_content">
<select-group-person rectifierData="{{subGroupList}}" multiple="{{true}}" bindselected="onAddGroupList"
index="3" :title="{{form.groupNames?form.groupNames:'请选择考勤班组'}}" choose="{{form.groupNames}}">
index="3" title="{{form.groupNames?form.groupNames:'请选择考勤班组'}}" choose="{{form.groupNames}}">
</select-group-person>
</view>
<view wx:if="{{form.subGroup && form.subGroup.length>0}}">

View File

@ -0,0 +1,24 @@
var formatDistance = function (distance) {
if (distance < 0) {
return "无法计算";
}
if (distance > 1000) {
// 保留两位小数
var km = (distance / 1000).toString();
var dotIndex = km.indexOf(".");
if (dotIndex !== -1) {
var decimalPart = km.substring(dotIndex + 1);
if (decimalPart.length > 2) {
km = km.substring(0, dotIndex + 3);
}
}
return km + ' <span class="txt-blue">km</span>';
} else {
return distance + ' <span class="txt-blue">m</span>';
}
};
module.exports = {
formatDistance: formatDistance,
};

View File

@ -0,0 +1,34 @@
/**
* 计算两点间距离单位
* @param {number} lon1 - 第一个点的经度
* @param {number} lat1 - 第一个点的纬度
* @param {number} lon2 - 第二个点的经度
* @param {number} lat2 - 第二个点的纬度
* @returns {number} 两点间距离
*/
function calculateDistance(lon1, lat1, lon2, lat2) {
// 将角度转换为弧度
const radLat1 = (lat1 * Math.PI) / 180.0;
const radLat2 = (lat2 * Math.PI) / 180.0;
const deltaRadLat = radLat1 - radLat2;
const deltaRadLon = ((lon1 - lon2) * Math.PI) / 180.0;
// Haversine公式计算距离
const a =
Math.sin(deltaRadLat / 2) * Math.sin(deltaRadLat / 2) +
Math.cos(radLat1) *
Math.cos(radLat2) *
Math.sin(deltaRadLon / 2) *
Math.sin(deltaRadLon / 2);
const b = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
// 地球半径(米)
const earthRadius = 6371000;
const distance = earthRadius * b;
return Math.round(distance);
}
module.exports = {
calculateDistance: calculateDistance,
};