移动端考勤管理
parent
6fce3ed81b
commit
7b8ee3dc75
|
@ -2058,4 +2058,10 @@ swiper-item video {
|
||||||
|
|
||||||
.txtb {
|
.txtb {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.txt-blue{
|
||||||
|
color: #728ce3;
|
||||||
|
}
|
||||||
|
.inline-block{
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
|
@ -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 |
|
@ -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 |
|
@ -14,6 +14,7 @@ Page({
|
||||||
initData: {},
|
initData: {},
|
||||||
type: "",
|
type: "",
|
||||||
cfgData: null,
|
cfgData: null,
|
||||||
|
arrSel: "in",
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,6 +27,11 @@ Page({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const proUserInfo = getUserInfo();
|
const proUserInfo = getUserInfo();
|
||||||
|
|
||||||
|
// 根据当前时间设置arrSel的值:14点前为in,14点后为out
|
||||||
|
const now = new Date();
|
||||||
|
const arrSel = now.getHours() < 14 ? "in" : "out";
|
||||||
|
|
||||||
this.setData({
|
this.setData({
|
||||||
projectUserInfo: proUserInfo.projectUserInfo,
|
projectUserInfo: proUserInfo.projectUserInfo,
|
||||||
projectId: app.globalData.useProjectId,
|
projectId: app.globalData.useProjectId,
|
||||||
|
@ -35,6 +41,7 @@ Page({
|
||||||
text: app.globalData.useProjectName,
|
text: app.globalData.useProjectName,
|
||||||
},
|
},
|
||||||
type: options.type,
|
type: options.type,
|
||||||
|
arrSel: arrSel,
|
||||||
});
|
});
|
||||||
if (options.id) {
|
if (options.id) {
|
||||||
this.loadData(options.id);
|
this.loadData(options.id);
|
||||||
|
@ -42,53 +49,25 @@ Page({
|
||||||
app.toast("参数错误!");
|
app.toast("参数错误!");
|
||||||
this.returnToPage();
|
this.returnToPage();
|
||||||
}
|
}
|
||||||
|
//todo 14点前 arrSel=in,之后arrSel=out
|
||||||
},
|
},
|
||||||
loadData(id) {
|
loadData(id) {
|
||||||
getMobileAttendanceConfigById(id).then((res) => {
|
try {
|
||||||
if (res.code == 200) {
|
let cfgData = wx.getStorageSync("editAttCfg");
|
||||||
|
if (cfgData) {
|
||||||
this.setData({
|
this.setData({
|
||||||
cfgData: res.data,
|
cfgData: cfgData,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
app.toast("参数错误!");
|
app.toast("参数错误!");
|
||||||
this.returnToPage();
|
this.returnToPage();
|
||||||
}
|
}
|
||||||
});
|
} catch (e) {
|
||||||
|
app.toast("参数错误!");
|
||||||
|
this.returnToPage();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* 生命周期函数--监听页面初次渲染完成
|
|
||||||
*/
|
|
||||||
onReady() {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生命周期函数--监听页面显示
|
|
||||||
*/
|
|
||||||
onShow() {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生命周期函数--监听页面隐藏
|
|
||||||
*/
|
|
||||||
onHide() {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生命周期函数--监听页面卸载
|
|
||||||
*/
|
|
||||||
onUnload() {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 页面相关事件处理函数--监听用户下拉动作
|
|
||||||
*/
|
|
||||||
onPullDownRefresh() {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 页面上拉触底事件的处理函数
|
|
||||||
*/
|
|
||||||
onReachBottom() {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户点击右上角分享
|
|
||||||
*/
|
|
||||||
onShareAppMessage() {},
|
|
||||||
onProjectSelect(e) {
|
onProjectSelect(e) {
|
||||||
let projectId = e.detail.id;
|
let projectId = e.detail.id;
|
||||||
let projectName = e.detail.text;
|
let projectName = e.detail.text;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
{
|
{
|
||||||
"usingComponents": {},
|
"usingComponents": {
|
||||||
|
"svg-icon": "/pageage/components/svg-icon/index"
|
||||||
|
},
|
||||||
"navigationStyle": "custom",
|
"navigationStyle": "custom",
|
||||||
"styleIsolation": "apply-shared",
|
"styleIsolation": "apply-shared",
|
||||||
"backgroundColor": "#191d28"
|
"backgroundColor": "#191d28"
|
||||||
|
|
|
@ -9,11 +9,28 @@
|
||||||
</view>
|
</view>
|
||||||
</van-col>
|
</van-col>
|
||||||
<van-col span="15">
|
<van-col span="15">
|
||||||
<view class="header_name">移动考勤配置详情</view>
|
<view class="header_name">创建移动考勤</view>
|
||||||
</van-col>
|
</van-col>
|
||||||
</van-row>
|
</van-row>
|
||||||
</view>
|
</view>
|
||||||
</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>
|
<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>
|
</scroll-view>
|
|
@ -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;
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import { getToken, getUserInfo } from "../../../../utils/auth.js";
|
import { getToken, getUserInfo } from "../../../../utils/auth.js";
|
||||||
import { getMobileAttendanceConfig } from "../../../../api/project.js";
|
import { getMobileAttendanceConfig } from "../../../../api/project.js";
|
||||||
|
import { calculateDistance } from "../../../../utils/location.js";
|
||||||
|
|
||||||
const app = getApp();
|
const app = getApp();
|
||||||
|
|
||||||
|
@ -8,13 +9,16 @@ Page({
|
||||||
* 页面的初始数据
|
* 页面的初始数据
|
||||||
*/
|
*/
|
||||||
data: {
|
data: {
|
||||||
projectUserInfo: {},
|
|
||||||
projectUserInfo: {},
|
projectUserInfo: {},
|
||||||
projectId: "",
|
projectId: "",
|
||||||
projectName: "",
|
projectName: "",
|
||||||
initData: {},
|
initData: {},
|
||||||
total: 0,
|
total: 0,
|
||||||
listData: [],
|
listData: [],
|
||||||
|
userLongitude: undefined,
|
||||||
|
userLatitude: undefined,
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,8 +40,31 @@ Page({
|
||||||
text: app.globalData.useProjectName,
|
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() {
|
getListData() {
|
||||||
let postData = {
|
let postData = {
|
||||||
pageNum: this.data.pageNum,
|
pageNum: this.data.pageNum,
|
||||||
|
@ -47,30 +74,63 @@ Page({
|
||||||
};
|
};
|
||||||
getMobileAttendanceConfig(postData).then((res) => {
|
getMobileAttendanceConfig(postData).then((res) => {
|
||||||
if (res.code == 200) {
|
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({
|
this.setData({
|
||||||
total: res.total,
|
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) {
|
onProjectSelect(e) {
|
||||||
let projectId = e.detail.id;
|
let projectId = e.detail.id;
|
||||||
let projectName = e.detail.text;
|
let projectName = e.detail.text;
|
||||||
app.globalData.useProjectId = projectId;
|
app.globalData.useProjectId = projectId;
|
||||||
app.globalData.useProjectName = projectName;
|
app.globalData.useProjectName = projectName;
|
||||||
this.onLoad();
|
// 项目切换后重新获取用户位置和列表数据
|
||||||
|
this.getUserLocation();
|
||||||
},
|
},
|
||||||
returnToPage: function () {
|
returnToPage: function () {
|
||||||
/*关闭当前页面,跳转到其它页面。*/
|
/*关闭当前页面,跳转到其它页面。*/
|
||||||
if (wx.getStorageSync("nav-menu") == "xmgl") {
|
if (wx.getStorageSync("nav-menu") == "xmgl") {
|
||||||
wx.redirectTo({
|
wx.redirectTo({
|
||||||
url: "../../project_more/index",
|
url: "../../../project_more/index",
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
wx.redirectTo({
|
wx.redirectTo({
|
||||||
url: "../../project_quality/index",
|
url: "../../../project_quality/index",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<wxs module="format" src="/utils/format.wxs"></wxs>
|
<wxs module="format" src="/utils/format.wxs"></wxs>
|
||||||
|
<wxs module="distance" src="/utils/distance.wxs"></wxs>
|
||||||
|
|
||||||
<view class="header_title">
|
<view class="header_title">
|
||||||
<view class="header_title_row">
|
<view class="header_title_row">
|
||||||
|
@ -15,7 +16,7 @@
|
||||||
</view>
|
</view>
|
||||||
</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>
|
<project-select init="{{ initData }}" bindchange="onProjectSelect" id="projectSel"></project-select>
|
||||||
|
|
||||||
<view class="modify_video_nav" style="margin-top: 5rpx;">
|
<view class="modify_video_nav" style="margin-top: 5rpx;">
|
||||||
|
@ -39,12 +40,16 @@
|
||||||
<view class="inspect_list_title_number">{{
|
<view class="inspect_list_title_number">{{
|
||||||
index < 10 ? "0" + (index + 1) : index + 1 }}</view>
|
index < 10 ? "0" + (index + 1) : index + 1 }}</view>
|
||||||
<view class="module_title">
|
<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>
|
</view>
|
||||||
|
|
||||||
<view class="inspect_list_content">
|
<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-right">
|
||||||
<view class="content-row first">
|
<view class="content-row first">
|
||||||
考勤标题:
|
考勤标题:
|
||||||
|
@ -62,6 +67,11 @@
|
||||||
考勤位置:
|
考勤位置:
|
||||||
{{item.address}}
|
{{item.address}}
|
||||||
</view>
|
</view>
|
||||||
|
<view class="content-row">
|
||||||
|
距离:
|
||||||
|
<view class="inline-block"><rich-text nodes="{{distance.formatDistance(item.distance)}}"></rich-text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
|
|
@ -25,4 +25,8 @@
|
||||||
.left-img{
|
.left-img{
|
||||||
position: relative;
|
position: relative;
|
||||||
top:36rpx;
|
top:36rpx;
|
||||||
|
}
|
||||||
|
.module_title{
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: right;
|
||||||
}
|
}
|
|
@ -108,6 +108,9 @@ Page({
|
||||||
cfgData: cfgData,
|
cfgData: cfgData,
|
||||||
form: form,
|
form: form,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
app.toast("参数错误!");
|
||||||
|
this.returnToPage();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
app.toast("参数错误!");
|
app.toast("参数错误!");
|
||||||
|
@ -560,6 +563,8 @@ Page({
|
||||||
ajax.then((res) => {
|
ajax.then((res) => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
app.toast("保存成功!");
|
app.toast("保存成功!");
|
||||||
|
// 清除editAttCfg
|
||||||
|
wx.removeStorageSync("editAttCfg");
|
||||||
this.doBack(true);
|
this.doBack(true);
|
||||||
} else {
|
} else {
|
||||||
app.toast("保存失败,请重试");
|
app.toast("保存失败,请重试");
|
||||||
|
@ -665,4 +670,12 @@ Page({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命周期函数--监听页面卸载
|
||||||
|
*/
|
||||||
|
onUnload() {
|
||||||
|
// 页面卸载时清除editAttCfg
|
||||||
|
wx.removeStorageSync("editAttCfg");
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -64,7 +64,7 @@
|
||||||
<view class="inspect_info_title">指定考勤班组</view>
|
<view class="inspect_info_title">指定考勤班组</view>
|
||||||
<view class="inspect_info_content">
|
<view class="inspect_info_content">
|
||||||
<select-group-person rectifierData="{{subGroupList}}" multiple="{{true}}" bindselected="onAddGroupList"
|
<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>
|
</select-group-person>
|
||||||
</view>
|
</view>
|
||||||
<view wx:if="{{form.subGroup && form.subGroup.length>0}}">
|
<view wx:if="{{form.subGroup && form.subGroup.length>0}}">
|
||||||
|
|
|
@ -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,
|
||||||
|
};
|
|
@ -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,
|
||||||
|
};
|
Loading…
Reference in New Issue