OrderDetail.vue 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895
  1. <template>
  2. <el-dialog
  3. :visible.sync="visible"
  4. :before-close="handleClose"
  5. title="订单信息"
  6. width="90%"
  7. >
  8. <el-form
  9. :inline="true"
  10. label-width="120px"
  11. class="dialog-info"
  12. v-if="orderData"
  13. >
  14. <el-form-item label="线下订单号">
  15. {{ orderData.orderNo }}
  16. </el-form-item>
  17. <el-form-item label="创建时间">
  18. {{ orderData.createTime | formatTime }}
  19. </el-form-item>
  20. <el-form-item label="合作方订单号">
  21. {{ orderData.partnerOrderNo }}
  22. </el-form-item>
  23. <el-form-item label="订单类型">
  24. {{ orderData.orderCategory | formatCategory }}
  25. </el-form-item>
  26. <el-form-item label="总价(¥)">
  27. {{ orderData.price }}
  28. </el-form-item>
  29. <el-form-item label="包含的票数">
  30. {{ orderData.ticketNum }}
  31. </el-form-item>
  32. <el-form-item label="支付类型">
  33. {{ orderData.payChannel }}
  34. </el-form-item>
  35. <el-form-item label="支付状态">
  36. <!-- 由于支付状态较多,且接口返回的状态码不固定,所以这里直接列出所有状态,避免遗漏 -->
  37. <div v-if="orderData.payStatus == 'CREATE'">已创建</div>
  38. <div v-if="orderData.payStatus == 'SUBMIT'">已提交</div>
  39. <div v-if="orderData.payStatus == 'PAYED'">已支付</div>
  40. <div v-if="orderData.payStatus == 'REFUNDED'">已退款</div>
  41. <div v-if="orderData.payStatus == 'CLOSED'">订单关闭</div>
  42. <div v-if="orderData.payStatus == 'FAILED'">支付失败</div>
  43. </el-form-item>
  44. <el-form-item label="支付时间">
  45. {{ orderData.payTime | formatTime }}
  46. </el-form-item>
  47. <el-form-item label="订单来源渠道">
  48. {{ orderData.otaSourceName }}
  49. </el-form-item>
  50. <el-form-item label="售票员">
  51. {{ orderData.saleAdminName }}
  52. </el-form-item>
  53. <el-form-item label="购买方名称">
  54. {{ orderData.buyerName }}
  55. </el-form-item>
  56. <el-form-item label="购买方手机号">
  57. {{ orderData.buyerPhone }}
  58. </el-form-item>
  59. <el-form-item label="购买方证件号">
  60. {{ orderData.buyerIdentify }}
  61. </el-form-item>
  62. <el-form-item label="是否是线上订单">
  63. {{ orderData.isOnlineOrder ? '是' : '否' }}
  64. </el-form-item>
  65. <el-form-item label="订单状态">
  66. <OrderStatusTag :value="orderData.status"></OrderStatusTag>
  67. </el-form-item>
  68. <el-form-item label="团队名称">
  69. {{ orderData.teamName || '无' }}
  70. </el-form-item>
  71. <el-form-item label="导游名称">
  72. {{ orderData.guideName || '无' }}
  73. </el-form-item>
  74. <el-tabs v-model="activeTab" type="card">
  75. <el-tab-pane class="block-title" label="门票信息" name="ticketCheckInfo">
  76. <div class="title" style="display: flex;justify-content: space-between;margin-bottom: 10px;">
  77. <div>
  78. 检票景点明细
  79. </div>
  80. <el-input v-model="ticketNoSearch1" placeholder="输入票号查询"></el-input>
  81. </div>
  82. <el-table border :data="checkDetailList" :max-height="450">
  83. <el-table-column type="expand">
  84. <template slot-scope="props">
  85. <div class="title">检票景点</div>
  86. <el-table :data="props.row.ticketCheckScenicList" :max-height="200">
  87. <el-table-column
  88. prop="scenicName"
  89. show-overflow-tooltip
  90. width="300"
  91. label="景点"
  92. ></el-table-column>
  93. <el-table-column
  94. prop="checkLimitTimes"
  95. label="可检票次数"
  96. width="150"
  97. >
  98. <template slot-scope="scope">
  99. {{ scope.row.checkLimitTimes === -1 ? "无限制" : scope.row.checkLimitTimes }}
  100. </template>
  101. </el-table-column>
  102. <el-table-column
  103. prop="checkedTimes"
  104. width="150"
  105. label="已检票次数"
  106. ></el-table-column>
  107. <el-table-column
  108. prop="singleDayLimitTimes"
  109. label="单日可检票次数"
  110. width="150"
  111. >
  112. <template slot-scope="scope">
  113. {{ scope.row.singleDayLimitTimes === -1 ? "无限制" : scope.row.singleDayLimitTimes }}
  114. </template>
  115. </el-table-column>
  116. </el-table>
  117. </template>
  118. </el-table-column>
  119. <el-table-column
  120. v-if="isColumnVisible('ticketNo')"
  121. width="160"
  122. prop="ticketNo"
  123. label="票号">
  124. <template slot-scope="scope">
  125. <div class="">{{ scope.row.ticketNo }}</div>
  126. <img v-if="scope.row.ticketNoImg" :src="scope.row.ticketNoImg || ''" style="width: 130px;height: 130px;" alt="">
  127. </template>
  128. </el-table-column>
  129. <el-table-column
  130. v-if="isColumnVisible('ticketTypeName')"
  131. width="100"
  132. prop="ticketTypeName"
  133. label="票种"> </el-table-column>
  134. <el-table-column
  135. v-if="isColumnVisible('unitPrice')"
  136. width="80"
  137. prop="price"
  138. label="单价(¥)">
  139. <template slot-scope="scope">
  140. <div class="">{{ scope.row.checkNum ? scope.row.price / scope.row.checkNum : scope.row.price }}</div>
  141. <div v-if="scope.row.discountPrice" style="color: #bbb">原价:{{ scope.row.originalPrice }}</div>
  142. <div v-if="scope.row.discountPrice" style="color: #52c41a">改价:{{ scope.row.discountPrice }}</div>
  143. <div v-if="scope.row.price !== scope.row.settlementPrice" style="color: #0080ff">结算价:{{ scope.row.settlementPrice }}</div>
  144. </template>
  145. </el-table-column>
  146. <el-table-column
  147. v-if="isColumnVisible('subtotal')"
  148. width="80"
  149. prop="price"
  150. label="小计"></el-table-column>
  151. <el-table-column
  152. v-if="isColumnVisible('status')"
  153. width="100"
  154. prop="status"
  155. align="center"
  156. label="状态">
  157. <template slot-scope="scope">
  158. <!-- 组件新增功能是否向左浮动展示,默认为false不浮动 -->
  159. <TicketStatusTag :float-left="true" :value="scope.row.status"></TicketStatusTag>
  160. </template>
  161. </el-table-column>
  162. <el-table-column
  163. v-if="isColumnVisible('guestInfo')"
  164. width="210"
  165. prop="guestInfo"
  166. label="游客信息">
  167. <template slot-scope="scope">
  168. <div class=""><span>姓名:</span>{{ scope.row.guestName }}</div>
  169. <div class=""><span>手机号:</span>{{ scope.row.guestPhone }}</div>
  170. <div class=""><span>证件类型:</span>{{ papersType[scope.row.guestIdentifyType] }}</div>
  171. <div class=""><span>证件号码:</span>{{ scope.row.guestIdentify }}</div>
  172. </template>
  173. </el-table-column>
  174. <el-table-column
  175. v-if="isColumnVisible('ticketCheckInfo')"
  176. width="260"
  177. prop="ticketCheckInfo"
  178. label="检票信息">
  179. <template slot-scope="scope">
  180. <div class=""><span>检票人数:</span>{{ scope.row.checkNum }}</div>
  181. <div class=""><span>首次检票时间:</span>{{ scope.row.firstCheckTime }}</div>
  182. <div class=""><span>最近一次检票时间:</span>{{ scope.row.checkTime }}</div>
  183. <div class=""><span>最近一次检票设备:</span>{{ scope.row.checkerName }}</div>
  184. </template>
  185. </el-table-column>
  186. <el-table-column
  187. v-if="isColumnVisible('ticketPrintInfo')"
  188. width="260"
  189. prop="ticketPrintInfo"
  190. label="取票信息">
  191. <template slot-scope="scope">
  192. <div class=""><span>取票状态:</span>
  193. <el-tag :type="scope.row.isPrint ? 'success' : 'info'">
  194. {{ scope.row.isPrint ? "已取票" : "未取票" }}
  195. </el-tag>
  196. </div>
  197. <div class=""><span>取票时间:</span>{{ scope.row.printTime }}</div>
  198. <div class=""><span>取票人:</span>{{ scope.row.printAdminName }}</div>
  199. <div class=""><span>取票自助机:</span>{{ scope.row.printTermName }}</div>
  200. </template>
  201. </el-table-column>
  202. <el-table-column
  203. v-if="isColumnVisible('ticketRefundInfo')"
  204. width="260"
  205. prop="ticketRefundInfo"
  206. label="退票信息">
  207. <template slot-scope="scope">
  208. <div class=""><span>退款操作人:</span>{{ scope.row.cancelAdminName }}</div>
  209. <div class=""><span>退款金额:</span>{{ scope.row.cancelPrice }}</div>
  210. <div class=""><span>退款申请时间:</span>{{ scope.row.cancelSubmitTime }}</div>
  211. <div class=""><span>退款完成时间:</span>{{ scope.row.cancelCompleteTime }}</div>
  212. <div class=""><span>是否强制取消:</span>{{ scope.row.isForceCancel ? '是' : '否' }}</div>
  213. </template>
  214. </el-table-column>
  215. <el-table-column
  216. v-if="isColumnVisible('playDate')"
  217. width="160"
  218. prop="playDateBegin"
  219. label="游玩时间">
  220. <template slot-scope="scope">
  221. <div v-if="scope.row.batchConfigName"><span>场次:</span>{{ scope.row.batchConfigName || '' }}</div>
  222. {{ scope.row.playDateBegin || scope.row.playDateEnd ? `${scope.row.playDateBegin || ''} - ${scope.row.playDateEnd || ''}` : "无限制" }}
  223. </template>
  224. </el-table-column>
  225. <el-table-column
  226. v-if="isColumnVisible('checkScenic')"
  227. min-width="180"
  228. label="检票景点">
  229. <template slot-scope="scope">
  230. {{ scope.row.ticketCheckScenicList.map(item => item.scenicName).join(',') }}
  231. </template>
  232. </el-table-column>
  233. <!-- 新增功能 -->
  234. <el-table-column width="240" prop="billingInformation" label="开票信息">
  235. <template slot-scope="scope">
  236. <div class=""><span>开票状态:</span>
  237. <el-tag :type="scope.row.isInvoice ? 'success' : 'info'">
  238. {{ scope.row.isInvoice ? "已开票" : "未开票" }}
  239. </el-tag>
  240. </div>
  241. <div class=""><span>发票信息:</span><button @click.prevent.stop="downloadInvoice(scope.row.invoiceDownloadUrl)">点击下载</button></div>
  242. </template>
  243. </el-table-column>
  244. <el-table-column
  245. v-if="isColumnVisible('ticketCardInfo')"
  246. width="240"
  247. prop="ticketCardInfo"
  248. label="卡信息">
  249. <template slot-scope="scope" v-if="scope.row.card">
  250. <div class=""><span>卡片编号:</span>{{ scope.row.card.cardNo }}</div>
  251. <div class=""><span>有效时间:</span>{{ scope.row.card.validDateStart }} - {{ scope.row.card.validDateEnd }}</div>
  252. <div class=""><span>卡片状态:</span>{{ scope.row.card.status | filterCardStatus }}</div>
  253. <div class="" v-if="scope.row.card.status === 1"><span>开卡时间:</span>{{ scope.row.card.activeTime }}</div>
  254. <div class="" v-if="scope.row.card.status === 0"><span>退卡时间:</span>{{ scope.row.card.cardNo }}</div>
  255. <div class="" v-if="scope.row.card.status === 2"><span>挂失时间:</span>{{ scope.row.card.repealTime }}</div>
  256. </template>
  257. </el-table-column>
  258. <el-table-column
  259. v-if="isColumnVisible('ticketFaceInfo')"
  260. width="240"
  261. prop="ticketFaceInfo"
  262. label="人脸信息">
  263. <template slot-scope="scope" v-if="scope.row.face">
  264. <div class=""><span>有效时间:</span>{{ scope.row.face.validDateStart }} - {{ scope.row.face.validDateEnd }}</div>
  265. <div class=""><span>卡片状态:</span>{{ scope.row.face.status === 0 ? '可用' : '不可用' }}</div>
  266. <div class=""><span>图片地址:</span>{{ scope.row.face.imageUrl }}</div>
  267. <div class=""><span>base64:</span>{{ scope.row.face.faceData }}</div>
  268. <div class=""><span>注册状态:</span>{{ scope.row.face.registerStatus === 0 ? '未注册' : '已注册' }}</div>
  269. </template>
  270. </el-table-column>
  271. </el-table>
  272. <!-- <el-table :data="checkDetailList" :max-height="200">
  273. <el-table-column prop="ticketNo" label="票号"> </el-table-column>
  274. <el-table-column prop="ticketTypeName" label="票种"> </el-table-column>
  275. <el-table-column width="80" prop="price" label="票价(¥)">
  276. <template slot-scope="scope">
  277. {{ scope.row.checkNum ? scope.row.price / scope.row.checkNum : scope.row.price }}
  278. </template>
  279. </el-table-column>
  280. <el-table-column
  281. prop="scenicName"
  282. label="景点"
  283. ></el-table-column>
  284. <el-table-column
  285. prop="checkLimitTimes"
  286. label="可检票次数"
  287. >
  288. <template slot-scope="scope">
  289. {{ scope.row.checkLimitTimes === -1 ? "无限制" : scope.row.checkLimitTimes }}
  290. </template>
  291. </el-table-column>
  292. <el-table-column
  293. prop="checkedTimes"
  294. label="已检票次数"
  295. ></el-table-column>
  296. </el-table> -->
  297. <div class="title" style="display: flex;justify-content: space-between;margin: 10px 0;">
  298. 门票检票日志
  299. <el-input v-model="ticketNoSearch2" placeholder="输入票号查询"></el-input>
  300. </div>
  301. <el-table border :data="checkLogList" :max-height="200">
  302. <el-table-column prop="ticketNo" label="票号"> </el-table-column>
  303. <!-- <el-table-column prop="ticketTypeName" label="票种"> </el-table-column>
  304. <el-table-column width="80" prop="price" label="票价(¥)">
  305. <template slot-scope="scope">
  306. {{ scope.row.checkNum ? scope.row.price / scope.row.checkNum : scope.row.price }}
  307. </template>
  308. </el-table-column> -->
  309. <el-table-column prop="checkType" label="检票类型">
  310. <template slot-scope="prop">
  311. {{ prop.row.checkType | checkTypeFilter }}
  312. </template>
  313. </el-table-column>
  314. <el-table-column prop="scenicName" label="景点名称"> </el-table-column>
  315. <el-table-column prop="checkerAdminName" label="检票员"> </el-table-column>
  316. <el-table-column prop="checkerName" label="检票设备名称"> </el-table-column>
  317. <el-table-column prop="checkTime" label="检票时间"> </el-table-column>
  318. </el-table>
  319. </el-tab-pane>
  320. <el-dialog
  321. title="选择显示列"
  322. :visible.sync="dialogVisible"
  323. append-to-body>
  324. <el-checkbox-group v-model="tempSelectedColumns">
  325. <el-checkbox v-for="column in fixedColumns" :key="column.value" :label="column.value">{{ column.label }}</el-checkbox>
  326. </el-checkbox-group>
  327. <span slot="footer" class="dialog-footer">
  328. <el-button @click="dialogVisible = false">取 消</el-button>
  329. <el-button type="primary" @click="saveUserConfig">确 定</el-button>
  330. </span>
  331. </el-dialog>
  332. <el-tab-pane class="block-title" label="支付信息" name="payInfo">
  333. <el-form-item label="支付方式">
  334. {{ orderData.payChannel }}
  335. </el-form-item>
  336. <template v-if="orderData.payContext">
  337. <div class="title">支付信息列表</div>
  338. <el-table border :data="orderData.payContext.payList || []">
  339. <el-table-column prop="orderNo" label="支付订单号">
  340. </el-table-column>
  341. <el-table-column prop="payStatus" label="支付状态">
  342. <template slot-scope="scope">
  343. <el-tag :type="getPayStatus(scope.row.payStatus, 'type')">
  344. {{ getPayStatus(scope.row.payStatus) }}
  345. </el-tag>
  346. </template>
  347. </el-table-column>
  348. <el-table-column prop="submitTime" label="提交时间"> </el-table-column>
  349. <el-table-column prop="payTime" label="支付完成时间">
  350. </el-table-column>
  351. <el-table-column prop="fee" label="支付金额">
  352. </el-table-column>
  353. <el-table-column prop="outOrderNo" label="合作方订单号">
  354. </el-table-column>
  355. <el-table-column prop="errMsg" label="支付错误信息">
  356. </el-table-column>
  357. </el-table>
  358. <div class="title">退款信息</div>
  359. <el-table border :data="orderData.payContext.payRefundList || []">
  360. <el-table-column prop="status" label="退款状态">
  361. <template slot-scope="scope">
  362. {{ ({ SUBMIT: '已提交', UNKNOWN: '未知', SUCCESS: '成功', FAILURE: '失败' })[scope.row.status] || scope.row.status }}
  363. </template>
  364. </el-table-column>
  365. <el-table-column prop="refundFee" label="退款金额">
  366. </el-table-column>
  367. <el-table-column prop="refundOrderNo" label="退款订单号">
  368. </el-table-column>
  369. <el-table-column prop="outRefundOrderNo" label="第三方退款单号">
  370. </el-table-column>
  371. <el-table-column prop="submitTime" label="退款提交时间">
  372. </el-table-column>
  373. <el-table-column prop="completeTime" label="退款完成时间">
  374. </el-table-column>
  375. <el-table-column prop="errMsg" label="退款错误信息">
  376. </el-table-column>
  377. </el-table>
  378. <div class="title">退款明细</div>
  379. <el-table
  380. border
  381. :data="orderData.payContext.payRefundTaskList || []">
  382. <el-table-column prop="status" label="退款明细状态">
  383. <template slot-scope="scope">
  384. {{ ({ CREATE: '已创建', NEED_RETRY: '待重试', UNKNOWN: '未知', REFUND_SUCCESS: '退款成功', SUCCESS: '退款完成', FAILURE: '失败' })[scope.row.status] || scope.row.status }}
  385. </template>
  386. </el-table-column>
  387. <el-table-column prop="refundFee" label="退款金额">
  388. </el-table-column>
  389. <el-table-column prop="refundRetryCount" label="退款重试次数">
  390. </el-table-column>
  391. <el-table-column prop="submitTime" label="退款提交时间">
  392. </el-table-column>
  393. <el-table-column prop="completeTime" label="退款完成时间">
  394. </el-table-column>
  395. <el-table-column prop="errMsg" label="退款错误信息">
  396. </el-table-column>
  397. </el-table>
  398. <!-- 新增功能:工行分账信息,但if判断需要后续改动 -->
  399. <div class="title" v-if="orderData.payContext" style="display: flex;justify-content: space-between;margin: 10px 0;">
  400. 工行分账明细
  401. </div>
  402. <el-table border :data="orderData.payContext.payGonghangSplitRecordList || []" :max-height="200">
  403. <el-table-column prop="id" label="ID"> </el-table-column>
  404. <el-table-column prop="createTime" label="创建时间"> </el-table-column>
  405. <el-table-column prop="recNum" label="拆分顺序号"> </el-table-column>
  406. <el-table-column prop="originalGhMerId" label="原交易商户编号"> </el-table-column>
  407. <el-table-column prop="ghOrderId" label="原工行订单编号"> </el-table-column>
  408. <el-table-column prop="ghAppId" label="应用APPID"> </el-table-column>
  409. <el-table-column prop="subMerId" label="分账二级商户编号"> </el-table-column>
  410. <el-table-column prop="subMerPrtclNo" label="分账二级商户协议编号"> </el-table-column>
  411. <el-table-column prop="subOrderId" label="商户子订单编号"> </el-table-column>
  412. <el-table-column prop="ghSubOrderId" label="工行子订单编号"> </el-table-column>
  413. <el-table-column prop="ghSubOrderTransactionId" label="工行交易流水号"> </el-table-column>
  414. <el-table-column prop="splitFee" label="分账金额"> </el-table-column>
  415. <el-table-column prop="termId" label="交易终端号"> </el-table-column>
  416. <el-table-column prop="status" label="分账状态"> </el-table-column>
  417. <el-table-column prop="splitSubmitTime" label="分账开始时间"> </el-table-column>
  418. <el-table-column prop="splitCompleteTime" label="分账完成时间"> </el-table-column>
  419. <el-table-column prop="splitCode" label="错误代码"> </el-table-column>
  420. <el-table-column prop="splitMsg" label="错误信息"> </el-table-column>
  421. <el-table-column prop="refundSubOrderId" label="子订单退货编号"> </el-table-column>
  422. <el-table-column prop="refundSubmitTime" label="退款提交时间"> </el-table-column>
  423. <el-table-column prop="refundCompleteTime" label="退款开始时间"> </el-table-column>
  424. <el-table-column prop="refundFee" label="退款金额"> </el-table-column>
  425. <el-table-column prop="refundCode" label="退款错误代码"> </el-table-column>
  426. <el-table-column prop="refundMsg" label="退款错误信息"> </el-table-column>
  427. </el-table>
  428. </template>
  429. </el-tab-pane>
  430. <!-- <el-tab-pane class="block-title" label="购票信息" name="customerInfo">
  431. <div style="display: flex;justify-content: space-between;">
  432. <el-form-item label="包含的票数">
  433. {{ orderData.ticketNum || 0 }}
  434. </el-form-item>
  435. <el-input v-model="ticketNoSearch" placeholder="输入票号查询"></el-input>
  436. </div>
  437. <el-table border :data="orderTicketList" :max-height="400">
  438. <el-table-column type="expand">
  439. <template slot-scope="props">
  440. <div class="title">检票景点明细</div>
  441. <el-table :data="props.row.ticketCheckScenicList" :max-height="200">
  442. <el-table-column
  443. prop="scenicName"
  444. label="景点"
  445. ></el-table-column>
  446. <el-table-column
  447. prop="checkLimitTimes"
  448. label="可检票次数"
  449. >
  450. <template slot-scope="scope">
  451. {{ scope.row.checkLimitTimes === -1 ? "无限制" : scope.row.checkLimitTimes }}
  452. </template>
  453. </el-table-column>
  454. <el-table-column
  455. prop="checkedTimes"
  456. label="已检票次数"
  457. ></el-table-column>
  458. </el-table>
  459. </template>
  460. </el-table-column>
  461. <el-table-column width="160" prop="ticketNo" label="票号"> </el-table-column>
  462. <el-table-column width="100" prop="ticketTypeName" label="票种"> </el-table-column>
  463. <el-table-column width="80" prop="price" label="票价(¥)">
  464. <template slot-scope="scope">
  465. {{ scope.row.checkNum ? scope.row.price / scope.row.checkNum : scope.row.price }}
  466. </template>
  467. </el-table-column>
  468. <el-table-column width="100" prop="guestName" label="游客姓名">
  469. </el-table-column>
  470. <el-table-column width="140" prop="guestPhone" label="游客手机号">
  471. </el-table-column>
  472. <el-table-column width="100" prop="guestIdentifyType" label="证件类型">
  473. <template slot-scope="scope">
  474. {{ papersType[scope.row.guestIdentifyType] }}
  475. </template>
  476. </el-table-column>
  477. <el-table-column prop="guestIdentify" label="证件号码">
  478. </el-table-column>
  479. <el-table-column width="80" prop="checkNum" label="检票人数">
  480. </el-table-column>
  481. <el-table-column width="160" prop="playDateBegin" label="游玩时间">
  482. <template slot-scope="scope">
  483. {{ scope.row.playDateBegin || scope.row.playDateEnd ? `${scope.row.playDateBegin || ''} - ${scope.row.playDateEnd || ''}` : "无限制" }}
  484. </template>
  485. </el-table-column>
  486. <el-table-column width="80" label="取票状态">
  487. <template slot-scope="scope">
  488. <el-tag :type="scope.row.isPrint ? 'success' : 'info'">
  489. {{ scope.row.isPrint ? "已取票" : "未取票" }}
  490. </el-tag>
  491. </template>
  492. </el-table-column>
  493. <el-table-column width="80" label="状态">
  494. <template slot-scope="scope">
  495. <TicketStatusTag :value="scope.row.status"></TicketStatusTag>
  496. </template>
  497. </el-table-column>
  498. <el-table-column width="80" prop="price" label="小计">
  499. </el-table-column>
  500. <el-table-column min-width="180" label="检票景点">
  501. <template slot-scope="scope">
  502. {{ scope.row.ticketCheckScenicList.map(item => item.scenicName).join(',') }}
  503. </template>
  504. </el-table-column>
  505. </el-table>
  506. </el-tab-pane> -->
  507. <el-tab-pane class="block-title" label="修改记录" name="orderUpdateLog">
  508. <el-table border :data="orderData.orderUpdateLogList" :max-height="400">
  509. <el-table-column prop="updateType" label="修改类型">
  510. <template slot-scope="scope">
  511. {{ scope.row.updateType | updateTypeFilter }}
  512. </template>
  513. </el-table-column>
  514. <el-table-column prop="orderNo" label="订单号">
  515. </el-table-column>
  516. <el-table-column prop="ticketNo" label="票号">
  517. </el-table-column>
  518. <el-table-column prop="oldValue" label="修改前">
  519. <template slot-scope="scope">
  520. {{ getValueDetail(scope.row, 'oldValue') }}
  521. </template>
  522. </el-table-column>
  523. <el-table-column prop="newValue" label="修改后">
  524. <template slot-scope="scope">
  525. {{ getValueDetail(scope.row, 'newValue') }}
  526. </template>
  527. </el-table-column>
  528. <el-table-column prop="updateAdminName" label="操作人">
  529. </el-table-column>
  530. <el-table-column prop="createTime" label="修改时间">
  531. </el-table-column>
  532. </el-table>
  533. </el-tab-pane>
  534. <el-tab-pane class="block-title" label="补打信息" name="secondPrintInfo">
  535. <el-table border :data="orderData.ticketSecondPrintLogList" :max-height="400">
  536. <el-table-column prop="printAdminName" label="操作人"> </el-table-column>
  537. <el-table-column prop="printTime" label="操作时间"> </el-table-column>
  538. </el-table>
  539. </el-tab-pane>
  540. </el-tabs>
  541. <el-dialog
  542. label="检票景点明细"
  543. :visible.sync="detailVisible"
  544. append-to-body
  545. >
  546. <div style="padding:20px">
  547. <el-table :data="record.ticketListScenic">
  548. <el-table-column
  549. prop="scenic_name"
  550. label="景点"
  551. ></el-table-column>
  552. <el-table-column
  553. prop="checkLimitTimes"
  554. label="可检票次数"
  555. ></el-table-column>
  556. <el-table-column
  557. prop="checked_times"
  558. label="已检票次数"
  559. ></el-table-column>
  560. </el-table>
  561. </div>
  562. </el-dialog>
  563. </el-form>
  564. </el-dialog>
  565. </template>
  566. <script>
  567. import { channelList, IDENTIFY_TYPES } from '@/assets/staticData'
  568. import { getPayStatus } from '@/utils/index'
  569. import { addUserConfig, getUserConfig } from '@/api/configSetting'
  570. import QRCode from 'qrcode'
  571. const fixedColumns = [
  572. { value: 'ticketNo', label: '票号' },
  573. { value: 'ticketTypeName', label: '票种' },
  574. { value: 'unitPrice', label: '单价(¥)' },
  575. { value: 'subtotal', label: '小计' },
  576. { value: 'status', label: '状态' },
  577. { value: 'guestInfo', label: '游客信息' },
  578. { value: 'ticketCheckInfo', label: '检票信息' },
  579. { value: 'ticketPrintInfo', label: '取票信息' },
  580. { value: 'ticketRefundInfo', label: '退票信息' },
  581. { value: 'playDate', label: '游玩时间' },
  582. { value: 'checkScenic', label: '检票景点' },
  583. { value: 'ticketCardInfo', label: '卡信息' },
  584. { value: 'ticketFaceInfo', label: '人脸信息' }
  585. ]
  586. const STAT_KEY = 'orderDetailTicketColumns'
  587. export default {
  588. created () {
  589. this.posType = this.$localStore.get('posType')
  590. },
  591. computed: {
  592. previewList () {
  593. return this.orderData.pictureRemarks.map(i => i.url)
  594. },
  595. orderTicketList () {
  596. if (!this.orderData) return []
  597. return this.orderData.ticketList.filter(i =>
  598. this.ticketNoSearch
  599. ? i.ticketNo.includes(this.ticketNoSearch)
  600. : true
  601. )
  602. },
  603. checkDetailList () {
  604. if (!this.orderData) return []
  605. return this.orderData.ticketList.filter(i =>
  606. this.ticketNoSearch1
  607. ? !!i.ticketNo.includes(this.ticketNoSearch1)
  608. : true
  609. )
  610. },
  611. checkLogList () {
  612. if (!this.orderData) return []
  613. return this.ticketCheckLogList.filter(i =>
  614. this.ticketNoSearch2
  615. ? !!i.ticketNo.includes(this.ticketNoSearch2)
  616. : true
  617. )
  618. }
  619. },
  620. data () {
  621. return {
  622. channelList,
  623. papersType: IDENTIFY_TYPES,
  624. posType: '',
  625. orderData: null,
  626. visible: false,
  627. detailVisible: false,
  628. record: {},
  629. activeTab: 'ticketCheckInfo',
  630. dialogVisible: false,
  631. fixedColumns,
  632. selectedColumns: fixedColumns.map(i => i.value),
  633. tempSelectedColumns: fixedColumns.map(i => i.value),
  634. ticketNoSearch: '',
  635. ticketNoSearch1: '',
  636. ticketNoSearch2: '',
  637. ticketCheckScenicList: [],
  638. ticketSecondPrintLogList: [],
  639. ticketCheckLogList: []
  640. }
  641. },
  642. filters: {
  643. checkTypeFilter (input) {
  644. switch (input) {
  645. case 'qrcode':
  646. return '二维码'
  647. case 'face':
  648. return '人脸'
  649. case 'card':
  650. return 'IC卡'
  651. case 'idcard':
  652. return '身份证'
  653. case 'manual_check':
  654. return '人工检票'
  655. case 'print_check':
  656. return '取票即检票'
  657. case 'buy_check':
  658. return '购买即检票'
  659. default:
  660. break
  661. }
  662. },
  663. formatCategory (input) {
  664. switch (input) {
  665. case 'ticket':
  666. return '景区门票'
  667. case 'batch':
  668. return '场次售票'
  669. case 'member':
  670. return '年卡次卡'
  671. case 'other':
  672. return '其他'
  673. default:
  674. break
  675. }
  676. },
  677. updateTypeFilter (input) {
  678. switch (input) {
  679. case 'updateOrderPayChannel':
  680. return '订单修改支付方式'
  681. case 'updatePlayDate':
  682. return '门票修改游玩日期'
  683. case 'updateScenicTimes':
  684. return '门票修改检票次数'
  685. default:
  686. break
  687. }
  688. },
  689. filterCardStatus (input) {
  690. switch (input) {
  691. case 0:
  692. return '未使用'
  693. case 1:
  694. return '使用中'
  695. case 2:
  696. return '已挂失'
  697. default:
  698. return input
  699. }
  700. }
  701. },
  702. methods: {
  703. getPayStatus,
  704. async getQrCodeImg (ticketNo) {
  705. const opts = {
  706. errorCorrectionLevel: 'H',
  707. type: 'image/png',
  708. quality: 1,
  709. color: {
  710. dark: '#000000ff', // Blue dots
  711. light: '#0000' // Transparent background
  712. }
  713. }
  714. const img = await QRCode.toDataURL(ticketNo, opts)
  715. return img
  716. },
  717. getValueDetail (row, key) {
  718. console.log(row, key)
  719. if (row.updateType === 'updatePlayDate') {
  720. try {
  721. const val = JSON.parse(row[key])
  722. if (val && val.playDateBegin && val.playDateEnd) {
  723. return `${val.playDateBegin} - ${val.playDateEnd}`
  724. }
  725. } catch (error) {
  726. return ''
  727. }
  728. }
  729. return row[key]
  730. },
  731. async show (data) {
  732. this.orderData = data
  733. this.visible = true
  734. this.loadUserConfig(true)
  735. if (data.pictureRemarks) {
  736. data.pictureRemarks = data.pictureRemarks.filter(i => i.url)
  737. }
  738. this.ticketCheckScenicList = []
  739. this.ticketCheckLogList = []
  740. this.ticketSecondPrintLogList = []
  741. if (this.orderData.ticketList) {
  742. this.orderData.ticketList.forEach(async ticket => {
  743. const { ticketNo, ticketTypeName, price, ticketCheckScenicList, ticketCheckLogList, ticketSecondPrintLogList } = ticket
  744. const ticketNoImg = await this.getQrCodeImg(ticketNo)
  745. this.$set(ticket, 'ticketNoImg', ticketNoImg)
  746. if (ticketCheckScenicList && ticketCheckScenicList.length) {
  747. ticketCheckScenicList.forEach((scenic) => {
  748. this.ticketCheckScenicList.push({
  749. ...scenic,
  750. ticketNo,
  751. ticketTypeName,
  752. price
  753. })
  754. })
  755. }
  756. if (ticketCheckLogList && ticketCheckLogList.length) {
  757. ticketCheckLogList.forEach((log) => {
  758. this.ticketCheckLogList.push({
  759. ...log,
  760. ticketNo,
  761. ticketTypeName,
  762. price
  763. })
  764. })
  765. }
  766. if (ticketSecondPrintLogList && ticketSecondPrintLogList.length) {
  767. ticketSecondPrintLogList.forEach((log) => {
  768. this.ticketSecondPrintLogList.push({
  769. ...log,
  770. ticketNo,
  771. ticketTypeName,
  772. price
  773. })
  774. })
  775. }
  776. })
  777. }
  778. },
  779. handleClose () {
  780. this.visible = false
  781. this.activeTab = 'ticketCheckInfo'
  782. this.orderData = null
  783. },
  784. showColumnConfig () {
  785. this.dialogVisible = true
  786. this.loadUserConfig(false)
  787. },
  788. loadUserConfig (applyToTable = true) {
  789. getUserConfig({ statKey: STAT_KEY }).then(config => {
  790. const fields = config?.data?.fields || config?.fields || config?.data?.columns || config?.columns || config?.data || []
  791. let nextSelected = []
  792. if (Array.isArray(fields) && fields.length) {
  793. nextSelected = fields
  794. .filter(i => Number(i.isShow) === 1)
  795. .map(i => i.fieldKey)
  796. } else {
  797. nextSelected = fixedColumns.map(i => i.value)
  798. }
  799. if (applyToTable) {
  800. this.selectedColumns = nextSelected
  801. }
  802. this.tempSelectedColumns = [...nextSelected]
  803. }).catch(() => {
  804. const nextSelected = fixedColumns.map(i => i.value)
  805. if (applyToTable) {
  806. this.selectedColumns = nextSelected
  807. }
  808. this.tempSelectedColumns = [...nextSelected]
  809. })
  810. },
  811. saveUserConfig () {
  812. const fields = this.fixedColumns.map(item => ({
  813. fieldKey: item.value,
  814. fieldName: item.label,
  815. isShow: this.tempSelectedColumns.includes(item.value) ? 1 : 0
  816. }))
  817. addUserConfig({ statKey: STAT_KEY, fields }).then(() => {
  818. this.selectedColumns = [...this.tempSelectedColumns]
  819. this.dialogVisible = false
  820. })
  821. },
  822. isColumnVisible (columnKey) {
  823. return this.selectedColumns.includes(columnKey)
  824. },
  825. copySuccess () {
  826. this.$message.success('复制成功')
  827. },
  828. copyError () {
  829. this.$message.error('复制失败')
  830. },
  831. showDetail (record) {
  832. this.record = record
  833. this.detailVisible = true
  834. },
  835. isValidUrl (url) {
  836. try {
  837. const raw = String(url || '').trim()
  838. if (!raw) return false
  839. const parsedUrl = new URL(raw, window.location.origin)
  840. return ['http:', 'https:'].includes(parsedUrl.protocol)
  841. } catch (error) {
  842. return false
  843. }
  844. },
  845. // 下载方法
  846. downloadInvoice (url) {
  847. console.log(' downloadInvoice', url)
  848. if (!this.isValidUrl(url)) {
  849. this.$message.warning('暂无发票可下载')
  850. } else {
  851. window.open(url)
  852. }
  853. }
  854. }
  855. }
  856. </script>
  857. <style lang="scss">
  858. .el-table__expanded-cell[class*=cell] {
  859. padding: 10px 20px !important;
  860. }
  861. </style>
  862. <style lang="scss" scoped>
  863. .dialog-info {
  864. .el-form-item {
  865. width: 25%;
  866. }
  867. }
  868. .el-icon-document {
  869. cursor: pointer
  870. }
  871. .pic-remark {
  872. li {
  873. display: flex;
  874. align-items: center;
  875. ::v-deep .el-image {
  876. margin-right: 10px;
  877. }
  878. }
  879. }
  880. </style>