RoomZdfPriceTable.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. <template>
  2. <div>
  3. <a-table :columns="columns" :data-source="data" :pagination="false" :loading="loading">
  4. <span slot="prepay" slot-scope="text, record, index">
  5. <a-switch checked-children="是" un-checked-children="否" :checked="record.prepay"
  6. @change="changePrepay(record)" />
  7. </span>
  8. <span slot="isVip" slot-scope="text, record, index">
  9. <a-switch checked-children="是" un-checked-children="否" :checked="record.isVip" />
  10. </span>
  11. <span slot="startDate" slot-scope="text, record, index">
  12. {{ record.startDate }} ~ {{ record.endDate }}
  13. </span>
  14. <span slot="sellerId" slot-scope="text, record, index">
  15. {{ record.sellerId ? getSellerName(record.sellerId) : '' }}
  16. </span>
  17. <span slot="action" slot-scope="text, record">
  18. <a @click="handleEdit(record)">编辑</a>
  19. <a-divider type="vertical" />
  20. <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
  21. <a>删除</a>
  22. </a-popconfirm>
  23. </span>
  24. </a-table>
  25. <a-form-model layout="inline" ref="form" :model="model" :rules="validatorRules" slot="detail">
  26. <a-form-model-item label="价格名称" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="name">
  27. <a-input v-model="model.name" placeholder="请输入房价名称"></a-input>
  28. </a-form-model-item>
  29. <a-form-model-item label="原价" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="oprice">
  30. <a-input-number style="width:100%;" v-model="model.oprice" :min="1" placeholder="请填写原价"
  31. @change="formVipOpriceChange" />
  32. </a-form-model-item>
  33. <a-form-model-item label="现价" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="price">
  34. <a-input-number style="width:100%;" v-model="model.price" :min="1" placeholder="请填写现价" />
  35. </a-form-model-item>
  36. <a-form-model-item label="预付" prop="prepay">
  37. <a-radio-group v-model="model.prepay">
  38. <a-radio-button :value="1">
  39. </a-radio-button>
  40. <a-radio-button :value="0">
  41. </a-radio-button>
  42. </a-radio-group>
  43. </a-form-model-item>
  44. <a-form-model-item label="积分" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="integral">
  45. <a-input-number style="width:100%;" v-model="model.integral" placeholder="请填写积分" />
  46. </a-form-model-item>
  47. <a-form-model-item label="数量" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="num">
  48. <a-input-number style="width:100%;" v-model="model.num" placeholder="请填写数量" />
  49. </a-form-model-item>
  50. <a-form-model-item label="会员折扣" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="isVip">
  51. <a-radio-group v-model="model.isVip" @change="onVipChange">
  52. <a-radio-button :value="1">
  53. </a-radio-button>
  54. <a-radio-button :value="0">
  55. </a-radio-button>
  56. </a-radio-group>
  57. </a-form-model-item>
  58. <a-form-model-item label="适用时间" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="startDate">
  59. <a-time-picker :open.sync="open2" v-model="model.startDate" format="HH:mm" @change="onStartTimeChange">
  60. <a-button slot="addon" size="small" type="primary" @click="open2 = false">
  61. 确定
  62. </a-button>
  63. </a-time-picker>
  64. </a-form-model-item>
  65. <a-form-model-item label="" :labelCol="labelCol1" :wrapperCol="wrapperCol" prop="endDate">
  66. <a-time-picker :open.sync="open" v-model="model.endDate" format="HH:mm">
  67. <a-button slot="addon" size="small" type="primary" @click="open = false">
  68. 确定
  69. </a-button>
  70. </a-time-picker>
  71. </a-form-model-item>
  72. <a-form-model-item label="钟点房方案" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="sellerId">
  73. <a-select style="width: 120px" v-model="model.sellerId" placeholder="请选择">
  74. <a-select-option :value="item.id" v-for="item in hourRules" :key="item.id">
  75. {{ item.hourRoomName }}
  76. </a-select-option>
  77. </a-select>
  78. </a-form-model-item>
  79. <a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol">
  80. <a-button :disabled="submitLoading" :loading="submitLoading" @click="submitForm"
  81. type="primary">保存</a-button>
  82. </a-form-model-item>
  83. <a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol">
  84. <a-button :disabled="submitLoading" :loading="submitLoading" @click="clearForm" type="primary">清空</a-button>
  85. </a-form-model-item>
  86. </a-form-model>
  87. <div class="vip-config" v-if="model.isVip">
  88. <div class="config-heads h-title">
  89. <div class="head-item">会员等级</div>
  90. <div class="head-item">原价</div>
  91. <div class="head-item">折扣(%)</div>
  92. <div class="head-item">现价</div>
  93. </div>
  94. <div class="config-heads" v-for="item in vipLevels" :key="item.id">
  95. <div class="head-item">[{{ item.name }}]</div>
  96. <div class="head-item">
  97. <a-input-number style="width:80%;" v-model="model.oprice" :min="0" placeholder="请填写原价"
  98. @change="vipOpriceChange($event, item)" />
  99. </div>
  100. <div class="head-item">
  101. <a-input-number style="width:80%;" v-model="item.discount" :min="0" placeholder="请填写折扣"
  102. @change="vipDiscountChange($event, item)" />
  103. </div>
  104. <div class="head-item">
  105. <a-input-number style="width:80%;" :value="item.price" :min="0" placeholder="请填写现价"
  106. @change="vipPriceChange($event, item)" />
  107. </div>
  108. </div>
  109. </div>
  110. </div>
  111. </template>
  112. <script>
  113. Date.prototype.Format = function (fmt) {
  114. var o = {
  115. "M+": this.getMonth() + 1, //月份
  116. "d+": this.getDate(), //日
  117. "H+": this.getHours(), //小时
  118. "m+": this.getMinutes(), //分
  119. "s+": this.getSeconds(), //秒
  120. "q+": Math.floor((this.getMonth() + 3) / 3), //季度
  121. "S": this.getMilliseconds() //毫秒
  122. };
  123. if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
  124. for (var k in o)
  125. if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
  126. return fmt;
  127. }
  128. import { list, modify, create, getLayoutpriceLevels, getHourRoomRule } from '@/api/roomLayoutPrice'
  129. import { httpAction, getAction } from "@/api/manage";
  130. import * as api from '@/api/api'
  131. import { find } from 'lodash';
  132. import moment from 'moment';
  133. const columns = [
  134. {
  135. title: '房价名称',
  136. dataIndex: 'name',
  137. key: 'name',
  138. },
  139. {
  140. title: '原价',
  141. dataIndex: 'oprice',
  142. key: 'oprice',
  143. },
  144. {
  145. title: '现价',
  146. dataIndex: 'price',
  147. key: 'price',
  148. },
  149. {
  150. title: '适用时段',
  151. key: 'startDate',
  152. dataIndex: 'startDate',
  153. scopedSlots: { customRender: 'startDate' },
  154. },
  155. {
  156. title: '预付',
  157. key: 'prepay',
  158. dataIndex: 'prepay',
  159. scopedSlots: { customRender: 'prepay' },
  160. },
  161. {
  162. title: '积分',
  163. dataIndex: 'integral',
  164. key: 'integral',
  165. },
  166. {
  167. title: '数量',
  168. dataIndex: 'num',
  169. key: 'num',
  170. },
  171. {
  172. title: '使用会员折扣',
  173. dataIndex: 'isVip',
  174. key: 'isVip',
  175. scopedSlots: { customRender: 'isVip' },
  176. },
  177. {
  178. title: '钟点房方案',
  179. key: 'sellerId',
  180. dataIndex: 'sellerId',
  181. scopedSlots: { customRender: 'sellerId' },
  182. },
  183. {
  184. title: '操作',
  185. key: 'action',
  186. scopedSlots: { customRender: 'action' },
  187. },
  188. ];
  189. let hotelItem = JSON.parse(window.localStorage.getItem('storeInfo'))
  190. export default {
  191. props: {
  192. layoutId: null
  193. },
  194. data() {
  195. return {
  196. open: false,
  197. open2: false,
  198. submitLoading: false,
  199. labelCol1: {
  200. xs: { span: 0 },
  201. sm: { span: 0 },
  202. },
  203. labelCol: {
  204. xs: { span: 24 },
  205. sm: { span: 10 },
  206. },
  207. wrapperCol: {
  208. xs: { span: 24 },
  209. sm: { span: 14 },
  210. },
  211. loading: false,
  212. data: [],
  213. columns,
  214. searchType: 2,
  215. validatorRules: {
  216. name: [{ required: true, message: "请输入房价名称!" }],
  217. oprice: [{ required: true, message: "请填写原价价!" }],
  218. price: [{ required: true, message: "请填写现价!" }],
  219. startDate: [{ required: true, message: "请选择适用开始时间" }],
  220. endDate: [{ required: true, message: "请选择适用结束时间" }],
  221. integral: [{ required: true, message: "请填写积分!" }],
  222. lunchNum: [{ required: true, message: "请填写中餐数量!" }],
  223. dinnerNum: [{ required: true, message: "请填写晚餐数量!" }],
  224. },
  225. model: {
  226. id: '',
  227. name: '',
  228. oprice: null,
  229. price: null,
  230. prepay: 0,
  231. integral: 0,
  232. num: 0,
  233. startDate: null,
  234. endDate: null,
  235. isVip: 0,
  236. sellerId: null,
  237. },
  238. vipLevels: [],
  239. origiVipLevels: [],
  240. hourRules: []
  241. };
  242. },
  243. mounted() {
  244. this.getData()
  245. this.getVipLevels()
  246. this.getHourRoomRule()
  247. },
  248. methods: {
  249. onStartTimeChange(e, timeStr) {
  250. console.log(e, timeStr, this.model.startDate)
  251. },
  252. onEndTimeChange(e, timeStr) {
  253. this.model.endDate = timeStr
  254. },
  255. getSellerName(id) {
  256. let index = this.hourRules.findIndex(s => s.id == id)
  257. if (index > -1) {
  258. return this.hourRules[index].hourRoomName
  259. }
  260. return id
  261. },
  262. clearForm() {
  263. this.model = {
  264. id: '',
  265. name: '',
  266. oprice: null,
  267. price: null,
  268. prepay: 0,
  269. integral: 0,
  270. startDate: null,
  271. endDate: null,
  272. sellerId: null,
  273. num: 0,
  274. isVip: 0
  275. }
  276. this.vipLevels = JSON.parse(JSON.stringify(this.origiVipLevels))
  277. },
  278. vipPriceChange(e, item) {
  279. if (this.model.oprice) {
  280. item.discount = ((e / this.model.oprice) * 100).toFixed(2)
  281. }
  282. item.price = e
  283. },
  284. vipDiscountChange(e, item) {
  285. if (this.model.oprice) {
  286. item.price = (this.model.oprice * (e / 100)).toFixed(2)
  287. }
  288. item.discount = e
  289. },
  290. vipOpriceChange(e, item) {
  291. if (item.discount) {
  292. item.price = (this.model.oprice * (item.discount / 100)).toFixed(2)
  293. }
  294. this.model.oprice = e
  295. },
  296. formVipOpriceChange(e) {
  297. (this.vipLevels || []).forEach(item => {
  298. if (item.discount) {
  299. item.price = (this.model.oprice * (item.discount / 100)).toFixed(2)
  300. }
  301. })
  302. this.model.oprice = e
  303. },
  304. getHourRoomRule() {
  305. getHourRoomRule({
  306. pageNo: 1,
  307. pageSize: 999
  308. }).then(res => {
  309. if (res.code == 200) {
  310. this.hourRules = res.result.records
  311. } else {
  312. this.$message.warning('⚠️没有找到钟点房方案')
  313. }
  314. })
  315. },
  316. getVipLevels() {
  317. api.getVipLevels({
  318. pageNo: 1,
  319. pageSize: 999,
  320. hotelId: hotelItem.id
  321. }).then(res => {
  322. if (res.result && res.result.records) {
  323. res.result.records.forEach(s => {
  324. s['price'] = 0
  325. // 保存原有折扣率
  326. s['ldiscount'] = s.discount
  327. if (!s.discount) {
  328. s.discount = 100
  329. }
  330. })
  331. this.origiVipLevels = res.result.records
  332. this.vipLevels = JSON.parse(JSON.stringify(res.result.records))
  333. }
  334. })
  335. },
  336. changePrepay(record) {
  337. },
  338. onVipChange(e) {
  339. if (this.model.isVip) {
  340. }
  341. },
  342. handleEdit(record) {
  343. this.getRelationLevels(record.id, (rLevels) => {
  344. let cpData = JSON.parse(JSON.stringify(record))
  345. cpData.isVip = record.isVip ? 1 : 0
  346. cpData.prepay = record.prepay ? 1 : 0
  347. this.model = cpData
  348. this.model.startDate = moment(this.model.startDate, "HH:mm")
  349. this.model.endDate = moment(this.model.endDate, "HH:mm")
  350. let nowLvs = JSON.parse(JSON.stringify(this.origiVipLevels))
  351. if (this.model.oprice) {
  352. nowLvs.forEach(s => {
  353. if (rLevels) {
  354. let findIndex = rLevels.findIndex(q => q.levelId == s.id)
  355. if (findIndex > -1) {
  356. s.discount = rLevels[findIndex].discount
  357. s['memberPriceId'] = rLevels[findIndex].id
  358. } else {
  359. s['memberPriceId'] = ''
  360. }
  361. }
  362. s.price = (this.model.oprice * (s.discount / 100)).toFixed(2)
  363. })
  364. }
  365. this.vipLevels = nowLvs
  366. })
  367. },
  368. getRelationLevels(pid, callback) {
  369. getLayoutpriceLevels({
  370. parentId: pid
  371. }).then(res => {
  372. // 关联折扣等级
  373. let rLevels = []
  374. if (res.code == 200 && res.result.length > 0) {
  375. rLevels = res.result
  376. }
  377. callback(rLevels)
  378. })
  379. },
  380. getData() {
  381. this.loading = true
  382. list({
  383. type: this.searchType,
  384. // hotelId: hotelItem.id,
  385. roomLayoutId: this.layoutId,
  386. pageNo: 1,
  387. pageSize: 999
  388. }).then(res => {
  389. this.loading = false
  390. console.log(res)
  391. this.data = res.result.records
  392. }).catch(res => {
  393. this.loading = false
  394. })
  395. },
  396. handleDelete(id) {
  397. },
  398. submitForm() {
  399. const that = this;
  400. // 触发表单验证
  401. this.$refs.form.validate((valid) => {
  402. if (valid) {
  403. that.confirmLoading = true;
  404. if (this.model.id && this.model.id != '') {
  405. this.doModify()
  406. } else {
  407. this.doCreate()
  408. }
  409. }
  410. });
  411. },
  412. doModify() {
  413. let model = JSON.parse(JSON.stringify(this.model))
  414. model['hotelId'] = hotelItem.id
  415. model['layoutId'] = this.layoutId
  416. model['type'] = 2
  417. model.startDate = this.model.startDate
  418. model.endDate = this.model.endDate
  419. model.startDate = model.startDate.utcOffset(8).format("HH:mm")
  420. model.endDate = model.endDate.utcOffset(8).format("HH:mm")
  421. let memberPriceEntities = [];
  422. if (model.isVip) {
  423. (this.vipLevels || []).forEach(s => {
  424. let item = {
  425. id: s.memberPriceId,
  426. levelId: s.id,
  427. discount: parseFloat(s.discount || 100),
  428. ldiscount: parseFloat(s.ldiscount || 100),
  429. }
  430. memberPriceEntities.push(item)
  431. })
  432. }
  433. model['memberPriceEntities'] = memberPriceEntities
  434. this.submitLoading = true
  435. modify(model).then(s => {
  436. if (s.code == 200) {
  437. this.$message.success("保存成功")
  438. this.clearForm()
  439. this.getData()
  440. }
  441. }).catch(err => {
  442. this.$message.error("保存失败")
  443. }).finally(_ => {
  444. this.submitLoading = false
  445. })
  446. },
  447. doCreate() {
  448. let model = JSON.parse(JSON.stringify(this.model))
  449. model['hotelId'] = hotelItem.id
  450. model['layoutId'] = this.layoutId
  451. model['type'] = 2
  452. // 经过序列化的moment要重新赋值成moment对象
  453. model.startDate = this.model.startDate
  454. model.endDate = this.model.endDate
  455. model.startDate = model.startDate.utcOffset(8).format("HH:mm")
  456. model.endDate = model.endDate.utcOffset(8).format("HH:mm")
  457. let memberPriceEntities = [];
  458. if (model.isVip) {
  459. (this.vipLevels || []).forEach(s => {
  460. let item = {
  461. levelId: s.id,
  462. hotelId: hotelItem.id,
  463. discount: parseFloat(s.discount || 100),
  464. ldiscount: parseFloat(s.ldiscount || 100),
  465. }
  466. memberPriceEntities.push(item)
  467. })
  468. }
  469. model['memberPriceEntities'] = memberPriceEntities
  470. this.submitLoading = true
  471. create(model).then(s => {
  472. if (s.code == 200) {
  473. this.$message.success("保存成功")
  474. this.clearForm()
  475. this.getData()
  476. }
  477. }).catch(err => {
  478. this.$message.error("保存失败")
  479. }).finally(_ => {
  480. this.submitLoading = false
  481. })
  482. }
  483. },
  484. };
  485. </script>
  486. <style lang="css" scoped>
  487. .vip-config {
  488. width: 50%;
  489. height: 200px;
  490. overflow-y: auto;
  491. margin-top: 20px;
  492. }
  493. .config-heads {
  494. display: flex;
  495. }
  496. .config-heads .head-item {
  497. flex: 1;
  498. text-align: left;
  499. }
  500. .h-title {
  501. font-weight: 600;
  502. }
  503. /deep/ .ant-select-selection__placeholder,
  504. .ant-select-search__field__placeholder {
  505. display: inline-block !important;
  506. }
  507. </style>