leave.vue 17 KB

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