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.
 
 
 
 
 
 

390 lines
9.9 KiB

  1. <template>
  2. <view class="">
  3. <view v-if="ready" class="contentBox">
  4. <view class="rules">
  5. <view class="">
  6. <view class="">
  7. 上班 {{info.WorkTime}}
  8. </view>
  9. <view class="">
  10. {{info.UserWorkTime?info.UserWorkTime.split(' ')[1]+' 打卡':'未打卡'}}
  11. </view>
  12. </view>
  13. <view class="">
  14. <view class="">
  15. 下班 {{info.CloseTime}}
  16. </view>
  17. <view class="">
  18. {{info.UserCloseTime?info.UserCloseTime.split(' ')[1]+' 打卡':'未打卡'}}
  19. </view>
  20. </view>
  21. </view>
  22. <view class="content" id="attendContent">
  23. <view id="show">{{now}}</view>
  24. <view class="pen" @click="action('dk')">
  25. <img :class="{gray:info.AttendanceType != 1}" id="attimg" :src="imgsrc" alt="" width="100%">
  26. </view>
  27. <view class="title">
  28. <text>{{resInfo.AttendanceTypeString}}</text>
  29. <text>{{postData.AIsOut== 1 ? ' | ' + info.AttendanceTypeString:''}}</text>
  30. <view style="color: #666;">
  31. {{postData.ClockPlace}}
  32. </view>
  33. </view>
  34. </view>
  35. <view class="footer">
  36. <img src="../../common/images/2.png" alt="" width="100%">
  37. </view>
  38. </view>
  39. <view id='container'></view>
  40. </view>
  41. </template>
  42. <script>
  43. /*
  44. * 版 本 Learun-ADMS V7.0.3 力软敏捷开发框架(http://www.learun.cn)
  45. * Copyright (c) 2013-2020 上海力软信息技术有限公司
  46. * 创建人:超级管理员
  47. * 日 期:2022-03-10 15:30
  48. * 描 述:考勤打卡
  49. */
  50. /**
  51. * 本段代码由移动端代码生成器输出,移动端须 2.2.0 版本及以上可以使用
  52. * 请在移动端 /pages.json 中的 pages 字段中添加一条记录:
  53. * { "path": "pages/AttendanceCard/list", "style": { "navigationBarTitleText": "考勤打卡" } }
  54. *
  55. * (navigationBarTitleText 字段为本页面的标题文本,可以修改)
  56. * (必须自行操作该步骤,力软代码生成器不会自动帮您修改 /pages.json 文件)
  57. */
  58. import get from 'lodash/get'
  59. import set from 'lodash/set'
  60. import moment from 'moment'
  61. import customPageMixins from '@/common/custompage.js'
  62. import wxFn from '@/common/wxFn.js'
  63. //导入图片
  64. import dk from '../../common/images/dk.png'
  65. import dkred from '../../common/images/dkred.png'
  66. import dkyellow from '../../common/images/dkyellow.png'
  67. export default {
  68. mixins: [customPageMixins, wxFn],
  69. data() {
  70. return {
  71. // 页面相关参数
  72. info: {},
  73. resInfo:{},
  74. now: null,
  75. imgsrc: dk,
  76. ready: false,
  77. timer: '',
  78. timer1:'',
  79. map: null,
  80. postData: {},
  81. isGetingLocal:false,
  82. }
  83. },
  84. async onLoad() {
  85. await this.init()
  86. },
  87. methods: {
  88. // 页面初始化
  89. async init() {
  90. this.LOADING('加载数据中...')
  91. this.now = this.getCurrentTime()
  92. this.timer = setInterval(this.getCurrentTime, 1000)
  93. let res = await this.judgeIsDK()
  94. this.ready = res ? true : false
  95. this.HIDE_LOADING()
  96. },
  97. // 点击 「打卡」按钮
  98. async action(type) {
  99. switch (type) {
  100. case 'dk':
  101. if ([5].includes(this.info.AttendanceType)) {
  102. return
  103. }
  104. if(!this.postData.ClockPlace){
  105. this.TOAST('获取定位失败,无法打卡')
  106. return
  107. }
  108. if ([4].includes(this.info.AttendanceType)) {
  109. this.NAV_TO(`./single`, this.postData,true)
  110. return
  111. }
  112. this.LOADING()
  113. this.HTTP_POST('learun/adms/attendance/clockin', {}, '打卡失败').then(success => {
  114. this.HIDE_LOADING()
  115. if (!success) {
  116. this.TOAST('打卡失败')
  117. return
  118. }
  119. this.TOAST('打卡成功', 'success')
  120. setTimeout(this.back, 500)
  121. })
  122. return
  123. default:
  124. break
  125. }
  126. },
  127. //获取打卡信息
  128. async judgeIsDK() {
  129. let success = await this.HTTP_GET('learun/adms/attendance/IsAttendance', {}, '判断当前时间是否可以打卡失败')
  130. if (!success) {
  131. return false
  132. }
  133. this.info = success.data
  134. this.imgsrc = dk;
  135. // if ([1].includes(this.info.AttendanceType)) {
  136. // this.imgsrc=dk;
  137. // } else if ([2,3].includes(this.info.AttendanceType)) {
  138. // this.imgsrc=dkyellow;
  139. // }else {
  140. // this.imgsrc=dkred;
  141. // }
  142. // 保存原打卡状态
  143. this.resInfo = {
  144. AttendanceType:this.info.AttendanceType,
  145. AttendanceTypeString:this.info.AttendanceTypeString,
  146. }
  147. if (![5].includes(this.info.AttendanceType)) {
  148. this.$set(this.info, 'AttendanceType', 4)
  149. this.$set(this.info, 'AttendanceTypeString', '外勤打卡')
  150. this.$set(this.postData, 'AIsOut', 1)
  151. // 获取定位,不是外勤时候改变状态
  152. if (!window.BMapGL) await this.loadJScript()
  153. this.map = new BMapGL.Map('container');
  154. await this.isFieldPersonnel()
  155. if(!this.postData.ClockPlace){
  156. return true
  157. }
  158. this.timer1 = setInterval(async ()=>{
  159. if(this.isGetingLocal)return
  160. if(!this.postData.ClockPlace){
  161. clearInterval(this.timer1)
  162. }
  163. this.isGetingLocal = true
  164. await this.isFieldPersonnel()
  165. // console.log(this.postData)
  166. this.isGetingLocal = false
  167. },3000)
  168. }
  169. return true
  170. },
  171. //返回
  172. back() {
  173. this.NAV_BACK()
  174. },
  175. //获取当前时间
  176. getCurrentTime() {
  177. let nowDate = new Date();
  178. let hh = nowDate.getHours();
  179. let mf = nowDate.getMinutes() < 10 ? '0' + nowDate.getMinutes() : nowDate.getMinutes();
  180. let ss = nowDate.getSeconds() < 10 ? '0' + nowDate.getSeconds() : nowDate.getSeconds();
  181. this.now = hh + ':' + mf + ':' + ss;
  182. },
  183. // 判断是否外勤打卡
  184. async isFieldPersonnel() {
  185. let point = new BMapGL.Point(this.info.GPSLon, this.info.GPSLat)
  186. await this.getDistance(point)
  187. },
  188. //异步加载地图
  189. loadJScript() {
  190. return new Promise((resolve, reject) => {
  191. window.initMap = function() {
  192. resolve(BMapGL)
  193. }
  194. var script = document.createElement('script');
  195. script.type = 'text/javascript';
  196. script.src =
  197. 'https://api.map.baidu.com/api?v=1.0&type=webgl&ak=Nx9VQtQEgzUm5GuBVt5SHoO5jt204xNo' +
  198. '&callback=' + 'initMap';
  199. script.onerror = reject
  200. document.head.appendChild(script);
  201. })
  202. },
  203. // 计算距离打卡点的距离
  204. // 签到状态(1正常打卡,2迟到打卡,3早退打卡,4外勤打卡,5不在考勤时间范围)
  205. async getDistance(myP1) {
  206. // new BMapGL.Point(116.404, 39.915)
  207. let myP2 = await this.local();
  208. if (!myP2) {
  209. // this.TOAST('获取定位失败!')
  210. this.$set(this.info, 'AttendanceType', 4)
  211. this.$set(this.info, 'AttendanceTypeString', '外勤打卡')
  212. this.$set(this.postData, 'AIsOut', 1)
  213. return
  214. }
  215. let distance = this.map.getDistance(myP1, myP2).toFixed(2)
  216. // alert('距离'+ distance)
  217. // console.log('距离', distance, '打卡坐标:', myP1, '当前坐标:', myP2)
  218. if (Number(distance) > Number(this.info.GPSRange)) {
  219. this.$set(this.info, 'AttendanceType', 4)
  220. this.$set(this.info, 'AttendanceTypeString', '外勤打卡')
  221. this.$set(this.postData, 'AIsOut', 1)
  222. } else {
  223. this.$set(this.info, 'AttendanceType', this.resInfo.AttendanceType)
  224. this.$set(this.info, 'AttendanceTypeString', this.resInfo.AttendanceTypeString)
  225. this.$set(this.postData, 'AIsOut', 0)
  226. }
  227. },
  228. // 获取当前位置
  229. local() {
  230. return new Promise(async (resolve) => {
  231. let res = await this.getLocation()
  232. // let res = {
  233. // lng: 112.57205562051,
  234. // lat: 37.742374280962
  235. // }
  236. if (!res) {
  237. this.$set(this.postData, 'ALon', '')
  238. this.$set(this.postData, 'ALat', '')
  239. this.$set(this.postData, 'ClockPlace', '')
  240. resolve(false)
  241. }
  242. new BMapGL.Convertor().translate([res], 3, 5, data => {
  243. if (data.status == 0) {
  244. // alert(data.points[0].lng + '' + data.points[0].lat)
  245. this.$set(this.postData, 'ALon', data.points[0].lng)
  246. this.$set(this.postData, 'ALat', data.points[0].lat)
  247. let geoc = new BMapGL.Geocoder();
  248. geoc.getLocation(data.points[0], (rs) => {
  249. let addComp = rs.addressComponents;
  250. let address =
  251. addComp.province +
  252. addComp.city +
  253. addComp.district +
  254. addComp.street +
  255. addComp.streetNumber
  256. this.$set(this.postData, 'ClockPlace', address)
  257. resolve(data.points[0])
  258. });
  259. } else {
  260. this.$set(this.postData, 'ALon', '')
  261. this.$set(this.postData, 'ALat', '')
  262. this.$set(this.postData, 'ClockPlace', '')
  263. this.TOAST('获取定位失败!')
  264. resolve(false)
  265. }
  266. })
  267. });
  268. }
  269. },
  270. destroyed() {
  271. clearInterval(this.timer)
  272. clearInterval(this.timer1)
  273. }
  274. }
  275. </script>
  276. <style lang="less">
  277. uni-page-body {
  278. height: 100%;
  279. width: 100%;
  280. background-color: #fff;
  281. }
  282. .content {
  283. width: 100%;
  284. height: 50%;
  285. position: absolute;
  286. top: 15%;
  287. left: 50%;
  288. transform: translate(-50%, 10%);
  289. text-align: center;
  290. }
  291. .title {
  292. font-size: 14px;
  293. text-align: center;
  294. color: #333;
  295. margin-top: 8px;
  296. }
  297. .rules {
  298. display: flex;
  299. justify-content: space-between;
  300. color: #666;
  301. padding: 15px;
  302. line-height: 24px;
  303. }
  304. .rules>* {
  305. width: 49%;
  306. background-color: #BDE4FF;
  307. padding: 8px;
  308. border-radius: 8px 12px;
  309. }
  310. .rules>*>*:first-child {
  311. color: #333;
  312. }
  313. #show {
  314. text-align: center;
  315. height: 200rpx;
  316. font-size: 56rpx;
  317. }
  318. .pen {
  319. width: 48%;
  320. display: inline-block;
  321. border-radius: 50%;
  322. // background-color: #e7f5ff;
  323. }
  324. .pen2 {
  325. width: 91%;
  326. height: 91%;
  327. border-radius: 50%;
  328. background-color: #bde4ff;
  329. display: flex;
  330. align-items: center;
  331. justify-content: center;
  332. }
  333. .pen3 {
  334. width: 84%;
  335. height: 84%;
  336. border-radius: 50%;
  337. background-color: #0c86d8;
  338. text-align: center;
  339. font-size: 68rpx;
  340. display: flex;
  341. align-items: center;
  342. justify-content: center;
  343. color: #ffff;
  344. }
  345. .footer {
  346. width: 100%;
  347. position: fixed;
  348. left: 0;
  349. bottom: 0;
  350. overflow: hidden;
  351. }
  352. .gray {
  353. -webkit-filter: grayscale(100%);
  354. -moz-filter: grayscale(100%);
  355. -ms-filter: grayscale(100%);
  356. -o-filter: grayscale(100%);
  357. filter: grayscale(100%);
  358. filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
  359. filter: gray;
  360. }
  361. </style>