leave.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. <template>
  2. <view>
  3. <view style="padding:5rpx 20rpx 45rpx 20rpx;">
  4. <view>
  5. <view>
  6. <view class="desc">
  7. <uni-row>
  8. <uni-col :span="5">
  9. <view class="desc" style="font-size: 25rpx;">
  10. 请假类型
  11. </view>
  12. </uni-col>
  13. <uni-col :span="19">
  14. <view>
  15. <uni-data-select v-model="form.type" :localdata="actions" :clear="false">
  16. </uni-data-select>
  17. </view>
  18. </uni-col>
  19. </uni-row>
  20. </view>
  21. <view>
  22. <view class="desc">
  23. <view class="desc" style="font-size: 25rpx;">
  24. 请假事由:
  25. </view>
  26. <view>
  27. <uni-easyinput primaryColor="#37babd" type="textarea" autoHeight v-model="form.reason">
  28. </uni-easyinput>
  29. </view>
  30. </view>
  31. </view>
  32. <view class="desc">
  33. <uni-row>
  34. <uni-col :span="5">
  35. <view class="desc" style="font-size: 25rpx;">
  36. 开始时间
  37. </view>
  38. </uni-col>
  39. <uni-col :span="19">
  40. <view>
  41. <uni-datetime-picker type="date" :clear-icon="false" v-model="form.leaveStartTime"
  42. @maskClick="maskClick" @change="onchange()" />
  43. </view>
  44. </uni-col>
  45. </uni-row>
  46. </view>
  47. <view class="desc">
  48. <uni-row>
  49. <uni-col :span="5">
  50. <view class="desc" style="font-size: 25rpx;">
  51. 结束时间
  52. </view>
  53. </uni-col>
  54. <uni-col :span="19">
  55. <view>
  56. <uni-datetime-picker type="date" :clear-icon="false" v-model="form.leaveEndTime"
  57. @maskClick="maskClick" @change="onchange()" />
  58. </view>
  59. </uni-col>
  60. </uni-row>
  61. </view>
  62. <view class="desc">
  63. <uni-row>
  64. <uni-col :span="5">
  65. <view class="desc" style="font-size: 25rpx;">
  66. 天数
  67. </view>
  68. </uni-col>
  69. <uni-col :span="19">
  70. <view>
  71. <uni-easyinput primaryColor="#37babd" v-model="calculateDayNum" placeholder="天数">
  72. </uni-easyinput>
  73. </view>
  74. </uni-col>
  75. </uni-row>
  76. </view>
  77. <view style="color: #c4c4c4;font-size: 24rpx;">
  78. 注:1天按照8小时计算,如请4小时,即4/8=0.5天;
  79. </view>
  80. <view class="desc">
  81. <uni-row>
  82. <uni-col :span="5">
  83. <view style="font-size: 25rpx;">
  84. 是否离沪
  85. </view>
  86. </uni-col>
  87. <uni-col :span="19">
  88. <view>
  89. <uni-row>
  90. <radio-group @change="radioChange">
  91. <uni-col :span="12" v-for="(item, index) in radiolist1">
  92. <label :key="item.value">
  93. <radio color="rgb(55,186,189)" :value="item.value"
  94. :checked="index === current">
  95. {{item.value}}
  96. </radio>
  97. </label>
  98. </uni-col>
  99. </radio-group>
  100. </uni-row>
  101. </view>
  102. </uni-col>
  103. </uni-row>
  104. </view>
  105. <view class="desc">
  106. <uni-row>
  107. <uni-col :span="5">
  108. <view class="desc" style="font-size: 25rpx;">
  109. 出行方式
  110. </view>
  111. </uni-col>
  112. <uni-col :span="19">
  113. <view>
  114. <uni-easyinput primaryColor="#37babd" v-model="form.tripMode" placeholder="出行方式">
  115. </uni-easyinput>
  116. </view>
  117. </uni-col>
  118. </uni-row>
  119. </view>
  120. <view class="desc">
  121. <uni-row>
  122. <uni-col :span="5">
  123. <view class="desc" style="font-size: 25rpx;">
  124. 出行地址
  125. </view>
  126. </uni-col>
  127. <uni-col :span="19">
  128. <view>
  129. <pickerAddress @change="changeAddress">
  130. <view v-if="form.tripAddress"
  131. style="font-size: 30rpx;color: #848484;padding: 12rpx 0;">
  132. {{form.tripAddress}}
  133. </view>
  134. <view v-else style="color: #c4c4c4;font-size: 30rpx;padding: 12rpx 0;">
  135. 选择地址
  136. </view>
  137. </pickerAddress>
  138. </view>
  139. </uni-col>
  140. </uni-row>
  141. </view>
  142. <view>
  143. <view class="desc">
  144. <view class="desc" style="font-size: 25rpx;">
  145. 详细地址:
  146. </view>
  147. <view>
  148. <uni-easyinput primaryColor="#37babd" type="textarea" autoHeight
  149. v-model="form.detailAddr">
  150. </uni-easyinput>
  151. </view>
  152. </view>
  153. </view>
  154. <view class="desc">
  155. <view>
  156. 图片
  157. </view>
  158. <view style="width: 100%;overflow-x: scroll;white-space: nowrap">
  159. <u-upload style="margin: 0;" :fileList="fileList" @afterRead="afterRead" @delete="deletePic"
  160. name="1" multiple :maxCount="6" width="120" height="120" uploadIcon="plus-circle">
  161. </u-upload>
  162. </view>
  163. </view>
  164. </view>
  165. </view>
  166. </view>
  167. <u-gap height="70" bgColor="#ffffff"></u-gap>
  168. <view class="bottim_view">
  169. <view>
  170. <u-row>
  171. <u-col span="11">
  172. <u-button :disabled="isDisabled" class="btnDoPay" shape="circle" @click="submit"
  173. color="rgb(55,186,189)" text="提交"></u-button>
  174. </u-col>
  175. </u-row>
  176. </view>
  177. </view>
  178. <!-- 普通弹窗 -->
  179. <uni-popup ref="popup" background-color="#fff" @change="propChange">
  180. <view style="height: 800rpx;">
  181. <view class="desc">
  182. <uni-row>
  183. <uni-col :span="10">
  184. <view style="font-size: 40rpx;color: rgb(145, 145, 145);">
  185. </view>
  186. </uni-col>
  187. <uni-col :span="11">
  188. <view style="font-size: 40rpx;color: rgb(98, 98, 98);">
  189. 下一步
  190. </view>
  191. </uni-col>
  192. <uni-col :span="3">
  193. <view @click="submitPass" style="font-size: 40rpx;color: rgb(55,186,189);">
  194. 确认
  195. </view>
  196. </uni-col>
  197. </uni-row>
  198. </view>
  199. <view class="desc">
  200. <uni-row>
  201. <uni-col>
  202. <view style="padding: 10rpx 30rpx;">
  203. <uni-data-picker ref="picker" placeholder="请选择" :popup-title="selectTitle"
  204. :localdata="dataTree" v-model="hxForm.candidate" @change="nextApprovalChange">
  205. </uni-data-picker>
  206. </view>
  207. </uni-col>
  208. </uni-row>
  209. </view>
  210. </view>
  211. </uni-popup>
  212. </view>
  213. </template>
  214. <script>
  215. import pickerAddress from '../address/pickerAddress.vue'
  216. export default {
  217. components: {
  218. pickerAddress
  219. },
  220. data() {
  221. return {
  222. header: {
  223. "Authorization": "Bearer " + uni.getStorageSync('token')
  224. },
  225. selectTitle: '',
  226. type: 0,
  227. current: 0,
  228. data: uni.getStorageSync("approval"),
  229. fileList: [],
  230. // uni.getStorageSync("listImg"),
  231. disabled1: false,
  232. tips: '',
  233. value: '',
  234. showCalendar: false,
  235. showBirthday: false,
  236. model1: {},
  237. isDisabled: false,
  238. radiolist1: [{
  239. value: '不离沪'
  240. },
  241. {
  242. value: '离沪'
  243. }
  244. ],
  245. imageStyles: {
  246. width: 100,
  247. height: 100,
  248. display: 'block'
  249. },
  250. form: {
  251. isLh: '不离沪'
  252. },
  253. showSex: false,
  254. birthday: Number(new Date()),
  255. actions: [],
  256. rules: {
  257. type: {
  258. type: 'string',
  259. max: 1,
  260. required: true,
  261. message: '请选择请假类型',
  262. trigger: ['blur', 'change']
  263. },
  264. reason: {
  265. type: 'string',
  266. min: 3,
  267. required: true,
  268. message: '不低于3个字',
  269. trigger: ['change']
  270. },
  271. hotel: {
  272. type: 'string',
  273. min: 2,
  274. required: true,
  275. message: '请选择请假时间',
  276. trigger: ['change']
  277. },
  278. },
  279. dataTree: [],
  280. hxForm: {
  281. taskId: '',
  282. candidate: '',
  283. applyUserName: ''
  284. },
  285. app_vacate_type: [],
  286. imageValue: [{
  287. "name": "",
  288. "extname": "",
  289. "url": ""
  290. }]
  291. }
  292. },
  293. onReady() {
  294. // 如果需要兼容微信小程序,并且校验规则中含有方法等,只能通过setRules方法设置规则
  295. //this.$refs.form.setRules(this.rules)
  296. },
  297. onLoad() {
  298. this.actions = []
  299. this.app_vacate_type = uni.getStorageSync('app_vacate_type')
  300. for (var i = 0; i < this.app_vacate_type.length; i++) {
  301. this.actions.push({
  302. value: this.app_vacate_type[i].dictValue,
  303. text: this.app_vacate_type[i].dictLabel
  304. })
  305. }
  306. if (this.data) {
  307. this.form = {
  308. isLh: this.data.formData.is_lh,
  309. type: this.data.formData.type,
  310. title: this.data.formData.title,
  311. leaveStartTime: this.data.formData.leave_start_time.slice(0, 10).replace('/', '-').replace('/',
  312. '-'),
  313. reason: this.data.formData.reason,
  314. leaveEndTime: this.data.formData.leave_end_time.slice(0, 10).replace('/', '-').replace('/', '-'),
  315. candidate: this.data.formData.candidate,
  316. totalTime: this.data.formData.total_time,
  317. tripMode: this.data.formData.trip_mode,
  318. detailAddr: this.data.formData.detail_addr,
  319. tripAddress: this.data.formData.trip_address,
  320. applyUserName: this.data.formData.apply_user_name,
  321. applyUserId: this.data.formData.apply_user_id
  322. }
  323. if (this.data.formData.is_lh === '离沪') {
  324. this.current = 1
  325. } else {
  326. this.current = 0
  327. }
  328. }
  329. },
  330. computed: {
  331. calculateDayNum() {
  332. if (this.form.leaveStartTime &&
  333. this.form.leaveEndTime) {
  334. if (this.form.leaveStartTime >
  335. this.form.leaveEndTime) {
  336. this.$showModal('开始时间不能小于结束时间')
  337. return
  338. }
  339. let dayNum = ((new Date(this.form.leaveEndTime).getTime() -
  340. new Date(this.form.leaveStartTime).getTime()) / (1000 * 60 * 60 * 24)) + 1
  341. this.form.totalTime = dayNum
  342. return dayNum
  343. }
  344. },
  345. updateAddress() {
  346. return this.form.tripAddress
  347. }
  348. },
  349. methods: {
  350. propChange(e) {
  351. if (e.show) {
  352. // this.zindeButtion = 0
  353. } else {
  354. // this.zindeButtion = 1
  355. }
  356. },
  357. nextApprovalChange(e) {
  358. // console.log('onchange:', e.detail.value[1].text);
  359. this.hxForm.applyUserName = e.detail.value[1].text
  360. this.hxForm.candidate = e.detail.value[1].value
  361. },
  362. radioChange: function(evt) {
  363. this.form.isLh = evt.detail.value
  364. },
  365. // 获取上传状态
  366. select(e) {
  367. console.log('选择文件:', e)
  368. },
  369. // 获取上传进度
  370. progress(e) {
  371. console.log('上传进度:', e)
  372. },
  373. // 上传成功
  374. success(e) {
  375. console.log('上传成功')
  376. },
  377. changeAddress(data) {
  378. this.form.tripAddress = data.data.join('')
  379. this.$forceUpdate()
  380. },
  381. // 上传失败
  382. fail(e) {
  383. console.log('上传失败:', e)
  384. },
  385. myIsNaN(value) {
  386. return typeof value === 'number' && !isNaN(value)
  387. },
  388. changeType(e) {
  389. // console.log("e:", e);
  390. // this.form.type = e
  391. },
  392. async submitPass() {
  393. if (!this.hxForm.candidate) {
  394. uni.showModal({
  395. content: '请选择' + this.dataTree[0].text,
  396. title: '提交失败',
  397. showCancel: false,
  398. })
  399. }
  400. const {
  401. data: res
  402. } = await this.$httpRequest({
  403. url: '/app/task/submit/candidate?taskId=' + this.hxForm.taskId +
  404. '&candidate=' + this.hxForm.candidate + '&applyUserName=' + this.hxForm.applyUserName,
  405. method: 'get',
  406. });
  407. if (res.code === 200) {
  408. uni.showModal({
  409. content: '已提交给审批人员',
  410. title: '提交成功',
  411. showCancel: false,
  412. success() {
  413. uni.navigateBack()
  414. }
  415. })
  416. } else {
  417. uni.showModal({
  418. content: res.msg,
  419. title: '提交失败',
  420. showCancel: false,
  421. success() {
  422. uni.navigateBack()
  423. }
  424. })
  425. }
  426. },
  427. maskClick(e) {},
  428. datetimerange(newval) {
  429. // console.log('范围选:', newval);
  430. // if (newval.length !== 0) {
  431. // this.form.totalTime = parseFloat((new Date(newval[1]).getTime() - new Date(newval[0]).getTime()) / (
  432. // 1000 *
  433. // 60 *
  434. // 60)).toFixed(2);
  435. // this.form.leaveStartTime = newval[0]
  436. // this.form.leaveEndTime = newval[1]
  437. // }
  438. },
  439. // 删除图片
  440. deletePic(event) {
  441. this.fileList.splice(event.index, 1)
  442. },
  443. // 新增图片
  444. async afterRead(event) {
  445. // 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
  446. let lists = [].concat(event.file)
  447. let fileListLen
  448. if (this.fileList) {
  449. fileListLen = this.fileList.length
  450. } else {
  451. this.fileList = []
  452. fileListLen = 0
  453. }
  454. lists.map((item) => {
  455. this.fileList.push({
  456. ...item,
  457. status: 'uploading',
  458. message: '上传中'
  459. })
  460. })
  461. for (let i = 0; i < lists.length; i++) {
  462. const result = await this.uploadFilePromise(lists[i].url)
  463. let item = this.fileList[fileListLen]
  464. this.fileList.splice(fileListLen, 1, Object.assign(item, {
  465. status: 'success',
  466. message: '',
  467. url: this.$BASE_URL + result
  468. }))
  469. fileListLen++
  470. }
  471. // uni.setStorageSync("listImg", this.fileList)
  472. // console.log(this.fileList)
  473. },
  474. uploadFilePromise(url) {
  475. return new Promise((resolve, reject) => {
  476. let a = uni.uploadFile({
  477. url: this.$BASE_URL + '/common/upload', // 仅为示例,非真实的接口地址
  478. filePath: url,
  479. name: 'file',
  480. header: this.header,
  481. success: (res) => {
  482. // console.log(JSON.parse(res.data).url);
  483. setTimeout(() => {
  484. resolve(JSON.parse(res.data).url)
  485. }, 1000)
  486. }
  487. });
  488. })
  489. },
  490. onchange(e) {
  491. // setTimeout(() => {
  492. // this.calculateDayNum()
  493. // }, 200)
  494. },
  495. async submit() {
  496. this.isDisabled = true
  497. setTimeout(() => {
  498. this.isDisabled = false
  499. }, 1000)
  500. if (!this.form.type) {
  501. this.isDisabled = false
  502. uni.showModal({
  503. content: '请选择请假类型',
  504. title: '提交失败',
  505. showCancel: false
  506. })
  507. return
  508. }
  509. if (!this.form.reason) {
  510. this.isDisabled = false
  511. uni.showModal({
  512. content: '请填写请假事由',
  513. title: '提交失败',
  514. showCancel: false
  515. })
  516. return
  517. }
  518. if (!this.form.leaveStartTime) {
  519. this.isDisabled = false
  520. uni.showModal({
  521. content: '请选择请假时间',
  522. title: '提交失败',
  523. showCancel: false
  524. })
  525. return
  526. }
  527. if (!this.myIsNaN(parseFloat(this.form.totalTime))) {
  528. this.isDisabled = false
  529. uni.showModal({
  530. content: '请填写正确的请假天数',
  531. title: '提交失败',
  532. showCancel: false
  533. })
  534. return
  535. }
  536. let userInfo = uni.getStorageSync("userInfo")
  537. this.form.applyUserId = userInfo.userName
  538. this.form.applyUserName = userInfo.nickName
  539. this.form.imgUrls = this.fileList
  540. this.form.title = this.app_vacate_type[parseInt(this.form.type)].dictLabel + '申请'
  541. const {
  542. data: res
  543. } = await this.$httpRequest({
  544. url: '/app/submitApply/leave',
  545. method: 'post',
  546. data: this.form
  547. });
  548. if (res.code === 200) {
  549. this.dataTree = res.data.tree
  550. this.hxForm.taskId = res.data.taskId
  551. this.$refs.popup.open('bottom')
  552. this.selectTitle = "请选择" + this.dataTree[0].text
  553. this.isDisabled = false
  554. } else {
  555. this.$showModal(res.msg)
  556. }
  557. this.isDisabled = false
  558. },
  559. navigateBack() {
  560. uni.navigateBack()
  561. },
  562. typeSelect(e) {
  563. this.form.type = e.id
  564. this.form.typeText = e.name
  565. this.form.title = e.name + "申请"
  566. this.$refs.form.validateField('form.type')
  567. },
  568. formatter(day) {
  569. const d = new Date()
  570. let month = d.getMonth() + 1
  571. const date = d.getDate()
  572. return day
  573. },
  574. calendarConfirm(e) {
  575. // this.showCalendar = false
  576. // this.form.hotel = `${e[0]} / ${e[e.length - 1]}`
  577. // this.form.leaveStartTime = e[0]
  578. // this.form.leaveEndTime = e[e.length - 1]
  579. // this.$refs.form.validateField('hotel')
  580. },
  581. calendarClose() {
  582. this.showCalendar = false
  583. this.$refs.form.validateField('hotel')
  584. },
  585. reset() {
  586. const validateList = ['type', 'title', 'leaveStartTime', 'leaveEndTime', 'reason',
  587. 'hotel'
  588. ]
  589. this.$refs.form.resetFields()
  590. this.$refs.form.clearValidate()
  591. setTimeout(() => {
  592. this.$refs.form.clearValidate(validateList)
  593. //this.$refs.form.setRules(this.rules)
  594. // 或者使用 this.$refs.form.clearValidate()
  595. }, 10)
  596. },
  597. hideKeyboard() {
  598. uni.hideKeyboard()
  599. }
  600. }
  601. }
  602. </script>
  603. <style lang="scss" scoped>
  604. .desc {
  605. padding: 15rpx 5rpx;
  606. }
  607. .bottim_view {
  608. padding: 5px 20px 30px;
  609. position: fixed;
  610. left: 0px;
  611. bottom: 0px;
  612. width: 100%;
  613. height: 40px;
  614. background-color: #ffffff;
  615. }
  616. .title {
  617. font-size: 14px;
  618. font-weight: bold;
  619. margin: 20px 0 5px 0;
  620. }
  621. .data-pickerview {
  622. height: 400px;
  623. border: 1px #e5e5e5 solid;
  624. }
  625. .popper__arrow {
  626. top: -6px;
  627. left: 50%;
  628. margin-right: 3px;
  629. border-top-width: 0;
  630. border-bottom-color: #EBEEF5;
  631. }
  632. .popper__arrow {
  633. top: -6px;
  634. left: 50%;
  635. margin-right: 3px;
  636. border-top-width: 0;
  637. border-bottom-color: #EBEEF5;
  638. }
  639. </style>