TicketList.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062
  1. <template>
  2. <div
  3. class="ticket-list-wrap"
  4. :class="{focusFlash:isFocus}">
  5. <div
  6. v-if="!isPeriodTicket"
  7. class="select-date">
  8. <div class="choose-date d-flex">
  9. <div class="top-title">
  10. 游玩日期
  11. </div>
  12. <div class="date-list">
  13. <el-button
  14. v-for="(item,index) in quickDateList"
  15. :key="index"
  16. :type="playDate === item.value ? 'primary' : 'default'"
  17. :class="{ active: item.value === playDate}"
  18. @click="handleDateChange(item.value)">
  19. {{ item.label }}
  20. </el-button>
  21. </div>
  22. </div>
  23. <div class="select-date d-flex" style="margin-left: 90px">
  24. <div class="other-title">其他日期</div>
  25. <el-date-picker
  26. :clearable="false"
  27. :picker-options="dateOption"
  28. v-model="playDate"
  29. type="date"
  30. placeholder="选择日期时间"
  31. @change="handleDateChange"
  32. >
  33. </el-date-picker>
  34. </div>
  35. </div>
  36. <div
  37. v-if="category === 'batch'"
  38. class="select-batch">
  39. <div class="top-title">选择场次</div>
  40. <!-- <div
  41. class="noData"
  42. v-if="!batchList.length">
  43. 暂无数据
  44. </div>
  45. <div class="list-content">
  46. <div
  47. class="list-item"
  48. :class="{
  49. active: currentBatch && currentBatch.batchConfigId === item.batchConfigId,
  50. disabled: item && item.leftNums === 0
  51. }"
  52. v-for="(item, index) in batchList"
  53. :key="`batch-${index}`"
  54. @click="handleBatchChange(item)"
  55. >
  56. <div
  57. class="badge"
  58. v-if="item && item.leftNums === 0">
  59. 停售
  60. </div>
  61. <div class="title">
  62. <span class="name">{{ item.name }}</span>
  63. <span class="time">{{ removeSecond(item.startTime) }}-{{ removeSecond(item.endTime) }}</span>
  64. </div>
  65. <div class="left-count">
  66. 余票:{{ getLeftNums(item) }}
  67. </div>
  68. </div>
  69. </div> -->
  70. <el-table
  71. ref="singleTable"
  72. max-height="200px"
  73. :data="batchList"
  74. :row-key="row => row.id"
  75. highlight-current-row
  76. @current-change="handleBatchChange"
  77. border
  78. stripe>
  79. <el-table-column
  80. prop="name"
  81. label="场次名称"
  82. >
  83. </el-table-column>
  84. <el-table-column
  85. prop="startTime"
  86. label="开始时间"
  87. width="70px"
  88. >
  89. </el-table-column>
  90. <el-table-column
  91. prop="endTime"
  92. label="结束时间"
  93. width="70px"
  94. >
  95. </el-table-column>
  96. <el-table-column
  97. prop="leftNums"
  98. label="剩余数量"
  99. width="70px"
  100. >
  101. <template slot-scope="scope">
  102. <span class="num">{{ scope.row.leftNums === '-1' ? '不限' : scope.row.leftNums }}</span>
  103. </template>
  104. </el-table-column>
  105. </el-table>
  106. </div>
  107. <div class="select-ticket">
  108. <div class="search-ticket d-flex align-center">
  109. <div class="top-title">选择票种</div>
  110. <el-input
  111. ref="quickSearch"
  112. id="quick-search"
  113. clearable
  114. class="search-input"
  115. placeholder="按F2 快速筛选"
  116. v-model="keyword">
  117. <i
  118. class="el-icon-search el-input__icon"
  119. slot="suffix">
  120. </i>
  121. </el-input>
  122. <el-button
  123. v-if="category !== 'batch'"
  124. size="small"
  125. class="sort-btn"
  126. icon="el-icon-sort"
  127. title="票种排序"
  128. @click="openSortDialog">
  129. </el-button>
  130. </div>
  131. <div
  132. :class="['ticket-list', category === 'batch' && 'list-batch']"
  133. v-loading="loading">
  134. <div
  135. class="noData"
  136. v-if="!filterTableData.length">
  137. 暂无数据
  138. </div>
  139. <div class="list-content">
  140. <div
  141. class="list-item"
  142. :class="{
  143. active: currentTicket && currentTicket.id === item.id,
  144. active2: item.isTop && currentTicket && currentTicket.id !== item.id,
  145. disabled: item && item.isSale === 0
  146. }"
  147. v-for="(item, index) in filterTableData"
  148. :key="`ticket-${index}`"
  149. @click="changeTicket(item)"
  150. @contextmenu.prevent="showTopBtn(item)">
  151. <div class="badge" v-if="item && item.isSale === 0">
  152. 停售
  153. </div>
  154. <div class="title">
  155. <i class="el-icon-info" style="cursor: pointer; margin-right: 8px;" title="查看票种详情" @click.stop="showTicketInfo(item)"></i>
  156. <el-tooltip
  157. :content="getTicketTip(item)"
  158. placement="top"
  159. effect="dark">
  160. <div slot="content">
  161. <div>
  162. {{ item.name }}
  163. </div>
  164. <div>
  165. {{ getTicketTip(item) }}
  166. </div>
  167. </div>
  168. <span>
  169. {{ item.name }}
  170. </span>
  171. </el-tooltip>
  172. </div>
  173. <span
  174. class="price"
  175. v-if="item.price">
  176. <span class="num">{{ item.price }}</span> 元
  177. </span>
  178. <span
  179. class="price"
  180. v-else>
  181. 无今日价格
  182. </span>
  183. </div>
  184. </div>
  185. </div>
  186. </div>
  187. <ElDialog
  188. :title="ticketDetail.name"
  189. width="650px"
  190. v-model="ticketInfoVisible">
  191. <TicketInfo :data="ticketDetail"></TicketInfo>
  192. </ElDialog>
  193. <!-- 票种排序弹框 -->
  194. <native-dialog
  195. title="票种排序"
  196. :visible.sync="sortDialogVisible"
  197. width="600px"
  198. :close-on-click-modal="false">
  199. <div v-loading="sortLoading">
  200. <draggable
  201. v-model="sortList"
  202. handle=".sort-item"
  203. animation="200">
  204. <div
  205. class="sort-item"
  206. v-for="item in sortList"
  207. :key="item.ticketTypeId">
  208. <span class="sort-name">{{ item.name }}</span>
  209. <el-tag
  210. size="small"
  211. :type="item.isSale !== 0 ? 'success' : 'info'">
  212. {{ item.isSale !== 0 ? '已激活' : '已禁用' }}
  213. </el-tag>
  214. </div>
  215. </draggable>
  216. </div>
  217. <span
  218. slot="footer"
  219. class="dialog-footer">
  220. <el-button @click="sortDialogVisible = false">取 消</el-button>
  221. <el-button
  222. type="primary"
  223. @click="saveSortList">确 定</el-button>
  224. </span>
  225. </native-dialog>
  226. </div>
  227. </template>
  228. <script>
  229. import { getTicketTypeList, getTicketTypeByDate, saveTicketTypeSort } from '@/api/ticketType'
  230. import draggable from 'vuedraggable'
  231. import { getBatchList } from '@/api/batch'
  232. import moment from 'moment'
  233. import ElDialog from '@/components/Dialog'
  234. import { Dialog as NativeDialog } from 'element-ui'
  235. import TicketInfo from './TicketInfo'
  236. import { EventBus } from '@/utils/eventBus'
  237. // import TagSelector from './TagSelector.vue'
  238. export default {
  239. props: {
  240. typeId: {
  241. type: String,
  242. default: ''
  243. },
  244. value: {
  245. type: Object,
  246. default: () => {
  247. return {}
  248. }
  249. }
  250. },
  251. components: {
  252. ElDialog,
  253. NativeDialog,
  254. TicketInfo,
  255. draggable
  256. },
  257. data () {
  258. return {
  259. keyControl: 1, // 键盘控制:1,2,3标识选中顺序
  260. isFocus: false, // 组件是否是选中状态
  261. loading: false,
  262. keyword: '',
  263. tableData: [],
  264. currentTicket: {},
  265. playDate: moment().format('YYYY-MM-DD'),
  266. showTopBtnId: -1,
  267. ticketDetail: {},
  268. ticketInfoVisible: false,
  269. topIds: [],
  270. selectedScenic: [],
  271. ticketTagList: [],
  272. selectedTag: '',
  273. dateOption: {
  274. // 日历禁用日期
  275. disabledDate () {
  276. return false
  277. }
  278. },
  279. quickDateList: [
  280. { label: '今天', value: moment().format('YYYY-MM-DD') },
  281. { label: '明天', value: moment().add(1, 'days').format('YYYY-MM-DD') },
  282. { label: '后天', value: moment().add(2, 'days').format('YYYY-MM-DD') }
  283. ],
  284. allBatchList: [],
  285. currentBatch: {},
  286. sortDialogVisible: false,
  287. sortLoading: false,
  288. sortList: []
  289. }
  290. },
  291. computed: {
  292. category () {
  293. return this.$route.meta.category || 'ticket'
  294. },
  295. sortType () {
  296. const category = this.$route.meta.category || 'ticket'
  297. const type = this.$route.meta.type
  298. if (category === 'batch') return 'batch'
  299. if (category === 'member') return 'member'
  300. if (type === 'team') return 'team'
  301. return 'single'
  302. },
  303. userScenic () {
  304. return this.$store.state.app.account.managerScenicMatrix ? this.$store.state.app.account.managerScenicMatrix.map(i => i.id) : []
  305. },
  306. scenicList () {
  307. return this.$store.state.app.scenicList
  308. },
  309. filterTableData () {
  310. let result = this.tableData.filter(item => {
  311. if (
  312. ((item.name).toLowerCase().indexOf(this.keyword.toLowerCase()) > -1 ||
  313. (item.pinyin).toLowerCase().indexOf(this.keyword.toLowerCase()) > -1 ||
  314. (item.shorthand).toLowerCase().indexOf(this.keyword.toLowerCase()) > -1)
  315. ) {
  316. return true
  317. }
  318. })
  319. let topList = []
  320. for (let i = 0; i < this.topIds.length; i++) {
  321. let topItem = result.find(item => item.id === this.topIds[i])
  322. if (topItem) {
  323. topItem.isTop = true
  324. topList.push(topItem)
  325. }
  326. }
  327. let downList = result.filter(item => topList.indexOf(item) === -1)
  328. .map(item => {
  329. item.isTop = false
  330. return item
  331. })
  332. return [...topList, ...downList]
  333. },
  334. ticketType () {
  335. return this.$route.meta.category || 'ticket'
  336. },
  337. batchList () {
  338. if (this.category !== 'batch') {
  339. return this.currentTicket?.batchConfigList || []
  340. } else {
  341. return this.allBatchList
  342. }
  343. },
  344. // 是否期票
  345. isPeriodTicket () {
  346. const category = this.$route.meta.category || 'ticket'
  347. const { useDateType } = this.currentTicket || {}
  348. return category === 'ticket' && useDateType === 2
  349. },
  350. ticketListMaxHeight () {
  351. return this.this.category === 'batch' ? '300px' : '500px'
  352. },
  353. isTeam () {
  354. return this.category === 'ticket' && this.$route.meta.type === 'team'
  355. }
  356. },
  357. watch: {
  358. value: {
  359. handler (val) {
  360. if (!val || !val.id) {
  361. this.currentTicket = {}
  362. return
  363. }
  364. this.currentTicket = val
  365. },
  366. immediate: true
  367. },
  368. // 当数据变化时,默认不选择票种
  369. filterTableData (val) {
  370. // 默认不选中票种
  371. },
  372. selectedTag (val) {
  373. this.getTicketTypeList()
  374. },
  375. userScenic: {
  376. handler (val) {
  377. this.selectedScenic = val
  378. },
  379. immediate: true
  380. },
  381. currentTicket (val, oldVal) {
  382. if (val?.id && !oldVal?.id) {
  383. this.getTicketTypeInfo()
  384. }
  385. }
  386. },
  387. created () {
  388. if (this.category === 'batch') {
  389. this.getBatchList()
  390. } else {
  391. this.getTicketTypeList()
  392. }
  393. },
  394. mounted () {
  395. document.getElementById('quick-search').focus()
  396. // this.getTicketTagList()
  397. this.getTopIds()
  398. EventBus.$on('orderCreated', () => {
  399. if (this.category === 'batch') {
  400. this.getBatchList()
  401. } else {
  402. // this.changeTicket(this.currentTicket)
  403. }
  404. this.currentTicket = {}
  405. this.$emit('update', null)
  406. })
  407. },
  408. methods: {
  409. // 按enter,移动组件焦点
  410. // handleEnter (keyBind) {
  411. // keyBind.currentIndex++
  412. // keyBind.setFocus()
  413. // },
  414. removeSecond (time) {
  415. return time ? time.slice(0, 5) : ''
  416. },
  417. getTicketTip (item) {
  418. let tip = ''
  419. if (item.useDateType === 2 || item.memberUseDateType === 2) {
  420. tip += '有效期:' + item.useDateStart + '至' + item.useDateEnd
  421. } else if (item.useDateType === 1 || item.memberUseDateType === 1) {
  422. tip += item.useDays ? `使用天数:${item.useDays}天` : ''
  423. } else {
  424. }
  425. return tip
  426. },
  427. getTicketTypeList () {
  428. this.loading = true
  429. const params = {
  430. pageNum: 1,
  431. isSale: 1,
  432. pageSize: 1000,
  433. ticketTypeName: '',
  434. orderBy: true,
  435. category: this.ticketType,
  436. sortType: this.sortType
  437. }
  438. // 根据售票类型筛选团散票种:(散客)筛选0和1,(团队)筛选0和2
  439. if (this.ticketType === 'ticket') {
  440. params.teamIndividualList = this.isTeam ? [0, 2] : [0, 1]
  441. }
  442. getTicketTypeList(params).then(res => {
  443. this.tableData = res.data.records.map(item => {
  444. // 添加拼音首字母
  445. item.pinyin = pinyinUtil.getFirstLetter(item.name)
  446. return item
  447. })
  448. }).finally(() => {
  449. this.loading = false
  450. })
  451. },
  452. getBatchList () {
  453. getBatchList({
  454. batchDateStart: this.playDate,
  455. batchDateEnd: this.playDate
  456. }).then(res => {
  457. if (res.code === '200') {
  458. console.log('获取场次数据成功', res.data)
  459. this.allBatchList = (res.data || []).map(item => {
  460. return {
  461. ...item,
  462. name: item.batchName,
  463. ...(item.batchResponseList?.[0] || {})
  464. }
  465. })
  466. if (this.allBatchList && this.allBatchList[0]) {
  467. this.currentBatch = this.allBatchList[0]
  468. this.$refs.singleTable.setCurrentRow(this.allBatchList[0])
  469. this.tableData = (this.currentBatch?.ticketTypes || []).map(item => {
  470. return {
  471. ...item,
  472. batchConfigId: this.currentBatch.batchConfigId
  473. }
  474. })
  475. // this.changeTicket(this.tableData[0])
  476. this.$emit('set-batch', this.currentBatch)
  477. }
  478. }
  479. })
  480. },
  481. async handleDateChange (val) {
  482. this.playDate = moment(val).format('YYYY-MM-DD')
  483. if (this.category === 'batch') {
  484. this.getBatchList()
  485. } else {
  486. this.getTicketTypeInfo()
  487. }
  488. },
  489. async getTicketTypeInfo () {
  490. if (!this.currentTicket || !this.currentTicket.id) {
  491. this.$message.warning('未选择票种')
  492. return
  493. }
  494. const playDate = moment(this.playDate).format('YYYY-MM-DD')
  495. this.$emit('changePlayDate', playDate)
  496. const res = await getTicketTypeByDate({
  497. ticketTypeId: this.currentTicket.id,
  498. playDateBegin: playDate
  499. })
  500. if (res.code === '200') {
  501. console.log(playDate, '获取票种数据成功', res.data)
  502. this.currentTicket = res.data
  503. this.currentTicket.playDate = playDate
  504. this.$emit('update', this.currentTicket)
  505. this.$emit('input', this.currentTicket)
  506. this.tableData.forEach(item => {
  507. if (item.id === this.currentTicket.id) {
  508. item.price = this.currentTicket.price
  509. item.isSale = this.currentTicket.isSale
  510. }
  511. })
  512. }
  513. },
  514. async changeTicket (ticket) {
  515. if (!ticket) {
  516. return
  517. }
  518. const playDate = moment(this.playDate).format('YYYY-MM-DD')
  519. this.$emit('changePlayDate', playDate)
  520. const res = await getTicketTypeByDate({
  521. ticketTypeId: ticket.id,
  522. playDateBegin: playDate
  523. })
  524. if (res.code === '200') {
  525. console.log(playDate, '获取票种数据成功', res.data)
  526. this.currentTicket = res.data
  527. } else {
  528. this.currentTicket = ticket
  529. }
  530. this.currentTicket.playDate = playDate
  531. // 设置不可选日期
  532. this.dateOption.disabledDate = (date) => {
  533. let beforeToday = moment().subtract(1, 'days').isAfter(date)
  534. let beforeStart = moment(ticket.useDateStart).isAfter(date)
  535. let afterEnd = moment(ticket.useDateEnd).isBefore(date)
  536. return beforeToday || beforeStart || afterEnd
  537. }
  538. this.$emit('update', this.currentTicket)
  539. this.$emit('input', this.currentTicket)
  540. this.tableData.forEach(item => {
  541. if (item.id === this.currentTicket.id) {
  542. item.price = this.currentTicket.price
  543. item.isSale = this.currentTicket.isSale
  544. }
  545. })
  546. EventBus.$emit('ticketChanged', this.currentTicket)
  547. },
  548. handleBatchChange (row) {
  549. console.log('当前选择的场次', row)
  550. if (!row || this.currentBatch?.batchConfigId === row.batchConfigId) {
  551. return
  552. }
  553. if (row.leftNums === 0) {
  554. this.$message.error('该场次已售完')
  555. return
  556. }
  557. this.currentBatch = row
  558. this.tableData = (this.currentBatch?.ticketTypes || []).map(item => {
  559. return {
  560. ...item,
  561. batchConfigId: row.batchConfigId
  562. }
  563. })
  564. this.$emit('set-batch', row)
  565. },
  566. formatDate (input) {
  567. return moment(input).format('YYYY-MM-DD')
  568. },
  569. showTicketInfo (data) {
  570. data.scenics = data.ticketTypeScenic?.map(s => s.scenic)
  571. this.ticketInfoVisible = true
  572. this.ticketDetail = data
  573. },
  574. setFocus () {
  575. this.$refs.quickSearch.focus()
  576. this.keyword = ''
  577. },
  578. arrowUp () {
  579. this.arrowCtrl(-1)
  580. },
  581. arrowDown () {
  582. this.arrowCtrl(1)
  583. },
  584. arrowCtrl (n) {
  585. let currentIndex = this.filterTableData.findIndex(item => item.id === this.currentTicket.id)
  586. let i = currentIndex + n
  587. if (this.filterTableData[i]) {
  588. this.changeTicket(this.filterTableData[i])
  589. }
  590. },
  591. showTopBtn (item) {
  592. this.showTopBtnId = item.id
  593. },
  594. getTopIds () {
  595. let arr = this.$localStore.get('topIds')
  596. if (!arr) arr = []
  597. this.topIds = arr
  598. // console.log('置顶', this.topIds)
  599. },
  600. setTop (item) {
  601. let arr = this.$localStore.get('topIds')
  602. if (!arr) arr = []
  603. if (arr.indexOf(item.id) !== -1) {
  604. arr.splice(arr.indexOf(item.id), 1)
  605. }
  606. arr.unshift(item.id)
  607. this.$localStore.set({
  608. 'topIds': arr
  609. })
  610. this.getTopIds()
  611. this.showTopBtnId = -1
  612. },
  613. cancelTop (item) {
  614. let arr = this.$localStore.get('topIds')
  615. if (!arr) arr = []
  616. if (arr.indexOf(item.id) !== -1) {
  617. arr.splice(arr.indexOf(item.id), 1)
  618. }
  619. this.$localStore.set({
  620. 'topIds': arr
  621. })
  622. this.getTopIds()
  623. this.showTopBtnId = -1
  624. },
  625. getLeftNums (item) {
  626. return item.leftNums <= -1 ? '不限' : item.leftNums
  627. },
  628. // 打开票种排序弹框
  629. async openSortDialog () {
  630. this.sortDialogVisible = true
  631. this.sortLoading = true
  632. try {
  633. // const sortRes = await getTicketTypeSort(this.sortType)
  634. // const sortData = sortRes?.data || []
  635. // 用排序接口的顺序排列 tableData
  636. const sortMap = new Map(this.tableData.map(s => [s.ticketTypeId, s.sort]))
  637. this.sortList = [...this.tableData]
  638. .map(item => ({
  639. ticketTypeId: item.id,
  640. name: item.name,
  641. isSale: item.isSale,
  642. sort: sortMap.has(item.id) ? sortMap.get(item.id) : 9999
  643. }))
  644. .sort((a, b) => a.sort - b.sort)
  645. } catch (e) {
  646. this.sortList = this.tableData.map((item, index) => ({
  647. ticketTypeId: item.id,
  648. name: item.name,
  649. isSale: item.isSale,
  650. sort: index
  651. }))
  652. } finally {
  653. this.sortLoading = false
  654. }
  655. },
  656. // 保存票种排序
  657. async saveSortList () {
  658. const sorts = this.sortList.map((item, index) => ({
  659. ticketTypeId: item.ticketTypeId,
  660. sort: index + 1
  661. }))
  662. const data = {
  663. type: this.sortType,
  664. sorts
  665. }
  666. try {
  667. await saveTicketTypeSort(data)
  668. this.$message.success('排序保存成功')
  669. this.sortDialogVisible = false
  670. // 按新排序更新 tableData
  671. const sortMap = new Map(sorts.map(s => [s.ticketTypeId, s.sort]))
  672. this.tableData.sort((a, b) => {
  673. return (sortMap.get(a.id) || 9999) - (sortMap.get(b.id) || 9999)
  674. })
  675. } catch (e) {
  676. this.$message.error('排序保存失败')
  677. }
  678. }
  679. },
  680. beforeDestroy () {
  681. EventBus.$off('orderCreated')
  682. }
  683. }
  684. </script>
  685. <style lang="scss">
  686. .d-flex {
  687. display: flex;
  688. }
  689. .align-center {
  690. align-items: center;
  691. }
  692. .el-table tr.current-row>td {
  693. background-color: #ccd5de !important;
  694. color: #0075ff !important;
  695. }
  696. </style>
  697. <style lang="scss" scoped>
  698. .el-radio {
  699. margin-right: 0;
  700. }
  701. .noData {
  702. width: 100px;
  703. padding: 10px;
  704. font-size: 14px;
  705. color: #666;
  706. text-align: center;
  707. }
  708. .price b {
  709. font-weight: 600;
  710. }
  711. .top-title {
  712. display: flex;
  713. padding: 10px 10px;
  714. font-size: 16px;
  715. line-height: 1.4;
  716. color: #333;
  717. background: #fff;
  718. justify-content: space-between;
  719. align-items: center;
  720. font-weight: 600;
  721. .right-btn {
  722. display: flex;
  723. }
  724. }
  725. .ticket-list-wrap {
  726. display: flex;
  727. padding: 20px 10px;
  728. height: 100%;
  729. box-sizing: border-box;
  730. flex-direction: column;
  731. background: #fff;
  732. border: 1px solid #ddd;
  733. border-radius: 4px;
  734. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
  735. .select-date {
  736. margin-bottom: 5px;
  737. align-items: center;
  738. .date-list {
  739. display: inline-flex;
  740. align-items: center;
  741. .el-button {
  742. height: 32px;
  743. }
  744. .other-title {
  745. margin-left: 20px;
  746. }
  747. }
  748. .el-date-editor {
  749. margin: 0 10px;
  750. width: 140px;
  751. }
  752. }
  753. .select-ticket {
  754. margin-bottom: 10px;
  755. margin-top: 10px;
  756. align-items: center;
  757. .search-input {
  758. width: calc(100% - 130px);
  759. }
  760. .sort-btn {
  761. margin-left: 2px;
  762. }
  763. .ticket-list {
  764. width: 100%;
  765. .list-content {
  766. margin: 5px 10px;
  767. width: calc(100% - 20px);
  768. max-height: 650px;
  769. overflow-y: auto;
  770. .list-item {
  771. position: relative;
  772. margin-bottom: 3px;
  773. flex-shrink: 0;
  774. width: auto;
  775. height: 32px;
  776. display: flex;
  777. color: #333;
  778. cursor: pointer;
  779. background: #F2F6FF;
  780. border: 2px solid #f0f0f0;
  781. transition: all .3s;
  782. justify-content: space-between;
  783. align-items: center;
  784. border-radius: 6px;
  785. padding: 0 10px;
  786. .title {
  787. width: calc(100% - 80px);
  788. margin-top: 4px;
  789. display: flex;
  790. span {
  791. overflow: hidden;
  792. white-space: nowrap;
  793. text-overflow: ellipsis;
  794. display: inline-block;
  795. max-width: 100%;
  796. }
  797. }
  798. .price {
  799. margin-left: 10px;
  800. .num {
  801. font-size: 18px;
  802. font-weight: bold;
  803. }
  804. }
  805. &:hover {
  806. z-index: 1;
  807. background: rgba(216, 225, 253, .3);
  808. border: 2px solid darken($blue, 1%);
  809. }
  810. &.active {
  811. z-index: 2;
  812. background: $blue;
  813. color: #fff;
  814. border: 2px solid darken($blue, 1%);
  815. .price {
  816. color: #fff;
  817. }
  818. }
  819. &.disabled {
  820. cursor: not-allowed;
  821. // background: $darkgray !important;
  822. border: 2px solid darken($darkgray, 8%);
  823. overflow: hidden;
  824. .badge {
  825. position: absolute;
  826. background: $darkgray;
  827. z-index: 1;
  828. width: 55px;
  829. text-align: center;
  830. height: 40px;
  831. line-height: 50px;
  832. border-radius: 3px;
  833. color: #fff;
  834. font-size: 12px !important;
  835. padding: 2px 4px 0;
  836. top: -14px;
  837. right: -23px;
  838. -ms-transform: rotate(45deg);
  839. -webkit-transform: rotate(45deg);
  840. transform: rotate(45deg);
  841. -webkit-transition: 0 0.1s ease-in;
  842. -moz-transition: 0 0.1s ease-in;
  843. -o-transition: 0 0.1s ease-in;
  844. transition: transform 0.1s ease-in;
  845. }
  846. }
  847. }
  848. }
  849. &.list-batch {
  850. .list-content {
  851. max-height: 450px;
  852. }
  853. }
  854. }
  855. }
  856. .select-batch {
  857. // display: flex;
  858. align-content: top;
  859. .list-content {
  860. display: flex;
  861. .list-item {
  862. position: relative;
  863. color: #333;
  864. cursor: pointer;
  865. background: #F2F6FF;
  866. border: 2px solid #f0f0f0;
  867. transition: all .3s;
  868. justify-content: space-between;
  869. align-items: center;
  870. border-radius: 6px;
  871. padding: 10px;
  872. margin-right: 10px;
  873. text-align: center;
  874. .title {
  875. .name {
  876. margin-right: 10px;
  877. }
  878. }
  879. .left-count {
  880. margin-top : 10px;
  881. font-size: 16px;
  882. }
  883. &:hover {
  884. z-index: 1;
  885. background: rgba(216, 225, 253, .3);
  886. border: 2px solid darken($blue, 1%);
  887. .goTop {
  888. i {
  889. display: inline-block;
  890. }
  891. }
  892. }
  893. &.active {
  894. z-index: 2;
  895. background: $blue;
  896. color: #fff;
  897. border: 2px solid darken($blue, 1%);
  898. .price {
  899. color: #fff;
  900. }
  901. }
  902. &.disabled {
  903. cursor: not-allowed;
  904. // background: $darkgray !important;
  905. border: 2px solid darken($darkgray, 8%);
  906. overflow: hidden;
  907. .badge {
  908. position: absolute;
  909. background: $darkgray;
  910. z-index: 1;
  911. width: 55px;
  912. text-align: center;
  913. height: 40px;
  914. line-height: 50px;
  915. border-radius: 3px;
  916. color: #fff;
  917. font-size: 12px !important;
  918. padding: 2px 4px 0;
  919. top: -14px;
  920. right: -23px;
  921. -ms-transform: rotate(45deg);
  922. -webkit-transform: rotate(45deg);
  923. transform: rotate(45deg);
  924. -webkit-transition: 0 0.1s ease-in;
  925. -moz-transition: 0 0.1s ease-in;
  926. -o-transition: 0 0.1s ease-in;
  927. transition: transform 0.1s ease-in;
  928. }
  929. }
  930. // &.active2 {
  931. // border-color: rgb(67, 125, 233);
  932. // }
  933. .top-sign {
  934. position: absolute;
  935. top: 0;
  936. right: 0;
  937. width: 0;
  938. height: 0;
  939. border: 5px solid red;
  940. border-bottom-color: transparent;
  941. border-left-color: transparent;
  942. }
  943. }
  944. }
  945. }
  946. }
  947. .mutipleTag {
  948. position: absolute;
  949. top: 0;
  950. left: 0;
  951. width: 0;
  952. height: 0;
  953. color: #fff;
  954. pointer-events: none;
  955. border: 14px solid rgb(255, 94, 0);
  956. border-right-color: transparent;
  957. border-bottom-color: transparent;
  958. i {
  959. position: absolute;
  960. font-size: 12px;
  961. transform: translate(-12px, -12px);
  962. }
  963. }
  964. .list-wrap-batch {
  965. max-height: calc(100vh - 400px);
  966. flex: 1;
  967. }
  968. .sort-item {
  969. display: flex;
  970. align-items: center;
  971. justify-content: space-between;
  972. padding: 12px 16px;
  973. border-bottom: 1px solid #eee;
  974. cursor: grab;
  975. background: #fff;
  976. transition: background 0.2s;
  977. &:hover {
  978. background: #f5f7fa;
  979. }
  980. &:active {
  981. cursor: grabbing;
  982. }
  983. .sort-name {
  984. font-size: 14px;
  985. color: #333;
  986. }
  987. }
  988. </style>