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.

726 lines
22 KiB

3 months ago
1 week ago
3 months ago
1 week ago
4 days ago
4 days 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
3 months ago
3 months ago
1 week 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 week 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
1 week ago
1 week 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
1 week 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 week ago
1 week ago
1 week 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 week ago
1 week ago
1 week ago
3 months ago
  1. <script setup>
  2. import { ref, reactive, onMounted, toRefs, nextTick, computed } from 'vue'
  3. import { ElMessage, ElMessageBox } from 'element-plus'
  4. import request from '@/util/http.js'
  5. import dayjs from 'dayjs'
  6. import { useI18n } from 'vue-i18n'
  7. import { refundOnline,performanceSelect,exportPerformance,adjustment } from '@/api/cash/financialAccount.js'
  8. import { getUserInfo } from '@/api/common/common.js'
  9. import { useAdminStore } from '@/store/index.js'
  10. import { permissionMapping, hasMenuPermission } from "@/utils/menuTreePermission.js"
  11. import { storeToRefs } from 'pinia'
  12. const adminStore = useAdminStore()
  13. const { menuTree,flag } = storeToRefs(adminStore)
  14. const adminData = ref({})
  15. const { t } = useI18n()
  16. const paytypeList = [
  17. t('cash.payMethods.stripe'),
  18. t('cash.payMethods.paymentAsia'),
  19. t('cash.payMethods.ipay88'),
  20. t('cash.payMethods.bankTransfer'),
  21. t('cash.payMethods.card'),
  22. t('cash.payMethods.cash'),
  23. t('cash.payMethods.check'),
  24. t('cash.payMethods.grabpay'),
  25. t('cash.payMethods.nets'),
  26. t('cash.payMethods.transfer'),
  27. t('cash.payMethods.iotPay'),
  28. t('cash.payMethods.stripe3'),
  29. t('cash.payMethods.paypal'),
  30. ]
  31. const hasperformanceAdjustment = ref(false)
  32. // 初始化权限状态
  33. const initPermissions = async () => {
  34. if (!menuTree.value || !menuTree.value.length) return;
  35. // 业绩调整
  36. hasperformanceAdjustment.value = hasMenuPermission(menuTree.value, permissionMapping.performance_adjustment);
  37. console.log('业绩调整权限',hasperformanceAdjustment.value);
  38. };
  39. const payPlatformOptions = ref([...paytypeList])
  40. const statusOptions = [
  41. { label: t('cash.statusList.received'), value: 4 },
  42. { label: t('cash.statusList.refunded'), value: 6 }
  43. ]
  44. // 地区树
  45. const marketOptions = ref([])
  46. // 查询参数
  47. const queryParams = reactive({
  48. jwcode: '',
  49. adminMarket: [], // 下拉多选
  50. timeRange: [], // [startTime, endTime]
  51. customerMarket: [], // 客户地区
  52. pageNum: 1,
  53. pageSize: 20
  54. })
  55. const total = ref(0)
  56. const tableData = ref([])
  57. const tableRef = ref(null)
  58. const scrollTableTop = () => {
  59. tableRef.value?.setScrollTop?.(0)
  60. }
  61. const loading = ref(false)
  62. // 转换树形结构(参考 coinConsumeDetail.vue)
  63. const transformTree = (nodes) => {
  64. const allChildren = nodes.flatMap(node => node.children || []);
  65. return allChildren.map(child => {
  66. const grandchildren = child.children && child.children.length
  67. ? transformTree([child])
  68. : null;
  69. return {
  70. value: child.id,
  71. label: child.name,
  72. children: grandchildren
  73. };
  74. });
  75. };
  76. // 获取地区数据
  77. const getMarket = async () => {
  78. try {
  79. const result = await request({ url: '/market/selectMarket' });
  80. if (result && result.data) {
  81. marketOptions.value = transformTree(result.data)
  82. console.log('地区树:', marketOptions.value)
  83. }
  84. } catch (error) {
  85. console.error('获取地区失败', error)
  86. }
  87. }
  88. // 查询列表
  89. const fetchData = async () => {
  90. loading.value = true
  91. try {
  92. // 构建请求参数
  93. console.log('adminData.value.markets:', adminData.value.markets)
  94. const params = {
  95. pageNum: queryParams.pageNum,
  96. pageSize: queryParams.pageSize,
  97. performanceDTO:{
  98. jwcode: queryParams.jwcode,
  99. adminMarket: adminData.value.marketName.split(',').filter(item => item.trim() !== '') || [],
  100. customerMarket: queryParams.customerMarket,
  101. startTime: queryParams.timeRange?.[0] ? dayjs(queryParams.timeRange[0]).format('YYYY-MM-DD HH:mm:ss') : '',
  102. endTime: queryParams.timeRange?.[1] ? dayjs(queryParams.timeRange[1]).format('YYYY-MM-DD HH:mm:ss') : '',
  103. }
  104. }
  105. console.log('查询参数:', params)
  106. const res = await performanceSelect(params)
  107. if (res.code == 200) {
  108. tableData.value = res.data.list || []
  109. await nextTick()
  110. scrollTableTop()
  111. total.value = res.data.total || 0
  112. loading.value = false
  113. } else {
  114. ElMessage.error(res.msg || t('elmessage.getDataFailed'))
  115. loading.value = false
  116. }
  117. } catch (error) {
  118. console.error(error)
  119. loading.value = false
  120. ElMessage.error(t('elmessage.getDataFailed'))
  121. }
  122. }
  123. const handleAdminInfo = async () => {
  124. try {
  125. const res = await getUserInfo()
  126. adminData.value = res || {}
  127. console.log('adminData.value:', adminData.value);
  128. } catch (error) {
  129. console.error(error)
  130. ElMessage.error(t('elmessage.getDataFailed'))
  131. }
  132. }
  133. const handleSearch = () => {
  134. queryParams.pageNum = 1
  135. fetchData()
  136. }
  137. const handleReset = () => {
  138. queryParams.jwcode = ''
  139. queryParams.adminMarket = []
  140. queryParams.timeRange = null
  141. queryParams.customerMarket = []
  142. handleSearch()
  143. }
  144. const handlePageSizeChange = (val) => {
  145. queryParams.pageSize = val
  146. fetchData()
  147. }
  148. const handleCurrentChange = (val) => {
  149. queryParams.pageNum = val
  150. fetchData()
  151. }
  152. // 退款操作
  153. const handleRefund = (row) => {
  154. ElMessageBox.confirm(t('elmessage.refundConfirmContent', { orderNo: row.systemTradeNo }), t('elmessage.refundConfirmTitle'), {
  155. confirmButtonText: t('common.confirm'),
  156. cancelButtonText: t('common.cancel'),
  157. type: 'warning'
  158. }).then(() => {
  159. ElMessage.success(t('elmessage.refundSubmitSuccess'))
  160. // 刷新列表
  161. fetchData()
  162. }).catch(() => {})
  163. }
  164. // ==================== 导出相关逻辑 ====================
  165. const exportListVisible = ref(false)
  166. const exportList = ref([])
  167. const exportListLoading = ref(false)
  168. // 导出Excel
  169. const handleExport = async () => {
  170. try {
  171. const params = {
  172. pageNum: queryParams.pageNum,
  173. pageSize: queryParams.pageSize,
  174. performanceDTO:{
  175. jwcode: queryParams.jwcode,
  176. adminMarket: adminData.value.marketName.split(',').filter(item => item.trim() !== '') || [],
  177. customerMarket: queryParams.customerMarket,
  178. startTime: queryParams.timeRange?.[0] ? dayjs(queryParams.timeRange[0]).format('YYYY-MM-DD HH:mm:ss') : '',
  179. endTime: queryParams.timeRange?.[1] ? dayjs(queryParams.timeRange[1]).format('YYYY-MM-DD HH:mm:ss') : '',
  180. }
  181. }
  182. // TODO: 确认导出接口 URL
  183. const res = await exportPerformance(params)
  184. if(res.code == 200){
  185. console.log('导出参数', params)
  186. ElMessage.success(t('elmessage.exportSuccess'))
  187. }
  188. } catch (error) {
  189. console.error(error)
  190. ElMessage.error(t('elmessage.exportError'))
  191. }
  192. }
  193. // 打开导出列表弹窗
  194. const openExportList = () => {
  195. getExportList()
  196. exportListVisible.value = true
  197. }
  198. // 获取导出列表
  199. const getExportList = async () => {
  200. exportListLoading.value = true
  201. try {
  202. const result = await request({ url: '/export/export' })
  203. if (result.code === 200) {
  204. const filteredData = result.data.filter(item => item.type == 14);
  205. exportList.value = filteredData || []
  206. } else {
  207. ElMessage.error(result.msg || t('elmessage.getExportListError'))
  208. }
  209. } catch (error) {
  210. console.error('获取导出列表出错:', error)
  211. ElMessage.error(t('elmessage.getExportListError'))
  212. } finally {
  213. exportListLoading.value = false
  214. }
  215. }
  216. // 下载导出文件
  217. const downloadExportFile = (item) => {
  218. if (item.state === 2) {
  219. const link = document.createElement('a')
  220. link.href = item.url
  221. link.download = item.fileName
  222. link.click()
  223. } else {
  224. ElMessage.warning(t('elmessage.exportingInProgress'))
  225. }
  226. }
  227. // 根据状态返回对应的标签类型
  228. const getTagType = (state) => {
  229. switch (state) {
  230. case 0: return 'info';
  231. case 1: return 'primary';
  232. case 2: return 'success';
  233. case 3: return 'danger';
  234. default: return 'info';
  235. }
  236. }
  237. // 根据状态返回对应的标签文案
  238. const getTagText = (state) => {
  239. switch (state) {
  240. case 0: return t('elmessage.pendingExecution');
  241. case 1: return t('elmessage.executing');
  242. case 2: return t('elmessage.executed');
  243. case 3: return t('elmessage.errorExecution');
  244. default: return t('elmessage.unknownStatus');
  245. }
  246. }
  247. // ==================== 业绩调整弹窗相关逻辑 ====================
  248. const adjustVisible = ref(false)
  249. const adjustTime = ref('')
  250. const adjustCoefficient = ref('')
  251. const matrixMarkets = [
  252. { key: 'sg', label: '新加坡' },
  253. { key: 'my', label: '马来西亚' },
  254. { key: 'hk', label: '香港' },
  255. { key: 'th', label: '泰国' },
  256. { key: 'vn', label: '越南' },
  257. { key: 'ca', label: '加拿大' }
  258. ]
  259. const adjustData = ref([])
  260. const initAdjustData = () => {
  261. adjustData.value = matrixMarkets.map(rowMarket => {
  262. const row = { inMarket: rowMarket.label + '客户' }
  263. matrixMarkets.forEach(colMarket => {
  264. row[colMarket.key] = '' // 默认空
  265. })
  266. return row
  267. })
  268. }
  269. const handleAdjustment = () => {
  270. adjustTime.value = dayjs().format('YYYY-MM-DD HH:mm:ss')
  271. adjustCoefficient.value = ''
  272. initAdjustData()
  273. adjustVisible.value = true
  274. }
  275. const computedAdjustData = computed(() => {
  276. const data = [...adjustData.value]
  277. const sumRow = { inMarket: '合计', isSum: true }
  278. matrixMarkets.forEach(colMarket => {
  279. let colSum = 0
  280. adjustData.value.forEach(row => {
  281. const val = parseFloat(row[colMarket.key])
  282. if (!isNaN(val)) colSum += val
  283. })
  284. sumRow[colMarket.key] = colSum
  285. })
  286. data.push(sumRow)
  287. return data
  288. })
  289. const getRowTotal = (row) => {
  290. let sum = 0
  291. matrixMarkets.forEach(colMarket => {
  292. const val = parseFloat(row[colMarket.key])
  293. if (!isNaN(val)) sum += val
  294. })
  295. return sum
  296. }
  297. const formatNumber = (val) => {
  298. if (val === '' || val === '-' || val === undefined || val === null) return val;
  299. val = String(val);
  300. let formatted = val.replace(/[^\d.-]/g, ''); // 移除非数字、点和负号
  301. formatted = formatted.replace(/(?!^)-/g, ''); // 负号只能在开头
  302. formatted = formatted.replace(/(\..*?)\..*/g, '$1'); // 只能有一个点
  303. return formatted;
  304. }
  305. const submitAdjustment = async () => {
  306. if (!adjustTime.value) {
  307. ElMessage.warning('请选择时间')
  308. return
  309. }
  310. if (!adjustCoefficient.value) {
  311. ElMessage.warning('请输入系数')
  312. return
  313. }
  314. // 组装矩阵数据 matrix (二维数组,6行6列)
  315. // 如果单元格为空或者非数字,默认为 0
  316. const matrix = adjustData.value.map(row => {
  317. return matrixMarkets.map(colMarket => {
  318. const val = parseFloat(row[colMarket.key])
  319. return isNaN(val) ? 0 : val
  320. })
  321. })
  322. // 构造最终提交的数据结构
  323. const payload = {
  324. matrix: matrix,
  325. weight: parseFloat(adjustCoefficient.value), // 系数
  326. createTime: adjustTime.value,
  327. submitterId: adminData.value.id || 1000063, // 从全局 adminData 获取
  328. submitterMarket: adminData.value.marketName || '总部' // 如果为空默认传总部
  329. }
  330. console.log('提交的封装数据:', JSON.stringify(payload, null, 2))
  331. await adjustment(payload)
  332. ElMessage.success('提交成功')
  333. adjustVisible.value = false
  334. fetchData()
  335. }
  336. onMounted( async() => {
  337. await initPermissions()
  338. await handleAdminInfo()
  339. getMarket()
  340. await fetchData()
  341. })
  342. </script>
  343. <template>
  344. <div class="cash-flow-container">
  345. <!-- 搜索区域 -->
  346. <el-card class="search-card">
  347. <div class="search-bar">
  348. <!-- 第一行 -->
  349. <div class="search-row">
  350. <div class="search-item">
  351. <span class="label">{{ t('common.jwcode') }}</span>
  352. <el-input v-model="queryParams.jwcode" :placeholder="t('common.jwcodePlaceholder')" clearable />
  353. </div>
  354. <div class="search-item">
  355. <span class="label">{{ t('common.market') }}</span>
  356. <!-- 下拉多选使用 el-cascader 匹配地区树结构 -->
  357. <el-cascader
  358. v-model="queryParams.customerMarket"
  359. :options="marketOptions"
  360. :props="{ multiple: true, emitPath: false }"
  361. collapse-tags
  362. collapse-tags-tooltip
  363. :placeholder="t('common.marketPlaceholder')"
  364. clearable
  365. style="width: 8vw;"
  366. />
  367. </div>
  368. <div class="search-item" style="width: auto;">
  369. <span class="label">{{ t('common.payTime2') }}</span>
  370. <el-date-picker
  371. v-model="queryParams.timeRange"
  372. type="datetimerange"
  373. :range-separator="t('common.to')"
  374. :start-placeholder="t('common.startTime')"
  375. :end-placeholder="t('common.endTime')"
  376. :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
  377. style="width: 18vw;"
  378. />
  379. </div>
  380. </div>
  381. <div class="search-row">
  382. <el-button type="primary" @click="handleSearch">{{ t('common.search') }}</el-button>
  383. <el-button type="primary" @click="handleExport">{{ t('common.exportExcel') }}</el-button>
  384. <el-button type="primary" @click="openExportList">{{ t('common.viewExportList') }}</el-button>
  385. <el-button type="success" @click="handleReset">{{ t('common.reset') }}</el-button>
  386. <button v-if="hasperformanceAdjustment" class="adjust-btn" @click="handleAdjustment">业绩调整</button>
  387. </div>
  388. </div>
  389. </el-card>
  390. <!-- 表格区域 -->
  391. <el-card class="table-card">
  392. <el-table ref="tableRef" :data="tableData" v-loading="loading" style="width: 100%; flex: 1;" :cell-style="{ textAlign: 'center' }" :header-cell-style="{ background: '#F3FAFE', color: '#333',textAlign: 'center' }">
  393. <el-table-column type="index" :label="t('common_list.id')" min-width="60" align="center" fixed="left" >
  394. <template #default="scope">
  395. <span>{{ scope.$index + 1 + (queryParams.pageNum - 1) * queryParams.pageSize }}</span>
  396. </template>
  397. </el-table-column>
  398. <el-table-column prop="jwcode" :label="t('common_list.jwcode')" min-width="120" fixed="left" />
  399. <el-table-column prop="name" :label="t('common_list.name')" min-width="150" show-overflow-tooltip />
  400. <el-table-column prop="marketName" :label="t('common_list.market')" min-width="120" show-overflow-tooltip />
  401. <el-table-column prop="orderCode" :label="t('common_list.orderCode')" min-width="280" show-overflow-tooltip />
  402. <el-table-column prop="paymentAmount" :label="t('common_list.payAmount')" min-width="150" align="right">
  403. <!-- <template #default="{ row }">
  404. {{ row.paymentAmount }} {{ row.paymentCurrency }}
  405. </template> -->
  406. </el-table-column>
  407. <el-table-column prop="paymentCurrency" :label="t('common_list.payCurrency')" min-width="180" show-overflow-tooltip />
  408. <el-table-column prop="receivedAmount" :label="t('common_list.receiveAmount')" min-width="150" align="right">
  409. <!-- <template #default="{ row }">
  410. {{ row.receivedAmount }} {{ row.receivedCurrency }}
  411. </template> -->
  412. </el-table-column>
  413. <el-table-column prop="receivedCurrency" :label="t('common_list.receiveCurrency')" min-width="180" show-overflow-tooltip />
  414. <el-table-column prop="handlingCharge" :label="t('common_list.fee')" min-width="100" align="right" />
  415. </el-table>
  416. <!-- 分页 -->
  417. <div class="pagination-container">
  418. <el-pagination
  419. background
  420. layout="total, sizes, prev, pager, next, jumper"
  421. :total="total"
  422. :current-page="queryParams.pageNum"
  423. :page-size="queryParams.pageSize"
  424. :page-sizes="[10, 20, 50, 100]"
  425. @size-change="handlePageSizeChange"
  426. @current-change="handleCurrentChange"
  427. />
  428. </div>
  429. </el-card>
  430. <!-- 导出列表弹窗 -->
  431. <el-dialog v-model="exportListVisible" :title="t('common_export.exportList')" width="80%">
  432. <el-table :data="exportList" style="width: 100% ;height: 60vh;" :loading="exportListLoading">
  433. <el-table-column prop="fileName" :label="t('common_export.fileName')" />
  434. <el-table-column prop="state" :label="t('common_export.status')">
  435. <template #default="scope">
  436. <el-tag :type="getTagType(scope.row.state)" :effect="scope.row.state === 3 ? 'light' : 'plain'">
  437. {{ getTagText(scope.row.state) }}
  438. </el-tag>
  439. </template>
  440. </el-table-column>
  441. <el-table-column prop="createTime" :label="t('common_export.createTime')">
  442. <template #default="scope">
  443. {{ dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
  444. </template>
  445. </el-table-column>
  446. <el-table-column :label="t('common_export.operation')">
  447. <template #default="scope">
  448. <el-button type="primary" size="small" @click="downloadExportFile(scope.row)"
  449. :disabled="scope.row.state !== 2">
  450. {{ t('common_export.download') }}
  451. </el-button>
  452. </template>
  453. </el-table-column>
  454. </el-table>
  455. <template #footer>
  456. <div class="dialog-footer">
  457. <el-button text @click="exportListVisible = false">{{ t('common_export.close') }}</el-button>
  458. </div>
  459. </template>
  460. </el-dialog>
  461. <!-- 业绩调整弹窗 -->
  462. <el-dialog v-model="adjustVisible" title="市场消耗金币业绩调整" width="80%" top="5vh" align-center class="custom-adjust-dialog">
  463. <template #header="{ titleId, titleClass }">
  464. <div style="text-align: center; font-weight: bold; font-size: 18px;" :id="titleId" :class="titleClass">市场消耗金币业绩调整</div>
  465. </template>
  466. <div style="display: flex; gap: 40px; margin-bottom: 20px; align-items: center;">
  467. <div style="display: flex; align-items: center;">
  468. <span style="margin-right: 10px; font-weight: bold;">选择时间</span>
  469. <el-date-picker
  470. v-model="adjustTime"
  471. type="datetime"
  472. placeholder="选择时间"
  473. value-format="YYYY-MM-DD HH:mm:ss"
  474. />
  475. </div>
  476. <div style="display: flex; align-items: center;">
  477. <span style="margin-right: 10px; font-weight: bold;">系数调整</span>
  478. <el-input v-model="adjustCoefficient" placeholder="请输入系数调整" style="width: 200px;" @input="adjustCoefficient = formatNumber(adjustCoefficient)" />
  479. </div>
  480. </div>
  481. <el-table :data="computedAdjustData" border style="width: 100%" :cell-style="{ textAlign: 'center' }" :header-cell-style="{ background: '#F3FAFE', color: '#333', textAlign: 'center', padding: '0' }">
  482. <el-table-column width="150" align="center" fixed="left">
  483. <template #header>
  484. <div class="diagonal-header">
  485. <span class="top-right">调入</span>
  486. <span class="bottom-left">调出</span>
  487. </div>
  488. </template>
  489. <template #default="{ row }">
  490. <span style="font-weight: bold;">{{ row.inMarket }}</span>
  491. </template>
  492. </el-table-column>
  493. <el-table-column v-for="col in matrixMarkets" :key="col.key" :label="col.label + '市场团队'" min-width="120" align="center">
  494. <template #default="{ row }">
  495. <span v-if="row.isSum">{{ row[col.key] }}</span>
  496. <el-input v-else v-model="row[col.key]" @input="row[col.key] = formatNumber($event)" placeholder="" class="seamless-input" />
  497. </template>
  498. </el-table-column>
  499. <el-table-column label="合计" min-width="120" align="center" fixed="right">
  500. <template #default="{ row }">
  501. {{ getRowTotal(row) }}
  502. </template>
  503. </el-table-column>
  504. </el-table>
  505. <template #footer>
  506. <div class="dialog-footer" style="text-align: center;">
  507. <el-button type="primary" plain @click="adjustVisible = false" style="width: 100px;">取消</el-button>
  508. <el-button type="primary" @click="submitAdjustment" style="width: 100px;">提交</el-button>
  509. </div>
  510. </template>
  511. </el-dialog>
  512. </div>
  513. </template>
  514. <style scoped lang="scss">
  515. .cash-flow-container {
  516. display: flex;
  517. flex-direction: column;
  518. height: 100%;
  519. }
  520. .search-card {
  521. margin-bottom: 10px;
  522. background: #F3FAFE; // 浅蓝背景
  523. border: none;
  524. :deep(.el-card__body) {
  525. padding: 15px;
  526. }
  527. }
  528. .search-bar {
  529. display: flex;
  530. flex-direction: column;
  531. gap: 15px;
  532. }
  533. .search-row {
  534. display: flex;
  535. flex-wrap: wrap;
  536. gap: 20px;
  537. align-items: center;
  538. }
  539. .search-item {
  540. display: flex;
  541. align-items: center;
  542. .label {
  543. font-size: 15px; // 参考 coinConsumeDetail 的 .text size="large"
  544. color: #000; // 或 #606266
  545. white-space: nowrap;
  546. margin-right: 8px;
  547. min-width: 60px;
  548. text-align: right;
  549. }
  550. .el-input, .el-select {
  551. width: 8vw;
  552. }
  553. }
  554. .search-btn-group {
  555. margin-left: 2vw;
  556. display: flex;
  557. gap: 10px;
  558. }
  559. .adjust-btn {
  560. color: #fff;
  561. padding: 8px 15px;
  562. border-radius: 4px;
  563. cursor: pointer;
  564. border: none;
  565. background-color: #7349ad;
  566. margin-left: auto;
  567. }
  568. .table-card {
  569. background: #E7F4FD;
  570. flex: 1;
  571. border: none;
  572. display: flex;
  573. flex-direction: column;
  574. :deep(.el-card__body) {
  575. padding: 20px;
  576. flex: 1;
  577. display: flex;
  578. flex-direction: column;
  579. overflow: hidden;
  580. }
  581. }
  582. .pagination-container {
  583. margin-top: 15px;
  584. display: flex;
  585. justify-content: flex-start;
  586. }
  587. // 表格样式覆盖 (参考 coinConsumeDetail)
  588. :deep(.el-table__header-wrapper),
  589. :deep(.el-table__body-wrapper),
  590. :deep(.el-table__cell),
  591. :deep(.el-table__body td) {
  592. background-color: #F3FAFE !important; // 如果想完全一致可以加这个,但有时候会影响阅读,暂保留头部颜色
  593. }
  594. :deep(.el-table__row:hover > .el-table__cell) {
  595. background-color: #E5EBFE !important;
  596. }
  597. .diagonal-header {
  598. position: relative;
  599. width: 100%;
  600. height: 50px; /* Set a fixed height to make diagonal line work well */
  601. background: linear-gradient(to top right, transparent 49.5%, #dcdfe6 49.5%, #dcdfe6 50.5%, transparent 50.5%);
  602. }
  603. .diagonal-header .top-right {
  604. position: absolute;
  605. top: 5px;
  606. right: 15px;
  607. font-weight: bold;
  608. }
  609. .diagonal-header .bottom-left {
  610. position: absolute;
  611. bottom: 5px;
  612. left: 15px;
  613. font-weight: bold;
  614. }
  615. /* 业绩调整弹窗全局样式 */
  616. :deep(.custom-adjust-dialog) {
  617. background-color: #f3fafe !important; /* 统一淡蓝色背景 */
  618. border-radius: 8px;
  619. }
  620. :deep(.custom-adjust-dialog .el-dialog__header) {
  621. padding-bottom: 20px;
  622. border-bottom: 1px solid #EBEEF5;
  623. margin-right: 0;
  624. }
  625. :deep(.custom-adjust-dialog .el-dialog__body) {
  626. padding-top: 20px;
  627. }
  628. /* 无缝输入框样式(去除边框和背景) */
  629. .seamless-input :deep(.el-input__wrapper) {
  630. box-shadow: none !important;
  631. background-color: transparent !important;
  632. padding: 0;
  633. }
  634. .seamless-input :deep(.el-input__inner) {
  635. text-align: center;
  636. font-size: 14px;
  637. height: 100%;
  638. }
  639. .seamless-input :deep(.el-input__inner:focus) {
  640. outline: none;
  641. }
  642. </style>