fieldService.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. <template>
  2. <view class="page" :style="{'min-height':h+'px', 'padding-top':mt+'px'}">
  3. <cus-header title='外勤打卡'></cus-header>
  4. <div class="map">
  5. <map id="mapContainer" class="map" :latitude="latitude" :longitude="longitude" :markers="markers"
  6. :scale="18" show-location></map>
  7. </div>
  8. <div class="box">
  9. <div class="title">打卡位置</div>
  10. <div class="place">{{address}}</div>
  11. <div class="building">{{nearestBuilding}}附近</div>
  12. <div class="title" style="margin-top: 64rpx;">外出签到拍照</div>
  13. <div class="photo">
  14. <u-upload width="180" height="180"
  15. :fileList="fileList"
  16. @afterRead="afterRead"
  17. @delete="deletePic"
  18. :maxCount="1"
  19. :capture="['camera']"
  20. :previewFullImage="true"
  21. ></u-upload>
  22. </div>
  23. <div class="btn" @tap="confirm">确认外勤打卡</div>
  24. </div>
  25. </view>
  26. </template>
  27. <script>
  28. const baseApi = require('@/http/baseApi.js')
  29. const QQMapWX = require('../static/lib/qqmap-wx-jssdk.min.js');
  30. const qqmapsdk = new QQMapWX({
  31. key: '2JCBZ-MTMWQ-4N55Z-2F3SP-W72A7-YGB7L'
  32. });
  33. export default {
  34. data() {
  35. return {
  36. url:'',
  37. outUserId:'',
  38. isSW:'',
  39. latitude: '',
  40. longitude: '',
  41. markers: [],
  42. nearestBuilding: '正在定位...',
  43. address: '正在获取地址...',
  44. mapCtx: null,
  45. fileList: [],
  46. canClick:true
  47. }
  48. },
  49. onLoad(option) {
  50. this.url = option.url;
  51. this.outUserId = option.outUserId;
  52. this.isSW = option.isSW;
  53. // 初始化地图上下文
  54. this.mapCtx = wx.createMapContext('mapContainer', this);
  55. // 初始化定位
  56. this.initLocation();
  57. },
  58. methods: {
  59. deletePic(event) {
  60. this.fileList.splice(event.index, 1);
  61. },
  62. // 新增图片
  63. async afterRead(event) {
  64. // 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
  65. let lists = [].concat(event.file);
  66. let fileListLen = this.fileList.length;
  67. lists.map((item) => {
  68. this.fileList.push({
  69. ...item,
  70. status: "uploading",
  71. message: "上传中",
  72. });
  73. });
  74. for (let i = 0; i < lists.length; i++) {
  75. const result = await this.uploadFilePromise(lists[i].url);
  76. let item = this.fileList[fileListLen];
  77. this.fileList.splice(
  78. fileListLen,
  79. 1,
  80. Object.assign(item, {
  81. status: "success",
  82. message: "",
  83. url: result,
  84. })
  85. );
  86. fileListLen++;
  87. }
  88. },
  89. uploadFilePromise(url) {
  90. return new Promise((resolve, reject) => {
  91. let a = uni.uploadFile({
  92. url: baseApi.BaseApi + '/uploadFile',
  93. filePath: url,
  94. name: "file",
  95. formData: {
  96. user: "test",
  97. },
  98. success: (res) => {
  99. let data = JSON.parse(res.data);
  100. if(data){
  101. if(data.code!==0) return
  102. setTimeout(() => {
  103. resolve(data.data);
  104. }, 1000);
  105. }
  106. },
  107. });
  108. });
  109. },
  110. // 初始化定位
  111. initLocation() {
  112. uni.authorize({
  113. scope: 'scope.userLocation',
  114. success: () => {
  115. this.getLocation();
  116. },
  117. fail: () => {
  118. uni.showModal({
  119. title: '定位权限申请',
  120. content: '需要获取您的位置信息',
  121. success: (res) => {
  122. if (res.confirm) {
  123. uni.openSetting();
  124. }
  125. }
  126. })
  127. }
  128. })
  129. },
  130. getLocation() {
  131. uni.getLocation({
  132. type: 'gcj02',
  133. altitude: true,
  134. success: (res) => {
  135. this.latitude = res.latitude;
  136. this.longitude = res.longitude;
  137. this.updateMarker();
  138. this.getAddressInfo();
  139. },
  140. fail: (err) => {
  141. uni.showToast({
  142. title: '定位失败',
  143. icon: 'none'
  144. })
  145. }
  146. })
  147. },
  148. updateMarker() {
  149. this.markers = [{
  150. id: 1,
  151. latitude: this.latitude,
  152. longitude: this.longitude,
  153. // iconPath: '/static/location.png',
  154. width: 30,
  155. height: 30
  156. }]
  157. },
  158. getAddressInfo() {
  159. qqmapsdk.reverseGeocoder({
  160. location: {
  161. latitude: this.latitude,
  162. longitude: this.longitude
  163. },
  164. success: (res) => {
  165. const result = res.result;
  166. this.nearestBuilding = result.address_reference?.building?.title || result
  167. .address_reference?.street?.title || '未知建筑';
  168. this.address = result.address;
  169. },
  170. fail: (err) => {
  171. console.error('逆地理编码失败:', err)
  172. }
  173. })
  174. },
  175. confirm() {
  176. if(!this.canClick) return
  177. if(this.fileList.length===0) return this.$showToast('请先外出签到拍照')
  178. let params = { outUserId:this.outUserId };
  179. params[this.isSW==1?'checkInTime':'clockOutTime'] = new Date().Format('yyyy-MM-dd hh:mm');
  180. params.file = this.fileList[0].url;
  181. params.position = this.address;
  182. this.canClick = false;
  183. this.$api.post(this.url,params).then(res=>{
  184. if(res.data.code!==0) return this.$showToast(res.data.msg);
  185. this.$showToast('外出签到成功')
  186. this.canClick = true;
  187. setTimeout(()=>{
  188. uni.reLaunch({
  189. url:'/pagesClockin/index'
  190. })
  191. },1500)
  192. })
  193. }
  194. }
  195. }
  196. </script>
  197. <style scoped lang="less">
  198. .page {
  199. background: #FFFFFF;
  200. .map {
  201. width: 100%;
  202. height: 640rpx;
  203. }
  204. .box {
  205. width: 100%;
  206. background: #fff;
  207. padding: 48rpx 29rpx;
  208. box-sizing: border-box;
  209. .title {
  210. font-family: PingFang-SC, PingFang-SC;
  211. font-weight: bold;
  212. font-size: 36rpx;
  213. color: #1D2129;
  214. line-height: 36rpx;
  215. }
  216. .place {
  217. font-family: PingFangSC, PingFang SC;
  218. font-weight: 400;
  219. font-size: 28rpx;
  220. color: #1D2129;
  221. line-height: 28rpx;
  222. margin-top: 30rpx;
  223. }
  224. .building {
  225. font-family: PingFangSC, PingFang SC;
  226. font-weight: 400;
  227. font-size: 28rpx;
  228. color: #86909C;
  229. line-height: 28rpx;
  230. padding-top: 20rpx;
  231. border-top: 1rpx solid #EFEFEF;
  232. margin-top: 20rpx;
  233. }
  234. .photo {
  235. width: 180rpx;
  236. height: 180rpx;
  237. margin-top: 36rpx;
  238. }
  239. .btn {
  240. width: 100%;
  241. height: 88rpx;
  242. background: #2E69EB;
  243. border-radius: 16rpx;
  244. font-family: PingFang-SC, PingFang-SC;
  245. font-weight: bold;
  246. font-size: 32rpx;
  247. color: #FFFFFF;
  248. line-height: 88rpx;
  249. text-align: center;
  250. letter-spacing: 2rpx;
  251. margin-top: 168rpx;
  252. }
  253. }
  254. }
  255. </style>