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.

1491 lines
54 KiB

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