orderList.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. <template>
  2. <view class="orderList">
  3. <!-- 头部筛选 -->
  4. <view class="orderList_header">
  5. <view class="orderList_header_item" @click="openPicker('gdState')">
  6. <text class="orderList_header_itemText">{{selectedGdState}}</text>
  7. <text class="pda pda-xiala"></text>
  8. </view>
  9. <view class="orderList_header_item" @click="openPicker('associationType')">
  10. <text class="orderList_header_itemText">{{selectedAssociationType}}</text>
  11. <text class="pda pda-xiala"></text>
  12. </view>
  13. </view>
  14. <!-- 列表 -->
  15. <view class="orderList_list">
  16. <view class="orderList_listItem" v-for="newOrder in newOrderList" :key="newOrder.id">
  17. <image class="ji" src="../../static/imgs/icon_ji.png" mode="widthFix"
  18. v-if="newOrder.emergencyType && newOrder.emergencyType.value == 2"></image>
  19. <image class="jiaji" src="../../static/imgs/icon_jiaji.png" mode="widthFix"
  20. v-if="newOrder.emergencyType && newOrder.emergencyType.value == 3"></image>
  21. <view class="orderList_listItem_header">
  22. <view class="orderList_listItem_header_title">
  23. <view class="associationType_icon" v-if="newOrder.isHalfInspect === 1"> 半 </view>
  24. <view class="associationType_icon" v-else-if="newOrder.taskType.associationType.value == 'specimen'">标
  25. </view>
  26. <view class="associationType_icon" v-else-if="newOrder.taskType.associationType.value == 'drugsBag'"> 药
  27. </view>
  28. <view class="associationType_icon" v-else-if="newOrder.taskType.associationType.value == 'specimenPlan'"> 巡
  29. </view>
  30. <view class="associationType_icon" v-else-if="newOrder.taskType.associationType.value == 'jPBag'"> 静 </view>
  31. <view class="associationType_icon" v-else-if="newOrder.taskType.associationType.value == 'inspect'"> 病
  32. </view>
  33. <view class="associationType_icon"
  34. v-else-if="newOrder.taskType.associationType.value == 'patientTransport'"> 病
  35. </view>
  36. <view class="associationType_icon" v-else-if="newOrder.taskType.associationType.value == 'other'"> 其
  37. </view>
  38. <view class="taskNameAndWorkerName">
  39. <text class="taskName">{{newOrder.isHalfInspect === 1? "半程陪检": newOrder.taskType.taskName}}</text>
  40. <text class="workerName"
  41. v-if="newOrder.patient &&(newOrder.taskType.associationType.value =='patientTransport' ||newOrder.taskType.associationType.value =='inspect')">-{{newOrder.patient.patientName}}</text>
  42. </view>
  43. </view>
  44. <text class="orderList_listItem_header_more"
  45. :class="newOrder.stateTextClass">{{newOrder.gdState.name }}</text>
  46. </view>
  47. <view class="orderList_listItem_item">
  48. <view class="orderList_listItem_item_content">
  49. <text class="orderList_listItem_item_name"
  50. v-if="newOrder.worker">{{newOrder.worker.name}}{{newOrder.worker.phone? "-" + newOrder.worker.phone: ""}}</text>
  51. <text class="orderList_listItem_item_name" v-else>暂未接单</text>
  52. <text class="orderList_listItem_item_time" v-if="newOrder.showCreateTime">{{newOrder.showCreateTime}}</text>
  53. <text class="orderList_listItem_item_time"
  54. v-else-if="newOrder.yyjdTime && newOrder.gdState.value == GDSTATE['定时预约']">{{newOrder.yyjdTime | formatDate('MM-dd HH:mm')}}</text>
  55. </view>
  56. <view class="orderList_listItem_item_btns" v-if="
  57. newOrder.gdState.value == GDSTATE['待抢单'] ||
  58. newOrder.gdState.value == GDSTATE['待接单'] ||
  59. newOrder.gdState.value == GDSTATE['待到达'] ||
  60. newOrder.gdState.value == GDSTATE['定时预约'] ||
  61. newOrder.gdState.value == GDSTATE['待评价']
  62. ">
  63. <button type="primary" class="btn" v-if="newOrder.gdState.value == GDSTATE['待评价']"
  64. @click="showAppraise(newOrder.id)">评价</button>
  65. <button type="primary" class="btn" v-if="
  66. newOrder.gdState.value == GDSTATE['待抢单'] ||
  67. newOrder.gdState.value == GDSTATE['待接单'] ||
  68. newOrder.gdState.value == GDSTATE['待到达'] ||
  69. newOrder.gdState.value == GDSTATE['定时预约']
  70. " @click="openRecallModal(newOrder.id)">撤销</button>
  71. <button type="primary" class="btn" v-if="newOrder.gdState.value == GDSTATE['定时预约']"
  72. @click="openExecModal(newOrder.id)">立即执行</button>
  73. <button type="primary" class="btn" v-if="
  74. (newOrder.gdState.value == GDSTATE['待抢单'] ||
  75. newOrder.gdState.value == GDSTATE['待到达']) &&
  76. newOrder.taskType.allowUrgent == 1 &&
  77. !newOrder.urgentDetails
  78. " @click="showJiaji(newOrder.id)">加急</button>
  79. </view>
  80. </view>
  81. </view>
  82. </view>
  83. <seiminFooterNav></seiminFooterNav>
  84. <seiminModel ref="seiminModel"></seiminModel>
  85. <seiminPicker ref="sPicker" titleColor="#808080" titleFontSize="28rpx" confirmColor="#333" confirmFontSize="38rpx"
  86. confirmFontWeight="500" itemFontSize="28rpx" @onClose="closePicker" @onConfirm="confirmPicker"
  87. :pickerList="pickerList">
  88. </seiminPicker>
  89. </view>
  90. </template>
  91. <script>
  92. import {
  93. mapState,
  94. mapActions
  95. } from "vuex";
  96. import {
  97. reqFetchDataList,
  98. reqDelWorkOrder,
  99. reqUrge,
  100. reqDirectStartOrder
  101. } from "../../request/api.js";
  102. import {
  103. GDSTATE
  104. } from "../../utils/enum.gdstate.js";
  105. export default {
  106. name: 'orderList',
  107. data() {
  108. return {
  109. // 工单状态
  110. GDSTATE: GDSTATE,
  111. // 当前筛选的工单状态
  112. selectedGdState: '执行中',
  113. // 当前筛选的关联类型
  114. selectedAssociationType: '全部',
  115. //工单状态筛选列表
  116. gdStates: [{
  117. value: -1,
  118. label: '全部'
  119. },
  120. {
  121. value: 1,
  122. label: '执行中'
  123. },
  124. {
  125. value: 2,
  126. label: '待评价'
  127. },
  128. ],
  129. //关联类型筛选列表
  130. associationTypes: [{
  131. value: -1,
  132. label: '全部'
  133. }, ],
  134. newOrderList: [], //工单列表
  135. totalNum: 0, //工单总数量
  136. idx: 0, //页码
  137. pageNum: 20, //每页的工单数量
  138. pickerList: [], //picker列表
  139. type: '', //打开picker的类型,工单状态||关联类型
  140. checkStatus: {}, //审核状态列表
  141. };
  142. },
  143. computed: {
  144. ...mapState("login", ["loginInfo"]),
  145. },
  146. methods: {
  147. ...mapActions("dictionary", ["vxDictionary"]),
  148. //评价
  149. showAppraise(id) {
  150. this.$refs.seiminModel.show({
  151. skin: 'evaluate',
  152. content: "工单已完成,请对本次服务做出评价!",
  153. btns: [{
  154. click: () => {
  155. console.log('取消');
  156. this.$refs.seiminModel.close();
  157. }
  158. },
  159. {
  160. click: () => {
  161. console.log('确定');
  162. this.$refs.seiminModel.close();
  163. uni.showLoading({
  164. title: '加载中',
  165. mask: true,
  166. })
  167. reqDelWorkOrder(id).then(res => {
  168. uni.hideLoading();
  169. if (res.status == 200) {
  170. this.$refs.seiminModel.show({
  171. skin: 'toast',
  172. icon: 'success',
  173. content: '撤销成功',
  174. })
  175. this.init();
  176. } else {
  177. this.$refs.seiminModel.show({
  178. skin: 'toast',
  179. icon: 'error',
  180. content: '撤销失败',
  181. })
  182. }
  183. })
  184. }
  185. }
  186. ]
  187. });
  188. },
  189. //撤销
  190. openRecallModal(id) {
  191. this.$refs.seiminModel.show({
  192. icon: "warn",
  193. content: "您确认要撤销工单吗?撤销工单我们会通知服务台、支助人员不再执行此工单,请谨慎操作,如确认撤销请点击确认。",
  194. btns: [{
  195. click: () => {
  196. console.log('取消');
  197. this.$refs.seiminModel.close();
  198. }
  199. },
  200. {
  201. click: () => {
  202. console.log('确定');
  203. this.$refs.seiminModel.close();
  204. uni.showLoading({
  205. title: '加载中',
  206. mask: true,
  207. })
  208. reqDelWorkOrder(id).then(res => {
  209. uni.hideLoading();
  210. if (res.status == 200) {
  211. this.$refs.seiminModel.show({
  212. skin: 'toast',
  213. icon: 'success',
  214. content: '撤销成功',
  215. })
  216. this.init();
  217. } else {
  218. this.$refs.seiminModel.show({
  219. skin: 'toast',
  220. icon: 'error',
  221. content: '撤销失败',
  222. })
  223. }
  224. })
  225. }
  226. }
  227. ]
  228. });
  229. },
  230. //立即执行
  231. openExecModal(id) {
  232. this.$refs.seiminModel.show({
  233. icon: 'warn',
  234. content: '您确认要立即执行该工单吗?',
  235. btns: [{
  236. click: () => {
  237. console.log('取消');
  238. this.$refs.seiminModel.close();
  239. }
  240. }, {
  241. click: () => {
  242. console.log('确认');
  243. this.$refs.seiminModel.close();
  244. uni.showLoading({
  245. title: '加载中',
  246. mask: true,
  247. })
  248. reqDirectStartOrder(id).then(res => {
  249. uni.hideLoading();
  250. if (res.status == 200) {
  251. this.$refs.seiminModel.show({
  252. skin: 'toast',
  253. icon: 'success',
  254. content: '您的加急申请已成功,调度人员会紧急处理!',
  255. })
  256. this.init();
  257. } else {
  258. this.$refs.seiminModel.show({
  259. skin: 'toast',
  260. icon: 'error',
  261. content: '加急失败',
  262. })
  263. }
  264. })
  265. }
  266. }, ]
  267. })
  268. },
  269. //加急
  270. showJiaji(id) {
  271. this.$refs.seiminModel.urgentTextArea = '';
  272. this.$refs.seiminModel.show({
  273. title: '',
  274. skin: 'urgent',
  275. content: "请填写加急原因,填写后我们会根据您的诉求优先处理",
  276. btns: [{
  277. click: () => {
  278. console.log('取消');
  279. this.$refs.seiminModel.close();
  280. }
  281. },
  282. {
  283. click: () => {
  284. console.log('确定', this.$refs.seiminModel.urgentTextArea);
  285. const urgentTextArea = this.$refs.seiminModel.urgentTextArea;
  286. if (urgentTextArea.trim() === '') {
  287. return;
  288. }
  289. this.$refs.seiminModel.close();
  290. uni.showLoading({
  291. title: '加载中',
  292. mask: true,
  293. })
  294. let postData = {
  295. urgentDetails: {
  296. workerOrder: id,
  297. checkStatus: {
  298. id: this.checkStatus[1]
  299. },
  300. urgentReason: urgentTextArea,
  301. },
  302. };
  303. reqUrge(postData).then(res => {
  304. uni.hideLoading();
  305. if (res.status == 200) {
  306. this.$refs.seiminModel.show({
  307. skin: 'toast',
  308. icon: 'success',
  309. content: '加急成功',
  310. })
  311. this.init();
  312. } else {
  313. this.$refs.seiminModel.show({
  314. skin: 'toast',
  315. icon: 'error',
  316. content: '加急失败',
  317. })
  318. }
  319. })
  320. }
  321. }
  322. ]
  323. });
  324. },
  325. //关闭
  326. closePicker() {
  327. this.$refs.sPicker._close();
  328. },
  329. //打开
  330. openPicker(type) {
  331. this.type = type;
  332. this.$refs.sPicker._open();
  333. if (type === 'gdState') {
  334. //工单状态
  335. this.pickerList = this.gdStates;
  336. let index = this.pickerList.findIndex(v => v.label === this.selectedGdState);
  337. let obj = this.pickerList.find(v => v.label === this.selectedGdState);
  338. this.$refs.sPicker._changeValue(index);
  339. this.selectedGdState = obj && obj.label;
  340. } else if (type === 'associationType') {
  341. //关联类型
  342. this.pickerList = this.associationTypes;
  343. let index = this.pickerList.findIndex(v => v.label === this.selectedAssociationType);
  344. let obj = this.pickerList.find(v => v.label === this.selectedAssociationType);
  345. this.$refs.sPicker._changeValue(index);
  346. this.selectedAssociationType = obj && obj.label;
  347. }
  348. },
  349. //确定:接收子组件传来的参数
  350. confirmPicker(checkedObj) {
  351. if (this.type === 'gdState') {
  352. //工单状态
  353. this.selectedGdState = checkedObj.label;
  354. } else if (this.type === 'associationType') {
  355. //关联类型
  356. this.selectedAssociationType = checkedObj.label;
  357. }
  358. let index = this.pickerList.findIndex(v => v.label === checkedObj.label);
  359. this.$refs.sPicker._changeValue(index);
  360. this.init();
  361. },
  362. // 获取页面数据
  363. init() {
  364. uni.showLoading({
  365. title: "加载中",
  366. mask: true,
  367. });
  368. Promise.all([
  369. this.queryWorkOrdersRequest(), //查询最新工单列表
  370. this.queryDictionary('association_types'), //获取数据字典-关联类型
  371. this.queryDictionary('check_status'), //获取数据字典-审核状态
  372. ]).then((values) => {
  373. uni.hideLoading();
  374. uni.stopPullDownRefresh();
  375. this.queryWorkOrdersResponse(values[0]);
  376. this.queryDictionaryResponse(values[1], 'association_types');
  377. this.queryDictionaryResponse(values[2], 'check_status');
  378. });
  379. },
  380. // 查询最新工单列表(上拉)
  381. reachBottom() {
  382. //没有更多
  383. if (this.newOrderList.length == this.totalNum) {
  384. uni.showToast({
  385. icon: 'none',
  386. title: '没有更多工单了'
  387. })
  388. return;
  389. }
  390. uni.showLoading({
  391. title: "加载中",
  392. mask: true,
  393. });
  394. Promise.all([
  395. this.queryWorkOrdersRequest(true), //查询最新工单列表
  396. ]).then((values) => {
  397. uni.hideLoading();
  398. this.queryWorkOrdersResponse(values[0], true);
  399. });
  400. },
  401. // 查询最新工单列表
  402. queryWorkOrdersRequest(idxPlus = false) {
  403. console.log(this.selectedGdState, this.selectedAssociationType);
  404. console.log(this.gdStates, this.associationTypes);
  405. if (idxPlus) {
  406. //累加
  407. ++this.idx;
  408. } else {
  409. this.idx = 0;
  410. }
  411. let postData = {
  412. workOrder: {
  413. createDept: this.loginInfo.user.dept.id,
  414. platform: 2,
  415. searchDays: 2,
  416. },
  417. idx: this.idx,
  418. sum: this.pageNum,
  419. };
  420. let selectedGdStateValue = this.gdStates.find(v => v.label == this.selectedGdState).value;
  421. let associationTypesValue = this.associationTypes.find(v => v.label == this.selectedAssociationType).value;
  422. // 工单状态
  423. // 执行中包含状态:待抢单、待接单、待到达、待送达、执行中、定时预约
  424. if (selectedGdStateValue == 1) {
  425. // 执行中
  426. postData.workOrder.nurseState = 1;
  427. } else if (selectedGdStateValue == 2) {
  428. // 待评价
  429. postData.workOrder.gdState = {
  430. id: "73"
  431. };
  432. }
  433. //关联类型
  434. if (associationTypesValue != -1) {
  435. postData.workOrder.taskType = {
  436. associationType: {
  437. id: associationTypesValue,
  438. }
  439. }
  440. }
  441. return reqFetchDataList("nurse", "workOrder", postData);
  442. },
  443. // 查询最新工单列表
  444. queryWorkOrdersResponse(res, idxPlus = false) {
  445. if (res.status == 200) {
  446. res.list = res.list || [];
  447. this.totalNum = res.totalNum || 0;
  448. let newOrderList = res.list.map((v) => {
  449. if (v.gdState) {
  450. if (
  451. v.gdState.value == GDSTATE["待接单"] ||
  452. v.gdState.value == GDSTATE["待抢单"]
  453. ) {
  454. v.stateTextClass = "red";
  455. } else if (
  456. v.gdState.value == GDSTATE["待评价"] ||
  457. v.gdState.value == GDSTATE["已完成"]
  458. ) {
  459. v.stateTextClass = "green";
  460. } else {
  461. v.stateTextClass = "yellow";
  462. }
  463. }
  464. return v;
  465. });
  466. if (idxPlus) {
  467. //累加
  468. this.newOrderList = this.newOrderList.concat(newOrderList);
  469. } else {
  470. this.newOrderList = newOrderList;
  471. }
  472. } else {
  473. this.$refs.seiminModel.show({
  474. skin: "toast",
  475. icon: "error",
  476. content: res.msg || "获取数据失败",
  477. });
  478. throw new Error(res.msg || '获取数据失败');
  479. }
  480. },
  481. // 获取数据字典
  482. queryDictionary(key) {
  483. let postData = {
  484. "type": "list",
  485. key
  486. };
  487. return this.vxDictionary(postData);
  488. },
  489. // 获取数据字典
  490. queryDictionaryResponse(res, type) {
  491. let obj = {};
  492. let arr = [];
  493. switch (type) {
  494. case 'association_types':
  495. arr = res.map(v => ({
  496. value: v.id,
  497. label: v.name
  498. }));
  499. this.associationTypes = [{
  500. label: '全部',
  501. value: -1
  502. }, ...arr];
  503. break;
  504. case 'check_status':
  505. obj = {};
  506. res.forEach(v => {
  507. obj[v.value] = v.id;
  508. })
  509. this.checkStatus = obj;
  510. break;
  511. }
  512. },
  513. },
  514. mounted() {
  515. this.init();
  516. },
  517. onPullDownRefresh() {
  518. this.init();
  519. },
  520. onReachBottom() {
  521. this.reachBottom();
  522. }
  523. }
  524. </script>
  525. <style lang="scss" scoped>
  526. .orderList {
  527. padding-bottom: 108rpx;
  528. // 头部筛选
  529. .orderList_header {
  530. height: 88rpx;
  531. background-color: #fff;
  532. border-bottom: 1px solid #E5E9ED;
  533. position: fixed;
  534. left: 0;
  535. z-index: 99;
  536. width: 100%;
  537. @include flex(center, center);
  538. .orderList_header_item {
  539. flex: 1;
  540. height: 100%;
  541. padding: 0 50rpx;
  542. border-right: 1px solid #E5E9ED;
  543. @include flex(space-between, center);
  544. &:last-of-type {
  545. border-right: none;
  546. }
  547. .orderList_header_itemText {
  548. color: #333;
  549. font-size: 38rpx;
  550. }
  551. .pda-xiala {
  552. color: #DDE1E5;
  553. }
  554. }
  555. }
  556. // 列表
  557. .orderList_list {
  558. padding: 88rpx 24rpx 0;
  559. .orderList_listItem {
  560. width: 702rpx;
  561. min-height: 320rpx;
  562. background-color: #fff;
  563. margin-top: 8rpx;
  564. border-radius: 8rpx;
  565. border: 2rpx solid #e5e9ed;
  566. position: relative;
  567. padding: 0 24rpx;
  568. font-size: 32rpx;
  569. @include semicircle(#f9fafb, 82rpx);
  570. @include flex(flex-start, stretch, column);
  571. .ji,
  572. .jiaji {
  573. width: 60rpx;
  574. position: absolute;
  575. right: 0;
  576. top: 0;
  577. }
  578. .orderList_listItem_header {
  579. height: 86rpx;
  580. border-bottom: 2rpx dashed #e5e9ed;
  581. @include flex(space-between, center);
  582. .orderList_listItem_header_title {
  583. color: #333;
  584. flex: 1;
  585. @include flex(flex-start, center);
  586. .associationType_icon {
  587. width: 48rpx;
  588. height: 48rpx;
  589. border-radius: 50%;
  590. background-color: #F0F6ED;
  591. border: 1px solid #39b199;
  592. font-size: 24rpx;
  593. color: #39b199;
  594. margin-right: 8rpx;
  595. @include flex(center, center);
  596. }
  597. .taskNameAndWorkerName {
  598. flex: 1;
  599. @include flex;
  600. .taskName {
  601. max-width: 10em;
  602. @include clamp;
  603. }
  604. .workerName {
  605. flex: 1;
  606. @include clamp;
  607. }
  608. }
  609. }
  610. .orderList_listItem_header_more {
  611. color: #666;
  612. }
  613. }
  614. .orderList_listItem_item {
  615. height: 88rpx;
  616. border-bottom: 1px solid #e5e9ed;
  617. color: #333;
  618. font-size: 30rpx;
  619. flex: 1;
  620. @include flex(flex-start, stretch, column);
  621. &:last-of-type {
  622. border-bottom: none;
  623. }
  624. .orderList_listItem_item_content {
  625. min-height: 143rpx;
  626. flex: 1;
  627. @include flex(space-between, center);
  628. .orderList_listItem_item_name {
  629. font-size: 38rpx;
  630. font-weight: bold;
  631. }
  632. .orderList_listItem_item_time {
  633. color: #666;
  634. font-size: 28rpx;
  635. }
  636. }
  637. .orderList_listItem_item_btns {
  638. position: relative;
  639. left: -24rpx;
  640. width: 698rpx;
  641. height: 88rpx;
  642. @include btn_background;
  643. @include flex;
  644. .btn {
  645. flex: 1;
  646. background-color: transparent;
  647. position: relative;
  648. @include flex(center,center);
  649. &::before {
  650. content: '';
  651. position: absolute;
  652. right: 0;
  653. top: 0;
  654. width: 2rpx;
  655. height: 100%;
  656. border-right: 2rpx solid #fff;
  657. }
  658. &:last-of-type::before {
  659. border-right: none;
  660. }
  661. &::after {
  662. border: none;
  663. }
  664. }
  665. }
  666. }
  667. }
  668. }
  669. }
  670. </style>