fieldService.vue 6.2 KB

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