clockIn.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. <template>
  2. <page-meta root-font-size="system" />
  3. <view class="container">
  4. <!-- 时间日期信息 -->
  5. <view class="header">
  6. <text class="day">{{ currentDay }}</text>
  7. <text class="date">{{ currentDate }}</text>
  8. <text class="nowTime">{{ nowTime }}</text>
  9. </view>
  10. <!-- 打卡记录 -->
  11. <view class="record">
  12. <!-- <view class="record-item" v-if="nowTime != '' && nowTime <= '12:00:00' || signName == '上班签到'">
  13. <text class="ygoa_icon icon-goToWork"></text>
  14. <text class="title">上班</text>
  15. <text class="time">{{ signInTime || '未打卡' }}</text>
  16. <text class="signStatus" v-if="!isSignInStatusDisabled">({{ signInStatusName }})</text>
  17. </view>
  18. <view class="record-item" v-else-if="nowTime > '12:00:00' && signName == '下班签退'">
  19. <text class="ygoa_icon icon-afterWork"></text>
  20. <text class="title">下班</text>
  21. <text class="time">{{ signOutTime || '未打卡' }}</text>
  22. <text class="signStatus" v-if="!isSignOutStatusDisabled" style="color: #e64340;">({{ signOutStatusName
  23. }})</text>
  24. </view> -->
  25. <view class="record-item" @click="changeAttType">
  26. <text class="ygoa_icon icon-goToWork"></text>
  27. <text class="title">打卡类型</text>
  28. <picker mode="selector" :range="typeRanges" @change="onTypeRangeChange" class="attTypePicker">
  29. <text class="time">
  30. {{ selectedTypeRange }}
  31. </text>
  32. <text class="time">(点击切换)</text>
  33. </picker>
  34. </view>
  35. <view class="record-item" @click="getAddress">
  36. <text class="ygoa_icon icon-location"></text>
  37. <text class="title">当前位置</text>
  38. <text class="time">{{ address || '点击获取定位' }}</text>
  39. </view>
  40. </view>
  41. <!-- 地图 -->
  42. <atl-map :mapKey="config.mapKey" :mapType="mapType" :longitude="longitude" :latitude="latitude" :marker="marker"
  43. :polygons="polygons" :isPolygons="true">
  44. <template v-slot:content>
  45. </template>
  46. </atl-map>
  47. <!-- 打卡按钮 -->
  48. <view class="footer">
  49. <!-- <button type="default" @click="signInOrOut" style="background-color: #3c9cff; color: #fcfcfc;"
  50. v-if="signName == '上班签到'">上班签到</button>
  51. <button type="default" @click="signInOrOut" style="background-color: #1aad19; color: #fcfcfc;"
  52. v-else-if="signName == '下班签退'">下班签退</button> -->
  53. <button type="default" @click="signInOrOut" style="background-color: #3c9cff; color: #fcfcfc;"
  54. >{{selectedTypeRange}}打卡</button>
  55. </view>
  56. </view>
  57. </template>
  58. <script setup lang="ts">
  59. import { onBeforeUnmount, onMounted, reactive, ref } from 'vue';
  60. // 导入地理位置相关函数
  61. import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
  62. import { point, polygon } from "@turf/helpers";
  63. import { useUserStore } from '@/store/user';
  64. import { useConfigStore } from '@/store/config'
  65. import $modal from '@/plugins/modal.js';
  66. import $tab from '@/plugins/tab.js';
  67. import config from '@/config.js';
  68. import { createAttendance, tranAddress, checkAttendance, getAttendanceRule, getAttendanceSegment } from '@/api/mine.js'
  69. const userStore = useUserStore();
  70. const configStore = useConfigStore();
  71. const thisUser = userStore.user;
  72. const intervalId = ref(null); // 定时器ID
  73. onBeforeUnmount(() => {
  74. clearInterval(intervalId.value);
  75. })
  76. // 组件挂载后初始化当前日期与位置
  77. onMounted(() => {
  78. // getAttRule();
  79. dateInit();
  80. getAddress();
  81. });
  82. // 当前日期和时间相关信息
  83. const currentDate = ref('2023-04-01');
  84. const currentDay = ref('星期三');
  85. const nowTime = ref(''); // 当前时间
  86. const weekArr = reactive(['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']); // 星期数组
  87. // 初始化日期
  88. function dateInit() {
  89. showNowTime();
  90. const nowDate = new Date();
  91. const year = nowDate.getFullYear(); // 获取年份
  92. const month = nowDate.getMonth() + 1; // 获取月份
  93. const day = nowDate.getDate(); // 获取日期
  94. // 格式化月份和日期为两位数
  95. const formattedMonth = month < 10 ? '0' + month : month;
  96. const formattedDay = day < 10 ? '0' + day : day;
  97. currentDate.value = `${year}-${formattedMonth}-${formattedDay}`; // 设置当前日期
  98. const dayOfWeek = nowDate.getDay(); // 获取当前星期
  99. currentDay.value = weekArr[dayOfWeek]; // 设置当前星期
  100. getTodayAtt();
  101. // if (nowTime.value > '12:00') {
  102. // signName.value = '下班签退'
  103. // }
  104. }
  105. function showNowTime() {
  106. intervalId.value = setInterval(() => {
  107. nowTime.value = getNowTime()
  108. }, 1000); // 每1秒更新一次
  109. }
  110. const signInTime = ref(''); // 上午上班签到时间
  111. const signOutTime = ref(''); // 下午下班签到时间
  112. const signOutTimeAm = ref(''); // 上午下班签到时间
  113. const signInTimePm= ref(''); // 下午上班签到时间
  114. //打卡按钮文字显示
  115. const signName = ref('')
  116. //迟到早退状态,默认隐藏
  117. const signInStatusName = ref('迟到')
  118. const signOutStatusName = ref('早退')
  119. const isSignInStatusDisabled = ref(true)
  120. const isSignOutStatusDisabled = ref(true)
  121. //获取今天考勤状态
  122. function getTodayAtt() {
  123. const params = {
  124. universalid: thisUser.useId,
  125. rizi: currentDate.value
  126. }
  127. checkAttendance(params).then(res => {
  128. if ("success" == res.returnMsg) {
  129. // console.log("kaoqin",res);
  130. const attList = res.returnParams.list;
  131. let time1;
  132. let time2;
  133. let time3;
  134. let time4;
  135. //上午上班
  136. const filteredRecord1 = attList.filter(item => item.att_type_id === '1');
  137. if (filteredRecord1.length > 0) {
  138. time1 = filteredRecord1.reduce((latest, current) => {
  139. const latestTime = new Date(latest.att_time);
  140. const currentTime = new Date(current.att_time);
  141. return (currentTime < latestTime) ? current : latest;
  142. });
  143. }
  144. //下午下班拿到所有签退数据后,取最大时间的那个
  145. const filteredRecord2 = attList.filter(item => item.att_type_id === '2');
  146. if (filteredRecord2.length > 0) {
  147. time2 = filteredRecord2.reduce((latest, current) => {
  148. const latestTime = new Date(latest.att_time);
  149. const currentTime = new Date(current.att_time);
  150. return (currentTime > latestTime) ? current : latest;
  151. });
  152. }
  153. //上午下班,取最大时间的那个
  154. const filteredRecord3 = attList.filter(item => item.att_type_id === '7');
  155. if (filteredRecord3.length > 0) {
  156. time3 = filteredRecord3.reduce((latest, current) => {
  157. const latestTime = new Date(latest.att_time);
  158. const currentTime = new Date(current.att_time);
  159. return (currentTime > latestTime) ? current : latest;
  160. });
  161. }
  162. //下午上班,取最小时间
  163. const filteredRecord4 = attList.filter(item => item.att_type_id === '8');
  164. if (filteredRecord4.length > 0) {
  165. time4 = filteredRecord4.reduce((latest, current) => {
  166. const latestTime = new Date(latest.att_time);
  167. const currentTime = new Date(current.att_time);
  168. return (currentTime < latestTime) ? current : latest;
  169. });
  170. }
  171. //打卡状态修改
  172. //打了上班卡
  173. let checkContinue = false;
  174. if (time1 !== undefined) {
  175. // console.log('getTime1',time1);
  176. signInTime.value = time1.att_time.split(' ')[1];
  177. if(config.clock && config.clock == 'multiple'){
  178. selectedTypeRange.value='上午下班'
  179. }else{
  180. selectedTypeRange.value='下班'
  181. }
  182. checkContinue = true;
  183. // signName.value = '下班签退';
  184. // if (isTimeInRange(subOneMinute(signInTime.value), ...configStore.lateTimeRange)) {//迟到
  185. // signInStatusName.value = '迟到';
  186. // isSignInStatusDisabled.value = false;
  187. // } else if (isTimeInRange(signInTime.value, configStore.lateTimeRange[1], '23:59:59')) {
  188. // signInStatusName.value = '旷工';
  189. // isSignInStatusDisabled.value = false;
  190. // }
  191. }
  192. // else if (new Date().getHours() >= 12) {
  193. // signName.value = '下班签退'
  194. // }
  195. else {
  196. // signName.value = '上班签到';
  197. if(config.clock && config.clock == 'multiple'){
  198. selectedTypeRange.value='上午上班'
  199. }else{
  200. selectedTypeRange.value='上班'
  201. }
  202. checkContinue = false;
  203. }
  204. //上午下班卡
  205. if (time3 !== undefined) {
  206. signOutTimeAm.value = time3.att_time.split(' ')[1];
  207. if(checkContinue){
  208. selectedTypeRange.value='下午上班'
  209. }
  210. }else{
  211. checkContinue = false;
  212. }
  213. //下午上班卡
  214. if (time4 !== undefined) {
  215. signInTimePm.value = time4.att_time.split(' ')[1];
  216. if(checkContinue){
  217. selectedTypeRange.value='下午下班'
  218. }
  219. }else{
  220. checkContinue = false;
  221. }
  222. //打了下班卡
  223. if (time2 !== undefined) {
  224. signOutTime.value = time2.att_time.split(' ')[1];
  225. // if (isTimeInRange(signOutTime.value, "00:00:00", configStore.earlyTimeRange[0])) {//旷工
  226. // signOutStatusName.value = '旷工';
  227. // isSignOutStatusDisabled.value = false;
  228. // }
  229. // else if (isTimeInRange(signOutTime.value, ...configStore.earlyTimeRange)) {
  230. // signOutStatusName.value = '早退';
  231. // isSignOutStatusDisabled.value = false;
  232. // }
  233. // else {
  234. // isSignOutStatusDisabled.value = true; //隐藏早退状态
  235. // }
  236. }
  237. }
  238. })
  239. }
  240. let typeRanges;
  241. if(config.clock && config.clock == 'multiple'){
  242. typeRanges=ref(['上午上班','上午下班','下午上班','下午下班','外出','外出返回'])
  243. }else{
  244. typeRanges=ref(['上班','下班','外出','外出返回'])
  245. }
  246. const selectedTypeRange=ref('上班')
  247. //打卡类型切换
  248. function onTypeRangeChange(event){
  249. const selectedIndex = event.detail.value;
  250. selectedTypeRange.value=typeRanges.value[selectedIndex]
  251. }
  252. //上班卡或下班卡
  253. function signInOrOut() {
  254. // if ('上班签到' == signName.value) {
  255. // signIn();
  256. // } else {
  257. // signOut();
  258. // }
  259. if(config.clock && config.clock == 'multiple'){
  260. switch(selectedTypeRange.value){
  261. case '上午上班':
  262. signInForMultiple('上午上班')
  263. break
  264. case '下午下班':
  265. signOutForMultiple('下午下班')
  266. break
  267. case '外出':
  268. case '外出返回':
  269. otherTypeClockIn()
  270. break
  271. case '下午上班':
  272. signInForMultiple('下午上班')
  273. break
  274. case '上午下班':
  275. signOutForMultiple('上午下班')
  276. break
  277. }
  278. }else{
  279. switch(selectedTypeRange.value){
  280. case '上班':
  281. signIn()
  282. break
  283. case '下班':
  284. signOut()
  285. break
  286. case '外出':
  287. case '外出返回':
  288. otherTypeClockIn()
  289. break
  290. }
  291. }
  292. }
  293. //外出或外出返回等其他类型的打卡
  294. function otherTypeClockIn(){
  295. //拿到打卡类型
  296. const signIn = typeRanges.value.indexOf(selectedTypeRange.value)+1
  297. getAddress().then(() => {
  298. clockIn(signIn);
  299. });
  300. }
  301. //上班签到
  302. function signIn() {
  303. // const now = getNowTime();
  304. const signIn = 1;
  305. getAddress().then(() => {
  306. clockIn(signIn);
  307. });
  308. };
  309. function signInForMultiple(selectTypeName) {
  310. let signIn = 1;
  311. if(selectTypeName == '上午上班'){
  312. signIn = 1
  313. }else if(selectTypeName == '下午上班'){
  314. signIn = 8
  315. }
  316. getAddress().then(() => {
  317. clockIn(signIn);
  318. });
  319. };
  320. // 下班签退
  321. function signOut() {
  322. const now = getNowTime();
  323. const signOut = 2;
  324. //判断打卡时间是否符合
  325. const currentRangeIndex = 1;
  326. if (!isTimeInRange(now, ...configStore.signOutTimeRange[currentRangeIndex])) {
  327. $modal.confirm('当前非正常签退时间,是否继续?').then(res => {
  328. if (res) {
  329. getAddress().then(() => {
  330. clockIn(signOut); // 执行打卡并获取结果
  331. });
  332. }
  333. }).catch(() => { })
  334. } else {
  335. getAddress().then(() => {
  336. clockIn(signOut);
  337. });
  338. }
  339. };
  340. function signOutForMultiple(selectTypeName) {
  341. const now = getNowTime();
  342. let signOut = 2;
  343. if(selectTypeName == '上午下班'){
  344. signOut = 7
  345. }else if(selectTypeName == '下午下班'){
  346. signOut = 2
  347. }
  348. //判断打卡时间是否符合
  349. const currentRangeIndex = signOut === 7 ? 0 : 1;
  350. if (!isTimeInRange(now, ...configStore.signOutTimeRange[currentRangeIndex])) {
  351. $modal.confirm('当前非正常签退时间,是否继续?').then(res => {
  352. if (res) {
  353. getAddress().then(() => {
  354. clockIn(signOut); // 执行打卡并获取结果
  355. });
  356. }
  357. }).catch(() => { })
  358. } else {
  359. getAddress().then(() => {
  360. clockIn(signOut);
  361. });
  362. }
  363. };
  364. //获取当前时间
  365. function getNowTime() {
  366. return new Date().toLocaleTimeString('en-US', {
  367. hour12: false
  368. }).substring(0, 8)
  369. }
  370. //判断时间是否在区间内
  371. function isTimeInRange(time, startTime, endTime) {
  372. // 将时间字符串转换为Date对象
  373. const timeObj = new Date('1970-01-01T' + time + 'Z');
  374. const startObj = new Date('1970-01-01T' + startTime + 'Z');
  375. const endObj = new Date('1970-01-01T' + endTime + 'Z');
  376. // 比较时间
  377. return timeObj >= startObj && timeObj < endObj;
  378. }
  379. //减一分钟
  380. function subOneMinute(timeStr) {
  381. // 将时间字符串转换为 Date 对象
  382. const [hours, minutes, seconds] = timeStr.split(':').map(Number);
  383. const date = new Date();
  384. date.setHours(hours, minutes, seconds, 0); // 设置时间为给定的时分秒
  385. // 减去一分钟
  386. date.setMinutes(date.getMinutes() - 1);
  387. return date.toTimeString().slice(0, 8);
  388. }
  389. // 地图配置信息
  390. // const mapKey = config.mapKey; // 地图API密钥
  391. const mapType = ref('tmap'); // 地图类型
  392. const address = ref(''); // 初始化地址
  393. // 打卡定位信息
  394. const longitude = ref(); // 经度
  395. const latitude = ref(); // 纬度
  396. // 标记信息
  397. const marker = reactive({
  398. id: 1,
  399. latitude: 25.958812,
  400. longitude: 119.213036,
  401. width: 50, // 标记宽度
  402. height: 50, // 标记高度
  403. title: '宇光同行' // 标记标题
  404. });
  405. // 获取当前定位经纬度
  406. function getlocation() {
  407. return new Promise((resolve, reject) => {
  408. //判断用户是否打开位置权限
  409. uni.getSetting({
  410. success(res) {
  411. // 如果用户未授权
  412. if (!res.authSetting['scope.userLocation']) {
  413. $modal.confirm('需要您授权获取地理位置信息').then(res => {
  414. if (res) {
  415. // 打开权限设置页面
  416. uni.openSetting({
  417. success: (settingData) => {
  418. if (settingData.authSetting[
  419. 'scope.userLocation']) {
  420. $modal.msg('授权后请重新打开此页面')
  421. // reject("用户未授权");
  422. }
  423. }
  424. });
  425. }
  426. })
  427. .catch(err => {
  428. //用户点击取消
  429. if (!err) {
  430. uni.showToast({
  431. title: '获取地理位置授权失败',
  432. icon: 'none',
  433. success: () => {
  434. // 返回上一页
  435. setTimeout(() => {
  436. $tab.navigateBack()
  437. }, 1000);
  438. }
  439. });
  440. // reject("用户未授权");
  441. }
  442. })
  443. } else {
  444. // 已授权,获取位置
  445. fetchLocation(resolve, reject);
  446. }
  447. },
  448. fail(err) {
  449. reject(err); // 拒绝 Promise
  450. }
  451. });
  452. });
  453. }
  454. // 封装获取位置的函数
  455. function fetchLocation(resolve, reject) {
  456. wx.getLocation({
  457. type: 'gcj02',
  458. isHighAccuracy: true, // 开启高精度定位
  459. highAccuracyExpireTime: 4000, // 高精度定位超时时间
  460. success: (res) => {
  461. longitude.value = res.longitude; // 保存经度
  462. latitude.value = res.latitude; // 保存纬度
  463. resolve(); // 解析 Promise
  464. },
  465. fail: (err) => {
  466. if (err.errMsg.includes("频繁调用")) {
  467. $modal.msg('请勿频繁调用');
  468. // reject("频繁调用错误");
  469. return;
  470. }
  471. // console.log('getLocationErr', err);
  472. reject(err); // 拒绝 Promise
  473. },
  474. });
  475. }
  476. // 获取当前位置地址
  477. function getAddress() {
  478. return new Promise((resolve, reject) => {
  479. getlocation()
  480. .then(res => {
  481. tranLocationToAddress(); // 执行地址转换
  482. resolve(res); // 地址获取成功
  483. })
  484. .catch(err => {
  485. // console.error('获取地址失败', err);
  486. reject(err); // 地址获取失败
  487. });
  488. });
  489. }
  490. // 经纬度转地址
  491. function tranLocationToAddress() {
  492. let locationStr = latitude.value + ',' + longitude.value; // 组合经纬度
  493. tranAddress(locationStr).then(res => {
  494. address.value = res.result.address; // 保存地址
  495. })
  496. .catch(err => {
  497. console.log('地址转换请求失败', err); // 请求错误处理
  498. })
  499. }
  500. // 多边形区域设置
  501. const polygons = reactive([{
  502. points: [{
  503. latitude: 25.9591401,
  504. longitude: 119.21292356
  505. },
  506. {
  507. latitude: 25.95828592,
  508. longitude: 119.21261955
  509. },
  510. {
  511. latitude: 25.9576709,
  512. longitude: 119.21458294
  513. },
  514. {
  515. latitude: 25.95845106,
  516. longitude: 119.21486162
  517. },
  518. {
  519. latitude: 25.9591401,
  520. longitude: 119.21292356
  521. }
  522. ],
  523. strokeWidth: 1, // 边框宽度
  524. strokeColor: "#ff000066", // 边框颜色
  525. fillColor: "#ff000016", // 填充颜色
  526. }]);
  527. // 打卡
  528. function clockIn(attType) {
  529. // 发起打卡请求相关业务逻辑
  530. //判断是否已经打过上班卡
  531. if (isClockIn(attType)) {
  532. return;
  533. }
  534. var now = new Date();
  535. // 使用toISOString()获取一个ISO格式的字符串,然后替换T为空格,并去除最后的Z(表示UTC时间)
  536. var formatted = now.toISOString().replace('T', ' ').replace('Z', '');
  537. var localString = new Date(formatted + '-08:00').toISOString().replace('T', ' ').replace('Z', '');
  538. const params = {
  539. user_name: thisUser.name,
  540. user_id: thisUser.useId,
  541. kaoqin_type: attType,
  542. now_date: localString,
  543. longitude: longitude.value,
  544. latitude: latitude.value,
  545. address: address.value,
  546. unitId: thisUser.unitId
  547. };
  548. createAttendance(params).then(res => {
  549. if ("success" == res.returnMsg) {
  550. if(1==attType || 2==attType || 7==attType || 8==attType){
  551. getTodayAtt(); //更新今日考勤数据
  552. }
  553. isToFillClock(attType, localString.substring(11, 19));//判断考勤状态是否异常
  554. } else {
  555. uni.showToast({
  556. title: "未在指定范围,打卡失败",
  557. icon: 'none'
  558. });
  559. }
  560. })
  561. // const _polygons = polygons.map((polygon) => {
  562. // return polygon.points.map((i) => [
  563. // Number(i.longitude),
  564. // Number(i.latitude),
  565. // ]);
  566. // });
  567. // const _point = point([longitude.value, latitude.value]); // 用当前坐标创建点
  568. // const _polygon = polygon(_polygons); // 创建多边形
  569. // const f = booleanPointInPolygon(_point, _polygon); // 判断点是否在多边形内
  570. }
  571. //是否补卡、请假判断
  572. function isToFillClock(attType, time) {
  573. // console.log('isToFillClock',attType,time);
  574. // 早上迟到跳补卡
  575. let status = '';
  576. if (attType === 1 || attType === 8) {
  577. const currentRangeIndex = attType === 1 ? 0 : 1;
  578. if (isTimeInRange(subOneMinute(time), ...configStore.lateTimeRange[currentRangeIndex])) {
  579. status = '迟到';
  580. } else if (isTimeInRange(time, configStore.lateTimeRange[currentRangeIndex][1], '23:59:59')) {
  581. status = '旷工';
  582. } else {
  583. $modal.msgSuccess(' 打卡成功');
  584. setTimeout(() => {
  585. $tab.navigateTo('/pages/mine/checkIn/checkIn');
  586. }, 1000);
  587. return;
  588. }
  589. if(config.companyCode && config.companyCode == 'yg'){
  590. $modal.confirm(' 当前状态为' + status + '!\n是否跳转补卡页面').then(() => {
  591. $tab.reLaunch('/pages/work/index');
  592. })
  593. .catch(() => {
  594. $tab.navigateTo('/pages/mine/checkIn/checkIn');
  595. });
  596. }else{
  597. $tab.navigateTo('/pages/mine/checkIn/checkIn');
  598. }
  599. } else if (attType === 2 || attType === 7) {
  600. const currentRangeIndex = attType === 7 ? 0 : 1;
  601. // 早退请假提示
  602. if (isTimeInRange(time, '00:00:00', configStore.earlyTimeRange[currentRangeIndex][0])) {
  603. status = '旷工';
  604. } else if (isTimeInRange(time, ...configStore.earlyTimeRange[currentRangeIndex])) {
  605. status = '早退';
  606. } else {
  607. $modal.msgSuccess(' 打卡成功');
  608. setTimeout(() => {
  609. $tab.navigateTo('/pages/mine/checkIn/checkIn');
  610. }, 1000);
  611. return;
  612. }
  613. $modal.confirm(' 当前状态为' + status + '!\n是否跳转请假页面').then(() => {
  614. $tab.reLaunch('/pages/work/index');
  615. })
  616. .catch(() => {
  617. $tab.navigateTo('/pages/mine/checkIn/checkIn');
  618. });
  619. } else {
  620. $modal.msgSuccess(' 打卡成功');
  621. setTimeout(() => {
  622. $tab.navigateBack();
  623. }, 1000);
  624. }
  625. }
  626. //判断是否已经打过上班卡
  627. function isClockIn(attType) {
  628. if (1==attType && '' != signInTime.value) {
  629. $modal.showToast('请勿重复打卡')
  630. return true;
  631. }else if (8==attType && '' != signInTimePm.value) {
  632. $modal.showToast('请勿重复打卡')
  633. return true;
  634. }
  635. return false;
  636. }
  637. </script>
  638. <style lang="scss" scoped>
  639. // @import "@/static/font/ygoa/iconfont.css";
  640. .ygoa_icon {
  641. margin-right: 20rpx;
  642. /* font-size: calc(26px + .5(1rem - 16px)); */
  643. font-size: calc(1.625rem + 0px) !important;
  644. }
  645. .container {
  646. display: flex;
  647. flex-direction: column;
  648. align-items: center;
  649. padding: 20rpx;
  650. .header {
  651. width: 100%;
  652. height: 200rpx;
  653. background-color: #f8f8f8;
  654. display: flex;
  655. flex-direction: column;
  656. align-items: center;
  657. justify-content: center;
  658. .day {
  659. font-size: calc(1.5rem + 0px);
  660. color: #333;
  661. /* font-weight: bold; */
  662. }
  663. .date,
  664. .nowTime {
  665. font-size: calc(1rem + 0px);
  666. color: #666;
  667. }
  668. // .nowTime {
  669. // font-size: 16px;
  670. // color: #666;
  671. // }
  672. }
  673. }
  674. .record {
  675. width: 100%;
  676. margin-top: 20rpx;
  677. border-top: 1px solid #ddd;
  678. border-bottom: 1px solid #ddd;
  679. padding: 0 15rpx;
  680. .record-item {
  681. display: flex;
  682. align-items: center;
  683. height: 100rpx;
  684. border-bottom: 1px solid #eee;
  685. .icon {
  686. width: 50rpx;
  687. height: 50rpx;
  688. margin-right: 10rpx;
  689. }
  690. .title {
  691. font-size: calc(0.9rem + 0px);
  692. }
  693. .time {
  694. font-size: calc(0.8rem + 0px);
  695. color: #999;
  696. margin-left: auto;
  697. }
  698. .signStatus {
  699. font-size: calc(0.9rem + 0px);
  700. color: orange;
  701. /* margin-left: auto; */
  702. }
  703. picker{
  704. width: 73%;
  705. text-align: right;
  706. .attType{
  707. font-size: calc(0.8rem + 0px);
  708. }
  709. }
  710. }
  711. }
  712. ::v-deep.map-content {
  713. .map {
  714. margin-top: 20rpx;
  715. height: 56vh !important;
  716. }
  717. }
  718. .footer {
  719. width: 100%;
  720. // margin-top: 20rpx;
  721. display: flex;
  722. justify-content: space-around;
  723. position: sticky;
  724. z-index: 10;
  725. bottom: 10px;
  726. button {
  727. font-size: calc(18px + .5*(1rem - 16px));
  728. width: 100%;
  729. }
  730. }
  731. </style>