fieldService.vue 6.1 KB

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