punchClocks.jsx 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. import React, { Component } from 'react'
  2. import { connect } from 'react-redux'
  3. import { Map, OpenData, View, Image, Text, Button } from '@tarojs/components'
  4. import Taro from '@tarojs/taro';
  5. import { AtIcon, AtModal, AtModalHeader, AtModalContent, AtModalAction, AtTextarea, AtRadio, AtList } from "taro-ui";
  6. import dayjs from 'dayjs';
  7. import Skeleton from 'taro-skeleton'
  8. import HistoricalClock from '../../components/historicalClock';
  9. import ImagePicker from '../../components/common/imagePicker';
  10. import { add, minus, asyncAdd } from '../../actions/counter'
  11. import { getPublicReleaseList, publicReleaseClockIn, getPunchClockInfo, getReleasetDails } from '../../utils/servers/servers';
  12. import './index.less'
  13. import switchIocn from '../../image/switch.png';
  14. import Location from '../../image/location.png';
  15. import PunchRange from '../../image/punchRange.png';
  16. import 'taro-ui/dist/style/components/noticebar.scss';
  17. import 'taro-ui/dist/style/components/icon.scss';
  18. import 'taro-ui/dist/style/components/list.scss';
  19. import "taro-ui/dist/style/components/radio.scss";
  20. import "taro-ui/dist/style/components/icon.scss";
  21. import { getClockState, getNewOptions } from "../../utils/tools";
  22. const QQMapWX = require('../../components/common/mapSDK/qqmap-wx-jssdk.min.js');
  23. @connect(({ counter }) => ({
  24. counter
  25. }), (dispatch) => ({
  26. add() {
  27. dispatch(add())
  28. },
  29. dec() {
  30. dispatch(minus())
  31. },
  32. asyncAdd() {
  33. dispatch(asyncAdd())
  34. }
  35. }))
  36. class PunchClocks extends Component {
  37. constructor(props) {
  38. super(props);
  39. this.state = {
  40. imgs: [],
  41. nowTime: '00:00:00',
  42. newArrder: {},
  43. addressLatitude: '',
  44. addressLongitude: '',
  45. defaultLat: '28.2424',
  46. defaultLng: '112.957',
  47. distance: '',
  48. dtails: {},
  49. data: {
  50. prdcList: []
  51. },
  52. loading: true,
  53. isAbnormalOpen: false,
  54. clockInRemarks: "",//打卡说明
  55. }
  56. this.onChange = this.onChange.bind(this);
  57. this.getSpacing = this.getSpacing.bind(this);
  58. this.getData = this.getData.bind(this);
  59. this.publicReleaseClockIn = this.publicReleaseClockIn.bind(this);
  60. this.abnormalClockIn = this.abnormalClockIn.bind(this);
  61. this.refresh = this.refresh.bind(this);
  62. this.getDtails = this.getDtails.bind(this);
  63. this.selectArrder = this.selectArrder.bind(this);
  64. this.selectOn = this.selectOn.bind(this);
  65. }
  66. nowTime = null;
  67. wxConfig = null;
  68. mapCtx = Taro.createMapContext('map');
  69. qqmapsdk = new QQMapWX({
  70. key: 'AWBBZ-GRAC2-JFYUO-CLA7I-JAHXK-YFFGT'
  71. });
  72. componentDidMount() {
  73. this.getDtails();
  74. }
  75. selectOn() {
  76. const { dtails, selectUid } = this.state
  77. if (!selectUid) {
  78. Taro.showToast({ title: '请选择您要打卡的企业', icon: 'none' });
  79. return
  80. }
  81. let list = dtails.prdList
  82. for (var i = 0; i < list.length; i++) {
  83. if (list[i].uid == selectUid) {
  84. console.log(list[i])
  85. this.setState({
  86. data: list[i],
  87. addressLatitude: parseFloat(list[i].latitude || this.state.defaultLat),
  88. addressLongitude: parseFloat(list[i].longitude || this.state.defaultLng),
  89. isTips: false,
  90. selectUid: "",
  91. })
  92. }
  93. }
  94. }
  95. selectArrder() {
  96. const { dtails, data } = this.state
  97. this.props.getId(dtails.id, data.uid)
  98. this.props.getHome()
  99. const key = "AWBBZ-GRAC2-JFYUO-CLA7I-JAHXK-YFFGT"; //使用在腾讯位置服务申请的key
  100. const referer = "科德打卡定位"; //调用插件的app的名称
  101. const category = "公司企业,房产小区";
  102. Taro.navigateTo({
  103. url:
  104. "plugin://chooseLocation/index?key=" +
  105. key +
  106. "&referer=" +
  107. referer +
  108. "&category=" +
  109. category,
  110. });
  111. }
  112. getDtails() {
  113. this.getData(() => {
  114. Taro.startLocationUpdate({
  115. success: () => {
  116. Taro.onLocationChange((v) => {
  117. this.getSpacing(v.latitude, v.longitude)
  118. })
  119. },
  120. fail: (err) => {
  121. Taro.getSetting({
  122. success: (res) => {
  123. if (!res.authSetting['scope.userLocation']) {
  124. Taro.authorize({
  125. scope: 'scope.userLocation',
  126. success: () => {
  127. },
  128. fail: () => {
  129. this.setState({
  130. isOpened: true
  131. })
  132. }
  133. })
  134. }
  135. }
  136. })
  137. this.setState({
  138. loading: false
  139. })
  140. }
  141. })
  142. });
  143. }
  144. componentWillMount() {
  145. let obj = Taro.getStorageSync('userInfor');
  146. if (!obj) {
  147. // 判断是否登录
  148. return
  149. }
  150. this.wxConfig = Taro.getStorageSync('wxConfig');
  151. //获得当前位置
  152. Taro.getLocation({
  153. type: 'gcj02',
  154. isHighAccuracy: true,
  155. success: (res) => {
  156. const latitude = res.latitude
  157. const longitude = res.longitude
  158. this.setState({
  159. newArrder: {
  160. latitude,
  161. longitude
  162. },
  163. })
  164. }
  165. })
  166. this.nowTime = setInterval(() => {
  167. this.setState({
  168. nowTime: dayjs().format('HH:mm:ss')
  169. })
  170. }, 1000)
  171. Taro.eventCenter.on('punchClockComponentDidShow', () => {
  172. if (Object.keys(this.state.dtails).length === 0) {
  173. this.getDtails();
  174. }
  175. })
  176. Taro.eventCenter.on('GoPunchIn', (arg) => {
  177. getReleasetDails({
  178. id: arg.id,
  179. }).then((v) => {
  180. if (v.error.length === 0) {
  181. if (v.data) {
  182. if (!v.data.prdList) {
  183. return
  184. }
  185. let data = v.data.prdList[0]
  186. this.setState({
  187. dtails: v.data,
  188. data,
  189. addressLatitude: parseFloat(data.latitude || this.state.defaultLat),
  190. addressLongitude: parseFloat(data.longitude || this.state.defaultLng),
  191. }, () => {
  192. Taro.showToast({ title: '切换成功' });
  193. Taro.startLocationUpdate({
  194. success: () => {
  195. Taro.onLocationChange((v) => {
  196. this.getSpacing(v.latitude, v.longitude)
  197. })
  198. },
  199. fail: () => {
  200. this.setState({
  201. loading: false
  202. })
  203. }
  204. })
  205. })
  206. } else {
  207. }
  208. } else {
  209. Taro.showToast({ title: v.error[0].message, icon: "none" });
  210. }
  211. }).catch((err) => {
  212. Taro.showToast({ title: "系统错误,请稍后再试", icon: "none" });
  213. });
  214. })
  215. }
  216. componentDidHide() {
  217. Taro.offLocationChange();
  218. this.nowTime && this.nowTime.clearTimeout();
  219. }
  220. // 正常打卡
  221. publicReleaseClockIn(uid) {
  222. const { dtails } = this.state
  223. if (dtails.status !== 2) {
  224. Taro.hideLoading()
  225. Taro.showToast({ title: '公出审核中,不可打卡', icon: 'none' });
  226. return;
  227. }
  228. if (dtails.type === 3 && dtails.publicAssistAdvice === 0) {
  229. Taro.hideLoading()
  230. Taro.showToast({ title: '未填写协单意见,不可打卡', icon: 'none' });
  231. return;
  232. }
  233. if (dtails.status === 3) {
  234. Taro.hideLoading()
  235. Taro.showToast({ title: '申请已撤销,无法打卡', icon: 'none' });
  236. return;
  237. }
  238. if (Object.keys(dtails).length === 0) {
  239. Taro.hideLoading()
  240. Taro.showToast({ title: '暂无公出申请,无法打卡', icon: 'none' });
  241. return;
  242. }
  243. if (![5, 6].includes(dtails.type) && isNaN(parseInt(this.state.distance))) {
  244. Taro.hideLoading()
  245. Taro.showToast({ title: '定位错误,请联系管理员', icon: 'none' })
  246. return;
  247. }
  248. if ([5, 6].includes(dtails.type)) {
  249. let nowTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
  250. let startTime = dayjs(dtails.releaseStarts).format('YYYY-MM-DD 00:00:00')
  251. let endTime = dayjs(dtails.releaseEnds).format('YYYY-MM-DD 23:59:59')
  252. if (dayjs(nowTime).isAfter(dayjs(startTime)) && dayjs(nowTime).isBefore(dayjs(endTime)) ) {
  253. Taro.hideLoading()
  254. Taro.showToast({ title: '当前时间不在打卡时间范围内,无法打卡', icon: 'none' })
  255. return
  256. }
  257. } else {
  258. if ((dayjs().isBefore(dtails.releaseStarts) || dayjs().isAfter(dtails.releaseEnds))) {
  259. Taro.hideLoading()
  260. Taro.showToast({ title: '当前时间不在打卡时间范围内,无法打卡', icon: 'none' })
  261. return
  262. }
  263. }
  264. // 非公出协单不受位置影响
  265. if ([5, 6].indexOf(dtails.type) === -1 && !(this.state.distance <= this.wxConfig.clockInRange && this.state.distance >= 0)) {
  266. Taro.hideLoading()
  267. Taro.showToast({ title: '当前位置未处于可打卡范围,无法打卡', icon: 'none' })
  268. return;
  269. }
  270. // if (dtails.type == 0 && (dtails.publicType == 1 || dtails.publicType == 3)) {
  271. // Taro.hideLoading()
  272. // Taro.showToast({ title: '公出他人企业!需通过审核,才可打卡!', icon: 'none' });
  273. // return
  274. // }
  275. // if (dtails.type == 1 && (dtails.techStartProcess == 1 || dtails.techStartProcess == 3)) {
  276. // Taro.hideLoading()
  277. // Taro.showToast({ title: '已超过合同规定时限,需审核通过,才可打卡!', icon: 'none' });
  278. // return
  279. // }
  280. if (this.state.imgs.length === 0) {
  281. Taro.hideLoading()
  282. Taro.showToast({ title: '请上传打卡照片', icon: 'none' })
  283. return;
  284. }
  285. publicReleaseClockIn({
  286. id: dtails.id,
  287. photoUrl: this.state.imgs.join(','),
  288. clockIn: 1,
  289. uid: this.state.data.uid,
  290. }).then(v => {
  291. Taro.hideLoading()
  292. if (v.error.length === 0) {
  293. Taro.showToast({
  294. title: dtails.type == 1
  295. ? ((dtails.techStartProcess == 1 || dtails.techStartProcess == 3)
  296. ? '打卡成功!此次公出未通过营销审核!'
  297. : '打卡成功!')
  298. : '打卡成功!',
  299. icon: 'none'
  300. });
  301. this.imagePicker.clear();
  302. this.state.data.prdcList[0].status = 1;
  303. this.setState({
  304. data: this.state.data,
  305. imgs: []
  306. })
  307. } else {
  308. Taro.showToast({ title: v.error[0].message, icon: 'none' })
  309. }
  310. }).catch(() => {
  311. Taro.hideLoading()
  312. Taro.showToast({
  313. title: '系统错误,请稍后再试',
  314. icon: 'none'
  315. })
  316. })
  317. }
  318. // 异常打卡
  319. abnormalClockIn() {
  320. if (!this.state.clockInRemarks) {
  321. Taro.showToast({ title: '请填写异常打卡原因!', icon: 'none' })
  322. return;
  323. }
  324. Taro.showLoading({ title: '正在提交...' });
  325. publicReleaseClockIn({
  326. id: this.state.dtails.id,
  327. photoUrl: this.state.imgs.join(','),
  328. clockInRemarks: this.state.clockInRemarks,
  329. clockIn: 2,
  330. }).then(v => {
  331. Taro.hideLoading()
  332. if (v.error.length === 0) {
  333. Taro.showToast({ title: '打卡成功', icon: 'none' });
  334. this.imagePicker.clear();
  335. this.state.data.prdcList[0].status = 2;
  336. this.setState({
  337. data: this.state.data,
  338. imgs: [],
  339. clockInRemarks: "",
  340. isAbnormalOpen: false,
  341. })
  342. } else {
  343. Taro.showToast({ title: v.error[0].message, icon: 'none' })
  344. }
  345. }).catch(() => {
  346. Taro.hideLoading()
  347. Taro.showToast({
  348. title: '系统错误,请稍后再试',
  349. icon: 'none'
  350. })
  351. })
  352. }
  353. getData(fn) {
  354. this.setState({
  355. loading: true
  356. })
  357. getPunchClockInfo().then(v => {
  358. if (v.error.length === 0) {
  359. this.setState({
  360. loading: false
  361. })
  362. if (v.data) {
  363. let data = v.data.prdList[0]
  364. this.setState({
  365. dtails: v.data,
  366. data,
  367. addressLatitude: data.latitude || this.state.defaultLat,
  368. addressLongitude: data.longitude || this.state.defaultLng,
  369. }, () => {
  370. fn();
  371. })
  372. } else {
  373. this.setState({
  374. dtails: {},
  375. data: {},
  376. })
  377. }
  378. } else {
  379. this.setState({
  380. loading: false
  381. })
  382. Taro.showToast({
  383. title: v.error[0].message,
  384. icon: 'none'
  385. })
  386. }
  387. })
  388. }
  389. getSpacing(latitude, longitude) {
  390. let _this = this;
  391. this.qqmapsdk.calculateDistance({
  392. mode: 'straight',
  393. from: {
  394. latitude: this.state.addressLatitude,
  395. longitude: this.state.addressLongitude,
  396. },
  397. to: [
  398. {
  399. latitude,
  400. longitude,
  401. }
  402. ],
  403. success: function (res) {//成功后的回调
  404. _this.setState({
  405. distance: res.result.elements[0].distance,
  406. loading: false
  407. })
  408. },
  409. fail: function (error) {
  410. _this.setState({
  411. loading: false
  412. })
  413. console.error(error);
  414. },
  415. complete: function (res) {
  416. }
  417. });
  418. }
  419. onChange(value, type) {
  420. let arr = this.state.imgs.concat([]);
  421. if (type === 'add') {
  422. arr.push(value)
  423. } else if (type === 'remove') {
  424. arr.splice(value, 1)
  425. }
  426. this.setState({
  427. imgs: arr,
  428. })
  429. }
  430. refresh() {
  431. this.getData(() => {
  432. Taro.startLocationUpdate({
  433. success: () => {
  434. Taro.onLocationChange((v) => {
  435. this.getSpacing(v.latitude, v.longitude)
  436. })
  437. }
  438. })
  439. });
  440. }
  441. getClockBgColor() {
  442. const { dtails, distance, data } = this.state
  443. const newClockIn = !!data.prdcList && data.prdcList.length > 0 ? data.prdcList[0] : {};
  444. if ([5, 6].indexOf(dtails.type) > -1) {
  445. let nowTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
  446. let startTime = dayjs(dtails.releaseStarts).format('YYYY-MM-DD 00:00:00')
  447. let endTime = dayjs(dtails.releaseEnds).format('YYYY-MM-DD 23:59:59')
  448. if (dayjs(nowTime).isAfter(dayjs(startTime)) && dayjs(nowTime).isBefore(dayjs(endTime)) ) {
  449. return [1, 2].includes(newClockIn.status) ? '#3f82e8' : '#72cb78'
  450. } else {
  451. return '#828e83'
  452. }
  453. } else {
  454. return (!isNaN(parseInt(distance)))
  455. && distance <= this.wxConfig.clockInRange
  456. && distance >= 0
  457. && !(dayjs().isBefore(dtails.releaseStarts) || dayjs().isAfter(dtails.releaseEnds))
  458. && dtails.status === 2
  459. ? dtails.type === 3
  460. ? dtails.publicAssistAdvice > 0
  461. ? ((newClockIn.status === 1 || newClockIn.status === 2) ? '#3f82e8' : '#72cb78')
  462. : '#828e83'
  463. : ((newClockIn.status === 1 || newClockIn.status === 2) ? '#3f82e8' : '#72cb78')
  464. : '#828e83'
  465. }
  466. }
  467. render() {
  468. const { dtails, data } = this.state;
  469. const newClockIn = !!data.prdcList && data.prdcList.length > 0 ? data.prdcList[0] : {};
  470. return (
  471. <View className='punchClock'>
  472. <View className='header'>
  473. <Skeleton
  474. title
  475. avatar
  476. row={2}
  477. animateName='elastic'
  478. avatarShape='square'
  479. loading={this.state.loading}
  480. >
  481. <View className='headerContent'>
  482. <View className='userAvatarUrl'>
  483. <OpenData type='userAvatarUrl' />
  484. </View>
  485. <View className='infor'>
  486. <View className='name'>
  487. {
  488. Object.keys(dtails).length <= 0 ?
  489. Taro.getStorageSync('userInfor').name :
  490. dtails.aname
  491. }
  492. </View>
  493. <View className='types'
  494. style={{ color: ["#1D4FEA", "#1E90FF", "#FF5500", "red", "", "#1D4FEA"][dtails.type] }}
  495. >
  496. {["业务公出", "技术公出", "行政公出", "技术协单", "", "非公出协单", "非公出协单"][dtails.type]}
  497. </View>
  498. </View>
  499. {
  500. Object.keys(this.state.dtails).length <= 0 ?
  501. <View onClick={this.refresh} className='state' style={{
  502. alignSelf: 'center',
  503. textAlign: 'center',
  504. color: '#b6b5b5',
  505. fontSize: '11px'
  506. }}>
  507. <AtIcon value='reload' size='20' />
  508. <View>刷新</View>
  509. </View> :
  510. <View className='state' style={{
  511. color: getClockState(dtails.status).color
  512. }}>
  513. <View style={{ textAlign: 'right' }}>
  514. {
  515. getClockState(dtails.status).title
  516. }
  517. </View>
  518. <View className='switchContent' onClick={() => {
  519. Taro.switchTab({
  520. url: '/pages/mybusiness/index',
  521. })
  522. }}>
  523. <View className='switchTitle'>切换打卡</View>
  524. <Image src={switchIocn} className='switchItem' />
  525. </View>
  526. </View>
  527. }
  528. </View>
  529. </Skeleton>
  530. </View>
  531. {
  532. Object.keys(this.state.dtails).length <= 0 ?
  533. <View className='content'>
  534. <View className='punchClockContent'
  535. onClick={this.publicReleaseClockIn}
  536. style={{
  537. boxShadow: '1px 1px 15px 1px #acb8ad',
  538. background: '#828e83',
  539. marginTop: '85px',
  540. }}>
  541. <View className='punchClockTitle'>公出打卡</View>
  542. <View className='punchClockTime'>{this.state.nowTime}</View>
  543. </View>
  544. <View className='noData'>
  545. <View className='tipsNoData'>
  546. 暂无公出申请
  547. </View>
  548. <View className='goOut' onClick={() => {
  549. Taro.switchTab({
  550. url: '/pages/applyDepart/index',
  551. })
  552. }}>
  553. 点击前往申请公出
  554. </View>
  555. </View>
  556. </View> :
  557. <View>
  558. <View className='content'>
  559. <View className="enterprise">
  560. <View className='entit'>公出企业</View>
  561. <View className='userlist'>
  562. <Text className='username'>
  563. {data.userName}
  564. {(newClockIn.status === 1 || newClockIn.status === 2) && <Text style={{ color: "#72cb78" }}>(已打卡)</Text>}
  565. </Text>
  566. {
  567. this.state.dtails.prdList?.length > 1 &&
  568. <View className='switch' onClick={() => { this.setState({ isTips: true }) }}>
  569. <View className='stxt'>切换企业</View>
  570. <Image src={switchIocn} className='sicon' />
  571. </View>
  572. }
  573. </View>
  574. </View>
  575. <View className='timeContent'>
  576. <View className='timeItem'>
  577. <View className='timeTitle'>公出开始时间</View>
  578. <View className='timeValue'>{dtails.releaseStarts}</View>
  579. </View>
  580. <View className='timeItem'>
  581. <View className='timeTitle'>公出结束时间</View>
  582. <View className='timeValue'>{dtails.releaseEnds}</View>
  583. </View>
  584. </View>
  585. <View className='photographContent'>
  586. <View className='photographTitle'>打卡拍照<Text className='tips'>〔可以上传多张〕</Text></View>
  587. <AtIcon onClick={() => {
  588. Taro.chooseImage({
  589. count: 1,
  590. sizeType: ['compressed'],
  591. sourceType: ['camera'],
  592. success: (res) => {
  593. // tempFilePath可以作为img标签的src属性显示图片
  594. const tempFilePaths = res.tempFilePaths
  595. this.imagePicker.onImgChange([{ url: tempFilePaths[0] }], 'add', 0, 'camera')
  596. }
  597. })
  598. }} value='camera' size='25' color='#4395ff' />
  599. </View>
  600. <View style={{ alignSelf: 'flex-start', width: '100%' }}>
  601. <ImagePicker ref={ref => this.imagePicker = ref} url='/api/admin/release/upload' showAddBtn={false} onChange={this.onChange} />
  602. </View>
  603. {/* 异常打卡 */}
  604. {
  605. // dtails.type == 3 &&
  606. false &&
  607. <View
  608. className="photographUnusual"
  609. style={{ background: newClockIn.status === 1 ? "#f69c9f" : "red" }}
  610. onClick={() => {
  611. if (this.state.imgs.length === 0) {
  612. Taro.hideLoading()
  613. Taro.showToast({ title: '请上传打卡照片', icon: 'none' })
  614. return;
  615. }
  616. this.setState({
  617. isAbnormalOpen: true
  618. })
  619. }}
  620. >{(newClockIn.status === 1 || newClockIn.status === 2) ? "更新打卡" : "异常打卡"}</View>
  621. }
  622. <View className='punchClockContent'
  623. onClick={() => {
  624. let _this = this;
  625. Taro.showLoading({ title: '加载中...' })
  626. Taro.getSetting({
  627. success: (res) => {
  628. if (!res.authSetting['scope.userLocation']) {
  629. Taro.authorize({
  630. scope: 'scope.userLocation',
  631. success: () => {
  632. _this.publicReleaseClockIn();
  633. },
  634. fail: () => {
  635. Taro.hideLoading()
  636. this.setState({
  637. isOpened: true
  638. })
  639. }
  640. })
  641. } else {
  642. _this.publicReleaseClockIn();
  643. }
  644. }
  645. })
  646. }}
  647. style={{
  648. boxShadow: '1px 1px 15px 1px '+this.getClockBgColor(),
  649. background: this.getClockBgColor()
  650. }}>
  651. <View className='punchClockTitle'>
  652. {
  653. (newClockIn.status === 1 || newClockIn.status === 2) ?
  654. '更新打卡' : '公出打卡'
  655. }
  656. </View>
  657. <View className='punchClockTime'>{this.state.nowTime}</View>
  658. <View
  659. onClick={e => {
  660. e.stopPropagation()
  661. this.refresh()
  662. }}
  663. className='refresh'
  664. style={{
  665. alignSelf: 'center',
  666. textAlign: 'center',
  667. color: '#b6b5b5',
  668. fontSize: '11px'
  669. }}>
  670. <AtIcon value='reload' size='20' />
  671. <View>刷新</View>
  672. </View>
  673. </View>
  674. {
  675. !(this.state.distance <= this.wxConfig.clockInRange && this.state.distance >= 0) && ![5, 6].includes(dtails.type) &&
  676. <View className='switchposition'>您不在打卡范围:
  677. <Text className='stxt' onClick={this.selectArrder}>切换位置</Text>
  678. </View>
  679. }
  680. {/* {
  681. !(this.state.distance <= this.wxConfig.clockInRange && this.state.distance >= 0) ?
  682. <View className='switchposition'>您不在打卡范围:
  683. <Text className='stxt' onClick={this.selectArrder}>切换位置</Text>
  684. </View> : (dtails.type == 0 && (dtails.publicType == 1 || dtails.publicType == 3)) ?
  685. <View className='switchposition'>公出他人企业!需通过审核,才可打卡!</View>
  686. : (dtails.type == 1 && (dtails.techStartProcess == 1 || dtails.techStartProcess == 3)) ?
  687. <View className='switchposition'>已超过合同规定时限,需审核通过,才可打卡!</View>
  688. : null
  689. } */}
  690. <View className='map'>
  691. <View className='locationContent'>
  692. <View className='location' onClick={() => {
  693. this.mapCtx.moveToLocation();
  694. }}>
  695. <Image src={Location} className='locationIcon' />
  696. </View>
  697. <View className='punchRange'
  698. onClick={() => {
  699. this.mapCtx.moveToLocation({
  700. latitude: this.state.addressLatitude,
  701. longitude: this.state.addressLongitude,
  702. });
  703. }}>
  704. <Image src={PunchRange} className='punchRangeIcon' />
  705. </View>
  706. </View>
  707. <Map
  708. id='map'
  709. {...this.state.newArrder}
  710. circles={[
  711. {
  712. latitude: this.state.addressLatitude,
  713. longitude: this.state.addressLongitude,
  714. color: '#c92ddc82',
  715. fillColor: '#c92ddc82',
  716. radius: this.wxConfig.clockInRange,
  717. strokeWidth: 1
  718. }
  719. ]}
  720. showLocation
  721. />
  722. </View>
  723. <View className='tips'>紫色区域为可打卡区域</View>
  724. </View>
  725. <View className='content' onClick={() => {
  726. this.setState({
  727. historicalIsOpened: true
  728. })
  729. }}>
  730. <View className='history'>
  731. <View>查看公出申请日志</View>
  732. <AtIcon value='chevron-right' size='20' color='#767272' />
  733. </View>
  734. </View>
  735. </View>
  736. }
  737. <AtModal
  738. isOpened={this.state.isOpened}
  739. title='提醒'
  740. cancelText='取消'
  741. confirmText='确认'
  742. onClose={() => {
  743. this.setState({
  744. isOpened: false,
  745. })
  746. }}
  747. onCancel={() => {
  748. this.setState({
  749. isOpened: false,
  750. })
  751. }}
  752. onConfirm={() => {
  753. this.setState({
  754. isOpened: false,
  755. }, () => {
  756. Taro.openSetting({
  757. success: (value) => {
  758. if (value.authSetting['scope.userLocation']) {
  759. Taro.getLocation({
  760. type: 'gcj02',
  761. isHighAccuracy: true,
  762. success: (res) => {
  763. const latitude = res.latitude
  764. const longitude = res.longitude
  765. this.setState({
  766. newArrder: {
  767. latitude,
  768. longitude
  769. },
  770. })
  771. }
  772. })
  773. this.getDtails();
  774. }
  775. }
  776. })
  777. })
  778. }}
  779. content='您拒绝了定位权限,请先前往设置打开定位权限'
  780. />
  781. {/* 异常打卡原因 */}
  782. {
  783. this.state.isAbnormalOpen &&
  784. <AtModal isOpened={this.state.isAbnormalOpen}>
  785. <AtModalContent>
  786. <AtTextarea
  787. value={this.state.clockInRemarks}
  788. onChange={e => { this.setState({ clockInRemarks: e }) }}
  789. maxLength={200}
  790. placeholder='请填写异常打卡原因~'
  791. />
  792. </AtModalContent>
  793. <AtModalAction>
  794. <Button type='secondary' onClick={() => { this.setState({ isAbnormalOpen: false }) }}>取消</Button>
  795. <Button type='primary' onClick={this.abnormalClockIn}>提交</Button>
  796. </AtModalAction>
  797. </AtModal>
  798. }
  799. {
  800. this.state.historicalIsOpened &&
  801. <HistoricalClock
  802. id={dtails.id}
  803. isOpened={this.state.historicalIsOpened}
  804. onClose={() => {
  805. this.setState({
  806. historicalIsOpened: false
  807. })
  808. }}
  809. />
  810. }
  811. {
  812. this.state.isTips &&
  813. <AtModal isOpened={this.state.isTips}>
  814. <AtModalHeader>请选择</AtModalHeader>
  815. <AtModalContent>
  816. <AtRadio
  817. options={getNewOptions(dtails.prdList)}
  818. value={this.state.selectUid}
  819. onClick={e => { this.setState({ selectUid: e }) }}
  820. />
  821. </AtModalContent>
  822. <AtModalAction>
  823. <Button type='secondary' onClick={() => { this.setState({ isTips: false }) }}>取消</Button>
  824. <Button type='primary' onClick={this.selectOn}>确定</Button>
  825. </AtModalAction>
  826. </AtModal>
  827. }
  828. </View>
  829. )
  830. }
  831. }
  832. export default PunchClocks