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.
 
 
 
 
 
 

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