punchClocks.jsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. import React, { Component } from 'react'
  2. import { connect } from 'react-redux'
  3. import { Input, Textarea, View, Text, Picker, Button, Image } from '@tarojs/components'
  4. import Taro from '@tarojs/taro';
  5. import {
  6. AtButton, AtModal, AtModalContent, AtModalAction, AtTextarea
  7. } from "taro-ui";
  8. import dayjs from 'dayjs';
  9. import Skeleton from 'taro-skeleton'
  10. import ImagePicker from '../../components/common/imagePicker';
  11. import { add, minus, asyncAdd } from '../../actions/counter'
  12. import { recordAdd, myDuration, getInfo, myDurationMonth } from '../../utils/servers/servers';
  13. import Select from "../../image/dui.png";
  14. import { stageList } from '../../utils/tools/config';
  15. import './index.less';
  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. @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. loading: false,
  41. selector: stageList,
  42. dateSel: dayjs().format('YYYY-MM-DD'),
  43. duration: "",
  44. hours: 0,
  45. selectorChecked: {},
  46. remark: "",
  47. data: {},
  48. isOpened: false,
  49. clockId: "",
  50. dateList: [],
  51. isCalendar: true,
  52. }
  53. this.onChange = this.onChange.bind(this);
  54. this.publicReleaseClockIn = this.publicReleaseClockIn.bind(this);
  55. this.onClose = this.onClose.bind(this);
  56. this.onMyDurationMonth = this.onMyDurationMonth.bind(this);
  57. this.onmyDuration = this.onmyDuration.bind(this);
  58. }
  59. nowTime = null;
  60. componentDidMount() {
  61. this.imagePickerRef && this.imagePickerRef.clear();
  62. this.getInfo()
  63. }
  64. getInfo() {
  65. getInfo().then(v => {
  66. })
  67. }
  68. componentWillMount() {
  69. this.nowTime = setInterval(() => {
  70. this.setState({
  71. nowTime: dayjs().format('HH:mm:ss')
  72. })
  73. }, 1000)
  74. Taro.eventCenter.on('GoPunchIn', (arg) => {
  75. this.setState({
  76. data: arg
  77. }, () => {
  78. this.onmyDuration()
  79. })
  80. })
  81. }
  82. componentDidHide() {
  83. }
  84. // 剩余打卡时间
  85. onmyDuration() {
  86. myDuration({
  87. id: this.state.data.id,
  88. recordTime: this.state.dateSel,
  89. }).then(v => {
  90. if (v.code === 200) {
  91. this.setState({
  92. hours: v.data,
  93. })
  94. } else {
  95. Taro.showToast({ title: v.msg, icon: 'none' })
  96. }
  97. }).catch(() => {
  98. Taro.showToast({
  99. title: '系统错误,请稍后再试',
  100. icon: 'none'
  101. })
  102. })
  103. }
  104. onMyDurationMonth(val, time) {
  105. myDurationMonth({
  106. id: val.id,
  107. year: time.year,
  108. month: time.month,
  109. }).then(v => {
  110. if (v.code === 200) {
  111. this.setState({
  112. dateList: v.data,
  113. })
  114. } else {
  115. Taro.showToast({ title: v.msg, icon: 'none' })
  116. }
  117. }).catch(() => {
  118. Taro.showToast({
  119. title: '系统错误,请稍后再试',
  120. icon: 'none'
  121. })
  122. })
  123. }
  124. onChange(value, type) {
  125. let arr = this.state.imgs.concat([]);
  126. if (type === "add") {
  127. arr.push(value);
  128. } else if (type === "remove") {
  129. arr.splice(value, 1);
  130. }
  131. this.setState({
  132. imgs: arr,
  133. });
  134. }
  135. publicReleaseClockIn() {
  136. if (!this.state.dateSel) {
  137. Taro.showToast({ title: '请选择研发时间!', icon: 'none' });
  138. return
  139. }
  140. if (!this.state.duration) {
  141. Taro.showToast({ title: '请填写研发工时!', icon: 'none' });
  142. return
  143. }
  144. if (!this.state.selectorChecked) {
  145. Taro.showToast({ title: '请选择研发阶段!', icon: 'none' });
  146. return
  147. }
  148. Taro.showLoading({ title: '打卡中...' });
  149. recordAdd({
  150. pid: this.state.data.id,
  151. projectStatus: this.state.selectorChecked.value,
  152. duration: this.state.duration,
  153. content: this.state.remark,
  154. annexUrl: this.state.imgs.join(','),
  155. processStatus: 1,
  156. recordTime: this.state.dateSel,
  157. }).then(v => {
  158. Taro.hideLoading()
  159. if (v.code === 200) {
  160. Taro.showToast({ title: '打卡成功', icon: 'none' });
  161. this.setState({
  162. clockId: v.data.id,
  163. isOpened: true,
  164. isCalendar: false,
  165. })
  166. } else {
  167. Taro.showToast({ title: v.msg, icon: 'none' })
  168. }
  169. }).catch(() => {
  170. Taro.hideLoading()
  171. Taro.showToast({
  172. title: '系统错误,请稍后再试',
  173. icon: 'none'
  174. })
  175. })
  176. }
  177. refresh() {
  178. this.getData(() => {
  179. Taro.startLocationUpdate({
  180. success: () => {
  181. Taro.onLocationChange((v) => {
  182. this.getSpacing(v.latitude, v.longitude)
  183. })
  184. }
  185. })
  186. });
  187. }
  188. onClose() {
  189. const { clockId } = this.state
  190. this.imagePickerRef && this.imagePickerRef.clear();
  191. this.setState({
  192. dateSel: dayjs().format('YYYY-MM-DD'),
  193. duration: "",
  194. selectorChecked: {},
  195. remark: "",
  196. imgs: [],
  197. isOpened: false,
  198. isCalendar: true,
  199. })
  200. if (!!clockId) {
  201. Taro.navigateTo({
  202. url: `/pages/detail/index?id=${clockId}&type=0`
  203. })
  204. }
  205. }
  206. onSelectDate(val) {
  207. let data = val.detail;
  208. this.setState({
  209. dateSel: data
  210. }, () => {
  211. this.onmyDuration()
  212. })
  213. }
  214. onChangeDate(val) {
  215. let data = val.detail;
  216. this.onMyDurationMonth(this.state.data, data)
  217. }
  218. render() {
  219. const { data, dateList } = this.state;
  220. return (
  221. <View className='punchClock'>
  222. <View className='header'>
  223. <Skeleton
  224. title
  225. avatar
  226. row={2}
  227. animateName='elastic'
  228. avatarShape='square'
  229. loading={this.state.loading}
  230. >
  231. {
  232. !data.id ?
  233. <View className='content'>
  234. <View className='punchClockContent'
  235. style={{
  236. boxShadow: '1px 1px 15px 1px #acb8ad',
  237. background: '#828e83',
  238. marginTop: '85px',
  239. }}>
  240. <View className='punchClockTitle'>研发打卡</View>
  241. <View className='punchClockTime'>{this.state.nowTime}</View>
  242. </View>
  243. <View className='noData'>
  244. <View className='tipsNoData'>
  245. {/* 暂无打卡项目 */}
  246. </View>
  247. <View className='goOut' onClick={() => {
  248. Taro.switchTab({
  249. url: '/pages/project/index',
  250. })
  251. }}>
  252. 点击前往选择项目
  253. </View>
  254. </View>
  255. </View> :
  256. <View className='headerContent'>
  257. <View className='item' style={{ width: "100%", display: "flex", flexDirection: "row", JustifyContent: "space-between" }}>
  258. <View className="item_name">{data.name}</View>
  259. <AtButton type="primary" size="small"
  260. onClick={() => {
  261. Taro.switchTab({
  262. url: "/pages/project/index",
  263. });
  264. }}>切换</AtButton>
  265. </View>
  266. <View className='item'>
  267. <View className='ititle'><Text style={{ color: "red", width: "7px" }}>*</Text>研发时间:
  268. {/* <Picker mode='date'
  269. onChange={e => {
  270. this.setState({
  271. dateSel: e.detail.value
  272. })
  273. }}>
  274. <View className='picker'>
  275. {!!this.state.dateSel ? this.state.dateSel : "请选择"}
  276. </View>
  277. </Picker> */}
  278. <View className='picker'>
  279. {this.state.dateSel}
  280. </View>
  281. </View>
  282. </View>
  283. {
  284. this.state.isCalendar &&
  285. <calendar
  286. use_date_arr={dateList}
  287. year={new Date().getFullYear()}
  288. month={new Date().getMonth() + 1}
  289. nowMonth={new Date().getMonth() + 1}
  290. nowDay={new Date().getDate()}
  291. onselectdate={(v) => {
  292. this.onSelectDate(v)
  293. }}
  294. onchangedate={(v) => {
  295. this.onChangeDate(v)
  296. }}
  297. />
  298. }
  299. <View className='items'>
  300. <View className='ititle'><Text style={{ color: "red", width: "7px" }}>*</Text>研发工时:
  301. <Input value={this.state.duration} type='digit' className='input' placeholder='请输入'
  302. style={{ textAlign: "center", background: "#F5F5F5", borderRadius: "15px", padding: "3px 5px" }}
  303. // border: "1px solid #d6e4ef",
  304. onInput={e => {
  305. this.setState({
  306. duration: e.detail.value
  307. })
  308. }}
  309. />小时&nbsp;
  310. <Text style={{ color: "red", fontSize: "15px" }}>剩余打卡({this.state.hours}h)</Text>
  311. </View>
  312. </View>
  313. <View className='item'>
  314. <View className='ititle'><Text style={{ color: "red", width: "7px" }}>*</Text>研发阶段:
  315. <Picker mode='selector' range={this.state.selector} rangeKey="lable"
  316. value={this.state.selectorChecked.value}
  317. onChange={e => {
  318. this.setState({
  319. selectorChecked: this.state.selector[e.detail.value]
  320. })
  321. }}>
  322. <View className='picker'>
  323. {!!this.state.selectorChecked.lable ? this.state.selectorChecked.lable : "请选择"}
  324. </View>
  325. </Picker>
  326. </View>
  327. </View>
  328. <View className='items'>
  329. <View className='ititles'><Text style={{ width: "7px" }}></Text>研发记录:
  330. <AtTextarea
  331. value={this.state.remark}
  332. onChange={value => {
  333. this.setState({
  334. remark: value,
  335. });
  336. }}
  337. maxLength={500}
  338. placeholder="请填写研发过程记录"
  339. />
  340. {/*
  341. <Textarea
  342. value={this.state.remark}
  343. placeholder="请填写研发过程记录不能超过500字"
  344. style='background:#D7D7D7;width:66%;min-height:70px;padding:10px;border-radius: 10px'
  345. autoHeight
  346. maxlength={500}
  347. onInput={e => {
  348. this.setState({
  349. remark: e.detail.value
  350. })
  351. }}
  352. /> */}
  353. </View>
  354. </View>
  355. <View className='items'>
  356. <View className='ititles'><Text style={{ width: "7px" }}></Text>上传附件:</View>
  357. <ImagePicker
  358. showAddBtn
  359. ref={(ref) => (this.imagePickerRef = ref)}
  360. url="/api/project/upload"
  361. onChange={this.onChange}
  362. />
  363. <View>
  364. <Text className='text'>注:包括研发日志、实验报告、实验记录、检测报告、会议纪要、会议照片等</Text>
  365. </View>
  366. </View>
  367. <View className='content'>
  368. <View className='punchClockContent'
  369. onClick={this.publicReleaseClockIn}
  370. style={{
  371. boxShadow: '1px 1px 15px 1px #acb8ad',
  372. background: '#009DD9',
  373. }}>
  374. <View className='punchClockTitle'>研发打卡</View>
  375. </View>
  376. </View>
  377. </View>
  378. }
  379. </Skeleton>
  380. </View >
  381. <AtModal
  382. width="90%"
  383. isOpened={this.state.isOpened}
  384. >
  385. <AtModalContent>
  386. <View className='tips'>
  387. <Image src={Select} className="img" />
  388. <View className="tit">成功打卡</View>
  389. <View className="txt">您的研发打卡,已经确定</View>
  390. <View className="txt">请注意查看打卡审核情况!</View>
  391. </View>
  392. </AtModalContent>
  393. <AtModalAction>
  394. <Button onClick={this.onClose}>确定</Button>
  395. </AtModalAction>
  396. </AtModal>
  397. </View >
  398. )
  399. }
  400. }
  401. export default PunchClocks