cancelReport.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. <template>
  2. <div class="form-wrap">
  3. <div class="searchBox">
  4. <el-form
  5. ref="form"
  6. :model="form"
  7. :inline="true"
  8. label-width="150px">
  9. <el-form-item
  10. label="起始时间"
  11. prop="timeBegin">
  12. <el-date-picker
  13. v-model="form.timeBegin"
  14. type="datetime"
  15. placeholder="选择日期时间">
  16. </el-date-picker>
  17. </el-form-item>
  18. <el-form-item
  19. label="截止时间"
  20. prop="timeEnd">
  21. <el-date-picker
  22. v-model="form.timeEnd"
  23. type="datetime"
  24. placeholder="选择日期时间">
  25. </el-date-picker>
  26. </el-form-item>
  27. <el-form-item
  28. label="票种"
  29. prop="ticketTypeIdList">
  30. <el-select
  31. filterable
  32. v-model="form.ticketTypeIdList"
  33. multiple
  34. clearable
  35. placeholder="请选择">
  36. <el-option
  37. v-for="item in ticketTypeList"
  38. :key="item.id"
  39. :label="item.name"
  40. :value="item.ticketTypeId">
  41. </el-option>
  42. </el-select>
  43. </el-form-item>
  44. <el-form-item
  45. label="分销商名称"
  46. prop="otaSourceNameList">
  47. <el-select
  48. filterable
  49. multiple
  50. v-model="form.otaSourceNameList"
  51. placeholder="请选择">
  52. <el-option
  53. v-for="item in otaSourceList"
  54. :key="item.otaSourceCode"
  55. :label="item.otaSourceName"
  56. :value="item.otaSourceName">
  57. </el-option>
  58. </el-select>
  59. </el-form-item>
  60. <el-form-item
  61. label="分组筛选"
  62. style="width:100%">
  63. <el-checkbox-group
  64. v-model="selectKeys"
  65. :min="0"
  66. :max="4">
  67. <draggable :list="groupKeys">
  68. <el-checkbox
  69. :key="item.value"
  70. :label="item.value"
  71. v-for="(item) in groupKeys"
  72. >
  73. {{ item.label }}
  74. </el-checkbox>
  75. </draggable>
  76. </el-checkbox-group>
  77. </el-form-item>
  78. </el-form>
  79. <div class="btn-wrap">
  80. <el-button
  81. @click="reset">重置</el-button>
  82. <el-button
  83. type="primary"
  84. @click="getCancelOrderList($event,true)">搜索</el-button>
  85. <el-button
  86. type="primary"
  87. @click="reportExport">导出</el-button>
  88. </div>
  89. </div>
  90. <div class="tableBox">
  91. <!-- <div class="block-title">
  92. 查询信息
  93. </div> -->
  94. <el-table
  95. :data="tableData"
  96. stripe
  97. row-class-name="is-center"
  98. v-loading="loading"
  99. :span-method="objectSpanMethod">
  100. <el-table-column
  101. v-for="(item) in finalGroup"
  102. :key="item.value"
  103. :prop="item.prop || item.value"
  104. :label="item.label">
  105. </el-table-column>
  106. <el-table-column
  107. prop="otaSourceName"
  108. label="订单渠道">
  109. </el-table-column>
  110. <el-table-column
  111. prop="ticketTypeName"
  112. label="票种">
  113. </el-table-column>
  114. <el-table-column
  115. prop="unitPrice"
  116. label="单价">
  117. </el-table-column>
  118. <el-table-column
  119. prop="cancelCount"
  120. label="退票张数">
  121. </el-table-column>
  122. <el-table-column
  123. prop="cancelNum"
  124. label="退票人数">
  125. </el-table-column>
  126. <el-table-column
  127. prop="cancelPrice"
  128. label="退票金额">
  129. </el-table-column>
  130. </el-table>
  131. <el-pagination
  132. background
  133. :current-page.sync="form.pageNum"
  134. @current-change="getCancelOrderList"
  135. layout="total, prev, pager, next"
  136. :total="total">
  137. </el-pagination>
  138. </div>
  139. <ElDialog
  140. :title="type==='cancel'?'退单':'订单详情'"
  141. width="760px"
  142. v-model="orderDialogVisible"
  143. >
  144. <OrderDialog
  145. :current-item="currentItem"
  146. :can-cancel="canCancel"
  147. @updateList="getCancelOrderList"
  148. :type="type"></OrderDialog>
  149. </ElDialog>
  150. <ElDialog
  151. title="游客信息"
  152. width="760px"
  153. v-model="guestDialogVisible">
  154. <GuestDialog
  155. :current-item="currentItem"></GuestDialog>
  156. </ElDialog>
  157. <TicketInfo ref="ticketInfo"></TicketInfo>
  158. </div>
  159. </template>
  160. <script>
  161. import { getOrderCancelStatistics, getOtaSourceList } from '@/api/order'
  162. import { getTicketTypeList } from '@/api/ticketType'
  163. import ElDialog from '@/components/Dialog'
  164. import OrderDialog from './orderList/OrderDialog'
  165. import GuestDialog from './orderList/GuestDialog'
  166. import TicketInfo from './orderList/TicketInfo'
  167. import { orderStatus } from '@/const'
  168. import moment from 'moment'
  169. const groupKeys = [
  170. { value: 'orderDateDay', label: '日期' }
  171. ]
  172. export default {
  173. name: 'salesReport',
  174. components: {
  175. ElDialog,
  176. OrderDialog,
  177. GuestDialog,
  178. TicketInfo
  179. },
  180. data () {
  181. return {
  182. groupKeys,
  183. ticketTypeList: [],
  184. otaSourceList: [],
  185. projectName: localStorage.getItem('otaProject'),
  186. totalObj: {},
  187. type: '', // 操作状态 cancel退订单
  188. form: {
  189. timeBegin: moment().startOf('day'),
  190. timeEnd: moment().endOf('day'),
  191. ticketTypeIdList: [], // 票种名称
  192. otaSourceNameList: [], // 订单渠道
  193. export: false,
  194. pageNum: 1,
  195. pageSize: 10
  196. },
  197. selectKeys: [],
  198. finalGroup: [],
  199. tableIndex: 1,
  200. OrderIndexArr: [],
  201. orderStatusDic: orderStatus,
  202. loading: false,
  203. tableData: [],
  204. total: 0,
  205. currentItem: {},
  206. orderDialogVisible: false,
  207. guestDialogVisible: false,
  208. invoiceDialogVisible: false,
  209. invoiceLoading: false,
  210. invoiceTableData: [],
  211. invoiceTotal: 0,
  212. invoiceQuery: {
  213. pageNum: 1,
  214. pageSize: 10
  215. },
  216. currentInvoiceRow: {}
  217. }
  218. },
  219. created () {
  220. this.getTicketTypeList()
  221. this.getOtaSourceList()
  222. this.getCancelOrderList()
  223. },
  224. computed: {
  225. canCancel () {
  226. return this.$store.state.user.permissionList.includes('orders:cancel')
  227. },
  228. queryClear () {
  229. return this.$store.state.user.permissionList.includes('stats:clearwx_query')
  230. },
  231. otaList () {
  232. const list = JSON.parse(localStorage.getItem('otaList'))
  233. return this.projectName === 'YINXIANGMAZU' && !this.queryClear ? list.filter(item => item.otaSourceCode !== 'CLEARWX') : list
  234. },
  235. permissionList () {
  236. return this.$store.state.user.menuList || []
  237. }
  238. },
  239. methods: {
  240. hasPermission (key) {
  241. return !!this.permissionList.some(item => item.code === key)
  242. },
  243. checkRefundVisible (item) {
  244. if (item.status !== 'CANCELED') return true
  245. if (item.status === 'CANCELED') {
  246. if (item.tickets.some(i => i.status !== 'CANCELED')) {
  247. return true
  248. } else {
  249. return false
  250. }
  251. }
  252. return false
  253. },
  254. reset () {
  255. this.$refs.form.resetFields()
  256. },
  257. getTicketTypeList () {
  258. getTicketTypeList({
  259. pageNum: 1,
  260. pageSize: -1
  261. }).then(res => {
  262. this.ticketTypeList = res.data.records || []
  263. })
  264. },
  265. getOtaSourceList () {
  266. getOtaSourceList({
  267. pageNum: 1,
  268. pageSize: -1
  269. }).then(res => {
  270. this.otaSourceList = res.data.records || []
  271. })
  272. },
  273. getCancelOrderList (e, goFirst) {
  274. if (goFirst) { this.form.pageNum = 1 }
  275. if (!this.form.timeBegin || !this.form.timeEnd) {
  276. this.$message.error('请选择起始时间和截止时间')
  277. return
  278. }
  279. this.form.timeBegin = moment(this.form.timeBegin).format('YYYY-MM-DD HH:mm:ss')
  280. this.form.timeEnd = moment(this.form.timeEnd).format('YYYY-MM-DD HH:mm:ss')
  281. if (!this.form.ticketTypeIdList) {
  282. this.form.ticketTypeIdList = []
  283. }
  284. if (!this.form.otaSourceNameList) {
  285. this.form.otaSourceNameList = []
  286. }
  287. this.finalGroup = this.groupKeys.filter(i => {
  288. return this.selectKeys.includes(i.value)
  289. })
  290. this.form.groupByList = this.finalGroup.map(i => i.value)
  291. this.loading = true
  292. getOrderCancelStatistics(this.form).then(res => {
  293. this.tableData = res.data
  294. this.loading = false
  295. })
  296. },
  297. objectSpanMethod ({ row, column, rowIndex, columnIndex }) {
  298. if (columnIndex < this.finalGroup.length) {
  299. if (!(this.OrderIndexArr[columnIndex] && this.OrderIndexArr[columnIndex].length)) return
  300. for (let i = 0; i < this.OrderIndexArr[columnIndex].length; i++) {
  301. let element = this.OrderIndexArr[columnIndex][i]
  302. for (let j = 0; j < element.length; j++) {
  303. let item = element[j]
  304. if (rowIndex === item) {
  305. if (j === 0) {
  306. return {
  307. rowspan: element.length,
  308. colspan: 1
  309. }
  310. } else if (j !== 0) {
  311. return {
  312. rowspan: 0,
  313. colspan: 0
  314. }
  315. }
  316. }
  317. }
  318. }
  319. }
  320. },
  321. showOrderInfo (item, type) {
  322. if ((item.otaSourceCode === 'CLEARWX' || item.otaSourceCode === 'CLEARWXDEV') && type === 'cancel') return this.$message.info('自营平台订单请到自营后台办理退票')
  323. this.currentItem = item
  324. this.type = type
  325. this.orderDialogVisible = true
  326. },
  327. showGuestInfo (item) {
  328. this.currentItem = item
  329. this.guestDialogVisible = true
  330. },
  331. formatInvoiceDetails (details) {
  332. if (!details || !details.length) return ''
  333. return details.map(item => item.ticketNo).filter(Boolean).join('、')
  334. },
  335. reportExport () {
  336. this.$confirm(`是否要导出明细数据`, '确认提示', {
  337. confirmButtonText: '是',
  338. cancelButtonText: '否',
  339. type: 'warning'
  340. }).then(() => {
  341. this.handelExport({
  342. ...this.form,
  343. export: true,
  344. exportDetail: true
  345. })
  346. }).catch(() => {
  347. this.handelExport({
  348. ...this.form,
  349. export: true,
  350. exportDetail: false
  351. })
  352. })
  353. },
  354. handelExport (params) {
  355. getOrderCancelStatistics(params).then(res => {
  356. this.$confirm('导出成功,是否去下载页', '提示', {
  357. confirmButtonText: '确定',
  358. cancelButtonText: '取消',
  359. type: 'warning'
  360. }).then(() => {
  361. this.$router.push('/queryReport/reportExport')
  362. }).catch(() => {})
  363. }, () => {
  364. this.$notify.error({
  365. title: '提示',
  366. message: '导出失败'
  367. })
  368. })
  369. }
  370. }
  371. }
  372. </script>
  373. <style scoped>
  374. </style>