punchClocks.jsx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. import React, { Component } from 'react'
  2. import { connect } from 'react-redux'
  3. import {Map, OpenData, View, Image, Text} from '@tarojs/components'
  4. import Taro from '@tarojs/taro';
  5. import {AtIcon, AtModal} 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} 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 {getClockState} from "../../utils/tools";
  20. const QQMapWX = require('../../components/common/mapSDK/qqmap-wx-jssdk.min.js');
  21. @connect(({ counter }) => ({
  22. counter
  23. }), (dispatch) => ({
  24. add () {
  25. dispatch(add())
  26. },
  27. dec () {
  28. dispatch(minus())
  29. },
  30. asyncAdd () {
  31. dispatch(asyncAdd())
  32. }
  33. }))
  34. class PunchClocks extends Component {
  35. constructor(props) {
  36. super(props);
  37. this.state={
  38. imgs:[],
  39. nowTime:'00:00:00',
  40. newArrder:{},
  41. addressLatitude:'',
  42. addressLongitude:'',
  43. distance:'',
  44. dtails:{},
  45. loading:true
  46. }
  47. this.onChange = this.onChange.bind(this);
  48. this.getSpacing = this.getSpacing.bind(this);
  49. this.getPublicReleaseList = this.getPublicReleaseList.bind(this);
  50. this.publicReleaseClockIn = this.publicReleaseClockIn.bind(this);
  51. this.refresh = this.refresh.bind(this);
  52. this.getDtails = this.getDtails.bind(this);
  53. }
  54. nowTime = null;
  55. mapCtx = Taro.createMapContext('map');
  56. qqmapsdk = new QQMapWX({
  57. key: 'AWBBZ-GRAC2-JFYUO-CLA7I-JAHXK-YFFGT'
  58. });
  59. componentDidMount(){
  60. this.getDtails();
  61. }
  62. getDtails(){
  63. this.getPublicReleaseList(()=>{
  64. Taro.startLocationUpdate({
  65. success:()=>{
  66. Taro.onLocationChange((v)=>{
  67. this.getSpacing(v.latitude,v.longitude)
  68. })
  69. },
  70. fail:(err)=>{
  71. console.log(err,'err')
  72. Taro.getSetting({
  73. success:(res)=>{
  74. if (!res.authSetting['scope.userLocation']) {
  75. Taro.authorize({
  76. scope: 'scope.userLocation',
  77. success:()=>{
  78. },
  79. fail:()=>{
  80. this.setState({
  81. isOpened:true
  82. })
  83. }
  84. })
  85. }
  86. }
  87. })
  88. this.setState({
  89. loading:false
  90. })
  91. }
  92. })
  93. });
  94. }
  95. componentWillMount() {
  96. //获得当前位置
  97. Taro.getLocation({
  98. type: 'gcj02',
  99. isHighAccuracy:true,
  100. success: (res)=> {
  101. const latitude = res.latitude
  102. const longitude = res.longitude
  103. this.setState({
  104. newArrder:{
  105. latitude,
  106. longitude
  107. },
  108. })
  109. }
  110. })
  111. this.nowTime = setInterval(()=>{
  112. this.setState({
  113. nowTime:dayjs().format('HH:mm:ss')
  114. })
  115. },1000)
  116. Taro.eventCenter.on('punchClockComponentDidShow', () => {
  117. if(Object.keys(this.state.dtails).length === 0){
  118. this.getDtails();
  119. }
  120. })
  121. Taro.eventCenter.on('GoPunchIn', (arg) => {
  122. this.setState({
  123. dtails:arg,
  124. addressLatitude:parseFloat(arg.latitude),
  125. addressLongitude:parseFloat(arg.longitude),
  126. },()=>{
  127. Taro.startLocationUpdate({
  128. success:()=>{
  129. Taro.onLocationChange((v)=>{
  130. this.getSpacing(v.latitude,v.longitude)
  131. })
  132. },
  133. fail:()=>{
  134. this.setState({
  135. loading:false
  136. })
  137. }
  138. })
  139. })
  140. })
  141. }
  142. componentDidHide() {
  143. Taro.offLocationChange();
  144. this.nowTime && this.nowTime.clearTimeout();
  145. }
  146. publicReleaseClockIn(){
  147. if(this.state.dtails.status === 3){
  148. Taro.hideLoading()
  149. Taro.showToast({title:'申请已撤销,无法打卡',icon:'none'});
  150. return ;
  151. }
  152. if(Object.keys(this.state.dtails).length === 0){
  153. Taro.hideLoading()
  154. Taro.showToast({title:'暂无公出申请,无法打卡',icon:'none'});
  155. return ;
  156. }
  157. if(isNaN(parseInt(this.state.distance))){
  158. Taro.hideLoading()
  159. Taro.showToast({title:'定位错误,请联系管理员',icon:'none'})
  160. return ;
  161. }
  162. if(dayjs().isBefore(this.state.dtails.releaseStarts) || dayjs().isAfter(this.state.dtails.releaseEnds)){
  163. Taro.hideLoading()
  164. Taro.showToast({title:'当前时间不在打卡时间范围内,无法打卡',icon:'none'})
  165. return ;
  166. }
  167. if(!(this.state.distance <=100 && this.state.distance >= 0)){
  168. Taro.hideLoading()
  169. Taro.showToast({title:'当前位置未处于可打卡范围,无法打卡',icon:'none'})
  170. return ;
  171. }
  172. if(this.state.imgs.length === 0){
  173. Taro.hideLoading()
  174. Taro.showToast({title:'请上传打卡照片',icon:'none'})
  175. return ;
  176. }
  177. publicReleaseClockIn({
  178. id:this.state.dtails.id,
  179. photoUrl:this.state.imgs.join(',')
  180. }).then(v=>{
  181. Taro.hideLoading()
  182. if(v.error.length === 0){
  183. Taro.showToast({title:'打卡成功',icon:'none'});
  184. this.imagePicker.clear();
  185. this.state.dtails.clockIn = 1;
  186. this.setState({
  187. dtails:this.state.dtails,
  188. imgs:[]
  189. })
  190. }else{
  191. Taro.showToast({title:v.error[0].message,icon:'none'})
  192. }
  193. }).catch(()=>{
  194. Taro.hideLoading()
  195. Taro.showToast({
  196. title:'系统错误,请稍后再试',
  197. icon:'none'
  198. })
  199. })
  200. }
  201. getPublicReleaseList(fn){
  202. this.setState({
  203. loading:true
  204. })
  205. getPublicReleaseList({
  206. type:0,
  207. clockTime:dayjs().format('YYYY-MM-DD HH:mm:ss')
  208. }).then(v=>{
  209. if(v.error.length === 0){
  210. if(v.data.list.length === 0){
  211. getPublicReleaseList({
  212. type:0,
  213. }).then(value=>{
  214. if(value.error.length === 0){
  215. if(value.data.list.length === 0){
  216. this.setState({
  217. dtails: {},
  218. loading:false
  219. })
  220. }else{
  221. this.setState({
  222. dtails:value.data.list[0],
  223. addressLatitude:value.data.list[0].latitude,
  224. addressLongitude:value.data.list[0].longitude,
  225. },()=>{
  226. fn();
  227. })
  228. }
  229. }else{
  230. this.setState({
  231. loading:false
  232. })
  233. Taro.showToast({
  234. title:v.error[0].message,
  235. icon:'none'
  236. })
  237. }
  238. }).catch(()=>{
  239. this.setState({
  240. loading:false
  241. })
  242. Taro.showToast({
  243. title:'系统错误,请稍后再试',
  244. icon:'none'
  245. })
  246. })
  247. }else{
  248. this.setState({
  249. dtails:v.data.list[0],
  250. addressLatitude:v.data.list[0].latitude,
  251. addressLongitude:v.data.list[0].longitude,
  252. },()=>{
  253. fn();
  254. })
  255. }
  256. }else{
  257. this.setState({
  258. loading:false
  259. })
  260. Taro.showToast({
  261. title:v.error[0].message,
  262. icon:'none'
  263. })
  264. }
  265. }).catch((err)=>{
  266. console.log(err)
  267. this.setState({
  268. loading:false
  269. })
  270. Taro.showToast({
  271. title:'系统错误,请稍后再试',
  272. icon:'none'
  273. })
  274. })
  275. }
  276. getSpacing(latitude,longitude){
  277. let _this = this;
  278. this.qqmapsdk.calculateDistance({
  279. mode:'straight',
  280. from: {
  281. latitude: this.state.addressLatitude,
  282. longitude: this.state.addressLongitude,
  283. },
  284. to: [
  285. {
  286. latitude,
  287. longitude,
  288. }
  289. ],
  290. success: function(res) {//成功后的回调
  291. _this.setState({
  292. distance:res.result.elements[0].distance,
  293. loading:false
  294. })
  295. },
  296. fail: function(error) {
  297. _this.setState({
  298. loading:false
  299. })
  300. console.error(error);
  301. },
  302. complete: function(res) {
  303. }
  304. });
  305. }
  306. onChange(value,type){
  307. let arr = this.state.imgs.concat([]);
  308. if(type === 'add'){
  309. arr.push(value)
  310. }else if(type === 'remove'){
  311. arr.splice(value,1)
  312. }
  313. this.setState({
  314. imgs: arr,
  315. })
  316. }
  317. refresh(){
  318. this.getPublicReleaseList(()=>{
  319. Taro.startLocationUpdate({
  320. success:()=>{
  321. Taro.onLocationChange((v)=>{
  322. this.getSpacing(v.latitude,v.longitude)
  323. })
  324. }
  325. })
  326. });
  327. }
  328. render () {
  329. const {dtails} = this.state;
  330. return (
  331. <View className='punchClock'>
  332. <View className='header'>
  333. <Skeleton
  334. title
  335. avatar
  336. row={1}
  337. animateName='elastic'
  338. avatarShape='square'
  339. loading={this.state.loading}
  340. >
  341. <View className='headerContent'>
  342. <View className='userAvatarUrl'>
  343. <OpenData type='userAvatarUrl'/>
  344. </View>
  345. <View className='infor'>
  346. <View className='name'>
  347. {
  348. Object.keys(this.state.dtails).length <= 0 ?
  349. Taro.getStorageSync('userInfor').name:
  350. dtails.aname
  351. }
  352. </View>
  353. <View className='address'>
  354. 公出企业:
  355. <View className='nickname'>
  356. {
  357. Object.keys(this.state.dtails).length <= 0 ?
  358. '无':
  359. dtails.nickname
  360. }
  361. </View>
  362. </View>
  363. </View>
  364. {
  365. Object.keys(this.state.dtails).length <= 0 ?
  366. <View onClick={this.refresh} className='state' style={{
  367. alignSelf: 'center',
  368. textAlign:'center',
  369. color:'#b6b5b5',
  370. fontSize:'11px'
  371. }}>
  372. <AtIcon value='reload' size='20'/>
  373. <View>刷新</View>
  374. </View> :
  375. <View className='state' style={{
  376. color:getClockState(dtails.status).color
  377. }}>
  378. <View style={{textAlign:'right'}}>
  379. {
  380. getClockState(dtails.status).title
  381. }
  382. </View>
  383. <View className='switchContent' onClick={()=>{
  384. Taro.switchTab({
  385. url: '/pages/examine/index',
  386. })
  387. }}>
  388. <View className='switchTitle'>切换打卡</View>
  389. <Image src={switchIocn} className='switchItem'/>
  390. </View>
  391. </View>
  392. }
  393. </View>
  394. </Skeleton>
  395. </View>
  396. {
  397. Object.keys(this.state.dtails).length <= 0 ?
  398. <View className='content'>
  399. <View className='punchClockContent' onClick={this.publicReleaseClockIn} style={{
  400. boxShadow: '1px 1px 15px 1px #acb8ad',
  401. background: '#acb8ad',
  402. marginTop: '85px',
  403. }}>
  404. <View className='punchClockTitle'>公出打卡</View>
  405. <View className='punchClockTime'>{this.state.nowTime}</View>
  406. </View>
  407. <View className='noData'>
  408. <View className='tipsNoData'>
  409. 暂无公出申请
  410. </View>
  411. <View className='goOut' onClick={()=>{
  412. Taro.switchTab({
  413. url: '/pages/applyDepart/index',
  414. })
  415. }}>
  416. 点击前往申请公出
  417. </View>
  418. </View>
  419. </View>:
  420. <View>
  421. <View className='content'>
  422. <View className='timeContent'>
  423. <View className='timeItem'>
  424. <View className='timeTitle'>公出开始时间</View>
  425. <View className='timeValue'>{dtails.releaseStarts}</View>
  426. </View>
  427. <View className='timeItem'>
  428. <View className='timeTitle'>公出结束时间</View>
  429. <View className='timeValue'>{dtails.releaseEnds}</View>
  430. </View>
  431. </View>
  432. <View className='photographContent'>
  433. <View className='photographTitle'>打卡拍照<Text className='tips'>〔可以上传多张〕</Text></View>
  434. <AtIcon onClick={()=>{
  435. Taro.chooseImage({
  436. count: 1,
  437. sizeType: ['compressed'],
  438. sourceType: ['camera'],
  439. success:(res)=> {
  440. // tempFilePath可以作为img标签的src属性显示图片
  441. const tempFilePaths = res.tempFilePaths
  442. this.imagePicker.onImgChange([{url:tempFilePaths[0]}],'add',0,'camera')
  443. }
  444. })
  445. }} value='camera' size='25' color='#4395ff'/>
  446. </View>
  447. <View style={{alignSelf:'flex-start',width:'100%'}}>
  448. <ImagePicker ref={ref => this.imagePicker = ref} url='/api/admin/release/upload' showAddBtn={false} onChange={this.onChange}/>
  449. </View>
  450. <View className='punchClockContent' onClick={()=>{
  451. let _this = this;
  452. Taro.showLoading({title:'加载中...'})
  453. Taro.getSetting({
  454. success:(res)=>{
  455. if (!res.authSetting['scope.userLocation']) {
  456. Taro.authorize({
  457. scope: 'scope.userLocation',
  458. success:()=>{
  459. _this.publicReleaseClockIn();
  460. },
  461. fail:()=>{
  462. Taro.hideLoading()
  463. this.setState({
  464. isOpened:true
  465. })
  466. }
  467. })
  468. }else{
  469. _this.publicReleaseClockIn();
  470. }
  471. }
  472. })
  473. }} style={{
  474. boxShadow:
  475. (!isNaN(parseInt(this.state.distance)))
  476. && this.state.distance <=100 && this.state.distance >= 0 &&
  477. !(dayjs().isBefore(this.state.dtails.releaseStarts) || dayjs().isAfter(this.state.dtails.releaseEnds)) &&
  478. dtails.status !== 3
  479. ? (dtails.clockIn === 1 ? '1px 1px 15px 1px #3f82e8' : '1px 1px 15px 1px #659268') : '1px 1px 15px 1px #acb8ad',
  480. background: (!isNaN(parseInt(this.state.distance)))
  481. &&
  482. this.state.distance <=100 &&
  483. this.state.distance >= 0 &&
  484. !(dayjs().isBefore(this.state.dtails.releaseStarts) || dayjs().isAfter(this.state.dtails.releaseEnds))&&
  485. dtails.status !== 3
  486. ? (dtails.clockIn === 1 ? '#3f82e8' : '#72cb78') : '#acb8ad'
  487. }}>
  488. <View className='punchClockTitle'>
  489. {
  490. dtails.clockIn === 1 ?
  491. '刷新打卡' : '公出打卡'
  492. }
  493. </View>
  494. <View className='punchClockTime'>{this.state.nowTime}</View>
  495. </View>
  496. <View className='map'>
  497. <View className='locationContent'>
  498. <View className='location' onClick={()=>{
  499. this.mapCtx.moveToLocation();
  500. }}>
  501. <Image src={Location} className='locationIcon'/>
  502. </View>
  503. <View className='punchRange' onClick={()=>{
  504. this.mapCtx.moveToLocation({
  505. latitude: this.state.addressLatitude,
  506. longitude: this.state.addressLongitude,
  507. });
  508. }}>
  509. <Image src={PunchRange} className='punchRangeIcon'/>
  510. </View>
  511. </View>
  512. <Map
  513. id='map'
  514. {...this.state.newArrder}
  515. circles={[
  516. {
  517. latitude: this.state.addressLatitude,
  518. longitude: this.state.addressLongitude,
  519. color: '#c92ddc82',
  520. fillColor: '#c92ddc82',
  521. radius: 100,
  522. strokeWidth: 1
  523. }
  524. ]}
  525. showLocation
  526. />
  527. </View>
  528. <View className='tips'>紫色区域为可打卡区域</View>
  529. </View>
  530. <View className='content' onClick={()=>{
  531. this.setState({
  532. historicalIsOpened:true
  533. })
  534. }}>
  535. <View className='history'>
  536. <View>查看公出申请日志</View>
  537. <AtIcon value='chevron-right' size='20' color='#767272'/>
  538. </View>
  539. </View>
  540. </View>
  541. }
  542. <AtModal
  543. isOpened={this.state.isOpened}
  544. title='提醒'
  545. cancelText='取消'
  546. confirmText='确认'
  547. onClose={()=>{
  548. this.setState({
  549. isOpened:false,
  550. })
  551. }}
  552. onCancel={()=>{
  553. this.setState({
  554. isOpened:false,
  555. })
  556. }}
  557. onConfirm={()=>{
  558. this.setState({
  559. isOpened:false,
  560. },()=>{
  561. Taro.openSetting({
  562. success:(value)=> {
  563. if(value.authSetting['scope.userLocation']){
  564. Taro.getLocation({
  565. type: 'gcj02',
  566. isHighAccuracy:true,
  567. success: (res)=> {
  568. const latitude = res.latitude
  569. const longitude = res.longitude
  570. this.setState({
  571. newArrder:{
  572. latitude,
  573. longitude
  574. },
  575. })
  576. }
  577. })
  578. this.getDtails();
  579. }
  580. }
  581. })
  582. })
  583. }}
  584. content='您拒绝了定位权限,请先前往设置打开定位权限'
  585. />
  586. {this.state.historicalIsOpened ? <HistoricalClock
  587. id={dtails.id}
  588. isOpened={this.state.historicalIsOpened}
  589. onClose={()=>{
  590. this.setState({
  591. historicalIsOpened:false
  592. })
  593. }}
  594. /> : null}
  595. </View>
  596. )
  597. }
  598. }
  599. export default PunchClocks