BillRoomInfo.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. <template>
  2. <div>
  3. <div style="display: flex; gap: 15px">
  4. <div style="width: 40%">
  5. <div style="display: flex; justify-content: space-between">
  6. <h4
  7. style="
  8. color: rgba(255, 141, 26, 1);
  9. font-weight: 600;
  10. margin-top: 15px;
  11. "
  12. >
  13. 入住信息
  14. </h4>
  15. <div style="display: flex">
  16. <div style="display: flex; flex-direction: column">
  17. <a-icon
  18. type="clock-circle"
  19. style="color: rgba(255, 141, 26, 1); font-size: 18px"
  20. /><a-button type="link"> 叫醒服务 </a-button>
  21. </div>
  22. <div style="display: flex; flex-direction: column">
  23. <a-icon
  24. type="compass"
  25. style="color: rgba(255, 141, 26, 1); font-size: 18px"
  26. /><a-button type="link"> 拆分房间 </a-button>
  27. </div>
  28. </div>
  29. </div>
  30. <a-divider />
  31. <a-tabs>
  32. <a-tab-pane
  33. :key="item.id"
  34. :tab="item.roomName"
  35. v-for="(item, livingIndex) in model.livingRoomIds"
  36. >
  37. <a-descriptions :column="2">
  38. <a-descriptions-item label="主客姓名">
  39. {{ item.livingCustomers[0].customerName }}
  40. <a-icon
  41. type="edit"
  42. style="color: rgba(255, 141, 26, 1); font-size: 18px"
  43. /></a-descriptions-item>
  44. <a-descriptions-item label="性别">
  45. {{
  46. item.livingCustomers[0].gender === 1 ? "男" : "女"
  47. }}</a-descriptions-item
  48. >
  49. <a-descriptions-item label="房间数量">
  50. {{ livingIndex == 0 ? model.livingRoomIds.length : 1 }}间
  51. </a-descriptions-item>
  52. <a-descriptions-item label="手机号">
  53. {{ item.livingCustomers[0].phone }}
  54. <a-icon
  55. type="edit"
  56. style="color: rgba(255, 141, 26, 1); font-size: 18px"
  57. /></a-descriptions-item>
  58. <a-descriptions-item label="宾客类型">
  59. {{ customerTypeName(model.orderInfo.customerType) }}
  60. <a-icon
  61. type="edit"
  62. style="color: rgba(255, 141, 26, 1); font-size: 18px"
  63. /></a-descriptions-item>
  64. <a-descriptions-item label="入住时间">
  65. {{ model.orderInfo.arrivalTime }}
  66. </a-descriptions-item>
  67. <a-descriptions-item label="房价方案"> -- </a-descriptions-item>
  68. <a-descriptions-item label="预离时间">
  69. {{ model.orderInfo.dueOutTime }}
  70. </a-descriptions-item>
  71. <a-descriptions-item label="订单来源">
  72. {{ customerSourceName(model.orderInfo.customerSource) }}
  73. <a-icon
  74. type="edit"
  75. style="color: rgba(255, 141, 26, 1); font-size: 18px"
  76. /></a-descriptions-item>
  77. <a-descriptions-item label="入住类型">
  78. {{ model.orderInfo.bookingType == 1 ? "全天" : "钟点" }}
  79. </a-descriptions-item>
  80. <a-descriptions-item label="入住天数">
  81. {{ model.orderInfo.dayCount }}
  82. </a-descriptions-item>
  83. <a-descriptions-item label="早餐券">
  84. {{ model.orderInfo.breakfastNum }}
  85. </a-descriptions-item>
  86. <a-descriptions-item label="外部单号">
  87. {{ model.orderInfo.outerOrdersNo }}
  88. </a-descriptions-item>
  89. <a-descriptions-item label="销售员工">
  90. {{ warranterName(model.orderInfo.warranter) }}
  91. <a-icon
  92. type="edit"
  93. style="color: rgba(255, 141, 26, 1); font-size: 18px"
  94. /></a-descriptions-item>
  95. <a-descriptions-item label="订单备注" :span="2">
  96. {{ model.orderInfo.remark
  97. }}<a-icon
  98. type="edit"
  99. style="color: rgba(255, 141, 26, 1); font-size: 18px"
  100. />
  101. </a-descriptions-item>
  102. <a-descriptions-item
  103. label="叫醒服务"
  104. :span="2"
  105. v-for="(item, index) in wakeList"
  106. :key="index"
  107. >
  108. <a-select
  109. style="width: 100px"
  110. placeholder="房间号"
  111. @change="onChange"
  112. >
  113. <a-select-option value="jack"> 1001 </a-select-option>
  114. <a-select-option value="lucy"> 1002 </a-select-option>
  115. </a-select>
  116. <a-date-picker
  117. style="width: 120px; margin-left: 2px"
  118. placeholder="日期"
  119. @change="onChange"
  120. />
  121. <a-time-picker
  122. style="width: 100px; margin-left: 2px"
  123. :default-value="moment('12:08', 'HH:mm')"
  124. format="HH:mm"
  125. />
  126. <a-icon
  127. v-if="wakeList.length - 1 == index"
  128. type="plus-circle"
  129. class="dynamic-delete-button"
  130. @click="puls()"
  131. />
  132. <a-icon
  133. type="minus-circle"
  134. style="color: #f56c6c"
  135. class="dynamic-delete-button"
  136. v-if="wakeList.length > 1"
  137. @click="() => remove(index)"
  138. />
  139. </a-descriptions-item>
  140. </a-descriptions>
  141. <div style="display: flex; justify-content: space-between">
  142. <h4
  143. style="
  144. color: rgba(255, 141, 26, 1);
  145. font-weight: 600;
  146. margin-top: 15px;
  147. "
  148. >
  149. 同住人
  150. </h4>
  151. <div style="display: flex">
  152. <div style="display: flex; flex-direction: column">
  153. <a-icon
  154. type="user-add"
  155. style="color: rgba(255, 141, 26, 1); font-size: 18px"
  156. /><a-button
  157. type="link"
  158. @click="addlivingCustomer(item.livingOrder.id, item.roomId)"
  159. >
  160. 添加
  161. </a-button>
  162. </div>
  163. </div>
  164. </div>
  165. <div id="livingCustomers-grid">
  166. <a-row
  167. v-for="(customer, index) in item.livingCustomers"
  168. :key="customer.id"
  169. >
  170. <template v-if="index > 0">
  171. <a-col :span="7"> {{ customer.customerName }} </a-col>
  172. <a-col :span="1"
  173. >{{ customer.gender == 1 ? "男" : "女" }}
  174. </a-col>
  175. <a-col :span="8"> {{ customer.certNo }}</a-col>
  176. <a-col :span="6"> {{ customer.phone }}</a-col>
  177. <a-col :span="2">
  178. <a-icon
  179. type="minus-circle"
  180. style="color: #f56c6c"
  181. class="dynamic-delete-button"
  182. @click="() => removeLivingCustomer(customer.id)"
  183. /></a-col>
  184. </template>
  185. </a-row>
  186. </div>
  187. </a-tab-pane>
  188. </a-tabs>
  189. <!-- <h4
  190. style="
  191. color: rgba(255, 141, 26, 1);
  192. font-weight: 600;
  193. margin-top: 50px;
  194. "
  195. >
  196. 会员信息
  197. </h4>
  198. <a-divider />
  199. <a-descriptions :column="2">
  200. <a-descriptions-item label="姓名"> 张三 </a-descriptions-item>
  201. <a-descriptions-item label="证件号"
  202. >888888888888
  203. </a-descriptions-item>
  204. <a-descriptions-item label="卡号"> 1588888888 </a-descriptions-item>
  205. <a-descriptions-item label="手机号"> 1588888888 </a-descriptions-item>
  206. <a-descriptions-item label="会员级别"> 金卡 </a-descriptions-item>
  207. <a-descriptions-item label="余额"> 3000.00元 </a-descriptions-item>
  208. <a-descriptions-item label="积分"> 888888分 </a-descriptions-item>
  209. </a-descriptions> -->
  210. </div>
  211. <div style="width: 40%">
  212. <div style="display: flex; justify-content: space-between">
  213. <h4
  214. style="
  215. color: rgba(255, 141, 26, 1);
  216. font-weight: 600;
  217. margin-top: 15px;
  218. "
  219. >
  220. 消费详情
  221. </h4>
  222. <div style="display: flex">
  223. <div style="display: flex; flex-direction: column">
  224. <a-icon
  225. type="import"
  226. style="color: rgba(255, 141, 26, 1); font-size: 18px"
  227. /><a-button type="link"> 退单 </a-button>
  228. </div>
  229. <div style="display: flex; flex-direction: column">
  230. <a-icon
  231. type="tool"
  232. style="color: rgba(255, 141, 26, 1); font-size: 18px"
  233. /><a-button type="link"> 补单 </a-button>
  234. </div>
  235. <div style="display: flex; flex-direction: column">
  236. <a-icon
  237. type="property-safety"
  238. style="color: rgba(255, 141, 26, 1); font-size: 18px"
  239. /><a-button type="link"> 部分结账 </a-button>
  240. </div>
  241. </div>
  242. </div>
  243. <a-divider />
  244. <a-table
  245. :columns="columns"
  246. :data-source="data"
  247. :pagination="false"
  248. :scroll="{ y: 160, x: 500 }"
  249. rowKey="id"
  250. :rowSelection="{
  251. selectedRowKeys: selectedRowKeys,
  252. onChange: onSelectChange,
  253. }"
  254. />
  255. <div
  256. style="
  257. color: rgba(255, 87, 51, 1);
  258. font-weight: 600;
  259. text-align: right;
  260. "
  261. >
  262. 合计消费:2922:00
  263. </div>
  264. <div
  265. style="
  266. display: flex;
  267. justify-content: space-between;
  268. margin-top: 30px;
  269. "
  270. >
  271. <h4
  272. style="
  273. color: rgba(255, 141, 26, 1);
  274. font-weight: 600;
  275. margin-top: 15px;
  276. "
  277. >
  278. 收款详情
  279. </h4>
  280. <div style="display: flex">
  281. <div style="display: flex; flex-direction: column">
  282. <a-icon
  283. type="transaction"
  284. style="color: rgba(255, 141, 26, 1); font-size: 18px"
  285. /><a-button type="link"> 收款 </a-button>
  286. </div>
  287. <div style="display: flex; flex-direction: column">
  288. <a-icon
  289. type="trademark"
  290. style="color: rgba(255, 141, 26, 1); font-size: 18px"
  291. /><a-button type="link"> 退款 </a-button>
  292. </div>
  293. <div style="display: flex; flex-direction: column">
  294. <a-icon
  295. type="pound"
  296. style="color: rgba(255, 141, 26, 1); font-size: 18px"
  297. /><a-button type="link"> 冲账 </a-button>
  298. </div>
  299. </div>
  300. </div>
  301. <a-divider />
  302. <a-table
  303. :columns="columns2"
  304. :data-source="data2"
  305. :pagination="false"
  306. :scroll="{ y: 160, x: 500 }"
  307. rowKey="id"
  308. :rowSelection="{
  309. selectedRowKeys: selectedRowKeys,
  310. onChange: onSelectChange,
  311. }"
  312. />
  313. <div
  314. style="
  315. color: rgba(255, 87, 51, 1);
  316. font-weight: 600;
  317. text-align: right;
  318. "
  319. >
  320. 合计收款:2922:00
  321. </div>
  322. </div>
  323. <div style="width: 20%">
  324. <h4 style="color: rgba(255, 141, 26, 1); font-weight: 600">财务汇总</h4>
  325. <a-divider />
  326. <a-descriptions :column="1">
  327. <a-descriptions-item label="合计收款"> + 2500 </a-descriptions-item>
  328. <a-descriptions-item label="合计消费">-2500 </a-descriptions-item>
  329. <a-descriptions-item label="结账应退"> 0 </a-descriptions-item>
  330. </a-descriptions>
  331. <a-button @click="handleAdd" type="danger" style="margin-left: 100px"
  332. >结账退款</a-button
  333. >
  334. </div>
  335. </div>
  336. <customer-modal ref="modalCustomerForm" @ok="modalFormOk"></customer-modal>
  337. </div>
  338. </template>
  339. <script>
  340. import { httpAction, getAction, deleteAction } from "@/api/manage";
  341. import { validateDuplicateValue } from "@/utils/util";
  342. import moment from "moment";
  343. import CustomerModal from "./CustomerModal.vue";
  344. const columns = [
  345. // {
  346. // title: "",
  347. // dataIndex: "key",
  348. // width: 20,
  349. // },
  350. {
  351. title: "房间号",
  352. dataIndex: "name",
  353. width: 80,
  354. },
  355. {
  356. title: "费项",
  357. dataIndex: "age",
  358. width: 80,
  359. },
  360. {
  361. title: "入账日期",
  362. dataIndex: "address",
  363. width: 100,
  364. },
  365. {
  366. title: "单价",
  367. dataIndex: "address2",
  368. width: 60,
  369. },
  370. {
  371. title: "优惠价",
  372. dataIndex: "address3",
  373. width: 80,
  374. },
  375. {
  376. title: "数量",
  377. dataIndex: "address4",
  378. width: 60,
  379. },
  380. {
  381. title: "小计",
  382. dataIndex: "address5",
  383. width: 60,
  384. },
  385. ];
  386. const columns2 = [
  387. {
  388. title: "入账时间",
  389. dataIndex: "name",
  390. width: 160,
  391. },
  392. {
  393. title: "支付方式",
  394. dataIndex: "age",
  395. width: 100,
  396. },
  397. {
  398. title: "备注",
  399. dataIndex: "remark",
  400. width: 120,
  401. },
  402. {
  403. title: "金额",
  404. dataIndex: "amount",
  405. width: 60,
  406. },
  407. ];
  408. const data = [];
  409. for (let i = 0; i < 100; i++) {
  410. data.push({
  411. key: i,
  412. name: `100${i}`,
  413. age: "房费",
  414. address: 280,
  415. });
  416. }
  417. const data2 = [];
  418. for (let i = 0; i < 8; i++) {
  419. data2.push({
  420. key: i,
  421. name: `2023-02-0${i} 10:52`,
  422. age: "支付宝",
  423. remark: "押金",
  424. amount: 888,
  425. });
  426. }
  427. const date = new Date();
  428. const endDate = new Date(date.setDate(date.getDate() + 1));
  429. export default {
  430. name: "BusMeetingRoomForm",
  431. components: { CustomerModal },
  432. props: {
  433. //表单禁用
  434. disabled: {
  435. type: Boolean,
  436. default: false,
  437. required: false,
  438. },
  439. },
  440. data() {
  441. return {
  442. selectedRowKeys: [],
  443. data,
  444. columns,
  445. data2,
  446. columns2,
  447. wakeList: [{}],
  448. model: {
  449. // data: data,
  450. orderInfo: {},
  451. roomIds: [],
  452. layoutDayPrices: [],
  453. livingRoomIds: [],
  454. },
  455. labelCol: {
  456. xs: { span: 24 },
  457. sm: { span: 5 },
  458. },
  459. wrapperCol: {
  460. xs: { span: 24 },
  461. sm: { span: 16 },
  462. },
  463. confirmLoading: false,
  464. validatorRules: {
  465. dateRange: [{ required: true, message: "请选择维修时间!" }],
  466. remark: [{ required: true, message: "请输入维修原因!" }],
  467. },
  468. url: {
  469. add: "/business/busMeetingRoom/add",
  470. edit: "/business/busMeetingRoom/edit",
  471. queryById: "/business/busMeetingRoom/queryById",
  472. getBookingOrderInfo:
  473. "/business/busRoomBookingOrders/getBookingOrderInfo",
  474. },
  475. id: "",
  476. customerSourceList: [],
  477. warranterList: [],
  478. key: 0,
  479. };
  480. },
  481. computed: {
  482. formDisabled() {
  483. return this.disabled;
  484. },
  485. },
  486. created() {
  487. var _info = JSON.parse(localStorage.getItem("storeInfo"));
  488. if (_info) {
  489. this.model.hotelId = _info.id;
  490. }
  491. //备份model原始值
  492. this.modelDefault = JSON.parse(JSON.stringify(this.model));
  493. getAction("/business/busDictItem/list", {
  494. hotelId: _info.id,
  495. dictId: "1639538915239743490",
  496. }).then((res) => {
  497. if (res.success) {
  498. this.customerSourceList = res.result.records;
  499. }
  500. });
  501. getAction("/business/busSalesPerson/list", {
  502. hotelId: _info.id,
  503. pageNo: 1,
  504. pageSize: 100,
  505. }).then((res) => {
  506. if (res.success) {
  507. this.warranterList = res.result.records;
  508. }
  509. });
  510. },
  511. methods: {
  512. removeLivingCustomer(id) {
  513. deleteAction("/business/busLivingCustomer/delete", { id: id }).then(
  514. (res) => {
  515. if (res.success) {
  516. this.getBookingOrderInfo();
  517. }
  518. }
  519. );
  520. },
  521. addlivingCustomer(id, roomId) {
  522. console.log(id);
  523. this.$refs.modalCustomerForm.add(id, roomId);
  524. this.$refs.modalCustomerForm.title = "添加同住人";
  525. this.$refs.modalCustomerForm.disableSubmit = false;
  526. },
  527. modalFormOk(e) {
  528. this.getBookingOrderInfo();
  529. },
  530. customerTypeName(customerType) {
  531. switch (customerType) {
  532. case 1:
  533. return "散客";
  534. case 2:
  535. return "会员";
  536. case 3:
  537. return "协议单位";
  538. case 4:
  539. return "中介";
  540. default:
  541. return "散客";
  542. }
  543. },
  544. warranterName(warranter) {
  545. var find = this.warranterList.find((t) => t.id == warranter);
  546. return find ? find.name : "--";
  547. },
  548. customerSourceName(customerSource) {
  549. var find = this.customerSourceList.find((t) => t.id == customerSource);
  550. return find ? find.itemText : "--";
  551. },
  552. getBookingOrderInfo() {
  553. var obj = {
  554. bookingNo: this.id,
  555. };
  556. if (this.key && this.key == 1) {
  557. obj = {
  558. bookingOrderId: this.id,
  559. };
  560. }
  561. getAction(this.url.getBookingOrderInfo, obj).then((res) => {
  562. if (res.success) {
  563. var livingRoomId = JSON.parse(
  564. JSON.stringify(res.result.livingRoomIds[0])
  565. );
  566. livingRoomId.id = "1";
  567. livingRoomId.roomName = "全部";
  568. var list = [];
  569. res.result.livingRoomIds.forEach((t) => {
  570. list = [...list, ...t.livingCustomers];
  571. });
  572. livingRoomId.livingCustomers = list;
  573. res.result.livingRoomIds.unshift(livingRoomId);
  574. this.model = res.result;
  575. }
  576. });
  577. },
  578. onSelectChange(selectedRowKeys, selectionRows) {
  579. this.selectedRowKeys = selectedRowKeys;
  580. this.selectionRows = selectionRows;
  581. },
  582. handleAdd() {},
  583. puls() {
  584. this.wakeList.push({});
  585. },
  586. remove(index) {
  587. this.wakeList.splice(index, 1);
  588. },
  589. moment,
  590. onChange(e) {
  591. console.log(e);
  592. },
  593. add(id, key) {
  594. this.key = key;
  595. this.id = id;
  596. this.edit(this.modelDefault);
  597. this.getBookingOrderInfo();
  598. },
  599. edit(record) {
  600. this.model = Object.assign({}, record);
  601. this.visible = true;
  602. },
  603. submitForm() {
  604. const that = this;
  605. that.$message.warning("未实现");
  606. return;
  607. // 触发表单验证
  608. this.$refs.form.validate((valid) => {
  609. if (valid) {
  610. that.confirmLoading = true;
  611. let httpurl = "";
  612. let method = "";
  613. if (!this.model.id) {
  614. httpurl += this.url.add;
  615. method = "post";
  616. } else {
  617. httpurl += this.url.edit;
  618. method = "put";
  619. }
  620. httpAction(httpurl, this.model, method)
  621. .then((res) => {
  622. if (res.success) {
  623. that.$message.success(res.message);
  624. that.$emit("ok");
  625. } else {
  626. that.$message.warning(res.message);
  627. }
  628. })
  629. .finally(() => {
  630. that.confirmLoading = false;
  631. });
  632. }
  633. });
  634. },
  635. },
  636. };
  637. </script>
  638. <style scoped>
  639. /deep/ .ant-btn-link {
  640. flex: 1;
  641. color: rgba(255, 141, 26, 1) !important;
  642. }
  643. .menu {
  644. display: flex;
  645. flex-direction: column;
  646. flex: 1;
  647. color: #fff;
  648. margin-top: 12px;
  649. }
  650. .dynamic-delete-button {
  651. cursor: pointer;
  652. position: relative;
  653. /* top: 4px; */
  654. margin-left: 5px;
  655. font-size: 18px;
  656. color: #1890ff;
  657. transition: all 0.3s;
  658. }
  659. .dynamic-delete-button:hover {
  660. color: #777;
  661. }
  662. .dynamic-delete-button[disabled] {
  663. cursor: not-allowed;
  664. opacity: 0.5;
  665. }
  666. /deep/.ant-table-thead > tr > th {
  667. background: rgba(42, 130, 228, 1);
  668. color: #ffffff;
  669. }
  670. /deep/.ant-divider-horizontal {
  671. margin: 12px 0 !important;
  672. }
  673. /deep/ .ant-table-tbody .ant-table-row td {
  674. padding-top: 5px;
  675. padding-bottom: 5px;
  676. }
  677. /deep/.ant-table-thead > tr > th,
  678. .ant-table-tbody > tr > td {
  679. padding: 5px 5px !important;
  680. overflow-wrap: break-word;
  681. }
  682. #livingCustomers-grid [class~="ant-col"] {
  683. border: #ccc 1px solid;
  684. }
  685. #livingCustomers-grid [class~="ant-col"]:last-child {
  686. border: 0;
  687. }
  688. </style>