You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1479 lines
54 KiB

3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
1 month ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
  1. <script setup>
  2. import { ref, reactive, onMounted, nextTick, toRaw } from 'vue'
  3. import { useRoute } from 'vue-router'
  4. import { ElMessage, ElMessageBox } from 'element-plus'
  5. import request from '@/util/http.js'
  6. import dayjs from 'dayjs'
  7. import { useI18n } from 'vue-i18n'
  8. import { Moneyfunds, refundOnline, exportFunds } from '@/api/cash/financialAccount.js'
  9. import { useAdminStore } from '@/store/index.js'
  10. import { storeToRefs } from 'pinia'
  11. import _ from 'lodash';
  12. import { normalizePayType,MarketNameForId, CurrencyForId, } from '@/views/moneyManage/receiveDetail/utils/staticData.js'
  13. import { isTemplate } from 'element-plus/es/utils/index.mjs'
  14. import { Row } from 'vxe-pc-ui'
  15. import CashManagement from '@/components/workspace/CashManagement.vue'
  16. const adminStore = useAdminStore()
  17. const { adminData } = storeToRefs(adminStore)
  18. const { t } = useI18n()
  19. const route = useRoute()
  20. const paytypeList = [
  21. t('cash.payMethods.stripe'), // Stripe
  22. t('cash.payMethods.paymentAsia'), // PaymentAsia
  23. t('cash.payMethods.stripe2'), // Stripe2
  24. t('cash.payMethods.ipay88'), // Ipay88
  25. t('cash.payMethods.grabpay'), // Grabpay
  26. t('cash.payMethods.nets'), // Nets
  27. t('cash.payMethods.transfer'), // E-Transfer
  28. t('cash.payMethods.iotPay'), // IOT Pay
  29. t('cash.payMethods.stripe3'), // Stripe3
  30. t('cash.payMethods.paypal'), // PayPal
  31. t('cash.payMethods.paysolution'), // Paysolution
  32. t('cash.payMethods.bankTransfer'),// 银行转账
  33. t('cash.payMethods.card'), // 刷卡
  34. t('cash.payMethods.cash'), // 现金
  35. t('cash.payMethods.check'), // 支票
  36. ]
  37. const payPlatformOptions = ref([...paytypeList])
  38. const marketFilter = (value) => {
  39. const map = {
  40. 4: t('cash.markets.Singapore'),
  41. 5: t('cash.markets.Malaysia'),
  42. 13:t('cash.markets.HongKong'),
  43. 24016: t('cash.markets.Canada'),
  44. 24018:t('cash.markets.Thailand'),
  45. 24022:t('cash.markets.VietnamHCM'),
  46. 24033:t('cash.markets.Beijing'),
  47. };
  48. return map[value] || '-';
  49. };
  50. // 地区树
  51. const marketOptions = ref([])
  52. // 查询参数
  53. const queryParams = reactive({
  54. jwcode: '',
  55. markets: [], // 下拉多选
  56. performanceMarkets:[],
  57. timeRange: [], // [startTime, endTime]
  58. payType: '',
  59. orderCode: '',
  60. pageNum: 1,
  61. pageSize: 20,
  62. platformSelection: []
  63. })
  64. const total = ref(0)
  65. const tableData = ref([])
  66. const tableRef = ref(null)
  67. const scrollTableTop = () => {
  68. tableRef.value?.setScrollTop?.(0)
  69. }
  70. const loading = ref(false)
  71. // 转换树形结构(参考 coinConsumeDetail.vue)
  72. const transformTree = (nodes) => {
  73. const allChildren = nodes.flatMap(node => node.children || []);
  74. return allChildren.map(child => {
  75. const grandchildren = child.children && child.children.length
  76. ? transformTree([child])
  77. : null;
  78. return {
  79. value: child.id,
  80. label: child.name,
  81. children: grandchildren
  82. };
  83. });
  84. };
  85. // 获取地区数据
  86. const getMarket = async () => {
  87. try {
  88. const result = await request({ url: '/market/selectMarket' });
  89. if (result && result.data) {
  90. marketOptions.value = transformTree(result.data)
  91. }
  92. } catch (error) {
  93. console.error('获取地区失败', error)
  94. }
  95. }
  96. const formatStatuses = (statuses) => {
  97. // 情况1:非数组/空值 → 返回空数组
  98. if (!Array.isArray(statuses)) {
  99. return [];
  100. }
  101. // 情况2:数组中包含 null 或 undefined → 返回空数组
  102. if (statuses.some(item => item === null || item === undefined)) {
  103. return [];
  104. }
  105. // 情况3:正常数组 → 返回原数组
  106. return statuses;
  107. };
  108. const performanceMarket = ref([
  109. t('cash.markets.Malaysia'), // 马来西亚
  110. t('cash.markets.HongKong'), // 香港
  111. t('cash.markets.Singapore'), // 新加坡
  112. t('cash.markets.Thailand'), // 泰国
  113. t('cash.markets.VietnamHCM'), // 越南HCM
  114. t('cash.markets.Canada'), // 加拿大
  115. t('cash.markets.Beijing') // 北京
  116. ])
  117. const getPayPlatformOptions = async () => {
  118. try {
  119. const res = await request({
  120. url: '/market/getAreaPayTypeTree',
  121. method: 'POST'
  122. })
  123. if (res.code === 200) {
  124. payPlatformOptionsList.value = res.data
  125. console.log('支付平台数据加载成功:', payPlatformOptionsList.value)
  126. } else {
  127. ElMessage.error(res.msg || t('elmessage.getDataFailed'))
  128. }
  129. } catch (error) {
  130. console.error('请求支付平台数据出错:', error)
  131. ElMessage.error(t('elmessage.networkError'))
  132. }
  133. }
  134. // 查询列表
  135. const fetchData = async () => {
  136. loading.value = true
  137. try {
  138. //转换areaPayTypeList参数结构
  139. const areaPayTypeList = [];
  140. const options = toRaw(payPlatformOptionsList.value);
  141. const selectedPaths = queryParams.platformSelection;
  142. if (selectedPaths.length > 0 && options.length > 0) {
  143. selectedPaths.forEach(path => {
  144. const areaId = path[0];
  145. const payMethodId = path[path.length - 1];
  146. if (path.length === 1) {
  147. const countryNode = options.find(c => c.id === areaId);
  148. if (countryNode && countryNode.children) {
  149. countryNode.children.forEach(child => {
  150. areaPayTypeList.push({
  151. areaId: areaId,
  152. payType: child.name
  153. });
  154. });
  155. }
  156. }
  157. else {
  158. const countryNode = options.find(c => c.id === areaId);
  159. if (countryNode && countryNode.children) {
  160. const methodNode = countryNode.children.find(m => m.id === payMethodId);
  161. if (methodNode) {
  162. areaPayTypeList.push({
  163. areaId: areaId,
  164. payType: methodNode.name
  165. });
  166. }
  167. }
  168. }
  169. });
  170. }
  171. //转换performanceMarket参数结构
  172. let performanceMarkets = [];
  173. const selectedNames = queryParams.performanceMarket;
  174. if (Array.isArray(selectedNames) && selectedNames.length > 0) {
  175. performanceMarkets = selectedNames
  176. .map(name => {
  177. if (!name) return null;
  178. const id = MarketNameForId(name);
  179. return id;
  180. })
  181. .filter(id => id !== null && id !== 'null'); // 过滤无效值
  182. }
  183. const params = {
  184. pageNum: queryParams.pageNum,
  185. pageSize: queryParams.pageSize,
  186. fundsDTO: {
  187. jwcode: queryParams.jwcode,
  188. localMarket: queryParams.markets,
  189. performanceMarkets:performanceMarkets,
  190. areaPayTypeList: areaPayTypeList,
  191. startTime: queryParams.timeRange?.[0] ? dayjs(queryParams.timeRange[0]).format('YYYY-MM-DD HH:mm:ss') : '',
  192. endTime: queryParams.timeRange?.[1] ? dayjs(queryParams.timeRange[1]).format('YYYY-MM-DD HH:mm:ss') : '',
  193. payType: normalizePayType(queryParams.payType || ''),
  194. orderCode: queryParams.orderCode,
  195. markets: [],
  196. }
  197. }
  198. console.log('查询参数:', params)
  199. const res = await Moneyfunds(params)
  200. if (res.code == 200) {
  201. tableData.value = res.data.list || []
  202. await nextTick()
  203. scrollTableTop()
  204. total.value = res.data.total || 0
  205. loading.value = false
  206. } else {
  207. ElMessage.error(res.msg || t('elmessage.getDataFailed'))
  208. loading.value = false
  209. }
  210. } catch (error) {
  211. console.error(error)
  212. loading.value = false
  213. ElMessage.error(t('elmessage.getDataFailed'))
  214. }
  215. }
  216. const handleSearch = () => {
  217. queryParams.pageNum = 1
  218. fetchData()
  219. }
  220. const handleReset = () => {
  221. queryParams.jwcode = ''
  222. queryParams.performanceMarket = ''
  223. queryParams.timeRange = null
  224. queryParams.payType = ''
  225. queryParams.orderCode = ''
  226. queryParams.platformSelection=[]
  227. handleSearch()
  228. }
  229. const handlePageSizeChange = (val) => {
  230. queryParams.pageSize = val
  231. fetchData()
  232. }
  233. const handleCurrentChange = (val) => {
  234. queryParams.pageNum = val
  235. fetchData()
  236. }
  237. // 退款操作
  238. const openRefundConfirm = () => {
  239. showDetail.value=false
  240. textContent.value = t('common.willRefundOrder') + '?'
  241. refundConfirmDialog.value = true
  242. refundFormData.value = {
  243. ...formDataRow.value,
  244. oldpermanentGold: formDataRow.value.permanentGold || formDataRow.value.gold || 0,//退款永久金币
  245. oldfreeGold: formDataRow.value.freeGold || formDataRow.value.free || 0,//退款免费金币
  246. permanentGold: null,
  247. freeGold: null,
  248. }
  249. }
  250. const openRefundDialog = () => {
  251. refundDialog.value = true
  252. closeConfirmRefund()
  253. }
  254. const closeConfirmRefund = () => {
  255. refundConfirmDialog.value = false
  256. textContent.value = ''
  257. }
  258. const refundConfirmDialog = ref(false)
  259. const textContent = ref('')
  260. const refundDialog = ref(false)
  261. const refundFormData = ref({})
  262. const resetRefund = () => {
  263. refundFormData.value.refundModel = ''
  264. refundFormData.value.refundReason = ''
  265. refundFormData.value.permanentGold = null
  266. refundFormData.value.freeGold = null
  267. }
  268. const handleRefund = async () => {
  269. try {
  270. if (refundFormData.value.refundModel == 1) {
  271. if (Number(refundFormData.value.permanentGold || 0) > Number(refundFormData.value.oldpermanentGold || 0)) {
  272. ElMessage.error(t('elmessage.limitRefundGoldNotExceedOriginal'))
  273. return
  274. }
  275. if (Number(refundFormData.value.freeGold || 0) > Number(refundFormData.value.oldfreeGold || 0)) {
  276. ElMessage.error(t('elmessage.limitRefundGoldNotExceedOriginal'))
  277. return
  278. }
  279. }
  280. if (refundFormData.value.refundModel == 0) {
  281. refundFormData.value.permanentGold = refundFormData.value.oldpermanentGold
  282. refundFormData.value.freeGold = refundFormData.value.oldfreeGold
  283. }
  284. let params = {
  285. jwcode: refundFormData.value.jwcode,
  286. name: refundFormData.value.name,
  287. market: refundFormData.value.marketName,
  288. submitterMarket: adminData.value.markets,
  289. remark: refundFormData.value.remark,
  290. originalOrderId: refundFormData.value.id,
  291. refundReason: refundFormData.value.refundReason,
  292. refundModel: refundFormData.value.refundModel,
  293. orderCode: refundFormData.value.orderCode,
  294. submitterId: adminData.value.id,
  295. permanentGold: (refundFormData.value.permanentGold) * 100 || 0,
  296. handlingCharge: refundFormData.value.handlingCharge == null ? null : refundFormData.value.handlingCharge * 100,
  297. freeGold: (refundFormData.value.freeGold) * 100 || 0,
  298. partRefundGold: (refundFormData.value.permanentGold * 100 || 0),
  299. partRefundFree: (refundFormData.value.freeGold * 100 || 0),
  300. payType: refundFormData.value.payType,
  301. }
  302. console.log('这是退款参数:', params);
  303. const res = await refundOnline(params)
  304. if (res.code == 200) {
  305. ElMessage.success(t('elmessage.submitSuccess'))
  306. refundDialog.value = false
  307. fetchData()
  308. } else {
  309. ElMessage.error(res.msg || t('refund.refundFailed'))
  310. }
  311. } catch (error) {
  312. console.error(error)
  313. }
  314. }
  315. const payPlatformOptionsList = ref([])
  316. // ==================== 导出相关逻辑 ====================
  317. const exportListVisible = ref(false)
  318. const exportList = ref([])
  319. const exportListLoading = ref(false)
  320. // 导出Excel
  321. const handleExport = async () => {
  322. const formatStatuses = (statuses) => {
  323. // 情况1:非数组/空值 → 返回空数组
  324. if (!Array.isArray(statuses)) {
  325. return [];
  326. }
  327. // 情况2:数组中包含 null 或 undefined → 返回空数组
  328. if (statuses.some(item => item === null || item === undefined)) {
  329. return [];
  330. }
  331. // 情况3:正常数组 → 返回原数组
  332. return statuses;
  333. };
  334. try {
  335. const params = {
  336. pageNum: queryParams.pageNum,
  337. pageSize: queryParams.pageSize,
  338. fundsDTO: {
  339. jwcode: queryParams.jwcode,
  340. localMarket: queryParams.markets,
  341. startTime: queryParams.timeRange?.[0] ? dayjs(queryParams.timeRange[0]).format('YYYY-MM-DD HH:mm:ss') : '',
  342. endTime: queryParams.timeRange?.[1] ? dayjs(queryParams.timeRange[1]).format('YYYY-MM-DD HH:mm:ss') : '',
  343. payType: normalizePayType(queryParams.payType || ''),
  344. orderCode: queryParams.orderCode,
  345. statuses: formatStatuses(queryParams.statuses),
  346. markets: [],
  347. }
  348. }
  349. // TODO: 确认导出接口 URL
  350. const res = await exportFunds(params)
  351. if (res.code == 200) {
  352. console.log('导出参数', params)
  353. ElMessage.success(t('elmessage.exportSuccess'))
  354. }
  355. } catch (error) {
  356. console.error(error)
  357. ElMessage.error(t('elmessage.exportError'))
  358. }
  359. }
  360. // 打开导出列表弹窗
  361. const openExportList = () => {
  362. getExportList()
  363. exportListVisible.value = true
  364. }
  365. // 获取导出列表
  366. const getExportList = async () => {
  367. exportListLoading.value = true
  368. try {
  369. const result = await request({ url: '/export/export' })
  370. if (result.code === 200) {
  371. const filteredData = result.data.filter(item => item.type == 15);
  372. exportList.value = filteredData || []
  373. } else {
  374. ElMessage.error(result.msg || t('elmessage.getExportListError'))
  375. }
  376. } catch (error) {
  377. console.error('获取导出列表出错:', error)
  378. ElMessage.error(t('elmessage.getExportListError'))
  379. } finally {
  380. exportListLoading.value = false
  381. }
  382. }
  383. // 下载导出文件
  384. const downloadExportFile = (item) => {
  385. if (item.state === 2) {
  386. const link = document.createElement('a')
  387. link.href = item.url
  388. link.download = item.fileName
  389. link.click()
  390. } else {
  391. ElMessage.warning(t('elmessage.exportingInProgress'))
  392. }
  393. }
  394. // 根据状态返回对应的标签类型
  395. const getTagType = (state) => {
  396. switch (state) {
  397. case 0: return 'info';
  398. case 1: return 'primary';
  399. case 2: return 'success';
  400. case 3: return 'danger';
  401. default: return 'info';
  402. }
  403. }
  404. // 根据状态返回对应的标签文案
  405. const getTagText = (state) => {
  406. switch (state) {
  407. case 0: return t('elmessage.pendingExecution');
  408. case 1: return t('elmessage.executing');
  409. case 2: return t('elmessage.executed');
  410. case 3: return t('elmessage.errorExecution');
  411. default: return t('elmessage.unknownStatus');
  412. }
  413. }
  414. const throttledsubmitRefund = _.throttle(handleRefund, 5000, {
  415. trailing: false
  416. })
  417. // 递归查找地区ID
  418. // normalizeMarketLabel 标准化地区名称,用于对比匹配
  419. const normalizeMarketLabel = (value) => {
  420. return String(value ?? '')
  421. .trim()
  422. .toLowerCase()
  423. .replace(/[\s_-]+/g, '')
  424. }
  425. // 传入的这两个参数对比,是否有匹配的地区ID
  426. const findValueByLabel = (options, label) => {
  427. // option和label都调用normalizeMarketLabel函数
  428. const normalizedLabel = normalizeMarketLabel(label)
  429. for (const option of options) {
  430. if (normalizeMarketLabel(option.label) === normalizedLabel) {
  431. return option.value
  432. }
  433. if (option.children && option.children.length) {
  434. const found = findValueByLabel(option.children, label)
  435. if (found) return found
  436. }
  437. }
  438. return null
  439. }
  440. //记录详情表单
  441. const formDataRow = ref({
  442. jwcode:'',
  443. marketName:'',
  444. goodsName:'',
  445. paymentCurrencyName:'',
  446. paymentAmount:'',
  447. payTime:'',
  448. voucher:'',
  449. name:'',
  450. activity:'',
  451. payType:'',
  452. receivedCurrencyName:'',
  453. receivedAmount:'',
  454. receivedTime:'',
  455. handlingCharge:'',
  456. remark:'',
  457. });
  458. //记录点击函数
  459. const showDetail=ref(false)
  460. const showRecordDetail = async (row) => {
  461. showDetail.value=true
  462. formDataRow.value=row
  463. }
  464. const paymentCurrency = ref([
  465. t('cash.currency.usd'), // 美元(USD)
  466. t('cash.currency.hkd'), // 港币(HKD)
  467. t('cash.currency.sgd'), // 新币(SGD)
  468. t('cash.currency.myr'), // 马币(MYR)
  469. t('cash.currency.thb'), // 泰铢(THB)
  470. t('cash.currency.cad'), // 加币(CAD)
  471. t('cash.currency.vnd'), // 越南盾(VND)
  472. t('cash.currency.krw'), // 韩元(KRW)
  473. t('cash.currency.rmb'), // 人民币(CNY)
  474. ])
  475. //新增流水
  476. const showAddDetail=ref(false)
  477. const type = ref('other')
  478. const addCashFlow=(s)=>{
  479. showAddDetail.value=true
  480. type.value=s
  481. }
  482. const selectAddType= (s) => {
  483. otherFormRef.value?.resetFields?.();
  484. ipay88FormRef.value?.resetFields?.();
  485. type.value=s
  486. }
  487. const otherFormRef = ref(null);
  488. const addOtherForm=ref({
  489. performanceMarket:"", //业绩归属地
  490. goodsName:"", //收入类别
  491. goodNum:"", //个数
  492. payType:"", //支付方式
  493. paymentCurrency:"", //付款币种
  494. paymentAmount:"", //付款金额
  495. payTime:"", //支付时间
  496. handlingCharge:"", //手续费
  497. remark:"", //备注
  498. isPerformance:'',
  499. submitterId: adminData.value?.id || '', // 直接初始化为用户ID
  500. submitterMarket: adminData.value?.markets || [] // 直接初始化为用户地区(通常是数组)
  501. })
  502. const otherRules = {
  503. performanceMarket: [
  504. { required: true, message: t('common.performanceByRegionPlaceholder'), trigger: 'change' }
  505. ],
  506. goodsName: [
  507. { required: true, message: t('cash.cashFlow.incomeCategoryPlaceholder'), trigger: 'change' }
  508. ],
  509. goodNum: [
  510. { type: 'number', message: t('cash.cashFlow.quantityMustBeNumber'), trigger: 'blur' }
  511. ],
  512. payType: [
  513. { required: true, message: t('elmessage.checkPayModel'), trigger: 'change' }
  514. ],
  515. paymentCurrency: [
  516. { required: true, message: t('common.payCurrencyPlaceholder'), trigger: 'change' }
  517. ],
  518. paymentAmount: [
  519. { required: true, message: t('common_add.payAmountPlaceholder'), trigger: 'blur' },
  520. { pattern: /^[0-9]+(\.[0-9]{1,2})?$/, message: t('cash.cashFlow.invalidFormat'), trigger: 'blur' }
  521. ],
  522. payTime: [
  523. { required: true, message: t('common_add.payTimePlaceholder'), trigger: 'change' }
  524. ],
  525. handlingCharge: [
  526. { pattern: /^[0-9]+(\.[0-9]{1,2})?$/, message: t('cash.cashFlow.invalidFormat'), trigger: 'blur' }
  527. ]
  528. };
  529. const handleOther=async ()=>{
  530. if (!otherFormRef.value) return;
  531. try {
  532. await otherFormRef.value.validate();
  533. if(addOtherForm.value.goodsName=== t('cash.cashFlow.localIntercompany') ||
  534. addOtherForm.value.goodsName=== t('cash.cashFlow.corporateIntercompany') ||
  535. addOtherForm.value.goodsName=== t('cash.cashFlow.otherIncomeNon') ){
  536. addOtherForm.value.isPerformance='0'
  537. }else{
  538. addOtherForm.value.isPerformance='1'
  539. }
  540. const submitData={
  541. performanceMarket:String(MarketNameForId(addOtherForm.value.performanceMarket)),
  542. goodsName:addOtherForm.value.goodsName,
  543. goodNum:String(addOtherForm.value.goodNum),
  544. payType:addOtherForm.value.payType,
  545. paymentCurrency:String(CurrencyForId(addOtherForm.value.paymentCurrency)),
  546. paymentAmount:addOtherForm.value.paymentAmount,
  547. payTime:addOtherForm.value.payTime,
  548. handlingCharge:addOtherForm.value.handlingCharge,
  549. remark:addOtherForm.value.remark,
  550. isPerformance:addOtherForm.value.isPerformance,
  551. submitterId: addOtherForm.value.submitterId,
  552. submitterMarket: addOtherForm.value.submitterMarket,
  553. }
  554. const handle =await request({
  555. url:'/cashCollection/addExFund',
  556. data:submitData
  557. })
  558. console.log('提交的数据:', submitData);
  559. if (handle.code == 200 || handle.status == 200) {
  560. ElMessage.success(t('elmessage.submitSuccess'));
  561. otherFormRef.value?.resetFields?.();
  562. showAddDetail.value = false;
  563. }
  564. } catch (error) {
  565. console.log('校验失败', error);
  566. }
  567. };
  568. const ipay88FormRef = ref(null);
  569. const addIpay88Form=ref({
  570. performanceMarket:"", //业绩归属地
  571. payType:"", //支付方式
  572. paymentCurrency:"", //付款币种
  573. handlingCharge:"", //手续费
  574. remark:"", //备注
  575. submitterId: adminData.value?.id || '', // 直接初始化为用户ID
  576. submitterMarket: adminData.value?.markets || [] // 直接初始化为用户地区(通常是数组)
  577. })
  578. const ipay88Rules = {
  579. performanceMarket: [{ required: true, message: t('common.performanceByRegionPlaceholder'), trigger: 'change' } ],
  580. goodsName: [{ required: true, message: t('cash.cashFlow.incomeCategoryPlaceholder'), trigger: 'change' }],
  581. // 付款金额固定为0(根据表格要求)
  582. paymentAmount: [
  583. { required: true, message: t('cash.cashFlow.paymentMust'), trigger: 'change',
  584. validator: (rule, value, callback) => {
  585. const numValue = Number(value);
  586. if (numValue !== 0 && numValue !== 0.0) {
  587. callback(new Error(t('cash.cashFlow.paymentMust')));
  588. } else {
  589. callback();
  590. }
  591. }
  592. }
  593. ],
  594. payType: [ { required: true, message: t('common.payModelPlaceholder'), trigger: 'change' } ],
  595. paymentCurrency: [{ required: true, message: t('common.payCurrencyPlaceholder'), trigger: 'change' }],
  596. payTime: [{ required: true, message: t('common_add.payTimePlaceholder'), trigger: 'change' }],
  597. handlingCharge: [
  598. { required: true, message: t("common_add.feePlaceholder"),trigger: 'change'},
  599. { pattern: /^[0-9]+(\.[0-9]{1,2})?$/, message: t('cash.cashFlow.invalidFormat'),trigger: 'change' } ],
  600. remark: [{ max: 100, message: t('cash.cashFlow.remarksexceed'), trigger: 'change' }]
  601. };
  602. const handleIpay88 =async () =>{
  603. if (!ipay88FormRef.value) return;
  604. try {
  605. await ipay88FormRef.value.validate();
  606. const Data={
  607. performanceMarket:String(MarketNameForId(addIpay88Form.value.performanceMarket)),
  608. payType:addIpay88Form.value.payType,
  609. paymentCurrency:String(CurrencyForId(addIpay88Form.value.paymentCurrency)),
  610. handlingCharge:addIpay88Form.value.handlingCharge,
  611. remark:addIpay88Form.value.remark,
  612. submitterId: addIpay88Form.value.submitterId,
  613. submitterMarket: addIpay88Form.value.submitterMarket,
  614. }
  615. const handle =await request({
  616. url:'/cashCollection/addiPay88Fee',
  617. data:Data
  618. })
  619. console.log('提交的数据:', Data);
  620. if (handle.code == 200 || handle.status == 200) {
  621. ElMessage.success(t('elmessage.submitSuccess'));
  622. ipay88FormRef.value?.resetFields?.();
  623. showAddDetail.value = false;
  624. }
  625. } catch (error) {
  626. console.log('校验失败', error);
  627. }
  628. }
  629. // 修改 handleCancel 方法
  630. const handleCancel = () => {
  631. otherFormRef.value?.resetFields?.();
  632. ipay88FormRef.value?.resetFields?.();
  633. showAddDetail.value = false;
  634. };
  635. const previewVisible=ref(false)
  636. const handlePreviewClick=()=>{
  637. if(previewVisible.value){
  638. previewVisible.value=false
  639. }
  640. }
  641. onMounted(async () => {
  642. await getMarket()
  643. await getPayPlatformOptions()
  644. // 处理从工作台跳转过来的地区参数
  645. // 如果出现URL中的?region=a&region=b 这种重复key,router会解析为['a','b'], 取第一个地区ID
  646. const regionName = Array.isArray(route.query.region) ? route.query.region[0] : route.query.region
  647. if (regionName && marketOptions.value.length) {
  648. const matchedId = findValueByLabel(marketOptions.value, regionName)
  649. if (matchedId) {
  650. // el-cascader 绑定的 markets 是数组
  651. queryParams.markets = [matchedId]
  652. }
  653. }
  654. fetchData()
  655. })
  656. </script>
  657. <template>
  658. <div class="cash-flow-container">
  659. <!-- 搜索区域 -->
  660. <el-card class="search-card">
  661. <div class="search-bar">
  662. <!-- 第一行 -->
  663. <div class="search-row">
  664. <div class="search-item">
  665. <span class="label">{{ t('common.jwcode') }}</span>
  666. <el-input v-model="queryParams.jwcode" :placeholder="t('common.jwcodePlaceholder')" clearable />
  667. </div>
  668. <div class="search-item">
  669. <span class="label">{{ t('cash.cashFlow.performanceMarket') }}</span>
  670. <el-select v-model="queryParams.performanceMarket"
  671. :placeholder="t('cash.cashFlow.performanceMarketPlaceholder')"
  672. clearable :multiple="true"
  673. style="width: 220px;"
  674. :prop="performanceMarket"
  675. collapse-tags >
  676. <el-option v-for="item in performanceMarket" :key="item" :label="item" :value="item" />
  677. </el-select>
  678. <!-- <span class="label">{{ t('common.performanceByRegion') }}</span> -->
  679. <!-- 下拉多选使用 el-cascader 匹配地区树结构 -->
  680. <!-- <el-cascader v-model="queryParams.markets" :options="marketOptions"
  681. :props="{ multiple: true, emitPath: false }" collapse-tags collapse-tags-tooltip
  682. :placeholder="t('common.performanceByRegionPlaceholder')" clearable style="width: 240px;" /> -->
  683. </div>
  684. <!-- 选择平台二级表单 -->
  685. <div class="search-item">
  686. <span class="label">{{ t('common.payPlatform1') }}</span>
  687. <el-cascader v-model="queryParams.platformSelection" :options="payPlatformOptionsList"
  688. :props="{ multiple: true ,value:'id',label:'name'}"
  689. collapse-tags collapse-tags-tooltip :placeholder="t('common.payPlatformPlaceholder1')" clearable
  690. style="width: 220px;"
  691. />
  692. </div>
  693. <div class="search-item">
  694. <span class="label">{{ t('common.orderNo') }}</span>
  695. <el-input v-model="queryParams.orderCode" :placeholder="t('common.orderNoPlaceholder')" clearable />
  696. </div>
  697. <div class="search-item" style="width: auto;">
  698. <span class="label">{{ t('common.payTime2') }}</span>
  699. <el-date-picker v-model="queryParams.timeRange" type="datetimerange" :range-separator="t('common.to')"
  700. :start-placeholder="t('common.startTime')" :end-placeholder="t('common.endTime')"
  701. :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]" style="width: 350px;" />
  702. </div>
  703. <div class="search-btn-group">
  704. <el-button type="primary" @click="handleSearch">{{ t('common.search') }}</el-button>
  705. <el-button type="primary" @click="handleExport">{{ t('common.exportExcel') }}</el-button>
  706. <el-button type="primary" @click="openExportList">{{ t('common.viewExportList') }}</el-button>
  707. <el-button type="success" @click="handleReset">{{ t('common.reset') }}</el-button>
  708. </div>
  709. <div class="newAdd">
  710. <el-button class="newAdd_btn" @click="addCashFlow('other')">{{ t('common.addCashFlow') }}</el-button>
  711. </div>
  712. </div>
  713. </div>
  714. </el-card>
  715. <!-- 表格区域 -->
  716. <el-card class="table-card" >
  717. <el-table ref="tableRef" :data="tableData" v-loading="loading" style="width: 100%; flex: 1;"
  718. :cell-style="{ textAlign: 'center' }"
  719. :header-cell-style="{ background: '#F3FAFE', color: '#333', textAlign: 'center' }"
  720. @row-click="showRecordDetail" >
  721. <el-table-column type="index" :label="t('common_list.id')" width="60" align="center" fixed="left">
  722. <template #default="scope">
  723. <span>{{ scope.$index + 1 + (queryParams.pageNum - 1) * queryParams.pageSize }}</span>
  724. </template>
  725. </el-table-column>
  726. <el-table-column prop="payTime" :label="t('common_list.payTime2')" width="180" align="center" />
  727. <el-table-column prop="orderCode" :label="t('common_list.orderCode')" width="280" show-overflow-tooltip />
  728. <el-table-column prop="receivedMarket" :label="t('common_list.receiveArea')" width="280" show-overflow-tooltip >
  729. <template #default="{ row }">
  730. {{ marketFilter(row.receivedMarket) }}
  731. </template>
  732. </el-table-column>
  733. <el-table-column prop="performanceMarket" :label="t('common_list.performanceMarket')" width="120" show-overflow-tooltip >
  734. <template #default="{ row }">
  735. {{ marketFilter(row.performanceMarket) }}
  736. </template></el-table-column>
  737. <el-table-column prop="name" :label="t('common_list.name')" width="150" show-overflow-tooltip />
  738. <el-table-column prop="jwcode" :label="t('common_list.jwcode')" width="120" />
  739. <el-table-column prop="goodsName" :label="t('common_list.receiveType')" width="120" />
  740. <el-table-column prop="remark" :label="t('common_list.remark')" width="120" />
  741. <el-table-column prop="goodNum" :label="t('common_list.nums')" width="120" />
  742. <el-table-column prop="payType" :label="t('common_list.paymentMethod')" width="120" />
  743. <el-table-column prop="receivedCurrencyName" :label="t('common_list.receiveCurrency')" width="120"
  744. show-overflow-tooltip />
  745. <el-table-column prop="paymentAmount" :label="t('common_list.payAmount')" width="150" align="right">
  746. </el-table-column>
  747. <el-table-column prop="handlingCharge" :label="t('common_list.fee')" width="100" align="right" />
  748. <el-table-column prop="receivedAmount" :label="t('common_list.receiveAmount')" width="150" align="right">
  749. </el-table-column>
  750. <!-- <el-table-column :label="t('common_list.operation')" width="100" fixed="right" align="center">
  751. <template #default="{ row }">
  752. <el-button v-if="row.orderCode.slice(0, 4) == 'GOLD' && row.status === 4" type="danger" link size="small"
  753. @click="openRefundConfirm(row)">
  754. {{ t('common_list.refund') }}
  755. </el-button>
  756. </template>
  757. </el-table-column> -->
  758. </el-table>
  759. <!-- 分页 -->
  760. <div class="pagination-container">
  761. <el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="total"
  762. :current-page="queryParams.pageNum" :page-size="queryParams.pageSize" :page-sizes="[10, 20, 50, 100]"
  763. @size-change="handlePageSizeChange" @current-change="handleCurrentChange" />
  764. </div>
  765. </el-card>
  766. <!-- 详情显示页 -->
  767. <el-dialog class="detailDialog" v-model="showDetail" :title="t('common_add.originalOrderInfo')" width="700px" destroy-on-close>
  768. <el-form :model="formDataRow" label-width="100px" class="detail-form" disabled>
  769. <div style="display: flex;">
  770. <div class="left">
  771. <div class="add-item">
  772. <el-form-item :label="t('common_list.jwcode')">
  773. <el-input v-model="formDataRow.jwcode" />
  774. </el-form-item>
  775. </div>
  776. <div class="add-item">
  777. <el-form-item :label="t('common_list.market')">
  778. <el-input v-model="formDataRow.marketName" />
  779. </el-form-item>
  780. </div>
  781. <div class="add-item">
  782. <el-form-item :label="t('common_list.productName')">
  783. <el-input v-model="formDataRow.goodsName" />
  784. </el-form-item>
  785. </div>
  786. <div class="add-item">
  787. <el-form-item :label="t('common_list.payCurrency')">
  788. <el-input v-model="formDataRow.paymentCurrencyName" />
  789. </el-form-item>
  790. </div>
  791. <div class="add-item">
  792. <el-form-item :label="t('common_list.payAmount')">
  793. <el-input v-model="formDataRow.paymentAmount" />
  794. </el-form-item>
  795. </div>
  796. <div class="add-item">
  797. <el-form-item :label="t('common_list.payTime2')">
  798. <el-input v-model="formDataRow.payTime" />
  799. </el-form-item>
  800. </div>
  801. <div class="add-item">
  802. <el-form-item :label="t('common_list.transferVoucher')">
  803. <div v-if="formDataRow.voucher" class="voucher-container">
  804. <el-image :src="formDataRow.voucher" :preview-src-list="[formDataRow.voucher]"
  805. fit="cover" class="voucher-img" v-model:preview-visible="previewVisible"
  806. @click="handlePreviewClick"/>
  807. </div>
  808. <div v-else class="no-voucher">{{ t('common_list.noTransferVoucher') }}</div>
  809. </el-form-item>
  810. </div>
  811. </div>
  812. <div class="right">
  813. <div class="add-item">
  814. <el-form-item :label="t('common_list.customerName')">
  815. <el-input v-model="formDataRow.name" />
  816. </el-form-item>
  817. </div>
  818. <div class="add-item">
  819. <el-form-item :label="t('common_list.activity')">
  820. <el-input v-model="formDataRow.activityName" />
  821. </el-form-item>
  822. </div>
  823. <div class="add-item">
  824. <el-form-item :label="t('common_list.payModel')">
  825. <el-input v-model="formDataRow.payType" />
  826. </el-form-item>
  827. </div>
  828. <div class="add-item">
  829. <el-form-item :label="t('common_list.receiveCurrency')">
  830. <el-input v-model="formDataRow.receiveCurrency" />
  831. </el-form-item>
  832. </div>
  833. <div class="add-item">
  834. <el-form-item :label="t('common_list.receiveAmount')">
  835. <el-input v-model="formDataRow.receivedAmount" />
  836. </el-form-item>
  837. </div>
  838. <div class="add-item">
  839. <el-form-item :label="t('common_list.receiveTime')">
  840. <el-input v-model="formDataRow.receivedTime" />
  841. </el-form-item>
  842. </div>
  843. <div class="add-item">
  844. <el-form-item :label="t('common_list.fee')">
  845. <el-input v-model="formDataRow.handlingCharge" />
  846. </el-form-item>
  847. </div>
  848. <div class="add-item">
  849. <el-form-item :label="t('common_list.submitter')">
  850. <el-input v-model="adminData.adminName" />
  851. </el-form-item>
  852. </div>
  853. <div class="add-item">
  854. <el-form-item :label="t('common_list.remark')">
  855. <el-input v-model="formDataRow.remark" type="textarea" :rows="2" />
  856. </el-form-item>
  857. </div>
  858. </div>
  859. </div>
  860. </el-form>
  861. <div style="display:flex;justify-content: center;margin-top: 5vh;" class="btnDiv">
  862. <el-button type="default" style="background-color: #7E91FF;" @click="showDetail = false">{{t('common.cancel')}}</el-button>
  863. <el-button type="primary" style="background-color: #2741DE; margin-left: 2.5vw;" @click="openRefundConfirm">{{ t('common.refund') }}</el-button>
  864. </div>
  865. </el-dialog>
  866. <!-- 新增流水页面 -->
  867. <el-dialog class="adddialog" v-model="showAddDetail" style="width: 400px;">
  868. <div style="width: fit-content; height: fit-content;margin-bottom: 20px; ">
  869. <el-button
  870. class="btnItem"
  871. :style="{backgroundColor: type === 'other' ? '#2741DE' : '#E5EBFE', color: type === 'other' ? 'white' : '#666' }"
  872. @click="selectAddType('other')" >{{ t('cash.cashFlow.otherIncome') }}</el-button>
  873. <el-button
  874. class="btnItem"
  875. :style="{ backgroundColor: type === 'ipay88' ? '#2741DE' : '#E5EBFE', color: type === 'ipay88' ? 'white' : '#666' }"
  876. @click="selectAddType('ipay88')" >{{ t('cash.cashFlow.addFee') }}</el-button>
  877. </div>
  878. <!-- 其他收入填写表单 -->
  879. <div v-if="type === 'other'" >
  880. <el-form :model="addOtherForm" :rules="otherRules" ref="otherFormRef" label-width="120px" label-position="left">
  881. <el-form-item :label=" t('cash.cashFlow.performanceMarket')" prop="performanceMarket">
  882. <el-select v-model="addOtherForm.performanceMarket" :placeholder="t('cash.cashFlow.performanceMarketPlaceholder')" >
  883. <el-option v-for="item in performanceMarket" :key="item" :label="item" :value="item" />
  884. </el-select>
  885. </el-form-item>
  886. <el-form-item :label="t('cash.cashFlow.incomeCategory')" prop="goodsName">
  887. <el-select v-model="addOtherForm.goodsName" :placeholder="t('cash.cashFlow.incomeCategoryPlaceholder')" >
  888. <el-option :value="t('cash.cashFlow.investmentIncome')" />
  889. <el-option :value="t('cash.cashFlow.taxRefund')" />
  890. <el-option :value="t('cash.cashFlow.governmentSubsidy')" />
  891. <el-option :value="t('cash.cashFlow.localIntercompany')" />
  892. <el-option :value="t('cash.cashFlow.corporateIntercompany')" />
  893. <el-option :value="t('cash.cashFlow.otherIncomeNon')" />
  894. <el-option :value="t('cash.cashFlow.otherIncomeYes')" />
  895. </el-select>
  896. </el-form-item>
  897. <el-form-item :label="t('cash.cashFlow.quantity')" prop="goodNum">
  898. <el-input v-model.number="addOtherForm.goodNum" :placeholder="t('cash.cashFlow.quantityPlaceholder')" />
  899. </el-form-item>
  900. <el-form-item :label="t('cash.cashFlow.payType')" prop="payType">
  901. <el-select v-model="addOtherForm.payType" :placeholder="t('cash.cashFlow.payTypePlaceholder')" >
  902. <el-option v-for="item in paytypeList" :key="item" :value="item" :label="item"/>
  903. </el-select>
  904. </el-form-item>
  905. <el-form-item :label="t('cash.cashFlow.paymentCurrency')" prop="paymentCurrency">
  906. <el-select v-model="addOtherForm.paymentCurrency" :placeholder="t('cash.cashFlow.paymentCurrencyPlaceholder')" >
  907. <el-option v-for="item in paymentCurrency" :key="item" :label="item" :value="item"/>
  908. </el-select>
  909. </el-form-item>
  910. <el-form-item :label="t('cash.cashFlow.paymentAmount')" prop="paymentAmount">
  911. <el-input v-model="addOtherForm.paymentAmount" :placeholder="t('cash.cashFlow.paymentAmountPlaceholder')" />
  912. </el-form-item>
  913. <el-form-item :label="t('cash.cashFlow.paymentTime')" prop="payTime">
  914. <el-date-picker v-model="addOtherForm.payTime" type="datetime" :placeholder="t('cash.cashFlow.paymentTimePlaceholder')" value-format="YYYY-MM-DD HH:mm:ss"/>
  915. </el-form-item>
  916. <el-form-item :label="t('cash.cashFlow.bankHandlingFee')" prop="handlingCharge">
  917. <el-input v-model="addOtherForm.handlingCharge" :placeholder="t('cash.cashFlow.bankHandlingFeePlaceholder')" />
  918. </el-form-item>
  919. <el-form-item :label="t('cash.cashFlow.remarks')" prop="remark">
  920. <el-input v-model="addOtherForm.remark" type="textarea" :rows="3" :placeholder="t('cash.cashFlow.remarksPlaceholder')" :maxlength="100" show-word-limit />
  921. </el-form-item>
  922. </el-form>
  923. <div class="btnDiv" >
  924. <el-button type="default" style="background-color: #7E91FF;" @click="handleCancel">{{t('cash.cashFlow.cancel')}}</el-button>
  925. <el-button type="primary" style="background-color: #2741DE; margin-left: 2.5vw;" @click="handleOther">{{t('cash.cashFlow.submit')}}</el-button>
  926. </div>
  927. </div>
  928. <!-- ipay88手续费填写表单 -->
  929. <div v-if="type === 'ipay88'" >
  930. <el-form :model="addIpay88Form" :rules="ipay88Rules" ref="ipay88FormRef" label-width="120px" label-position="left">
  931. <el-form-item :label="t('cash.cashFlow.payType')" prop="payType">
  932. <el-select v-model="addIpay88Form.payType" :placeholder="t('cash.cashFlow.payTypePlaceholder')" >
  933. <el-option :value="t('cash.cashFlow.ipay88')" :label="t('cash.cashFlow.ipay88')"/>
  934. <el-option :value="t('cash.cashFlow.cardPayment')" :label="t('cash.cashFlow.cardPayment')"/>
  935. </el-select>
  936. </el-form-item>
  937. <el-form-item :label="t('cash.cashFlow.performanceMarket')" prop="performanceMarket">
  938. <el-select v-model="addIpay88Form.performanceMarket" :placeholder="t('cash.cashFlow.performanceMarketPlaceholder')" >
  939. <el-option v-for="item in performanceMarket" :key="item" :label="item" :value="item" />
  940. </el-select>
  941. </el-form-item>
  942. <el-form-item :label="t('cash.cashFlow.incomeCategory')">
  943. <el-input disabled :value="t('cash.cashFlow.fixedProcessingFee')"></el-input>
  944. </el-form-item>
  945. <el-form-item :label="t('cash.cashFlow.settlementRegion')">
  946. <el-input disabled :value="t('cash.cashFlow.Malaysia')"></el-input>
  947. </el-form-item>
  948. <el-form-item :label="t('cash.cashFlow.paymentCurrency')" prop="paymentCurrency">
  949. <el-select v-model="addIpay88Form.paymentCurrency" :placeholder="t('cash.cashFlow.paymentCurrencyPlaceholder')">
  950. <el-option v-for="item in paymentCurrency" :key="item" :label="item" :value="item"/>
  951. </el-select>
  952. </el-form-item>
  953. <el-form-item :label="t('cash.cashFlow.paymentAmount')" prop="paymentAmount">
  954. <el-input v-model="addIpay88Form.paymentAmount" :placeholder="t('cash.cashFlow.paymentAmountPlaceholder')"/>
  955. </el-form-item>
  956. <el-form-item :label="t('cash.cashFlow.processingFee')" prop="handlingCharge">
  957. <el-input v-model="addIpay88Form.handlingCharge" :placeholder="t('cash.cashFlow.processingFeePlaceholder')" />
  958. </el-form-item>
  959. <el-form-item :label="t('cash.cashFlow.remarks')" prop="remark">
  960. <el-input v-model="addIpay88Form.remark" type="textarea" :rows="3" :placeholder="t('cash.cashFlow.remarksPlaceholder')" :maxlength="100" show-word-limit/>
  961. </el-form-item>
  962. </el-form>
  963. <div class="btnDiv">
  964. <el-button type="default" style="background-color: #7E91FF;" @click="handleCancel">{{t('cash.cashFlow.cancel')}}</el-button>
  965. <el-button type="primary" style="background-color: #2741DE; margin-left: 2.5vw;" @click="handleIpay88">{{t('cash.cashFlow.submit')}}</el-button>
  966. </div>
  967. </div>
  968. </el-dialog>
  969. <!-- 导出列表弹窗 -->
  970. <el-dialog v-model="exportListVisible" :title="t('common_export.exportList')" width="80%">
  971. <el-table :data="exportList" style="width: 100% ;height: 60vh;" :loading="exportListLoading">
  972. <el-table-column prop="fileName" :label="t('common_export.fileName')" />
  973. <el-table-column prop="state" :label="t('common_export.status')">
  974. <template #default="scope">
  975. <el-tag :type="getTagType(scope.row.state)" :effect="scope.row.state === 3 ? 'light' : 'plain'">
  976. {{ getTagText(scope.row.state) }}
  977. </el-tag>
  978. </template>
  979. </el-table-column>
  980. <el-table-column prop="createTime" :label="t('common_export.createTime')">
  981. <template #default="scope">
  982. {{ dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
  983. </template>
  984. </el-table-column>
  985. <el-table-column :label="t('common_export.operation')">
  986. <template #default="scope">
  987. <el-button type="primary" size="small" @click="downloadExportFile(scope.row)"
  988. :disabled="scope.row.state !== 2">
  989. {{ t('common_export.download') }}
  990. </el-button>
  991. </template>
  992. </el-table-column>
  993. </el-table>
  994. <template #footer>
  995. <div class="dialog-footer">
  996. <el-button text @click="exportListVisible = false">{{ t('common_export.close') }}</el-button>
  997. </div>
  998. </template>
  999. </el-dialog>
  1000. <div class="recallDialog" v-show="refundConfirmDialog">
  1001. <div class="close">
  1002. <button @click="closeConfirmRefund" class="Btn">{{ t('common.close') }}</button>
  1003. </div>
  1004. <div class="text">
  1005. <text class="txt">{{ textContent }}</text>
  1006. </div>
  1007. <div class="cancle">
  1008. <button @click="closeConfirmRefund" class="Btn">{{ t('common.cancel') }}</button>
  1009. </div>
  1010. <div class="confirm">
  1011. <button @click="openRefundDialog" class="Btn">{{ t('common.confirm') }}</button>
  1012. </div>
  1013. </div>
  1014. <el-dialog v-model="refundDialog" :title="t('common_add.refund')" class="refundDialog" overflow draggable
  1015. style="width: 40vw;" :before-close="closeRefundForm">
  1016. <div style="display: flex;">
  1017. <div class="left">
  1018. <div class="add-item">
  1019. <el-text style="width:4vw;">{{ t('common_add.jwcode') }}</el-text>
  1020. <el-input v-model="refundFormData.jwcode" style="width:10vw;" disabled />
  1021. </div>
  1022. <div class="add-item">
  1023. <el-text style="width:4vw;">{{ t('common_add.customerName') }}</el-text>
  1024. <el-input v-model="refundFormData.name" style="width:10vw;" disabled />
  1025. </div>
  1026. <div class="add-item">
  1027. <el-text style="width:4vw;">{{ t('common_add.market') }}</el-text>
  1028. <el-input v-model="refundFormData.marketName" style="width:10vw;" disabled />
  1029. </div>
  1030. <div class="add-item">
  1031. <el-text style="width:4vw;">{{ t('common_add.activity') }}</el-text>
  1032. <el-input v-model="refundFormData.activityName" style="width:10vw;" disabled />
  1033. </div>
  1034. <div class="add-item">
  1035. <el-text style="width:4vw;">{{ t('common_add.productName') }}</el-text>
  1036. <el-input v-model="refundFormData.goodsName" style="width:10vw;" disabled />
  1037. </div>
  1038. <div style="display: flex; margin-bottom: 10px;">
  1039. <div style=" display: flex; align-items: center;justify-content: center; ">
  1040. <span style="color: #999999; white-space: nowrap;">{{ t('common_add.permanentGold')
  1041. }}</span>
  1042. <el-input style="padding-right: 10px; height: 30px; width: 70px;"
  1043. v-model="refundFormData.oldpermanentGold" disabled />
  1044. </div>
  1045. <div style=" display: flex; align-items: center;justify-content: center; ">
  1046. <span style="color: #999999; white-space: nowrap;">{{ t('common_add.freeGold') }}</span>
  1047. <el-input style="padding-right: 10px; height: 30px; width: 70px;" v-model="refundFormData.oldfreeGold"
  1048. disabled />
  1049. </div>
  1050. </div>
  1051. <div class="add-item">
  1052. <el-text style="width:4vw;">{{ t('common_add.payCurrency') }}</el-text>
  1053. <el-input v-model="refundFormData.paymentCurrency" style="width:10vw;" disabled />
  1054. </div>
  1055. <div class="add-item">
  1056. <el-text style="width:4vw;">{{ t('common_add.payAmount') }}</el-text>
  1057. <el-input v-model="refundFormData.paymentAmount" style="width:10vw;" disabled />
  1058. </div>
  1059. <div class="add-item">
  1060. <el-text style="width:4vw;">{{ t('common_add.payMethod') }}</el-text>
  1061. <el-input v-model="refundFormData.payType" style="width:10vw;" disabled />
  1062. </div>
  1063. <div class="add-item">
  1064. <el-text style="width:4vw;">{{ t('common_add.payTime') }}</el-text>
  1065. <el-date-picker v-model="refundFormData.payTime" type="datetime" style="width:10vw;" disabled />
  1066. </div>
  1067. <div class="add-item">
  1068. <el-text style="width:4vw;" size="small">{{ t('common_add.transferVoucher') }}</el-text>
  1069. <el-form-item :rules="{ required: true, message: t('common_add.uploadPhoto'), trigger: 'change' }">
  1070. <el-upload ref="uploadRef" :auto-upload="false" list-type="picture-card" :show-file-list="false">
  1071. <template #default>
  1072. <img v-if="refundFormData.voucher" :src="refundFormData.voucher"
  1073. style="width: 100%; height: 100%; object-fit: cover;">
  1074. <el-icon v-else>
  1075. <Plus />
  1076. </el-icon>
  1077. </template>
  1078. </el-upload>
  1079. </el-form-item>
  1080. </div>
  1081. <div class="add-item">
  1082. <el-text style="width:4vw;">{{ t('common_add.remark') }}</el-text>
  1083. <el-input v-model="refundFormData.remark" style="width:10vw;" :rows="2" type="textarea" maxLength="100"
  1084. disabled show-word-limit />
  1085. </div>
  1086. </div>
  1087. <div class="right">
  1088. <div class="add-item">
  1089. <el-text style="width:4vw;">{{ t('common_add.refundModel') }}</el-text>
  1090. <el-radio-group v-model="refundFormData.refundModel">
  1091. <el-radio value="0">{{ t('common_add.refundModelAll') }}</el-radio>
  1092. <el-radio value="1">{{ t('common_add.refundModelPart') }}</el-radio>
  1093. </el-radio-group>
  1094. </div>
  1095. <div v-show="refundFormData.refundModel == '1'" style="display: flex; margin-bottom: 10px;">
  1096. <div style=" display: flex; align-items: center;justify-content: center; ">
  1097. <span style="color: #999999; white-space: nowrap;">{{ t('common_add.permanentGold')
  1098. }}</span>
  1099. <el-input style="padding-right: 10px; height: 30px; width: 70px;"
  1100. v-model="refundFormData.permanentGold" />
  1101. </div>
  1102. <div style=" display: flex; align-items: center;justify-content: center; ">
  1103. <span style="color: #999999; white-space: nowrap;">{{ t('common_add.freeGold') }}</span>
  1104. <el-input style="padding-right: 10px; height: 30px; width: 70px;" v-model="refundFormData.freeGold" />
  1105. </div>
  1106. </div>
  1107. <div class="add-item">
  1108. <el-text style="width:4vw;">{{ t('common_add.refundReason') }}</el-text>
  1109. <el-input v-model="refundFormData.refundReason" style="width:10vw;" :rows="5" maxlength="150"
  1110. show-word-limit type="textarea" />
  1111. </div>
  1112. <div>{{ t('common_add.tip') }}</div>
  1113. <div style="display:flex;justify-content: center;margin-top: 5vh;">
  1114. <el-button type="default" @click="resetRefund">{{ t('common.reset') }}</el-button>
  1115. <el-button type="primary" @click="throttledsubmitRefund">{{ t('common.submit') }}</el-button>
  1116. </div>
  1117. </div>
  1118. </div>
  1119. </el-dialog>
  1120. </div>
  1121. </template>
  1122. <style lang="scss">
  1123. .refund-popover {
  1124. background-color: #EEF5FE !important;
  1125. border: none !important;
  1126. padding: 12px !important;
  1127. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  1128. width: 100px;
  1129. min-width: none;
  1130. .el-popper__arrow::before {
  1131. background-color: #EEF5FE !important;
  1132. border-color: #EEF5FE !important;
  1133. }
  1134. }
  1135. </style>
  1136. <style scoped lang="scss">
  1137. :deep(.detailDialog) {
  1138. background: #F3FAFE !important;
  1139. .left {
  1140. width: 50%;
  1141. height: 60vh;
  1142. min-height: 400px;
  1143. .add-item {
  1144. display: flex;
  1145. align-items: center;
  1146. margin-bottom: 1vh;
  1147. }
  1148. .image {
  1149. width: 4vw !important;
  1150. height: 4vw !important;
  1151. }
  1152. }
  1153. .right {
  1154. width: 50%;
  1155. height: 60vh;
  1156. .add-item {
  1157. display: flex;
  1158. align-items: center;
  1159. margin-bottom: 1vh;
  1160. }
  1161. }
  1162. .voucher-img {
  1163. width: 100px; /* 限制宽度 */
  1164. height: 100px; /* 限制高度 */
  1165. border-radius: 4px;
  1166. cursor: pointer; /* 鼠标放上去显示手型,提示可点击预览 */
  1167. }
  1168. .no-voucher {
  1169. color: #909399;
  1170. font-size: 14px;
  1171. }
  1172. }
  1173. :deep(.adddialog .el-form-item__label) {
  1174. min-width: 120px;
  1175. width: auto;
  1176. font-weight: 800;
  1177. padding-bottom: 15px;
  1178. }
  1179. .btnItem {
  1180. margin-left: 10px;
  1181. border-radius: 5px;
  1182. }
  1183. .btnDiv{
  1184. text-align: center;
  1185. margin-top: 30px;
  1186. }
  1187. :deep(.adddialog) {
  1188. min-width: 400px;
  1189. background-color: #F3FAFE !important;
  1190. margin-top: 8vh;
  1191. border-radius: 8px;
  1192. }
  1193. .popover-content {
  1194. .popover-title {
  1195. color: #409EFF;
  1196. font-weight: bold;
  1197. font-size: 14px;
  1198. margin-bottom: 8px;
  1199. }
  1200. .popover-item {
  1201. display: flex;
  1202. font-size: 13px;
  1203. color: #606266;
  1204. margin-bottom: 4px;
  1205. &:last-child {
  1206. margin-bottom: 0;
  1207. }
  1208. .label {
  1209. color: #606266;
  1210. }
  1211. .value {
  1212. color: #606266;
  1213. margin-left: 4px;
  1214. }
  1215. }
  1216. }
  1217. .cash-flow-container {
  1218. display: flex;
  1219. flex-direction: column;
  1220. height: 100%;
  1221. }
  1222. .search-card {
  1223. margin-bottom: 10px;
  1224. background: #F3FAFE; // 浅蓝背景
  1225. border: none;
  1226. :deep(.el-card__body) {
  1227. padding: 15px;
  1228. }
  1229. }
  1230. .search-bar {
  1231. display: flex;
  1232. flex-direction: column;
  1233. gap: 15px;
  1234. }
  1235. .search-row {
  1236. display: flex;
  1237. flex-wrap: wrap;
  1238. gap: 20px;
  1239. align-items: center;
  1240. }
  1241. .search-item {
  1242. display: flex;
  1243. align-items: center;
  1244. .label {
  1245. font-size: 15px; // 参考 coinConsumeDetail 的 .text size="large"
  1246. color: #000; // 或 #606266
  1247. white-space: nowrap;
  1248. margin-right: 8px;
  1249. min-width: 60px;
  1250. text-align: right;
  1251. }
  1252. .el-input,
  1253. .el-select {
  1254. width: 200px;
  1255. }
  1256. }
  1257. .search-btn-group {
  1258. margin-left: 20px; // 靠右对齐
  1259. display: flex;
  1260. gap: 10px;
  1261. }
  1262. .newAdd {
  1263. display: flex;
  1264. width: 240px;
  1265. justify-content: flex-end;
  1266. }
  1267. .newAdd_btn{
  1268. background-color: blueviolet;
  1269. color: white;
  1270. }
  1271. .table-card {
  1272. background: #E7F4FD;
  1273. flex: 1;
  1274. border: none;
  1275. display: flex;
  1276. flex-direction: column;
  1277. :deep(.el-card__body) {
  1278. padding: 20px;
  1279. flex: 1;
  1280. display: flex;
  1281. flex-direction: column;
  1282. overflow: hidden;
  1283. }
  1284. }
  1285. .pagination-container {
  1286. margin-top: 15px;
  1287. display: flex;
  1288. justify-content: flex-start;
  1289. }
  1290. // 表格样式覆盖 (参考 coinConsumeDetail)
  1291. :deep(.el-table__header-wrapper),
  1292. :deep(.el-table__body-wrapper),
  1293. :deep(.el-table__cell),
  1294. :deep(.el-table__body td) {
  1295. background-color: #F3FAFE !important;
  1296. }
  1297. :deep(.el-table__row:hover > .el-table__cell) {
  1298. background-color: #E5EBFE !important;
  1299. }
  1300. .refundDialog {
  1301. .left {
  1302. width: 50%;
  1303. height: 70vh;
  1304. min-height: 700px;
  1305. padding: 0 2vw;
  1306. .add-item {
  1307. display: flex;
  1308. align-items: center;
  1309. margin-bottom: 1vh;
  1310. }
  1311. .image {
  1312. width: 4vw !important;
  1313. height: 4vw !important;
  1314. }
  1315. }
  1316. .right {
  1317. width: 50%;
  1318. height: 50vh;
  1319. .add-item {
  1320. display: flex;
  1321. align-items: center;
  1322. margin-bottom: 1vh;
  1323. }
  1324. }
  1325. }
  1326. .recallDialog {
  1327. //撤回弹窗提示
  1328. height: 392px;
  1329. width: 700px;
  1330. background-image: url('/src/assets/receive-recall.png');
  1331. position: fixed; // 固定定位,相对于浏览器窗口
  1332. top: 50%; // 距离顶部50%
  1333. left: 50%; // 距离左侧50%
  1334. transform: translate(-50%, -50%); // 向左、向上平移自身宽高的50%,实现居中
  1335. z-index: 1000; // 确保在其他元素上层显示
  1336. .close {
  1337. position: absolute;
  1338. left: 625px;
  1339. top: 20px;
  1340. height: 38px;
  1341. width: 38px;
  1342. opacity: 0;
  1343. .Btn {
  1344. height: 100%;
  1345. width: 100%;
  1346. border-radius: 10px;
  1347. }
  1348. }
  1349. .text {
  1350. position: absolute;
  1351. left: 185px;
  1352. top: 190px;
  1353. height: 67px;
  1354. width: 500px;
  1355. .txt {
  1356. height: 100%;
  1357. width: 100%;
  1358. color: #001a42;
  1359. font-family: "PingFang SC";
  1360. font-size: 38px;
  1361. font-style: normal;
  1362. font-weight: 900;
  1363. line-height: normal;
  1364. }
  1365. }
  1366. .cancle {
  1367. position: absolute;
  1368. left: 185px;
  1369. top: 304px;
  1370. height: 55px;
  1371. width: 150px;
  1372. opacity: 0;
  1373. .Btn {
  1374. height: 100%;
  1375. width: 100%;
  1376. border-radius: 20px;
  1377. }
  1378. }
  1379. .confirm {
  1380. position: absolute;
  1381. left: 375px;
  1382. top: 304px;
  1383. height: 55px;
  1384. width: 150px;
  1385. opacity: 0;
  1386. .Btn {
  1387. height: 100%;
  1388. width: 100%;
  1389. border-radius: 20px;
  1390. }
  1391. }
  1392. }
  1393. </style>