修改签到打卡

This commit is contained in:
jiangyanshan
2025-12-17 14:17:10 +08:00
parent fc8a324a9f
commit 7b0a2472a3
2 changed files with 497 additions and 292 deletions

View File

@@ -10,23 +10,34 @@ export function addStartMap(data) {
});
}
//出差打卡接口
export function businessTripClockIn(data) {
return request.post({
url: '/crm/app/appVisistMap/businessTripClockIn',
data
},{isTransformResponse:false});
}
// //出差打卡接口
// export function businessTripClockIn(data) {
// return request.post({
// url: '/crm/app/appVisistMap/businessTripClockIn',
// data
// },{isTransformResponse:false});
// }
// //新增地图开始打卡接口
// export function addStartMapForClockIn(data) {
// return request.post({
// url: "/crm/app/appVisistMap/StartaddForClockIn",
// data,
// },{
// isTransformResponse:false
// });
// }
//出差打卡接口
export function businessTripClockIn(data) {
return request('/app/appVisistMap/businessTripClockIn', data, 'POST', 'application/json;charset=UTF-8');
}
//新增地图开始打卡接口
export function addStartMapForClockIn(data) {
return request('/app/appVisistMap/StartaddForClockIn', data, 'POST', 'application/json;charset=UTF-8');
}
//新增地图开始打卡接口
export function addStartMapForClockIn(data) {
return request.post({
url: "/crm/app/appVisistMap/StartaddForClockIn",
data,
},{
isTransformResponse:false
});
}
//打卡信息查看
export function CheckInInformationViewing(data) {

View File

@@ -1,183 +1,228 @@
<template>
<view class="con-body">
<view class="con-bg">
<!-- 头部 -->
<customHeader ref="customHeaderRef" :title="'签到打卡'" :leftFlag="true" :rightFlag="false"></customHeader>
<view class="content">
<view class="pub-add-box1" @click="addInsertMapForSignIn">
<view style="color: aliceblue; font-size: 22px;">签到</view>
</view>
<!-- 高度来避免头部遮挡 -->
<view class="top-height"></view>
<view class="pub-add-box" @click="addInsertMapClockIn">
<view style="color: aliceblue; font-size: 22px;">打卡</view>
</view>
<!-- 正文内容 -->
<view class="white-bg">
<image src="../../../../static/images/business/btn-qd.png" class="btn-image" @click="handleCheckIn"/>
<!-- <image src="../../../../static/images/business/btn-dk.png" class="btn-image" @click="handleClockIn"/>-->
<image src="../../../../static/images/business/btn-dk.png" class="btn-image" @click="handleClick"/>
<view class="check-desc">
业务人员可通过
<text class="font-orange">签到</text>
<text
class="font-blue">打卡
</text>
进行行为记录该时间会和走访报告中的时间进行关联便于查看
<!-- 自定义打卡确认弹窗 -->
<view class="clock-in-modal" v-if="showClockInModal" @click="cancelClockIn">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">请选择工作状态</text>
</view>
<view class="modal-body">
<text class="address-text">{{ clockInAddress }}</text>
</view>
<view class="modal-footer">
<view class="btn-group">
<button class="cancel-btn" @click="businessTripClockIn">出差</button>
<button class="confirm-btn" @click="confirmClockIn">未出差</button>
</view>
</view>
</view>
</view>
</view>
</view>
<closeable-modal v-model="modalVisible"
title="确认在此处打卡?"
:content="form.addressForStart"
closeTip="轻触空白处关闭"
cancelText="出差"
confirmText="打卡"
contentAlign="center"
@confirm="handleConfirm"
@cancel="handleCancel"/>
<!-- 打卡遮罩层 -->
<!-- <view class="check-con" v-if="checkFlag">
<view class="check-in">
<view class="check-tip">打卡</view>
<view class="check-title">确定要在此处打卡吗</view>
<view class="check-location">
<uni-icons type="location-filled" size="30" color="#0395E0"></uni-icons> 亚洲金融大厦
</view>
<view class="check-address">北京市朝阳区天辰东路1号院</view>
<view class="check-footer">
<button class="btn-default" type="default" @click="handleCancel" size="mini"> </button>
<button class="btn-primary" type="primary" @click="handleSubmit" size="mini"> </button>
</view>
</view>
</view> -->
</view>
</template>
<script setup>
import {ref, onMounted, reactive} from 'vue'
import customHeader from '@/components/customHeader.vue'
import {addStartMapForClockIn, businessTripClockIn} from '../../../../api/crm/activity/map';
import CloseableModal from "@/components/closeableModal.vue";
import {MapApiConfig} from "../../../../constants/mapApiConstants";
<script>
import { addStartMapForClockIn, businessTripClockIn } from '@/api/crm/activity/map.js';
let form = reactive({
export default {
data() {
return {
arrUrl: null,
mescroll: undefined,
// 打卡相关数据
showClockInModal: false,
clockInAddress: '',
clockInData: null,
downOption: {
auto: false //是否在初始化后,自动执行downCallback; 默认true
},
upOption: {
onScroll: true,
use: true, // 是否启用上拉加载; 默认true
auto: true, // 是否在初始化完毕之后自动执行上拉加载的回调; 默认true
page: {
num: 0, // 当前页码,默认0,回调之前会加1,即callback(page)会从1开始
size: 10 // 每页数据的数量,默认10
},
noMoreSize: 1, // 配置列表的总数量要大于等于5条才显示'-- END --'的提示
empty: {
tip: '暂无相关数据'
}
},
dataList: [],
dzList: [],
searchContent: '',
form: {
addressForStart: null,
addressForEnd: null,
createId: null,
staffName: null,
visistCode: null,
visistId: null,
remark: null,
mapId: null
})
// 签到
let handleCheckIn = () => {
mapId: null,
}
}
},
onLoad() {
// 修改顶部导航背景色
uni.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#29abe2',
animation: {
duration: 400,
timingFunc: 'easeIn'
}
})
let date = new Date();
this.form.createTime = this.dateFormat("YYYY-mm-dd", date);
},
onShow() {
this.arrUrl = uni.getStorageSync("avatar");
},
methods: {
addInsertMap() {
uni.navigateTo({
url: './insertMap'
})
},
//签到
addInsertMapForSignIn() {
uni.navigateTo({
url: './addRearkSignIn'
})
}
// 打卡
// let handleClockIn = () => {
// uni.getLocation({
// type: 'wgs84',
// success: (res) => {
// const latiude = res.latitude;
// const longitude = res.longitude;
// //进行解析
// inverseGeocoding(latiude, longitude);
// },
// fail: function (err) {
// console.log("获取地址失败" + err)
// }
// })
// }
let modalVisible = ref(false);
let handleClick = () => {
},
//打卡
addInsertMapClockIn() {
var that = this;
uni.getLocation({
type: 'wgs84',
success: (res) => {
const latitude = res.latitude;
const latiude = res.latitude;
const longitude = res.longitude;
console.log('纬度:',latitude,',经度:', longitude);
inverseGeocoding(latitude, longitude);
//进行解析
this.inverseGeocoding(latiude, longitude);
},
fail: function (err) {
console.log("获取地址失败" + err)
}
})
}
// 反馈提示
const feedback = (res, callback)=>{
if(res.code===200){
if(callback) callback();
},
// 显示打卡确认弹窗
showClockInConfirm(address, data) {
this.clockInAddress = address;
this.clockInData = data;
this.showClockInModal = true;
},
// 取消打卡(点击遮罩层)
cancelClockIn() {
this.showClockInModal = false;
this.clockInAddress = '';
this.clockInData = null;
},
// 确认打卡
confirmClockIn() {
const that = this;
addStartMapForClockIn(this.clockInData).then(res => {
if (res.code == 200) {
uni.showToast({
title: MapApiConfig.OTHER.typeName === form.addressForStart ? MapApiConfig.OTHER.typeName : res.msg,
icon: 'success'
})
setTimeout(()=>{
uni.navigateBack(1);
icon: 'success',
title: res.msg,
duration: 1500,
});
setTimeout(() => {
uni.navigateBack(1)
}, 500)
}
else{
} else {
uni.showToast({
icon: 'none',
title: res.msg
})
title: res.msg,
});
}
}
// 出差
const handleCancel = () => {
businessTripClockIn(form).then(res=>{
feedback(res,()=>console.log('出差打卡成功'));
}).catch(e=>{
console.log(e);
that.cancelClockIn(); // 关闭弹窗
})
}
// 打卡
let handleConfirm = () => {
addStartMapForClockIn(form).then(res=>{
feedback(res, ()=>console.log('打卡成功'));
}).catch(e=>{
console.log(e)
},
// 出差打卡
businessTripClockIn() {
const that = this;
businessTripClockIn(this.clockInData).then(res => {
if (res.code == 200) {
uni.showToast({
icon: 'success',
title: res.msg,
duration: 1500,
});
setTimeout(() => {
uni.navigateBack(1)
}, 500)
} else {
uni.showToast({
icon: 'none',
title: res.msg,
});
}
that.cancelClockIn(); // 关闭弹窗
})
}
// 判定是否在范围内
function isWithinRange(lat, lon, centerLat, centerLon, rangeKm) {
const distance = haversineDistance(centerLat, centerLon, lat, lon);
},
isWithinRange(lat, lon, centerLat, centerLon, rangeKm) {
const distance = this.haversineDistance(centerLat, centerLon, lat, lon);
return distance <= rangeKm;
}
function haversineDistance(lat1, lon1, lat2, lon2, radius = 6371) {
const dLat = degToRad(lat2 - lat1);
const dLon = degToRad(lon2 - lon1);
},
dateFormat(fmt, date) {
let ret;
const opt = {
"Y+": date.getFullYear().toString(), // 年
"m+": (date.getMonth() + 1).toString(), // 月
"d+": date.getDate().toString(), // 日
"H+": date.getHours().toString(), // 时
"M+": date.getMinutes().toString(), // 分
"S+": date.getSeconds().toString() // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
};
for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) {
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
};
};
return fmt;
},
haversineDistance(lat1, lon1, lat2, lon2, radius = 6371) {
const dLat = this.degToRad(lat2 - lat1);
const dLon = this.degToRad(lon2 - lon1);
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(degToRad(lat1)) * Math.cos(degToRad(lat2)) *
Math.cos(this.degToRad(lat1)) * Math.cos(this.degToRad(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return radius * c; // 距离,单位:公里
}
// 角度转弧度
function degToRad(deg) {
},
degToRad(deg) {
return deg * (Math.PI / 180);
}
//解析地址
function inverseGeocoding(latitude, longitude) {
uni.showLoading();
const apiURL = MapApiConfig.URL;
},
inverseGeocoding(latiude, longitude) {
var that = this;
let points = longitude + ',' + latiude
const apiURL = 'https://tiles.geovisearth.com/geo/v1/geocode/regeo';
const params = {
lat: latitude,
lat: latiude,
lng: longitude,
radius: 1000,
pageSize: 1,
currentPage: 1,
//classify: 220100
};
const token = MapApiConfig.token;
const token = '66c87c897f0251295afdc794e4fbf73046a070338a726fe04f06cece6cb1ffdf';
uni.request({
url: apiURL,
method: 'GET',
@@ -186,159 +231,308 @@ function inverseGeocoding(latitude, longitude) {
'Authorization': 'Bearer ' + token
},
success: (res) => {
modalVisible.value=true;
console.log(res, "经纬度解析成功")
if (res.statusCode === 200 && res.data.status === 200) {
if (res.statusCode == 200 && res.data.status == 200) {
let resdata = res.data.data.rows[0].address
if (resdata == null) {
console.log(resdata.srcLat)
if (isWithinRange(latitude1, longitude1, latiude, longitude, 1)) {
form.addressForStart = MapApiConfig.XI_AN_BAN.typeName;
form.path = MapApiConfig.XI_AN_BAN.longitude + ',' + MapApiConfig.XI_AN_BAN.latitude ;
const latiude1 = 34.1360;
const longitude1 = 108.9126;
if (this.isWithinRange(latiude1, longitude1, latiude, longitude, 1)) {
this.form.addressForStart = "西安办事处位置打卡"
let data = {
mapId: that.form.mapId,
addressForStart: that.form.addressForStart,
cusName: that.form.cusName,
cusId: that.form.cusId,
remark: that.form.remark,
path: longitude1 + "," + latiude1
}
}
else {
form.addressForStart = resdata;
form.path = longitude + ',' + latitude; // 经度,纬度
that.showClockInConfirm(that.form.addressForStart, data);
}
} else {
form.addressForStart = MapApiConfig.OTHER.typeName;
form.path = longitude + ',' + latitude; // 经度,纬度
this.form.addressForStart = resdata;
let data = {
mapId: that.form.mapId,
addressForStart: that.form.addressForStart,
cusName: that.form.cusName,
cusId: that.form.cusId,
path: points
}
that.showClockInConfirm(that.form.addressForStart, data);
}
} else {
this.form.addressForStart = "第三方维护打卡"
let data = {
mapId: that.form.mapId,
addressForStart: that.form.addressForStart,
cusName: that.form.cusName,
cusId: that.form.cusId,
path: points
}
that.showClockInConfirm(that.form.addressForStart, data);
}
uni.hideLoading();
},
fail(e) {
console.log("获取位置失败", e)
uni.hideLoading();
},
}
})
},
fail: function (err) {
console.log("调用失败" + err)
}
}
}
</script>
<style scoped>
.white-bg {
width: 650rpx;
margin: 0;
border-radius: 8px 8px 0 0;
padding: 50rpx;
/* #ifdef APP-PLUS */
height: calc(100vh - 125px);
/* #endif */
/* #ifndef APP-PLUS */
height: calc(100vh - 98px);
/* #endif */
<style scoped lang="scss">
.bg-green {
background-color: #29abe2;
}
.btn-image {
width: 340rpx;
height: 340rpx;
margin: 30rpx auto 60rpx;
display: block;
.avatar {
align-items: center;
overflow: hidden;
width: 50rpx;
height: 60rpx;
border-radius: 50%;
margin: 0 auto;
margin-right: 10px;
}
.check-desc {
background-color: #F5F5F5;
padding: 40rpx 50rpx;
font-size: 28rpx;
border-radius: 10px;
margin-top: 100rpx;
.pub-add-box {
z-index: 9999;
width: 320upx;
height: 320upx;
border-radius: 50%;
background: #13579E;
position: fixed;
right: 205upx;
bottom: 200upx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-shadow: 0px 0px 80upx #13579E;
.img {
width: 40upx;
height: 40upx;
}
}
.check-desc .font-orange {
color: #F5813A;
font-size: 32rpx;
font-weight: bold;
.pub-add-box1 {
z-index: 9999;
width: 320upx;
height: 320upx;
border-radius: 50%;
background: #EA8021;
position: fixed;
right: 205upx;
top: 100upx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-shadow: 0px 0px 80upx #EA8021;
.img {
width: 40upx;
height: 40upx;
}
}
.check-desc .font-blue {
color: #2CBAEF;
font-size: 32rpx;
font-weight: bold;
.avatarInner {
align-items: center;
overflow: hidden;
width: 50rpx;
height: 60rpx;
border-radius: 50%;
margin: 0 auto;
margin-right: 10px;
}
/* 弹窗处理 */
.check-con {
.info-item-flex2 {
width: 100rpx;
}
.info-item1 {
align-items: center;
// height: 100rpx;
}
.scroolView {
width: 630rpx;
white-space: nowrap;
display: flex;
align-items: baseline;
}
// 筛选
// .screen-cont{
// height: 80upx;
// background: #fff;
// margin-top: 100upx;
// }
// 客户列表
.cus-list {
background: #fff;
.item {
padding: 20upx 40upx;
border-bottom: 1px solid #f7f7f7;
&:last-child {
border-bottom: none;
}
.head {
display: flex;
align-items: center;
justify-content: space-between;
.text {
font-size: 32upx;
color: #000;
}
.btn-box {
.deal-btn {
width: 100upx;
text-align: center;
padding: 10upx 0;
font-size: 24upx;
border-radius: 4upx;
&.deal {
background: #29abe2;
color: #fff;
}
&.un-deal {
background: #EFEFEF;
color: #BDBDBD;
}
}
.nameContent {
font-size: 17upx;
}
}
}
.head {
display: flex;
align-items: center;
justify-content: space-between;
.name {
font-size: 32upx;
color: #000;
}
}
.cus-info {
.info-item {
&.flex {
display: flex;
align-items: center;
justify-content: space-between;
.img-box {
display: flex;
align-items: center;
.img {
width: 40upx;
height: 40upx;
margin-left: 10upx;
}
}
}
.left {
font-size: 28upx;
color: #737373;
}
}
}
}
}
/* 自定义打卡弹窗样式 */
.clock-in-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.4);
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
z-index: 999;
justify-content: center;
}
/* 遮罩层内容样式 */
.check-in {
.modal-content {
width: 80%;
max-width: 500rpx;
background-color: #fff;
padding: 40rpx 30rpx 60rpx;
border-radius: 10px;
/* width: 620rpx; */
width: 560rpx;
position: absolute;
top: 48%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 20rpx;
overflow: hidden;
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.3);
}
.modal-header {
padding: 40rpx 30rpx 20rpx;
text-align: center;
border-bottom: 1rpx solid #f0f0f0;
}
.modal-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.modal-body {
padding: 30rpx;
text-align: center;
}
.check-in .check-tip {
font-weight: bold;
.address-text {
font-size: 28rpx;
color: #666;
line-height: 1.6;
}
.check-in .check-title {
font-size: 32rpx;
padding: 20rpx 0;
.modal-footer {
padding: 20rpx 30rpx 30rpx;
}
.check-in .check-location {
color: #0395E0;
font-size: 42rpx;
font-weight: bold;
.btn-group {
display: flex;
align-items: center;
justify-content: center;
margin: 30rpx 0;
gap: 20rpx;
}
.check-in .check-location .uniui-location-filled {
font-weight: normal;
margin-right: 20rpx;
.cancel-btn,
.confirm-btn {
flex: 1;
height: 80rpx;
line-height: 80rpx;
text-align: center;
border-radius: 40rpx;
font-size: 28rpx;
border: none;
}
.check-in .check-address {
color: #919191;
font-size: 32rpx;
margin-bottom: 80rpx;
.cancel-btn {
background-color: #f5f5f5;
color: #666;
}
.check-in .check-footer {
display: flex;
}
.check-in .check-footer .btn-default,
.check-in .check-footer .btn-primary {
background-color: #fff;
border: 1px solid #05A3F4;
color: #05A3F4;
border-radius: 25px;
padding: 0rpx 80rpx;
font-size: 34rpx;
/* margin-left: 0;
margin-right: 20rpx; */
}
.check-in .check-footer .btn-primary {
background-color: #05A3F4;
border: 1px solid #05A3F4;
.confirm-btn {
background-color: #13579E;
color: #fff;
/* padding: 0rpx 60rpx; */
}
</style>