leave.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  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="calculateDayNum" 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. isMiddleLevelLeader: '否',
  284. isLh: '不离沪'
  285. },
  286. showSex: false,
  287. birthday: Number(new Date()),
  288. actions: [],
  289. rules: {
  290. type: {
  291. type: 'string',
  292. max: 1,
  293. required: true,
  294. message: '请选择请假类型',
  295. trigger: ['blur', 'change']
  296. },
  297. reason: {
  298. type: 'string',
  299. min: 3,
  300. required: true,
  301. message: '不低于3个字',
  302. trigger: ['change']
  303. },
  304. hotel: {
  305. type: 'string',
  306. min: 2,
  307. required: true,
  308. message: '请选择请假时间',
  309. trigger: ['change']
  310. },
  311. },
  312. dataTree: [],
  313. hxForm: {
  314. taskId: '',
  315. candidate: '',
  316. applyUserName: ''
  317. },
  318. app_vacate_type: [],
  319. imageValue: [{
  320. "name": "",
  321. "extname": "",
  322. "url": ""
  323. }]
  324. }
  325. },
  326. onReady() {
  327. // 如果需要兼容微信小程序,并且校验规则中含有方法等,只能通过setRules方法设置规则
  328. //this.$refs.form.setRules(this.rules)
  329. },
  330. onLoad() {
  331. this.actions = []
  332. this.app_vacate_type = uni.getStorageSync('app_vacate_type')
  333. for (var i = 0; i < this.app_vacate_type.length; i++) {
  334. this.actions.push({
  335. value: this.app_vacate_type[i].dictValue,
  336. text: this.app_vacate_type[i].dictLabel
  337. })
  338. }
  339. if (this.data) {
  340. this.form = {
  341. isLh: this.data.formData.is_lh,
  342. isMiddleLevelLeader: this.data.formData.is_middle_level_leader,
  343. type: this.data.formData.type,
  344. title: this.data.formData.title,
  345. leaveStartTime: this.data.formData.leave_start_time.slice(0, 10).replace('/', '-').replace('/',
  346. '-'),
  347. reason: this.data.formData.reason,
  348. leaveEndTime: this.data.formData.leave_end_time.slice(0, 10).replace('/', '-').replace('/', '-'),
  349. candidate: this.data.formData.candidate,
  350. totalTime: this.data.formData.total_time,
  351. tripMode: this.data.formData.trip_mode,
  352. detailAddr: this.data.formData.detail_addr,
  353. tripAddress: this.data.formData.trip_address,
  354. applyUserName: this.data.formData.apply_user_name,
  355. applyUserId: this.data.formData.apply_user_id
  356. }
  357. if (this.data.formData.is_lh === '离沪') {
  358. this.current = 1
  359. } else {
  360. this.current = 0
  361. }
  362. }
  363. },
  364. computed: {
  365. calculateDayNum() {
  366. if (this.form.leaveStartTime &&
  367. this.form.leaveEndTime) {
  368. if (this.form.leaveStartTime >
  369. this.form.leaveEndTime) {
  370. this.$showModal('开始时间不能小于结束时间')
  371. return
  372. }
  373. let dayNum = ((new Date(this.form.leaveEndTime).getTime() -
  374. new Date(this.form.leaveStartTime).getTime()) / (1000 * 60 * 60 * 24)) + 1
  375. this.form.totalTime = dayNum
  376. return dayNum
  377. }
  378. },
  379. updateAddress() {
  380. return this.form.tripAddress
  381. }
  382. },
  383. methods: {
  384. propChange(e) {
  385. if (e.show) {
  386. // this.zindeButtion = 0
  387. } else {
  388. // this.zindeButtion = 1
  389. }
  390. },
  391. nextApprovalChange(e) {
  392. // console.log('onchange:', e.detail.value[1].text);
  393. this.hxForm.applyUserName = e.detail.value[1].text
  394. this.hxForm.candidate = e.detail.value[1].value
  395. },
  396. radioChange: function(evt) {
  397. this.form.isLh = evt.detail.value
  398. },
  399. radioChange2: function(evt) {
  400. this.form.isMiddleLevelLeader = evt.detail.value
  401. },
  402. // 获取上传状态
  403. select(e) {
  404. console.log('选择文件:', e)
  405. },
  406. // 获取上传进度
  407. progress(e) {
  408. console.log('上传进度:', e)
  409. },
  410. // 上传成功
  411. success(e) {
  412. console.log('上传成功')
  413. },
  414. changeAddress(data) {
  415. this.form.tripAddress = data.data.join('')
  416. this.$forceUpdate()
  417. },
  418. // 上传失败
  419. fail(e) {
  420. console.log('上传失败:', e)
  421. },
  422. myIsNaN(value) {
  423. return typeof value === 'number' && !isNaN(value)
  424. },
  425. changeType(e) {
  426. // console.log("e:", e);
  427. // this.form.type = e
  428. },
  429. async submitPass() {
  430. if (!this.hxForm.candidate) {
  431. uni.showModal({
  432. content: '请选择' + this.dataTree[0].text,
  433. title: '提交失败',
  434. showCancel: false,
  435. })
  436. }
  437. const {
  438. data: res
  439. } = await this.$httpRequest({
  440. url: '/app/task/submit/candidate?taskId=' + this.hxForm.taskId +
  441. '&candidate=' + this.hxForm.candidate + '&applyUserName=' + this.hxForm.applyUserName,
  442. method: 'get',
  443. });
  444. if (res.code === 200) {
  445. uni.showModal({
  446. content: '已提交给审批人员',
  447. title: '提交成功',
  448. showCancel: false,
  449. success() {
  450. uni.navigateBack()
  451. }
  452. })
  453. } else {
  454. uni.showModal({
  455. content: res.msg,
  456. title: '提交失败',
  457. showCancel: false,
  458. success() {
  459. uni.navigateBack()
  460. }
  461. })
  462. }
  463. },
  464. maskClick(e) {},
  465. datetimerange(newval) {
  466. // console.log('范围选:', newval);
  467. // if (newval.length !== 0) {
  468. // this.form.totalTime = parseFloat((new Date(newval[1]).getTime() - new Date(newval[0]).getTime()) / (
  469. // 1000 *
  470. // 60 *
  471. // 60)).toFixed(2);
  472. // this.form.leaveStartTime = newval[0]
  473. // this.form.leaveEndTime = newval[1]
  474. // }
  475. },
  476. // 删除图片
  477. deletePic(event) {
  478. this.fileList.splice(event.index, 1)
  479. },
  480. // 新增图片
  481. async afterRead(event) {
  482. // 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
  483. let lists = [].concat(event.file)
  484. let fileListLen
  485. if (this.fileList) {
  486. fileListLen = this.fileList.length
  487. } else {
  488. this.fileList = []
  489. fileListLen = 0
  490. }
  491. lists.map((item) => {
  492. this.fileList.push({
  493. ...item,
  494. status: 'uploading',
  495. message: '上传中'
  496. })
  497. })
  498. for (let i = 0; i < lists.length; i++) {
  499. const result = await this.uploadFilePromise(lists[i].url)
  500. let item = this.fileList[fileListLen]
  501. this.fileList.splice(fileListLen, 1, Object.assign(item, {
  502. status: 'success',
  503. message: '',
  504. url: this.$BASE_URL + result
  505. }))
  506. fileListLen++
  507. }
  508. // uni.setStorageSync("listImg", this.fileList)
  509. // console.log(this.fileList)
  510. },
  511. uploadFilePromise(url) {
  512. return new Promise((resolve, reject) => {
  513. let a = uni.uploadFile({
  514. url: this.$BASE_URL + '/common/upload', // 仅为示例,非真实的接口地址
  515. filePath: url,
  516. name: 'file',
  517. header: this.header,
  518. success: (res) => {
  519. // console.log(JSON.parse(res.data).url);
  520. setTimeout(() => {
  521. resolve(JSON.parse(res.data).url)
  522. }, 1000)
  523. }
  524. });
  525. })
  526. },
  527. onchange(e) {
  528. // setTimeout(() => {
  529. // this.calculateDayNum()
  530. // }, 200)
  531. },
  532. async submit() {
  533. this.isDisabled = true
  534. setTimeout(() => {
  535. this.isDisabled = false
  536. }, 1000)
  537. if (!this.form.type) {
  538. this.isDisabled = false
  539. uni.showModal({
  540. content: '请选择请假类型',
  541. title: '提交失败',
  542. showCancel: false
  543. })
  544. return
  545. }
  546. if (!this.form.reason) {
  547. this.isDisabled = false
  548. uni.showModal({
  549. content: '请填写请假事由',
  550. title: '提交失败',
  551. showCancel: false
  552. })
  553. return
  554. }
  555. if (!this.form.leaveStartTime) {
  556. this.isDisabled = false
  557. uni.showModal({
  558. content: '请选择请假时间',
  559. title: '提交失败',
  560. showCancel: false
  561. })
  562. return
  563. }
  564. if (!this.myIsNaN(parseFloat(this.form.totalTime))) {
  565. this.isDisabled = false
  566. uni.showModal({
  567. content: '请填写正确的请假天数',
  568. title: '提交失败',
  569. showCancel: false
  570. })
  571. return
  572. }
  573. let userInfo = uni.getStorageSync("userInfo")
  574. this.form.applyUserId = userInfo.userName
  575. this.form.applyUserName = userInfo.nickName
  576. this.form.imgUrls = this.fileList
  577. this.form.title = this.app_vacate_type[parseInt(this.form.type)].dictLabel + '申请'
  578. const {
  579. data: res
  580. } = await this.$httpRequest({
  581. url: '/app/submitApply/leave',
  582. method: 'post',
  583. data: this.form
  584. });
  585. if (res.code === 200) {
  586. this.dataTree = res.data.tree
  587. this.hxForm.taskId = res.data.taskId
  588. this.$refs.popup.open('bottom')
  589. this.selectTitle = "请选择" + this.dataTree[0].text
  590. this.isDisabled = false
  591. } else {
  592. this.$showModal(res.msg)
  593. }
  594. this.isDisabled = false
  595. },
  596. navigateBack() {
  597. uni.navigateBack()
  598. },
  599. typeSelect(e) {
  600. this.form.type = e.id
  601. this.form.typeText = e.name
  602. this.form.title = e.name + "申请"
  603. this.$refs.form.validateField('form.type')
  604. },
  605. formatter(day) {
  606. const d = new Date()
  607. let month = d.getMonth() + 1
  608. const date = d.getDate()
  609. return day
  610. },
  611. calendarConfirm(e) {
  612. // this.showCalendar = false
  613. // this.form.hotel = `${e[0]} / ${e[e.length - 1]}`
  614. // this.form.leaveStartTime = e[0]
  615. // this.form.leaveEndTime = e[e.length - 1]
  616. // this.$refs.form.validateField('hotel')
  617. },
  618. calendarClose() {
  619. this.showCalendar = false
  620. this.$refs.form.validateField('hotel')
  621. },
  622. reset() {
  623. const validateList = ['type', 'title', 'leaveStartTime', 'leaveEndTime', 'reason',
  624. 'hotel'
  625. ]
  626. this.$refs.form.resetFields()
  627. this.$refs.form.clearValidate()
  628. setTimeout(() => {
  629. this.$refs.form.clearValidate(validateList)
  630. //this.$refs.form.setRules(this.rules)
  631. // 或者使用 this.$refs.form.clearValidate()
  632. }, 10)
  633. },
  634. hideKeyboard() {
  635. uni.hideKeyboard()
  636. }
  637. }
  638. }
  639. </script>
  640. <style lang="scss" scoped>
  641. .desc {
  642. padding: 15rpx 5rpx;
  643. }
  644. .bottim_view {
  645. padding: 5px 20px 30px;
  646. position: fixed;
  647. left: 0px;
  648. bottom: 0px;
  649. width: 100%;
  650. height: 40px;
  651. background-color: #ffffff;
  652. }
  653. .title {
  654. font-size: 14px;
  655. font-weight: bold;
  656. margin: 20px 0 5px 0;
  657. }
  658. .data-pickerview {
  659. height: 400px;
  660. border: 1px #e5e5e5 solid;
  661. }
  662. .popper__arrow {
  663. top: -6px;
  664. left: 50%;
  665. margin-right: 3px;
  666. border-top-width: 0;
  667. border-bottom-color: #EBEEF5;
  668. }
  669. .popper__arrow {
  670. top: -6px;
  671. left: 50%;
  672. margin-right: 3px;
  673. border-top-width: 0;
  674. border-bottom-color: #EBEEF5;
  675. }
  676. </style>