You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

543 lines
15 KiB

<template>
<view class="content">
<image src="https://static.ticket.sz-trip.com/tourGuide/images/index/topImg.png" class="topImg"></image>
<view class="title" style="margin-top: 40rpx;">·快捷入口</view>
<view class="flex-between">
<view class="nav-item flex-around" @click="goHX()">
立即核销
<image src="https://static.ticket.sz-trip.com/tourGuide/images/index/hexiao.png" mode=""></image>
</view>
<view class="nav-item flex-around" @click="gotoPath('/subPackages/order/orderList')">
查看订单
<image src="https://static.ticket.sz-trip.com/tourGuide/images/index/dingdan.png" mode=""></image>
</view>
</view>
<view v-if="!isShowClasses">
<view class="title">·我的打卡</view>
<view class="rule" @click="openRule">打卡规则</view>
<view class="punch-box flex-column" :style="{backgroundColor: isCanPunch ? '#96684F' : ''}" @click="punch">
<view>{{punchSuccess ? '打卡成功' : '上线打卡'}}</view>
{{currentTime}}
</view>
<!-- 未打卡 -->
<view v-if="!punchSuccess">
<view class="punch-text">{{isCanPunch ? '您已进入打卡范围:' + userPunch.clock_address[nearestFenceIndex].title : '您当前不在可打卡范围内'}}</view>
<view class="examine-btn flex-center" v-if="userPunch.is_open_examine" @click="examinePunch">审批打卡</view>
</view>
<!-- 打卡成功 -->
<view v-else>
<view class="punch-text">打卡时间:{{currentTime.slice(0,5)}}</view>
<view class="punch-text" style="margin: 0 auto;">{{timeSuccess}}s后自动进入排班页面</view>
</view>
</view>
<view v-else>
<view class="title">·我的排班</view>
<view class="type-box">
<view v-for="(item,index) in typeList" :key="index"
:class="['type-item', {'type-active': index == typeIndex}]" @click="typeIndex = index;getList()">
{{item.title}}
<view class="type-line" v-if="index == typeIndex"></view>
</view>
</view>
<!-- 日历 -->
<calendarVue :isShowLunar="true" :isCanChangeDate="userPunch.is_clock == 0 ? true : false" @changeDate="getDate"></calendarVue>
<!-- 选择场次 -->
<view v-for="(item,index) in typeIndex ? sessionLists : sessionList" :key="index"
class="session-item flex-between">
{{item.title}}
<switch :checked="item.isChecked" color="#96684F" @change="switchChange(item,index)" />
</view>
</view>
<!-- 打卡规则 -->
<uni-popup ref="popup" type="center" border-radius="10px" background-color="#fff">
<view v-html="formateRichText(ruleContent)" style="width: 90%;padding: 30rpx;border-radius: 10rpx;margin: auto;"></view>
</uni-popup>
</view>
</template>
<script>
import calendarVue from '../../components/calendar.vue';
export default {
components: {
calendarVue
},
data() {
return {
typeList: [{
title: '导游服务',
id: ''
},
// {
// title: '线上咨询',
// id: ''
// },
// {
// title: '拼团产品',
// id: ''
// },
{
title: '线路产品',
id: ''
}
],
typeIndex: 0,
selectDay: '',
sessionList: [{
title: '上午场',
isChecked: false
},
{
title: '下午场',
isChecked: false
},
{
title: '全天场',
isChecked: false
}
],
sessionLists: [{
title: '当天状态',
isChecked: false
}],
isAllChecked: false,
// 最近的打卡点索引
nearestFenceIndex: null,
// 打卡点半径(单位:米)
fenceRadius: 500,
// 用于存储 watchPosition 的返回值,方便后续清除监听
watchId: null,
ruleContent: '',
currentTime: '',
timeInterval: null,
isCanPunch: false, // 是否可打卡,
punchSuccess: false, // 打卡成功
timeSuccess: 3,
isShowClasses: true, // 是否显示排班表
userPunch: {},
myLonLat: {
lng: '',
lat: ''
}
}
},
onLoad() {
this.selectDay = this.getNowTime(new Date())
this.getList()
},
onShow() {
// 获取用户打卡信息
this.Post({},'/api/Merchants/getGuideClockStatus').then(res => {
this.userPunch = res.data
if(this.userPunch.clock_address.length == 0) return;
// 用户是否需要打卡、及打卡状态:0不需要打卡,1未打卡,2已打卡或审批打卡成功,3审批打卡审核中,4审批拒绝
switch (this.userPunch.is_clock){
case 0:
this.isShowClasses = true
break;
case 1:
this.isShowClasses = false
break;
case 2:
this.isShowClasses = true
break;
case 3:
this.isShowClasses = false
break;
case 4:
this.isShowClasses = false
break;
default:
break;
}
this.watchLocation(); // 开始监听用户位置
this.startTimeUpdate();
})
},
onHide() {
// 页面隐藏时清除位置监听
if (this.watchId) {
navigator.geolocation.clearWatch(this.watchId)
}
// 页面隐藏时清除时间更新定时器
if (this.timeInterval) {
clearInterval(this.timeInterval);
}
},
methods: {
// 点击打卡
punch() {
if (this.nearestFenceIndex === null) {
uni.showToast({
title: '您当前不在可打卡范围内,无法打卡',
icon: 'none'
});
return;
}
this.Post({
address_id: this.userPunch.clock_address[this.nearestFenceIndex].id,
lon: this.myLonLat.lng,
lat: this.myLonLat.lat
}, '/api/Merchants/guideClockLocate').then(res => {
if(res.code == 1) {
this.punchSuccess = true
clearInterval(this.timeInterval); // 打卡成功后清除时间定时器
navigator.geolocation.clearWatch(this.watchId); // 打卡成功时清除位置监听
let timer = setInterval(() => {
this.timeSuccess--;
if (this.timeSuccess == 0) {
clearInterval(timer);
this.isShowClasses = true
}
}, 1000);
}
})
},
// 审批打卡
examinePunch() {
if(this.userPunch.is_clock == 1) {
// 去审批打卡
this.gotoPath('/subPackages/clockIn/apply')
}else if([3,4].includes(this.userPunch.is_clock)) {
// 查看审批记录
this.gotoPath('/subPackages/clockIn/apply?id=' + this.userPunch.clock_id)
}
},
// 监听用户位置变化
watchLocation() {
if (navigator.geolocation) {
this.watchId = navigator.geolocation.watchPosition(
(position) => {
let coords = position.coords;
let [gcj02Lng, gcj02Lat] = this.wgs84ToGcj02(coords.longitude, coords.latitude);
this.myLonLat = {
lng: gcj02Lng,
lat: gcj02Lat
}
// 初始化是否可打卡为 false
this.isCanPunch = false;
// 遍历每个打卡点
for (let i = 0; i < this.userPunch.clock_address.length; i++) {
const item = this.userPunch.clock_address[i];
const distance = this.calculateDistance(item.lat, item.lon, gcj02Lat, gcj02Lng);
console.log(`与打卡点 ${item.title} 的距离:`, distance);
if (distance <= item.range) {
this.isCanPunch = true;
this.nearestFenceIndex = i;
break; // 找到满足条件的打卡点后结束循环
}
}
},
(error) => {
let locationStatus = ''
switch (error.code) {
case 1:
locationStatus = '定位未开启,用户拒绝了定位请求';
break;
case 2:
locationStatus = '定位信息不可用';
break;
case 3:
locationStatus = '定位请求超时';
break;
case 4:
locationStatus = '定位出现未知错误';
break;
}
uni.showToast({
title: locationStatus,
icon: 'none'
})
}
);
} else {
// 浏览器不支持地理定位
uni.showToast({
title: '浏览器不支持地理定位功能',
icon: 'none'
})
}
},
// WGS84坐标转换为GCJ-02坐标
// 判断是否在中国范围内
outOfChina(lng, lat) {
return (lng < 72.004 || lng > 137.8347) || (lat < 0.8293 || lat > 55.8271);
},
// 转换纬度
transformLat(x, y) {
let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0;
return ret;
},
// 转换经度
transformLng(x, y) {
let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x / 30.0 * Math.PI)) * 2.0 / 3.0;
return ret;
},
// WGS84 转换为 GCJ02
wgs84ToGcj02(lng, lat) {
const a = 6378245.0; // 地球长半轴
const ee = 0.00669342162296594323; // 扁率
if (this.outOfChina(lng, lat)) {
return [lng, lat];
}
let dLat = this.transformLat(lng - 105.0, lat - 35.0);
let dLng = this.transformLng(lng - 105.0, lat - 35.0);
const radLat = lat / 180.0 * Math.PI;
let magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
const sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * Math.PI);
dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * Math.PI);
const mgLat = lat + dLat;
const mgLng = lng + dLng;
return [mgLng, mgLat];
},
goHX() {
uni.switchTab({
url: '/pages/verification/index'
})
},
// 选择场次
switchChange(item, index) {
item.isChecked = !item.isChecked
// if(index == 2) {
// for (let i = 0; i < 2; i++) {
// this.sessionList[i].isChecked = this.sessionList[2].isChecked
// }
// }else {
// if(this.sessionList[0].isChecked && this.sessionList[1].isChecked) {
// this.sessionList[2].isChecked = true
// }else {
// this.sessionList[2].isChecked = false
// }
// }
let url = this.typeIndex ? '/api/Merchants/updateGuideSched' : '/api/Merchants/updateGuideSchedService'
this.Post({
date: this.selectDay,
online_type: item.isChecked ? 1 : 0, // 开关
date_half: this.typeIndex ? '' : index + 1, // 导游服务 1上午 2下午 3全天
classify: this.typeIndex ? 2 : '' // 1拼团,2线路
}, url).then(res => {
})
},
getDate(date) {
console.log('传递过来的日期', date)
this.selectDay = date
this.sessionList.forEach(item => item.isChecked = false)
this.sessionLists[0].isChecked = false
this.getList()
},
changeWork(date) {
// // 导游服务值班状态 date_half:分类(1上午,2下午,3全天)
// this.Post({
// date: date,
// date_half
// },'/api/Merchants/updateGuideSchedService').then(res => {
// })
},
getList() {
// 获取排班列表 classify:分类(1拼团,2线路,3导游服务)
this.Post({
start_date: this.selectDay,
end_date: this.selectDay,
classify: this.typeIndex ? 2 : 3
}, '/api/Merchants/getGuideSchedList').then(res => {
if (res.data && res.data.length > 0) {
let data = res.data[0]
if (this.typeIndex) {
// 线路
this.sessionLists[0].isChecked = data.online_type ? true : false
} else {
// 导游
this.sessionList[0].isChecked = data.morning_type ? true : false
this.sessionList[1].isChecked = data.afternoon_type ? true : false
this.sessionList[2].isChecked = data.day_type ? true : false
}
}
})
},
// 获取当前日期
formatDate(date, format = 'YYYY/MM/DD') {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hour = String(date.getHours()).padStart(2, '0');
const minute = String(date.getMinutes()).padStart(2, '0');
const second = String(date.getSeconds()).padStart(2, '0');
return format
.replace('YYYY', year)
.replace('MM', month)
.replace('DD', day)
.replace('HH', hour)
.replace('mm', minute)
.replace('ss', second);
},
getNowTime(time, type) {
const format = type === 1 ? (uni.getSystemInfoSync().platform === 'ios' ? 'YYYY/MM/DD HH:mm:ss' : 'YYYY-MM-DD HH:mm:ss') : 'YYYY/MM/DD';
return this.formatDate(time, format);
},
// 打卡规则
openRule() {
this.Post({
id: 7
},'/api/article/getArticleById').then(res => {
this.ruleContent = res.data.content
this.$refs.popup.open()
})
},
// 开始更新时间
startTimeUpdate() {
this.updateTime();
this.timeInterval = setInterval(() => {
this.updateTime();
}, 1000);
},
// 更新时间
updateTime() {
const now = new Date();
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
this.currentTime = `${hours}:${minutes}:${seconds}`;
}
}
}
</script>
<style lang="scss" scoped>
.content {
background: #FFFFFF;
min-height: 100vh;
padding: 40rpx 26rpx 200rpx;
}
.topImg {
width: 299.33rpx;
height: 70rpx;
display: flex;
margin: auto;
}
.title {
font-weight: bold;
font-size: 35rpx;
color: #000000;
margin: 68rpx 0 34rpx;
}
.rule {
font-weight: 500;
font-size: 31rpx;
color: #96684F;
text-align: right;
}
.punch-box {
width: 267rpx;
height: 267rpx;
background: #CCCCCC;
box-shadow: 0rpx 0rpx 29rpx 0rpx rgba(153,153,153,0.6);
border-radius: 50%;
justify-content: center;
align-items: center;
font-weight: bold;
font-size: 32rpx;
color: #FFFFFF;
margin: 200rpx auto 0;
}
.punch-text {
font-weight: bold;
font-size: 30rpx;
color: #111111;
margin: 40rpx auto;
text-align: center;
}
.examine-btn {
width: 257rpx;
height: 80rpx;
border-radius: 13rpx;
border: 1rpx solid #96684F;
font-weight: 500;
font-size: 31rpx;
color: #96684F;
margin: 0 auto;
}
.nav-item {
font-weight: 500;
font-size: 32rpx;
color: #000000;
width: 338rpx;
height: 118rpx;
background: #F5F5F5;
border-radius: 20rpx;
padding: 0 15rpx;
image {
width: 80.67rpx;
height: 80.67rpx;
}
}
.type-box {
display: flex;
.type-item {
margin-right: 44rpx;
font-weight: 500;
font-size: 32rpx;
color: #000000;
}
.type-active {
color: #96684F;
}
.type-line {
width: 117rpx;
height: 6rpx;
background: #96684F;
border-radius: 3rpx;
margin: 4rpx auto 0;
}
}
.session-item {
width: 697rpx;
height: 93rpx;
background: #F5F5F5;
border-radius: 47rpx;
margin: 28rpx auto 0;
font-family: PingFang SC;
font-weight: 500;
font-size: 32rpx;
color: #000000;
padding: 0 28rpx;
}
</style>