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.
 
 
 
 
 
 

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