detail.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. <template>
  2. <view class="container">
  3. <!-- 车牌号区域 -->
  4. <view class="box">
  5. <view class="left">车牌号</view>
  6. <view class="right2">
  7. <view class="item">
  8. <view :class="['select', form.selectValue != 0 ? 'selected' : '']" @tap="handleMultiple(form.selectIndex)">
  9. {{ form.selectValue != 0 ? form.selectValue : '请选择' }}
  10. </view>
  11. </view>
  12. <view class="right-img"><img src="../../static/bottom.png" /></view>
  13. </view>
  14. <!-- 车牌号选项弹窗区域 -->
  15. <transition>
  16. <multiple-picker
  17. title="请选择"
  18. :show="selectMultiple.show"
  19. :columns="selectMultiple.columns"
  20. :defaultIndex="selectMultiple.index"
  21. @confirm="confirmMultiple"
  22. @cancel="selectMultiple.show = false"
  23. @change="changeMultiple"
  24. ></multiple-picker>
  25. </transition>
  26. </view>
  27. <!-- 人数区域 -->
  28. <view class="box">
  29. <view class="left">容量</view>
  30. <view class="right">{{ info.contain }}</view>
  31. </view>
  32. <!-- 发车日期区域 -->
  33. <view class="box">
  34. <view class="left">发车日期</view>
  35. <view class="right">{{ info.yy_date }}</view>
  36. </view>
  37. <!-- 发车时间区域 -->
  38. <view class="box">
  39. <view class="left">发车时间</view>
  40. <picker style="width: 40%;" @change="bindPickerChange($event, 1)" mode="time" :value="info.ci_time" :start="getCurrentTime()">
  41. <view :class="['right', info.ci_time != 0 ? '' : 'unSelect']">
  42. {{ info.ci_time != 0 ? info.ci_time : '请选择' }}
  43. <view class="right-img"><img src="../../static/bottom.png" /></view>
  44. </view>
  45. </picker>
  46. </view>
  47. <!-- 扫码开始时间区域 -->
  48. <view class="box">
  49. <view class="left">扫码开始时间</view>
  50. <picker style="width: 40%;" @change="bindPickerChange($event, 4)" mode="time" :value="info.sm_start">
  51. <view :class="['right', info.sm_start != 0 ? '' : 'unSelect']">
  52. {{ info.sm_start != 0 ? info.sm_start : '请选择' }}
  53. <view class="right-img"><img src="../../static/bottom.png" /></view>
  54. </view>
  55. </picker>
  56. </view>
  57. <!-- 扫码结束时间区域 -->
  58. <view class="box">
  59. <view class="left">扫码结束时间</view>
  60. <picker style="width: 40%;" @change="bindPickerChange($event, 5)" mode="time" :value="info.sm_end">
  61. <view :class="['right', info.sm_end != 0 ? '' : 'unSelect']">
  62. {{ info.sm_end != 0 ? info.sm_end : '请选择' }}
  63. <view class="right-img"><img src="../../static/bottom.png" /></view>
  64. </view>
  65. </picker>
  66. </view>
  67. <!-- 预约截止时间区域 -->
  68. <view class="box">
  69. <view class="left">预约截止时间</view>
  70. <picker style="width: 40%;" @change="bindPickerChange($event, 7)" mode="time" :value="info.yy_end">
  71. <view :class="['right', info.yy_end != 0 ? '' : 'unSelect']">
  72. {{ info.yy_end != 0 ? info.yy_end : '请选择' }}
  73. <view class="right-img"><img src="../../static/bottom.png" /></view>
  74. </view>
  75. </picker>
  76. </view>
  77. <!-- 路线区域 -->
  78. <view class="box">
  79. <view class="left">路线</view>
  80. <picker style="width: 60%;" @change="bindPickerChange($event, 2)" :range="pathList" range-key="route">
  81. <view :class="['right', info.route ? '' : 'unSelect']">
  82. {{ info.route ? info.route : '请选择' }}
  83. <view class="right-img"><img src="../../static/bottom.png" /></view>
  84. </view>
  85. </picker>
  86. </view>
  87. <!-- 站点区域 -->
  88. <view class="box">
  89. <view class="left">站点</view>
  90. <picker style="width: 80%;" @change="bindPickerChange($event, 3)" :range="endList" range-key="route_end">
  91. <view :class="['right', info.route_end ? '' : 'unSelect']">
  92. {{ info.route_end ? info.route_end : '请选择' }}
  93. <view class="right-img"><img src="../../static/bottom.png" /></view>
  94. </view>
  95. </picker>
  96. </view>
  97. <!-- 状态区域 -->
  98. <view class="box">
  99. <view class="left">状态</view>
  100. <view class="right">{{ info.state_str }}</view>
  101. </view>
  102. <!-- 提前一天预约区域 -->
  103. <view class="box">
  104. <view class="left">可否提前一天预约</view>
  105. <view class="right">{{ info.before_state == 0 ? '不可以' : '可以' }}</view>
  106. </view>
  107. <!-- 保存按钮区域 -->
  108. <view class="saveBtn" @click="handleSave">保存</view>
  109. <!-- 人员名单区域 -->
  110. <view class="list">
  111. <view class="list-title" v-if="info.user_num != 0">
  112. <!-- 人员名单({{ info.user_num }}/{{ info.contain }}) -->
  113. <view class="list-title-left">人员名单({{ typeList[result_state].text }}{{ listData.length }}人)</view>
  114. <picker style="width: 38%;" :range="typeList" range-key="text" @change="bindPickerChange($event, 6)">
  115. <view class="list-title-right">
  116. {{ typeList[result_state].text }}
  117. <view class="right-img"><img src="../../static/bottom.png" /></view>
  118. </view>
  119. </picker>
  120. </view>
  121. <view class="list-item" v-for="(item, index) in listData" :key="index">
  122. <view class="item-img"><img src="../../static/man.png" /></view>
  123. <view class="item-info">
  124. <view class="info-name">
  125. <view>{{ item.user_name }}</view>
  126. </view>
  127. <view class="info-mes">
  128. {{ item.user_zz }}
  129. <span>{{ item.yy_time }}</span>
  130. </view>
  131. </view>
  132. <view v-if="item.yy_state === '1'" class="item-type"><img src="../../static/subscribe.png" /></view>
  133. <view v-else class="item-type"><img src="../../static/pass2.png" /></view>
  134. </view>
  135. <!-- 无数据时展示的区域 -->
  136. <view class="list-nodata" v-if="listData.length == 0">
  137. <img src="../../static/no-bus.png" />
  138. <view>暂无数据</view>
  139. </view>
  140. </view>
  141. </view>
  142. </template>
  143. <script setup>
  144. import { ref } from 'vue'
  145. import { onLoad } from '@dcloudio/uni-app'
  146. import { myRequest } from '@/util/api.js'
  147. import { isWeixin } from '@/util/isWeixin.js'
  148. import { time_to_sec, time_change } from '@/util/formatTime.js'
  149. onLoad(options => {
  150. if (isWeixin()) {
  151. let userInfo = JSON.parse(uni.getStorageSync('bus-userInfo'))
  152. if (userInfo.user_zz !== '车队长') {
  153. uni.redirectTo({
  154. url: '/pages/404/404?message=暂无权限'
  155. })
  156. } else {
  157. info.value = JSON.parse(options.info)
  158. // console.log(info.value)
  159. idRef.value = info.value.id
  160. // 获取人员列表
  161. getData()
  162. // 获取路线数组
  163. getPathList()
  164. // 获取终点站列表
  165. getEndList()
  166. // 获取车牌号列表
  167. getBusList()
  168. // 获取发车时间提前推迟多少分钟可以扫码数据
  169. getTimeConfig()
  170. // 处理车牌号数据
  171. form.value.selectValue = info.value.car_number
  172. setTimeout(() => {
  173. let temList = []
  174. selectMultiple.value.columns.forEach(item => {
  175. if (item.label == form.value.selectValue) {
  176. temList.push(item.value)
  177. }
  178. })
  179. form.value.selectIndex = temList
  180. }, 500)
  181. }
  182. } else {
  183. uni.redirectTo({
  184. url: '/pages/404/404?message=请在微信客户端打开链接'
  185. })
  186. }
  187. })
  188. // 带过来的预约详情数据
  189. const info = ref({})
  190. // 参数id
  191. const idRef = ref(null)
  192. // 车牌号绑定数据
  193. const form = ref({
  194. selectValue: '',
  195. selectIndex: []
  196. })
  197. // 车牌号数组相关数据
  198. const selectMultiple = ref({
  199. show: false,
  200. index: [],
  201. columns: []
  202. })
  203. // 路线数组
  204. const pathList = ref([])
  205. // 终点站数组
  206. const endList = ref([])
  207. // 人员列表数组
  208. const listData = ref([])
  209. // 发车时间提前多少分钟可以扫码
  210. const time_early = ref(null)
  211. // 发车时间推迟多少分钟可以扫码
  212. const time_late = ref(null)
  213. // 发车前多少分钟截止预约
  214. const time_yy_end = ref(null)
  215. // 人员名单筛选状态
  216. const result_state = ref(0)
  217. const typeList = ref([
  218. {
  219. text: '全部',
  220. value: 0
  221. },
  222. {
  223. text: '已预约未上车',
  224. value: 1
  225. },
  226. {
  227. text: '已上车',
  228. value: 2
  229. }
  230. ])
  231. // 获取路线数组请求
  232. const getPathList = async () => {
  233. const res = await myRequest({
  234. url: '/appqueryRoute.action'
  235. })
  236. // console.log(res);
  237. pathList.value = res.data
  238. }
  239. // 获取终点站数组请求
  240. const getEndList = async () => {
  241. const res = await myRequest({
  242. url: '/appqueryEndRoutes.action',
  243. data: {
  244. route: info.value.route
  245. }
  246. })
  247. // console.log(res);
  248. endList.value = res.data
  249. }
  250. // 获取车牌号数组请求
  251. const getBusList = async () => {
  252. const res = await myRequest({
  253. url: '/appqueryCarInfos.action'
  254. })
  255. // console.log(res);
  256. if (res.data.length) {
  257. let temList = []
  258. res.data.forEach((item, index) => {
  259. temList.push({
  260. label: item.car_number,
  261. value: index.toString()
  262. })
  263. })
  264. selectMultiple.value.columns = temList
  265. }
  266. }
  267. // 获取人员名单请求
  268. const getData = async () => {
  269. const res = await myRequest({
  270. url: '/appqueryAppointeds.action',
  271. data: {
  272. id: idRef.value,
  273. result_state: result_state.value
  274. }
  275. })
  276. // console.log(res)
  277. listData.value = res.data
  278. }
  279. // 保存按钮回调
  280. const handleSave = () => {
  281. if (info.value.car_number == 0) {
  282. uni.showToast({
  283. title: '请选择车牌号',
  284. icon: 'none'
  285. })
  286. return
  287. }
  288. if (info.value.ci_time == 0) {
  289. uni.showToast({
  290. title: '请选择发车时间',
  291. icon: 'none'
  292. })
  293. return
  294. }
  295. if (!info.value.sm_start) {
  296. uni.showToast({
  297. title: '请选择扫码开始时间',
  298. icon: 'none'
  299. })
  300. return
  301. }
  302. if (!info.value.sm_end) {
  303. uni.showToast({
  304. title: '请选择扫码结束时间',
  305. icon: 'none'
  306. })
  307. return
  308. }
  309. if (time_to_sec(info.value.sm_start) >= time_to_sec(info.value.ci_time)) {
  310. uni.showToast({
  311. title: '扫码开始时间不能晚于发车时间',
  312. icon: 'none',
  313. duration: 2000
  314. })
  315. return
  316. }
  317. if (time_to_sec(info.value.sm_end) < time_to_sec(info.value.ci_time)) {
  318. uni.showToast({
  319. title: '扫码结束时间不能早于发车时间',
  320. icon: 'none',
  321. duration: 2000
  322. })
  323. return
  324. }
  325. if (!info.value.yy_end) {
  326. uni.showToast({
  327. title: '请选择预约截止时间',
  328. icon: 'none'
  329. })
  330. return
  331. }
  332. if (!info.value.route) {
  333. uni.showToast({
  334. title: '请选择路线',
  335. icon: 'none'
  336. })
  337. return
  338. }
  339. if (!info.value.route_end) {
  340. uni.showToast({
  341. title: '请选择终点站',
  342. icon: 'none'
  343. })
  344. return
  345. }
  346. uni.showModal({
  347. title: '提示',
  348. content: '确定保存吗?',
  349. success: res => {
  350. if (res.confirm) {
  351. handleSaveRequest()
  352. } else if (res.cancel) {
  353. }
  354. }
  355. })
  356. }
  357. // 保存请求
  358. const handleSaveRequest = () => {
  359. // console.log(info.value)
  360. const { id, car_number, ci_time, route, route_end, contain, sm_start, sm_end, yy_end } = info.value
  361. uni.request({
  362. url: '/carstop/carbook/scheupdate.action',
  363. method: 'post',
  364. data: {
  365. id,
  366. car_number,
  367. ci_time,
  368. route,
  369. route_end,
  370. contain,
  371. sm_start,
  372. sm_end,
  373. yy_end
  374. },
  375. success: res => {
  376. if (res.data.code == 200) {
  377. uni.showToast({
  378. title: res.data.message
  379. })
  380. setTimeout(() => {
  381. uni.redirectTo({
  382. url: '/pages/record/record'
  383. })
  384. }, 1500)
  385. } else {
  386. uni.showToast({
  387. title: res.data.message,
  388. icon: 'error'
  389. })
  390. }
  391. }
  392. })
  393. }
  394. // 点击车牌号下拉框回调
  395. const handleMultiple = val => {
  396. // console.log(val);
  397. selectMultiple.value.index = val || []
  398. selectMultiple.value.show = true
  399. }
  400. // 车牌号下拉框确定按钮回调
  401. const confirmMultiple = e => {
  402. // console.log(e);
  403. // console.log(e.value);
  404. if (selectMultiple.value.index != e.value) {
  405. let temp = []
  406. e.selected.forEach(item => {
  407. temp.push(item.label)
  408. })
  409. form.value.selectValue = temp.toString()
  410. info.value.car_number = temp.toString()
  411. }
  412. form.value.selectIndex = e.value
  413. selectMultiple.value.show = false
  414. // 获取汽车容量
  415. getBusContain()
  416. }
  417. // 获取汽车容量请求
  418. const getBusContain = async () => {
  419. const res = await myRequest({
  420. url: '/appqueryCarContain.action',
  421. data: {
  422. car_number: form.value.selectValue
  423. }
  424. })
  425. // console.log(res);
  426. info.value.contain = res.data
  427. }
  428. // 获取发车时间提前推迟多少分钟可以扫码数据
  429. const getTimeConfig = async () => {
  430. const res = await myRequest({
  431. url: '/cnqueryHb.action'
  432. })
  433. // console.log(res)
  434. time_early.value = res.sm_end
  435. time_late.value = res.sm_start
  436. time_yy_end.value = res.yy_end
  437. }
  438. // 下拉框选择时的回调
  439. const changeMultiple = e => {
  440. // console.log(e);
  441. }
  442. // 原生下拉框的选择回调事件
  443. const bindPickerChange = (e, type) => {
  444. if (type == 1) {
  445. info.value.ci_time = e.detail.value
  446. info.value.sm_start = time_change(info.value.ci_time, time_early.value * -1)
  447. info.value.sm_end = time_change(info.value.ci_time, time_late.value)
  448. info.value.yy_end = time_change(info.value.ci_time, time_yy_end.value * -1)
  449. } else if (type == 2) {
  450. info.value.route = pathList.value[e.detail.value].route
  451. getEndList()
  452. info.value.route_end = ''
  453. } else if (type == 3) {
  454. info.value.route_end = endList.value[e.detail.value].route_end
  455. } else if (type == 4) {
  456. info.value.sm_start = e.detail.value
  457. } else if (type == 5) {
  458. info.value.sm_end = e.detail.value
  459. } else if (type == 6) {
  460. result_state.value = e.detail.value
  461. getData()
  462. } else if (type == 7) {
  463. info.value.yy_end = e.detail.value
  464. }
  465. }
  466. // 获取当前时间 hh:mm
  467. const getCurrentTime = () => {
  468. const date = new Date()
  469. let H = (date.getHours() + '').padStart(2, '0')
  470. let M = (date.getMinutes() + '').padStart(2, '0')
  471. return `${H}:${M}`
  472. }
  473. </script>
  474. <style lang="scss" scoped>
  475. .container {
  476. background-color: #fff;
  477. .box {
  478. display: flex;
  479. justify-content: space-between;
  480. align-items: center;
  481. padding: 0 30rpx;
  482. height: 98rpx;
  483. font-size: 28rpx;
  484. border-bottom: 1rpx solid #e6e6e6;
  485. .left {
  486. flex: 1;
  487. color: #999999;
  488. }
  489. .right {
  490. flex: 1;
  491. display: flex;
  492. justify-content: flex-end;
  493. .right-img {
  494. margin-left: 27rpx;
  495. margin-top: -5rpx;
  496. width: 17rpx;
  497. height: 12rpx;
  498. img {
  499. width: 100%;
  500. height: 100%;
  501. }
  502. }
  503. }
  504. .right2 {
  505. flex: 2;
  506. display: flex;
  507. justify-content: flex-end;
  508. align-items: center;
  509. .item {
  510. flex: 1;
  511. padding: 20rpx 0;
  512. .select {
  513. width: 100%;
  514. padding-top: 6px;
  515. padding-bottom: 6px;
  516. padding-left: 9px;
  517. border-radius: 4px;
  518. font-size: 15px;
  519. text-align: end;
  520. box-sizing: border-box;
  521. color: #cccccc;
  522. line-height: 26px;
  523. &.selected {
  524. color: black;
  525. }
  526. }
  527. }
  528. .right-img {
  529. margin-left: 27rpx;
  530. margin-top: -30rpx;
  531. width: 17rpx;
  532. height: 12rpx;
  533. img {
  534. width: 100%;
  535. height: 100%;
  536. }
  537. }
  538. }
  539. .unSelect {
  540. color: #ccc;
  541. }
  542. }
  543. .saveBtn {
  544. margin: 20rpx 30rpx;
  545. line-height: 100rpx;
  546. text-align: center;
  547. color: #fff;
  548. font-size: 34rpx;
  549. border-radius: 15rpx;
  550. background: linear-gradient(180deg, #8684ff 0%, #3c50e8 100%);
  551. }
  552. .list {
  553. padding: 13rpx 30rpx;
  554. .list-title {
  555. display: flex;
  556. margin-top: 20rpx;
  557. height: 41rpx;
  558. color: #999999;
  559. font-size: 28rpx;
  560. .list-title-left {
  561. flex: 1;
  562. }
  563. .list-title-right {
  564. flex: 1;
  565. display: flex;
  566. justify-content: flex-end;
  567. color: #000;
  568. .right-img {
  569. margin-left: 27rpx;
  570. margin-top: -5rpx;
  571. width: 17rpx;
  572. height: 12rpx;
  573. img {
  574. width: 100%;
  575. height: 100%;
  576. }
  577. }
  578. }
  579. }
  580. .list-item {
  581. display: flex;
  582. align-items: center;
  583. box-sizing: border-box;
  584. padding: 29rpx 0 26rpx 0;
  585. height: 155rpx;
  586. border-bottom: 1rpx solid #e6e6e6;
  587. .item-img {
  588. width: 100rpx;
  589. height: 100rpx;
  590. border-radius: 50%;
  591. img {
  592. width: 100%;
  593. height: 100%;
  594. }
  595. }
  596. .item-info {
  597. flex: 1;
  598. display: flex;
  599. flex-direction: column;
  600. justify-content: space-evenly;
  601. margin-left: 6rpx;
  602. height: 100rpx;
  603. .info-name {
  604. display: flex;
  605. align-items: center;
  606. font-size: 32rpx;
  607. .info-name-img {
  608. margin-left: 26rpx;
  609. width: 30rpx;
  610. height: 35rpx;
  611. img {
  612. width: 100%;
  613. height: 100%;
  614. }
  615. }
  616. }
  617. .info-mes {
  618. font-size: 24rpx;
  619. color: #999999;
  620. span {
  621. margin-left: 26rpx;
  622. color: #a6a6a6;
  623. }
  624. }
  625. }
  626. .item-type {
  627. width: 104rpx;
  628. height: 41rpx;
  629. img {
  630. width: 100%;
  631. height: 100%;
  632. }
  633. }
  634. }
  635. .list-nodata {
  636. padding: 50rpx 0;
  637. background-color: #fff;
  638. text-align: center;
  639. color: #999999;
  640. img {
  641. width: 500rpx;
  642. }
  643. }
  644. }
  645. }
  646. .v-enter-active,
  647. .v-leave-active {
  648. transition: opacity 0.5s ease;
  649. }
  650. .v-enter-from,
  651. .v-leave-to {
  652. opacity: 0;
  653. }
  654. </style>