Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. <template>
  2. <div>
  3. <crud-template v-if="itemStart" class="as-weight" :ref="(el) => crudRef = el" :home-data="field"
  4. @btnSearch="btnSearch" @refreshLeft="refreshLeft" :tableData="tableData" @CurrentChange="handleCurrentChange"
  5. @handleRemark="handleRemark" @cancel="cancel" @download="download" @pageSizeChange="(val) => {
  6. field.paging.currentPage = 1
  7. field.paging.pageSize = val
  8. getList()
  9. }">
  10. <template #search>
  11. <el-input maxlength="60" v-trim clearable v-model="searchForm.externalOrderNo" style="width: 160px;"
  12. placeholder="请输入支付单号" />
  13. <el-input maxlength="60" v-trim clearable v-model="searchForm.vehiclePlate" style="width: 160px;"
  14. placeholder="请输入车牌号" />
  15. <el-input maxlength="60" v-trim clearable v-model="searchForm.cardId" style="width: 160px;"
  16. placeholder="请输入卡号" />
  17. <el-select clearable v-model="searchForm.status" placeholder="请选择退费状态">
  18. <el-option v-for="item in statusList" :label="item.label" :value="item.value" />
  19. </el-select>
  20. <el-select clearable v-model="searchForm.businessPort" placeholder="请选择退费业务">
  21. <el-option v-for="item in portList" :label="item.label" :value="item.value" />
  22. </el-select>
  23. <div class="date-label">申请日期:</div>
  24. <el-date-picker unlink-panels clearable v-model="value1" type="daterange" range-separator="到"
  25. start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD" format="YYYY-MM-DD"
  26. @change="dateChangeHandle" :clearable="false" />
  27. </template>
  28. <template #operation="{ scope }">
  29. <el-button type="primary" @click="confirmRefund(scope.row)" size="small"
  30. v-if="scope.row.status === 'AUDITED' && IsPermission(route, 'REFUND_CONFIRM')">退款确认</el-button>
  31. <el-button type="primary" @click="handleCheck(scope.row.id, 'REFUNDED')" size="small"
  32. v-if="scope.row.status === 'ARTIFICIAL' && IsPermission(route, 'REFUNDED')">已退款</el-button>
  33. <el-button type="warning" @click="handleCheck(scope.row.id, 'REFUNDFAILED')" size="small"
  34. v-if="scope.row.status === 'ARTIFICIAL' && IsPermission(route, 'NO_REFUND')">未退款</el-button>
  35. </template>
  36. <template #dialog>
  37. <el-descriptions :column="3" border>
  38. <el-descriptions-item label="支付单号" label-align="right" align="center">{{ rowData.externalOrderNo
  39. }}</el-descriptions-item>
  40. <el-descriptions-item label="ETC卡号" label-align="right" align="center">{{ rowData.cardId
  41. }}</el-descriptions-item>
  42. <el-descriptions-item label="车牌号" label-align="right" align="center">{{ rowData.vehiclePlate
  43. }}</el-descriptions-item>
  44. <el-descriptions-item label="金额(元)" label-align="right" align="center">
  45. {{ conversion(rowData.amount) }}
  46. </el-descriptions-item>
  47. <el-descriptions-item label="状态" label-align="right" align="center">
  48. {{ getDictLabel(statusList, rowData.status) }}
  49. </el-descriptions-item>
  50. <el-descriptions-item label="业务端口" label-align="right" align="center">
  51. {{ getDictLabel(portList, rowData.businessPort) }}
  52. </el-descriptions-item>
  53. <el-descriptions-item label="申请时间" label-align="right" align="center">{{ rowData.insertTime
  54. }}</el-descriptions-item>
  55. <el-descriptions-item v-if="rowData.salesmanNickName !== null" label="业务员" label-align="right"
  56. align="center">{{
  57. rowData.salesmanNickName }}</el-descriptions-item>
  58. <el-descriptions-item label="联系人姓名" label-align="right" align="center">{{ rowData.userName
  59. }}</el-descriptions-item>
  60. <el-descriptions-item label="手机号" label-align="right" align="center">{{ rowData.userMobile
  61. }}</el-descriptions-item>
  62. <el-descriptions-item label="退费方式" label-align="right" align="center">
  63. {{ getDictLabel(refundOperateTypeList, rowData.operateType) }}
  64. </el-descriptions-item>
  65. </el-descriptions>
  66. <el-descriptions title="银行卡退费信息" v-if="rowData.operateType === 'BANK'" :column="3" border>
  67. <el-descriptions-item label="开户行" label-align="right" align="center">
  68. {{ getDictLabel(bankTypeList, rowData.bankType) }}
  69. </el-descriptions-item>
  70. <el-descriptions-item label="银行卡号" label-align="right" align="center">
  71. {{ rowData.bankCardId }}
  72. </el-descriptions-item>
  73. <el-descriptions-item label="开户行所在的省" label-align="right" align="center">
  74. {{ rowData.province }}
  75. </el-descriptions-item>
  76. <el-descriptions-item label="开户行所在的市" label-align="right" align="center">
  77. {{ rowData.sell }}
  78. </el-descriptions-item>
  79. <el-descriptions-item label="开户人名称" label-align="right" align="center">
  80. {{ rowData.cusName }}
  81. </el-descriptions-item>
  82. <el-descriptions-item label="开户用户类型" label-align="right" align="center">
  83. {{ getDictLabel(cusTypeList, rowData.cusType) }}</el-descriptions-item>
  84. <el-descriptions-item label="开户人联系方式" label-align="right" align="center">
  85. {{ rowData.cusTel }}
  86. </el-descriptions-item>
  87. <el-descriptions-item label="开户行支行名称" label-align="right" align="center">
  88. {{ rowData.branchName }}
  89. </el-descriptions-item>
  90. </el-descriptions>
  91. <el-descriptions title="实际退费信息" v-if="refundBtn || rowData.refundAmount" :column="3" border>
  92. <el-descriptions-item label="实际退费金额(元)" label-align="right" align="center">
  93. {{ rowData.refundAmount }}
  94. </el-descriptions-item>
  95. </el-descriptions>
  96. <el-descriptions title="付费银行账号信息" v-if="rowData.operateType === 'BANK'" :column="2" border>
  97. <el-descriptions-item label="付费银行" label-align="right" align="center" v-if="refundBtn">
  98. <el-select clearable v-model="rowData.paymentBankType" :disabled="!refundBtn" class="m-2"
  99. placeholder="请选择付费银行">
  100. <el-option v-for="item in bankTypeList" :key="item.value" :label="item.label" :value="item.value" />
  101. </el-select>
  102. </el-descriptions-item>
  103. <el-descriptions-item label="付费银行卡号" label-align="right" align="center" v-if="refundBtn">
  104. <el-input maxlength="60" v-trim clearable v-model="rowData.paymentBankCardId" :disabled="!refundBtn"
  105. placeholder="请输入银行卡号" />
  106. </el-descriptions-item>
  107. <el-descriptions-item label="付费银行" label-align="right" align="center" v-if="!refundBtn">
  108. {{ getDictLabel(bankTypeList, rowData.paymentBankType) }}
  109. </el-descriptions-item>
  110. <el-descriptions-item label="付费银行卡号" label-align="right" align="center" v-if="!refundBtn">
  111. {{ rowData.paymentBankCardId }}
  112. </el-descriptions-item>
  113. </el-descriptions>
  114. </template>
  115. <template #footer>
  116. <el-button type="primary" @click="refundSubmit(rowData.id, 'CONFIRM')" v-if="refundBtn">退费确认</el-button>
  117. <el-button type="primary" @click="refundSubmit(rowData.id, 'REFUNDFAILED')" v-if="refundBtn">重新审核</el-button>
  118. <el-button type="primary" @click="cancellation" v-if="refundBtn">取消</el-button>
  119. </template>
  120. </crud-template>
  121. </div>
  122. </template>
  123. <!-- 退款管理 -->
  124. <script lang="ts" setup>
  125. // @ts-ignore crudFrom模板
  126. import CrudTemplate from '@/crud/index.vue'
  127. import { reactive, ref, toRaw, getCurrentInstance, onMounted, computed } from 'vue'
  128. import { ElNotification, ElMessage } from "element-plus";
  129. import Cookies from 'js-cookie'
  130. import { useDebounce, getDictLabel } from "@/utils/utils";
  131. import BaseService from "@/utils/baseService";
  132. import { IHttpResponse, IObject } from "@/types/interface";
  133. import { logListApi } from "@/api/api";
  134. import { cloneDeep } from 'lodash';
  135. import { refundPageApi, refundQueryApi, refundExamineApi, refundOncemoreApi, refundCheckApi, refundConfirmApi, refundExportApi } from "@/api/onlineBusinessHall/salesAndQuery";
  136. import $storeinitData from "@/store/initData";
  137. import { useRoute } from 'vue-router';
  138. import { IsPermission } from "@/router/routerUtil";
  139. import { getDefaultTime } from '../../exportFn';
  140. import moment from 'moment';
  141. //或取路由传入过来的对象数据
  142. const route = useRoute();
  143. const crudRef = ref()
  144. const itemStart = ref(true)
  145. const tableType = ref("REQUESTED");
  146. const refundBtn = ref(false);
  147. const searchForm = ref({
  148. orderId: "",
  149. vehicleId: "",
  150. cardId: "",
  151. beginTime: "",
  152. finishTime: ""
  153. })
  154. const statusList = computed(() => {
  155. return $storeinitData.state.dictData['REFUND_STATUS'] || []
  156. })
  157. const portList = computed(() => {
  158. return $storeinitData.state.dictData['REFUND_BUSINESS'] || []
  159. })
  160. const refundOperateTypeList = computed(() => {
  161. return $storeinitData.state.dictData['REFUND_OPERATE_TYPE'] || []
  162. })
  163. const cusTypeList = computed(() => {
  164. return $storeinitData.state.dictData['CUS_TYPE'] || []
  165. })
  166. const bankTypeList = computed(() => {
  167. return $storeinitData.state.dictData['BANK_TYPE'] || []
  168. })
  169. const refundNum = ref(0)
  170. const tableData = ref([] as any[]);
  171. const rowData = ref({});
  172. const initItem = {
  173. id: "",
  174. };
  175. const addForm: any = ref(initItem);
  176. //表单数据配置
  177. const field = ref({
  178. tabSize: 'small', //Table 的尺寸 large / default /small (默认default)
  179. searchShow: IsPermission(route, 'QUERY_BASE'), //是否显示搜索模块(默认false)
  180. border: true, //是否添加边框(默认false)
  181. dialogCustom: true, //自定义Dialog (默认false)
  182. dialogFooter: true, //隐藏弹窗页脚显示 (默认false)
  183. dialogWidth: '60%', //dialog宽度 (默认40%)
  184. crudShow: true, //是否显示CURD操作栏 (默认true)
  185. crudChildShow: true, //是否显示CURD子操作栏 (默认true)
  186. paginStart: true, //是否显示分页查询 (默认false)
  187. isPageSizes: true,
  188. pageLayout: 'total, sizes, prev, pager, next',
  189. titleDialog: "", //table 标题
  190. tableOperation: true,
  191. paging: {
  192. pageSize: 10,
  193. currentPage: 1,
  194. total: 0
  195. },
  196. crud: {
  197. add: false,
  198. edit: false,
  199. delete: false,
  200. derive: false,
  201. search: false,
  202. refresh: false,
  203. },
  204. searchOperation: {
  205. isDownload: true,
  206. isAdd: false,
  207. isTransferMachine: false
  208. },
  209. tableSize: -1,
  210. operateShow: true, //是否为表格添加操作栏(默认true)
  211. operateTitle: '操作', //操作栏标题(默认为"")
  212. operateFixed: false, //操作栏是否固定(默认false)
  213. operateWidth: '150', //操作栏宽度
  214. operate: {
  215. edit: false, //是否编辑(默认true)
  216. delete: false, //是否删除(默认true)
  217. announcement: false, // 公告
  218. remark: IsPermission(route, 'VIEW_LIST'), // 详情
  219. forbidden: false, // 禁用
  220. enable: false, // 启用
  221. authorization: false, // 授权
  222. cancel: false,// 取消订单
  223. writeOff: false,// 注销
  224. make: false,// 补缴
  225. },
  226. extend: [
  227. {
  228. type: 'index',
  229. label: '序号',
  230. },
  231. ],
  232. field: [
  233. {
  234. label: '支付单号',
  235. prop: 'externalOrderNo',
  236. },
  237. {
  238. label: '卡号',
  239. prop: 'cardId',
  240. },
  241. {
  242. label: '车牌号',
  243. prop: 'vehiclePlate',
  244. },
  245. {
  246. label: '金额(元)',
  247. prop: 'amount',
  248. unit: "元",
  249. funRuleStarts: true,
  250. funRule: (val: any) => {
  251. var m = 0;
  252. var s1 = val.toString();
  253. var s2 = '0.01'.toString();
  254. try {
  255. m += s1.split(".")[1].length;
  256. } catch (e) { }
  257. try {
  258. m += s2.split(".")[1].length;
  259. } catch (e) { }
  260. return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m);
  261. // return val === null ? 0+"元" : val*0.01+"元"
  262. },
  263. },
  264. {
  265. label: '状态',
  266. prop: 'status',
  267. width: "170",
  268. funRuleStarts: true,
  269. funRule: (val: any) => {
  270. return getDictLabel(statusList.value, val)
  271. },
  272. },
  273. {
  274. label: '业务端口',
  275. prop: 'businessPort',
  276. width: "170",
  277. funRuleStarts: true,
  278. funRule: (val: any) => {
  279. return getDictLabel(portList.value, val)
  280. },
  281. },
  282. {
  283. label: '操作员',
  284. prop: 'salesmanNickName',
  285. },
  286. {
  287. prop: 'insertTime',
  288. label: '创建时间',
  289. width: '170px',
  290. funRuleStarts: true,
  291. funRule: (val: any) => {
  292. if (val) {
  293. return val.replaceAll('T', ' ')
  294. }
  295. return val
  296. },
  297. },
  298. {
  299. prop: 'auditTime',
  300. label: '审核时间',
  301. width: '170px',
  302. funRuleStarts: true,
  303. funRule: (val: any) => {
  304. if (val) {
  305. return val.replaceAll('T', ' ')
  306. }
  307. return val
  308. },
  309. },
  310. ],
  311. })
  312. // 搜索按钮
  313. function btnSearch() {
  314. field.value.paging.currentPage = 1;
  315. getList();
  316. }
  317. // 搜索重置
  318. function refreshLeft() {
  319. field.value.paging.currentPage = 1;
  320. searchForm.value = {
  321. orderId: "",
  322. vehicleId: "",
  323. cardId: "",
  324. beginTime: "",
  325. finishTime: ""
  326. }
  327. value1.value = []
  328. tableData.value = [];
  329. getList();
  330. }
  331. // const defaultTime: [Date, Date] = getDefaultTime('day', 1,'YYYY-MM-DD')
  332. // const value1: any = ref(defaultTime) // 筛选时间
  333. const value1 = ref([])
  334. // 时间
  335. function dateChangeHandle(val) {
  336. if (val) {
  337. searchForm.value.beginTime = val[0] + 'T00:00:00';
  338. searchForm.value.finishTime = val[1] + 'T23:59:59';
  339. } else {
  340. searchForm.value.beginTime = "";
  341. searchForm.value.finishTime = ""
  342. }
  343. }
  344. // function dateChange(time) {
  345. // if (time) {
  346. // time = moment(time).format("YYYY-MM-DD");
  347. // }
  348. // return time
  349. // }
  350. function download() {
  351. crudRef.value.tableLoding = true;
  352. let params: any = {
  353. }
  354. let searchFormList = { ...searchForm.value }
  355. for (let key in searchFormList) {
  356. if (searchFormList[key]) {
  357. params[key] = searchFormList[key]
  358. }
  359. }
  360. BaseService.postN('/settlew/agencymapping/refundexport', params).then((res: any) => {
  361. if (res && res.code === 0) {
  362. let bizContent = res.data
  363. BaseService.getDownload(import.meta.env.VITE_APP_UPLOAD_URL + bizContent.fileUrl, "退费信息")
  364. crudRef.value.tableLoding = false;
  365. getList()
  366. } else {
  367. crudRef.value.tableLoding = false;
  368. ElMessage.error(res.message)
  369. getList()
  370. }
  371. })
  372. }
  373. function getList() {
  374. crudRef.value.tableLoding = true;
  375. let params: any = {
  376. pageNo: field.value.paging.currentPage,
  377. pageSize: field.value.paging.pageSize,
  378. suppleStatus: tableType.value
  379. }
  380. let searchFormList = { ...searchForm.value }
  381. for (let key in searchFormList) {
  382. if (searchFormList[key]) {
  383. params[key] = searchFormList[key]
  384. }
  385. }
  386. BaseService.postN('/settlew/agencymapping/refundpage', params).then((res: any) => {
  387. if (res && res.code === 0) {
  388. let bizContent = res.data
  389. let data = bizContent.data || [];
  390. console.log("====data", data)
  391. tableData.value = data;
  392. crudRef.value.tableLoding = false;
  393. field.value.paging.total = bizContent.totalCount;
  394. } else {
  395. crudRef.value.tableLoding = false;
  396. ElMessage.error(res.message)
  397. }
  398. })
  399. }
  400. function handleCurrentChange(val: number) {
  401. field.value.paging.currentPage = val;
  402. getList();
  403. }
  404. // 导出
  405. function downloadHandle() {
  406. }
  407. // 切换列表
  408. // function tableTypeChange(val) {
  409. // if (val) {
  410. // let findItem = radioData.find((item) => item.value === val);
  411. // console.log("item", findItem)
  412. // if (findItem) {
  413. // crudRef.value.tableFrom.field = findItem.fieldData || [];
  414. // }
  415. // refreshLeft();
  416. // }
  417. // }
  418. function confirmRefund(row: IObject) {
  419. getRow(row.id)
  420. refundBtn.value = true;
  421. crudRef.value.title = "退款确认";
  422. crudRef.value.dialogFormVisible = true;
  423. }
  424. function cancellation() {
  425. refundBtn.value = false;
  426. crudRef.value.dialogFormVisible = false;
  427. }
  428. //查看
  429. function handleRemark(idx: any, row: any) {
  430. const data = toRaw(row);
  431. getRow(data.id);
  432. refundBtn.value = false;
  433. }
  434. // 获取数据
  435. function getRow(id: string) {
  436. BaseService.postN('/settlew/agencymapping/refundquery', { id: id }).then((res: any) => {
  437. if (res && res.code === 0) {
  438. let bizContent = res.data
  439. let data = bizContent.data || {};
  440. console.log("data:", data)
  441. rowData.value = data;
  442. if (data.cusType !== null) {
  443. rowData.value.cusType = '' + data.cusType;
  444. }
  445. if (data.bankType !== null) {
  446. rowData.value.bankType = '' + data.bankType;
  447. }
  448. if (data.refundAmount !== null) {
  449. rowData.value.refundAmount = data.refundAmount * 0.01;
  450. }
  451. } else {
  452. ElMessage.error(res.message)
  453. }
  454. })
  455. }
  456. //取消
  457. function cancel() {
  458. refundBtn.value = false;
  459. addForm.value = {
  460. ...initItem
  461. }
  462. }
  463. // const submitHandle = useDebounce(refundSubmit)
  464. // 退款审核
  465. let timer: any = null
  466. function refundSubmit(id: string, examine: string) {
  467. if (timer) return
  468. timer = setTimeout(() => {
  469. let params: any = {
  470. id: id,
  471. result: examine,
  472. paymentBankType: rowData.value.paymentBankType,
  473. paymentBankCardId: rowData.value.paymentBankCardId
  474. }
  475. let reqApi = '/settlew/agencymapping/refundconfirm';
  476. BaseService.post(reqApi, params).then((res: any) => {
  477. if (res && res.code === 0) {
  478. ElMessage.success("操作成功")
  479. crudRef.value.dialogFormVisible = false;
  480. getList()
  481. } else {
  482. ElMessage.error(res.message)
  483. }
  484. })
  485. timer = null
  486. }, 1000)
  487. }
  488. function conversion(val: any) {
  489. var m = 0;
  490. if (!val) return 0
  491. var s1 = val.toString();
  492. var s2 = '0.01'.toString();
  493. try {
  494. m += s1.split(".")[1].length;
  495. } catch (e) { }
  496. try {
  497. m += s2.split(".")[1].length;
  498. } catch (e) { }
  499. return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m);
  500. // return val === null ? 0+"元" : val*0.01+"元"
  501. }
  502. // 退款核对
  503. function handleCheck(id: string, examine: string) {
  504. let params: any = {
  505. id: id,
  506. result: examine,
  507. }
  508. // TODO 缺失接口
  509. BaseService.post(refundCheckApi, params).then((res: any) => {
  510. if (res && res.code === 0) {
  511. ElMessage.success("操作成功")
  512. crudRef.value.dialogFormVisible = false;
  513. getList()
  514. } else {
  515. ElMessage.error(res.message)
  516. }
  517. })
  518. }
  519. onMounted(() => {
  520. getList();
  521. })
  522. </script>
  523. <style scoped lang="less">
  524. .data-item {
  525. display: inline-block;
  526. padding: 10px;
  527. border: 1px solid #d7d7d7;
  528. height: 200px;
  529. width: 100%;
  530. overflow-y: auto;
  531. }
  532. .row-wrap {
  533. margin-bottom: 16px;
  534. }
  535. .col-wrap {
  536. display: flex;
  537. align-items: center;
  538. .label {
  539. color: #333;
  540. width: 100px;
  541. text-align: right;
  542. }
  543. &>span:last-child {
  544. color: #666;
  545. margin-left: 8px;
  546. }
  547. }
  548. </style>