|
@@ -0,0 +1,259 @@
|
|
|
+<template>
|
|
|
+ <view class="page" :style="{'min-height':h+'px', 'padding-top':mt+'px'}">
|
|
|
+ <cus-header title='外勤打卡'></cus-header>
|
|
|
+ <div class="map">
|
|
|
+ <map id="mapContainer" class="map" :latitude="latitude" :longitude="longitude" :markers="markers"
|
|
|
+ :scale="18" show-location></map>
|
|
|
+ </div>
|
|
|
+ <div class="box">
|
|
|
+ <div class="title">打卡位置</div>
|
|
|
+ <div class="place">{{address}}</div>
|
|
|
+ <div class="building">{{nearestBuilding}}附近</div>
|
|
|
+ <div class="title" style="margin-top: 64rpx;">外出签到拍照</div>
|
|
|
+ <div class="photo">
|
|
|
+ <u-upload width="180" height="180"
|
|
|
+ :fileList="fileList"
|
|
|
+ @afterRead="afterRead"
|
|
|
+ @delete="deletePic"
|
|
|
+ :maxCount="1"
|
|
|
+ :previewFullImage="true"
|
|
|
+ ></u-upload>
|
|
|
+ </div>
|
|
|
+ <div class="btn" @tap="confirm">确认外勤打卡</div>
|
|
|
+ </div>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+ const baseApi = require('@/http/baseApi.js')
|
|
|
+ const QQMapWX = require('../static/lib/qqmap-wx-jssdk.min.js');
|
|
|
+ const qqmapsdk = new QQMapWX({
|
|
|
+ key: '2JCBZ-MTMWQ-4N55Z-2F3SP-W72A7-YGB7L'
|
|
|
+ });
|
|
|
+ export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ url:'',
|
|
|
+ outUserId:'',
|
|
|
+ isSW:'',
|
|
|
+ latitude: '',
|
|
|
+ longitude: '',
|
|
|
+ markers: [],
|
|
|
+ nearestBuilding: '正在定位...',
|
|
|
+ address: '正在获取地址...',
|
|
|
+ mapCtx: null,
|
|
|
+ fileList: []
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onLoad(option) {
|
|
|
+ this.url = option.url;
|
|
|
+ this.outUserId = option.outUserId;
|
|
|
+ this.isSW = option.isSW;
|
|
|
+ // 初始化地图上下文
|
|
|
+ this.mapCtx = wx.createMapContext('mapContainer', this);
|
|
|
+ // 初始化定位
|
|
|
+ this.initLocation();
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ deletePic(event) {
|
|
|
+ this.fileList.splice(event.index, 1);
|
|
|
+ },
|
|
|
+ // 新增图片
|
|
|
+ async afterRead(event) {
|
|
|
+ // 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
|
|
|
+ let lists = [].concat(event.file);
|
|
|
+ let fileListLen = this.fileList.length;
|
|
|
+ lists.map((item) => {
|
|
|
+ this.fileList.push({
|
|
|
+ ...item,
|
|
|
+ status: "uploading",
|
|
|
+ message: "上传中",
|
|
|
+ });
|
|
|
+ });
|
|
|
+ for (let i = 0; i < lists.length; i++) {
|
|
|
+ const result = await this.uploadFilePromise(lists[i].url);
|
|
|
+ let item = this.fileList[fileListLen];
|
|
|
+ this.fileList.splice(
|
|
|
+ fileListLen,
|
|
|
+ 1,
|
|
|
+ Object.assign(item, {
|
|
|
+ status: "success",
|
|
|
+ message: "",
|
|
|
+ url: result,
|
|
|
+ })
|
|
|
+ );
|
|
|
+ fileListLen++;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ uploadFilePromise(url) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ let a = uni.uploadFile({
|
|
|
+ url: baseApi.BaseApi + '/uploadFile',
|
|
|
+ filePath: url,
|
|
|
+ name: "file",
|
|
|
+ formData: {
|
|
|
+ user: "test",
|
|
|
+ },
|
|
|
+ success: (res) => {
|
|
|
+ let data = JSON.parse(res.data);
|
|
|
+ if(data){
|
|
|
+ if(data.code!==0) return
|
|
|
+ setTimeout(() => {
|
|
|
+ resolve(data.data);
|
|
|
+ }, 1000);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 初始化定位
|
|
|
+ initLocation() {
|
|
|
+ uni.authorize({
|
|
|
+ scope: 'scope.userLocation',
|
|
|
+ success: () => {
|
|
|
+ this.getLocation();
|
|
|
+ },
|
|
|
+ fail: () => {
|
|
|
+ uni.showModal({
|
|
|
+ title: '定位权限申请',
|
|
|
+ content: '需要获取您的位置信息',
|
|
|
+ success: (res) => {
|
|
|
+ if (res.confirm) {
|
|
|
+ uni.openSetting();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ getLocation() {
|
|
|
+ uni.getLocation({
|
|
|
+ type: 'gcj02',
|
|
|
+ altitude: true,
|
|
|
+ success: (res) => {
|
|
|
+ this.latitude = res.latitude;
|
|
|
+ this.longitude = res.longitude;
|
|
|
+ this.updateMarker();
|
|
|
+ this.getAddressInfo();
|
|
|
+ },
|
|
|
+ fail: (err) => {
|
|
|
+ uni.showToast({
|
|
|
+ title: '定位失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ updateMarker() {
|
|
|
+ this.markers = [{
|
|
|
+ id: 1,
|
|
|
+ latitude: this.latitude,
|
|
|
+ longitude: this.longitude,
|
|
|
+ // iconPath: '/static/location.png',
|
|
|
+ width: 30,
|
|
|
+ height: 30
|
|
|
+ }]
|
|
|
+ },
|
|
|
+ getAddressInfo() {
|
|
|
+ qqmapsdk.reverseGeocoder({
|
|
|
+ location: {
|
|
|
+ latitude: this.latitude,
|
|
|
+ longitude: this.longitude
|
|
|
+ },
|
|
|
+ success: (res) => {
|
|
|
+ const result = res.result;
|
|
|
+ this.nearestBuilding = result.address_reference?.building?.title || result
|
|
|
+ .address_reference?.street?.title || '未知建筑';
|
|
|
+ this.address = result.address;
|
|
|
+ },
|
|
|
+ fail: (err) => {
|
|
|
+ console.error('逆地理编码失败:', err)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ confirm() {
|
|
|
+ if(this.fileList.length===0) return this.$showToast('请先外出签到拍照')
|
|
|
+ let params = { outUserId:this.outUserId };
|
|
|
+ params[this.isSW==1?'checkInTime':'clockOutTime'] = new Date().Format('hh:mm');
|
|
|
+ params.file = this.fileList[0].url;
|
|
|
+ params.position = this.address;
|
|
|
+ this.$api.post(this.url,params).then(res=>{
|
|
|
+ if(res.data.code!==0) return this.$showToast(res.data.msg);
|
|
|
+ this.$showToast('外出签到成功')
|
|
|
+ setTimeout(()=>{
|
|
|
+ uni.reLaunch({
|
|
|
+ url:'/pagesClockin/index'
|
|
|
+ })
|
|
|
+ },1500)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="less">
|
|
|
+ .page {
|
|
|
+ background: #FFFFFF;
|
|
|
+
|
|
|
+ .map {
|
|
|
+ width: 100%;
|
|
|
+ height: 640rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .box {
|
|
|
+ width: 100%;
|
|
|
+ background: #fff;
|
|
|
+ padding: 48rpx 29rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+
|
|
|
+ .title {
|
|
|
+ font-family: PingFang-SC, PingFang-SC;
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 36rpx;
|
|
|
+ color: #1D2129;
|
|
|
+ line-height: 36rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .place {
|
|
|
+ font-family: PingFangSC, PingFang SC;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #1D2129;
|
|
|
+ line-height: 28rpx;
|
|
|
+ margin-top: 30rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .building {
|
|
|
+ font-family: PingFangSC, PingFang SC;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #86909C;
|
|
|
+ line-height: 28rpx;
|
|
|
+ padding-top: 20rpx;
|
|
|
+ border-top: 1rpx solid #EFEFEF;
|
|
|
+ margin-top: 20rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .photo {
|
|
|
+ width: 180rpx;
|
|
|
+ height: 180rpx;
|
|
|
+ margin-top: 36rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn {
|
|
|
+ width: 100%;
|
|
|
+ height: 88rpx;
|
|
|
+ background: #2E69EB;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ font-family: PingFang-SC, PingFang-SC;
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 32rpx;
|
|
|
+ color: #FFFFFF;
|
|
|
+ line-height: 88rpx;
|
|
|
+ text-align: center;
|
|
|
+ letter-spacing: 2rpx;
|
|
|
+ margin-top: 168rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|