batchConfig.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. <template>
  2. <div class="form-wrap">
  3. <el-form
  4. class="search-box"
  5. ref="form"
  6. :model="form"
  7. :inline="true"
  8. >
  9. <div class="block-title">
  10. 查询条件
  11. </div>
  12. <el-form-item
  13. label="名称"
  14. prop="name"
  15. >
  16. <el-input v-model="form.name"></el-input>
  17. </el-form-item>
  18. <div class="btn-wrap">
  19. <el-button
  20. @click="reset"
  21. >
  22. 重置
  23. </el-button>
  24. <el-button
  25. type="primary"
  26. @click="getBatchConfigList"
  27. >
  28. 搜索
  29. </el-button>
  30. <el-button
  31. type="primary"
  32. @click="showDialog('add')"
  33. >
  34. 新增场次
  35. </el-button>
  36. </div>
  37. </el-form>
  38. <div class="table-box">
  39. <!-- <div class="block-title">
  40. 现有场次
  41. </div> -->
  42. <el-tag type="warning">场次时间默认不限制为-1</el-tag>
  43. <el-table
  44. border
  45. stripe
  46. v-loading="loading"
  47. :data="tableData"
  48. >
  49. <el-table-column type="expand">
  50. <template slot-scope="props">
  51. <div class="title" style="font-weight: bold;">绑定票种</div>
  52. <el-table :data="props.row.ticketTypes" :max-height="200">
  53. <el-table-column
  54. prop="id"
  55. label="票种ID"
  56. width="80"
  57. >
  58. </el-table-column>
  59. <el-table-column
  60. prop="name"
  61. label="票种名称"
  62. >
  63. </el-table-column>
  64. <el-table-column
  65. label="票种分类"
  66. >
  67. <template slot-scope="scope">
  68. {{ getTicketCate(scope.row.category) }}
  69. </template>
  70. </el-table-column>
  71. <el-table-column
  72. prop="price"
  73. label="窗口价格"
  74. >
  75. </el-table-column>
  76. <el-table-column
  77. label="在售状态"
  78. >
  79. <template slot-scope="scope">
  80. <el-tag
  81. :type="scope.row.isSale ? 'success' : 'danger'">
  82. {{ scope.row.isSale ? '在售' : '停售' }}
  83. </el-tag>
  84. </template>
  85. </el-table-column>
  86. <el-table-column
  87. prop="useDate"
  88. label="使用日期"
  89. >
  90. <template slot-scope="scope">
  91. {{ scope.row.useDateStart }} - {{ scope.row.useDateEnd }}
  92. </template>
  93. </el-table-column>
  94. <el-table-column
  95. prop="checkType"
  96. label="核销凭证"
  97. >
  98. <template slot-scope="scope">
  99. {{ scope.row.checkType | checkTypeFilter }}
  100. </template>
  101. </el-table-column>
  102. <el-table-column
  103. prop="checkRule"
  104. label="核销规则"
  105. >
  106. <template slot-scope="scope">
  107. {{ scope.row.checkRule | checkRuleFilter }}
  108. </template>
  109. </el-table-column>
  110. <el-table-column
  111. prop="checkScenic"
  112. label="核销景点"
  113. >
  114. <template slot-scope="scope">
  115. {{ getScenicName(scope.row.ticketTypeScenicList) }}
  116. </template>
  117. </el-table-column>
  118. </el-table>
  119. </template>
  120. </el-table-column>
  121. <el-table-column
  122. label="场次名称"
  123. prop="name">
  124. </el-table-column>
  125. <el-table-column
  126. label="开始时间"
  127. width="90"
  128. prop="startTime">
  129. </el-table-column>
  130. <el-table-column
  131. label="结束时间"
  132. width="90"
  133. prop="endTime">
  134. </el-table-column>
  135. <el-table-column
  136. label="场次策略"
  137. width="90"
  138. prop="strategy">
  139. <template slot-scope="scope">
  140. {{ scope.row.strategy | strategyFilter }}
  141. </template>
  142. </el-table-column>
  143. <el-table-column
  144. label="策略详情"
  145. prop="strategy">
  146. <template slot-scope="scope">
  147. <span v-if="scope.row.strategy === 'basic'"></span>
  148. <span v-else-if="scope.row.strategy === 'week'">
  149. {{ getWeekName(scope.row.strategyContent) }}
  150. </span>
  151. <span v-else>
  152. {{ getPeriodName(scope.row.strategyContent) }}
  153. </span>
  154. </template>
  155. </el-table-column>
  156. <el-table-column
  157. label="开场后X分钟停止售票"
  158. prop="saleStopMinutes">
  159. </el-table-column>
  160. <el-table-column
  161. label="开场前X分钟停止退票"
  162. prop="cancelStopBeforeStartMinutes"
  163. min-width="90">
  164. </el-table-column>
  165. <el-table-column
  166. label="开场后X分钟停止退票"
  167. prop="cancelStopAfterStartMinutes"
  168. min-width="90">
  169. </el-table-column>
  170. <el-table-column
  171. label="开场前X分钟允许检票入场"
  172. prop="preCheckMinutes"
  173. min-width="90">
  174. </el-table-column>
  175. <el-table-column
  176. label="开场后X分钟停止检票"
  177. prop="stopCheckMinutes"
  178. min-width="90">
  179. </el-table-column>
  180. <el-table-column
  181. label="无座位时的最大数量"
  182. prop="maxSaleNums"
  183. min-width="90">
  184. </el-table-column>
  185. <el-table-column
  186. width="110"
  187. class-name="align-item"
  188. label="操作">
  189. <template slot-scope="scope">
  190. <el-link
  191. type="primary"
  192. size="small"
  193. @click="editBatchConfig(scope.row)">
  194. 编辑
  195. </el-link>
  196. <el-link
  197. type="primary"
  198. size="small"
  199. @click="deleteBatchConfig(scope.row.id)">
  200. 删除
  201. </el-link>
  202. </template>
  203. </el-table-column>
  204. </el-table>
  205. <el-pagination
  206. background
  207. :current-page.sync="form.pageNum"
  208. :page-sizes="[10, 20, 50, 100]"
  209. :page-size="form.pageSize"
  210. @size-change="handleSizeChange"
  211. layout="total, sizes, prev, pager, next, jumper"
  212. @current-change="getBatchConfigList()"
  213. :total="total">
  214. </el-pagination>
  215. </div>
  216. <!-- 场次弹框 -->
  217. <BatchDialog
  218. ref="batchDialogRef"
  219. :dialog-type="dialogType"
  220. :batch-item="curItem"
  221. :scenic-list="scenicList"
  222. :batch-tag-list="batchTagList"
  223. :member-type-list="memberTypeList"
  224. :invoice-seller="InvoiceSeller"
  225. @update-list="initData"
  226. ></BatchDialog>
  227. <PriceCalendar ref="priceCalendarRef"></PriceCalendar>
  228. </div>
  229. </template>
  230. <script>
  231. import moment from 'moment'
  232. import { getBatchConfigList, updateBatchConfig, deleteBatchConfig } from '@/api/batch'
  233. import { getMemberType } from '@/api/member'
  234. import { strategyMap } from '@/assets/staticData'
  235. import BatchDialog from './batchConfig/Dialog'
  236. import PriceCalendar from './batchConfig/PriceCalendar'
  237. import { TicketCategory } from './ticket/constant'
  238. import { cloneDeep } from '@/utils'
  239. const getCheckTypeName = (type) => {
  240. switch (type) {
  241. case 'qrcode':
  242. return '二维码'
  243. case 'face':
  244. return '人脸'
  245. case 'card':
  246. return 'IC卡'
  247. case 'idcard':
  248. return '身份证'
  249. case 'manual_check':
  250. return '人工检票'
  251. case 'print_check':
  252. return '取票即检票'
  253. case 'buy_check':
  254. return '购买即检票'
  255. case 'system_check':
  256. return '系统自动检票'
  257. default:
  258. break
  259. }
  260. }
  261. const getCheckRuleName = (rule) => {
  262. switch (rule) {
  263. case '1':
  264. return '人工,检票设备核销'
  265. case '2':
  266. return '取票即核销'
  267. case '3':
  268. return '购买即核销(线下)'
  269. case '4':
  270. return '购买即核销(全局)'
  271. default:
  272. break
  273. }
  274. }
  275. export default {
  276. computed: {
  277. },
  278. data () {
  279. return {
  280. form: {
  281. name: '',
  282. pageNum: 1,
  283. pageSize: 10
  284. },
  285. loading: false,
  286. total: 0,
  287. tableData: [],
  288. memberTypeList: [],
  289. dialogVisible: false,
  290. // 弹框类型 'add' 或 'edit'
  291. dialogType: '',
  292. curItem: {},
  293. scenicList: [],
  294. batchTagList: [],
  295. batchPricePlanList: [],
  296. InvoiceSeller: []
  297. }
  298. },
  299. filters: {
  300. runStopColor (input) {
  301. return input ? 'success' : 'danger'
  302. },
  303. checkTypeFilter (input) {
  304. if (!input) return ''
  305. const types = input.split(',')
  306. let result = ''
  307. types.forEach(type => {
  308. result += getCheckTypeName(type) + '、'
  309. })
  310. return result.slice(0, -1) // 去掉最后一个逗号
  311. },
  312. checkRuleFilter (input) {
  313. if (!input) return ''
  314. const rules = input.split(',')
  315. let result = ''
  316. rules.forEach(rule => {
  317. result += getCheckRuleName(rule) + '、'
  318. })
  319. return result.slice(0, -1) // 去掉最后一个逗号
  320. },
  321. strategyFilter (input) {
  322. const item = strategyMap.find(s => s.value === input)
  323. return item ? item.label : ''
  324. }
  325. },
  326. created () {
  327. // this.getScenicList()
  328. this.getBatchConfigList()
  329. // this.getMemberList()
  330. // this.getTicketTagList()
  331. // this.getTicketPricePlanList()
  332. // this.getInvoiceSeller()
  333. },
  334. components: {
  335. BatchDialog,
  336. PriceCalendar
  337. },
  338. methods: {
  339. initData () {
  340. this.form.pageNum = 1
  341. this.getBatchConfigList()
  342. },
  343. getTicketCate (cate) {
  344. return TicketCategory[cate]
  345. },
  346. getScenicName (scenicList) {
  347. if (!scenicList || scenicList.length === 0) return ''
  348. return scenicList.map(s => s.scenicName).join('、')
  349. },
  350. getWeekName (sc) {
  351. try {
  352. const wks = JSON.parse(sc)
  353. const weekMap = {
  354. 1: '周日',
  355. 2: '周一',
  356. 3: '周二',
  357. 4: '周三',
  358. 5: '周四',
  359. 6: '周五',
  360. 7: '周六'
  361. }
  362. return wks.map(w => weekMap[w]).join('、')
  363. } catch (error) {
  364. return ''
  365. }
  366. },
  367. getPeriodName (period) {
  368. try {
  369. const periods = JSON.parse(period)
  370. return periods.map(p => p.start + '-' + p.end).join(' ')
  371. } catch (error) {
  372. return ''
  373. }
  374. },
  375. showDialog (type, item) {
  376. if (type === 'priceCalendar') {
  377. this.$refs.priceCalendarRef.show(item)
  378. return
  379. }
  380. this.dialogType = type
  381. this.curItem = item
  382. this.$refs.batchDialogRef.show(item, type)
  383. this.dialogVisible = true
  384. },
  385. // '创建场次失败,名称或助记符重复' 复制时去掉名称和助记符,待复制时用户填入
  386. itemWithoutCategoryAndShorthand (item) {
  387. const copyItem = cloneDeep(item)
  388. copyItem.name = '' // 名称
  389. copyItem.id = ''
  390. return copyItem
  391. },
  392. getMemberList () {
  393. getMemberType({
  394. pageNum: 0,
  395. pageSize: -1
  396. }).then(res => {
  397. this.memberTypeList = res.list
  398. })
  399. },
  400. handleSizeChange (size) {
  401. this.form.pageSize = size
  402. this.getBatchConfigList()
  403. },
  404. // 获取场次列表
  405. getBatchConfigList () {
  406. this.loading = true
  407. getBatchConfigList(this.form).then(res => {
  408. this.tableData = res.data.records
  409. this.total = res.data.total || 0
  410. }).finally(() => {
  411. this.loading = false
  412. })
  413. // 更新全局场次列表
  414. // this.$store.dispatch('getBatchConfigList')
  415. },
  416. editBatchConfig (item) {
  417. this.showDialog('edit', item)
  418. },
  419. // 删除场次
  420. deleteBatchConfig (id) {
  421. this.$confirm('确定删除?', '提示', {
  422. confirmButtonText: '确定',
  423. cancelButtonText: '取消',
  424. type: 'warning'
  425. }).then(() => {
  426. deleteBatchConfig({ idList: [id] }).then(res => {
  427. this.$message.success('删除成功')
  428. this.getBatchConfigList()
  429. })
  430. })
  431. },
  432. reset () {
  433. this.$refs.form.resetFields()
  434. },
  435. offSale (data) {
  436. let form = Object.assign({}, data)
  437. form.isSale = 0
  438. updateBatchConfig(form).then(res => {
  439. if (res.code !== '200') {
  440. this.$message.success(res.msg || '操作失败')
  441. return
  442. }
  443. this.$message.success('操作成功')
  444. this.getBatchConfigList()
  445. })
  446. },
  447. onSale (data) {
  448. let saleEnd = moment(data.saleDateEnd).hours(23).minutes(59).seconds(59)
  449. if (moment().isAfter(saleEnd)) {
  450. this.$alert('请修改场次可售日期', '场次已过期', {
  451. confirmButtonText: '知道了'
  452. })
  453. } else {
  454. let form = Object.assign({}, data)
  455. form.isSale = 1
  456. form.batchTypeSourceList = form.source || []
  457. updateBatchConfig(form).then(res => {
  458. if (res.code === '200') {
  459. this.$message.success('操作成功')
  460. this.getBatchConfigList()
  461. }
  462. })
  463. }
  464. },
  465. handleClose () {
  466. this.dialogVisible = false
  467. },
  468. handelStatusChange (value, batch) {
  469. const currentBatch = cloneDeep(batch)
  470. currentBatch.batchTypeSourceList = batch.batchTypeSourceList || batch.source || []
  471. if (!currentBatch.batchTypeSourceList) {
  472. currentBatch.batchTypeSourceList = []
  473. }
  474. if (!currentBatch.batchTypeScenicList) {
  475. currentBatch.batchTypeScenicList = []
  476. }
  477. if (!currentBatch.singleScenicList) {
  478. currentBatch.singleScenicList = []
  479. }
  480. if (!currentBatch.groupScenicList) {
  481. currentBatch.groupScenicList = []
  482. }
  483. if (!currentBatch.batchConfigList) {
  484. currentBatch.batchConfigList = []
  485. }
  486. let groupFlag = ''
  487. let groupIndex = 0
  488. currentBatch.batchTypeScenicList.forEach(item => {
  489. if (!item.groupFlag) {
  490. currentBatch.singleScenicList.push({
  491. scenicId: item.scenicId,
  492. checkLimitTimes: item.checkLimitTimes,
  493. singleDayLimitTimes: item.singleDayLimitTimes
  494. })
  495. } else {
  496. if (groupFlag !== item.groupFlag) {
  497. groupFlag = item.groupFlag
  498. groupIndex += 1
  499. currentBatch.groupScenicList.push({
  500. scenicId: [item.scenicId],
  501. checkLimitTimes: item.checkLimitTimes,
  502. scenicLimitTimes: item.scenicLimitTimes,
  503. singleDayLimitTimes: item.singleDayLimitTimes
  504. })
  505. } else {
  506. currentBatch.groupScenicList[groupIndex - 1].scenicId.push(item.scenicId)
  507. }
  508. }
  509. })
  510. const gsList = []
  511. const { groupScenicList } = currentBatch
  512. for (let i = 0; i < groupScenicList.length; i++) {
  513. const item = groupScenicList[i]
  514. const sList = item.scenicId.map(scenicId => {
  515. return {
  516. scenicId,
  517. checkLimitTimes: item.checkLimitTimes,
  518. singleDayLimitTimes: item.singleDayLimitTimes || -1,
  519. scenicLimitTimes: item.scenicLimitTimes || -1
  520. }
  521. })
  522. gsList.push(sList)
  523. }
  524. currentBatch.groupScenicList = gsList
  525. currentBatch.isSale = value
  526. updateBatchConfig(currentBatch).then(res => {
  527. if (res.code === '200') {
  528. this.$message.success('操作成功')
  529. this.getBatchConfigList()
  530. }
  531. })
  532. }
  533. }
  534. }
  535. </script>
  536. <style lang="scss" scoped>
  537. .offSale-btn{
  538. color: #F56C6C
  539. }
  540. .onSale-btn{
  541. color: #67C23A
  542. }
  543. </style>