jiaxing.zhou

feat(rebate):重构返利页面搜索和表格功能

- 使用原生HTML元素替换Element UI组件
- 新增操作类型、计算状态、审核状态、数据来源等搜索条件
- 添加表格控制按钮和自定义分页组件
- 实现状态标签样式和操作链接样式
- 优化表格样式和加载状态显示
- 完善搜索表单重置逻辑
- 调整页面布局和样式细节
...@@ -32,6 +32,8 @@ export interface RebateSearchParams { ...@@ -32,6 +32,8 @@ export interface RebateSearchParams {
32 productCode?: string 32 productCode?: string
33 operateType?: number 33 operateType?: number
34 calcFlag?: number 34 calcFlag?: number
35 + auditStatus?: number
36 + dataSource?: string
35 rebateStartDate?: string 37 rebateStartDate?: string
36 rebateEndDate?: string 38 rebateEndDate?: string
37 } 39 }
......
...@@ -2,51 +2,64 @@ ...@@ -2,51 +2,64 @@
2 <div class="rebate-page"> 2 <div class="rebate-page">
3 <!-- 搜索区域 --> 3 <!-- 搜索区域 -->
4 <div class="search-section"> 4 <div class="search-section">
5 - <div class="search-form">
6 <div class="search-row"> 5 <div class="search-row">
7 <div class="search-item"> 6 <div class="search-item">
8 - <span class="search-label">经销商名称</span> 7 + <label>经销商名称:</label>
9 - <el-input 8 + <input
10 v-model="searchForm.dealerName" 9 v-model="searchForm.dealerName"
10 + class="search-input"
11 placeholder="请输入经销商名称" 11 placeholder="请输入经销商名称"
12 - clearable
13 - size="small"
14 - style="width: 160px"
15 /> 12 />
16 </div> 13 </div>
17 <div class="search-item"> 14 <div class="search-item">
18 - <span class="search-label">返利编号</span> 15 + <label>返利编号:</label>
19 - <el-input 16 + <input
20 v-model="searchForm.rebateNo" 17 v-model="searchForm.rebateNo"
18 + class="search-input"
21 placeholder="请输入返利编号" 19 placeholder="请输入返利编号"
22 - clearable
23 - size="small"
24 - style="width: 160px"
25 /> 20 />
26 </div> 21 </div>
27 <div class="search-item"> 22 <div class="search-item">
28 - <span class="search-label">日期</span> 23 + <label>操作类型:</label>
29 - <el-date-picker 24 + <select v-model="searchForm.operateType" class="search-select">
30 - v-model="dateRange" 25 + <option value="">所有</option>
31 - type="daterange" 26 + <option value="1">新增</option>
32 - range-separator="至" 27 + <option value="2">修改</option>
33 - start-placeholder="开始日期" 28 + <option value="3">删除</option>
34 - end-placeholder="结束日期" 29 + </select>
35 - size="small"
36 - format="YYYY-MM-DD"
37 - value-format="YYYY-MM-DD"
38 - @change="handleDateRangeChange"
39 - style="width: 240px"
40 - />
41 </div> 30 </div>
42 - <div class="search-actions"> 31 + <div class="search-item">
43 - <el-button type="primary" size="small" @click="handleSearch" :loading="loading"> 32 + <label>计算状态:</label>
44 - 查询 33 + <select v-model="searchForm.calcFlag" class="search-select">
45 - </el-button> 34 + <option value="">所有</option>
46 - <el-button size="small" @click="handleReset"> 35 + <option value="0">未计算</option>
47 - 重置 36 + <option value="1">已计算</option>
48 - </el-button> 37 + </select>
38 + </div>
39 + </div>
40 + <div class="search-row">
41 + <div class="search-item">
42 + <label>审核状态:</label>
43 + <select v-model="searchForm.auditStatus" class="search-select">
44 + <option value="">所有</option>
45 + <option value="0">待审核</option>
46 + <option value="1">审核通过</option>
47 + <option value="2">审核中</option>
48 + <option value="3">审核拒绝</option>
49 + </select>
50 + </div>
51 + <div class="search-item">
52 + <label>数据来源:</label>
53 + <select v-model="searchForm.dataSource" class="search-select">
54 + <option value="">所有</option>
55 + <option value="ERP系统">ERP系统</option>
56 + <option value="手工录入">手工录入</option>
57 + <option value="API导入">API导入</option>
58 + </select>
49 </div> 59 </div>
60 + <div class="search-actions">
61 + <button @click="handleSearch" class="search-btn" :disabled="loading">🔍 搜索</button>
62 + <button @click="handleReset" class="reset-btn">🔄 重置</button>
50 </div> 63 </div>
51 </div> 64 </div>
52 </div> 65 </div>
...@@ -96,91 +109,99 @@ ...@@ -96,91 +109,99 @@
96 </div> 109 </div>
97 </div> 110 </div>
98 111
112 + <!-- 操作按钮区域 -->
113 + <div class="action-section">
114 + <div class="action-buttons">
115 + <button @click="handleExport" class="action-btn secondary" :disabled="exportLoading">
116 + 📋 导出
117 + </button>
118 + </div>
119 + </div>
120 +
99 <!-- 数据表格 --> 121 <!-- 数据表格 -->
100 <div class="table-section"> 122 <div class="table-section">
101 <div class="table-header"> 123 <div class="table-header">
102 - <div class="table-title"> 124 + <div class="table-controls">
103 - 返利记录 125 + <button @click="handleTableSearch" class="control-btn">🔍</button>
126 + <button @click="handleTableRefresh" class="control-btn">🔄</button>
127 + <button @click="handleTableExport" class="control-btn">📋</button>
128 + <button @click="handleTableViewToggle" class="control-btn">⊞</button>
104 </div> 129 </div>
105 - <div class="table-actions">
106 - <el-button type="primary" size="small" @click="handleExport" :loading="exportLoading">
107 - <el-icon><Download /></el-icon>
108 - 导出
109 - </el-button>
110 - <div class="table-info">
111 - 数据状态: {{ loading ? '加载中...' : `共${rebateList.length}条记录` }}
112 </div> 130 </div>
131 +
132 + <div class="table-container">
133 + <div v-if="loading" class="loading-overlay">
134 + <div class="loading-spinner">加载中...</div>
113 </div> 135 </div>
136 + <table class="data-table">
137 + <thead>
138 + <tr>
139 + <th>返利编号</th>
140 + <th>订单编号</th>
141 + <th>经销商代码</th>
142 + <th>经销商名称</th>
143 + <th>产品编码</th>
144 + <th>返利金额</th>
145 + <th>返利日期</th>
146 + <th>操作类型</th>
147 + <th>计算状态</th>
148 + <th>更新时间</th>
149 + <th>操作</th>
150 + </tr>
151 + </thead>
152 + <tbody>
153 + <tr v-if="rebateList.length === 0">
154 + <td colspan="11" class="empty-data">暂无数据</td>
155 + </tr>
156 + <tr v-for="row in rebateList" :key="row.rebateId">
157 + <td>{{ row.rebateNo }}</td>
158 + <td>{{ row.orderNo }}</td>
159 + <td>{{ row.dealerCode }}</td>
160 + <td>{{ row.dealerName }}</td>
161 + <td>{{ row.productCode }}</td>
162 + <td class="amount-text">{{ formatAmount(row.rebateAmount) }}</td>
163 + <td>{{ row.rebateDate }}</td>
164 + <td>
165 + <span :class="getOperateTypeClass(row.operateType || 0)">
166 + {{ row.operateTypeText || getOperateTypeText(row.operateType || 0) }}
167 + </span>
168 + </td>
169 + <td>
170 + <span :class="getCalcFlagClass(row.calcFlag || 0)">
171 + {{ row.calcFlagText || getCalcFlagText(row.calcFlag || 0) }}
172 + </span>
173 + </td>
174 + <td>{{ formatDate(row.updateTime || '') }}</td>
175 + <td>
176 + <button @click="handleViewDetail(row)" class="action-link">详情</button>
177 + </td>
178 + </tr>
179 + </tbody>
180 + </table>
114 </div> 181 </div>
115 182
116 - <el-table
117 - v-loading="loading"
118 - :data="rebateList"
119 - style="width: 100%"
120 - :header-cell-style="{ background: '#fafafa', color: '#333', fontWeight: 'normal' }"
121 - :empty-text="rebateList.length === 0 ? '暂无数据' : ''"
122 - size="small"
123 - >
124 - <el-table-column prop="rebateNo" label="返利编号" width="140" align="center" />
125 - <el-table-column prop="orderNo" label="订单编号" width="140" align="center" />
126 - <el-table-column prop="dealerCode" label="经销商代码" width="120" align="center" />
127 - <el-table-column prop="dealerName" label="经销商名称" min-width="150" />
128 - <el-table-column prop="productCode" label="产品编码" width="120" align="center" />
129 - <el-table-column prop="rebateAmount" label="返利金额" width="120" align="right">
130 - <template #default="{ row }">
131 - <span class="amount-text">{{ formatAmount(row.rebateAmount) }}</span>
132 - </template>
133 - </el-table-column>
134 - <el-table-column prop="rebateDate" label="返利日期" width="120" align="center" />
135 - <el-table-column prop="operateTypeText" label="操作类型" width="100" align="center">
136 - <template #default="{ row }">
137 - <el-tag :type="getOperateTypeTagType(row.operateType)" size="small">
138 - {{ row.operateTypeText || getOperateTypeText(row.operateType) }}
139 - </el-tag>
140 - </template>
141 - </el-table-column>
142 - <el-table-column prop="calcFlagText" label="计算状态" width="100" align="center">
143 - <template #default="{ row }">
144 - <el-tag :type="getCalcFlagTagType(row.calcFlag)" size="small">
145 - {{ row.calcFlagText || getCalcFlagText(row.calcFlag) }}
146 - </el-tag>
147 - </template>
148 - </el-table-column>
149 - <el-table-column prop="updateTime" label="更新时间" width="150" align="center">
150 - <template #default="{ row }">
151 - {{ formatDate(row.updateTime) }}
152 - </template>
153 - </el-table-column>
154 - <el-table-column label="操作" width="80" align="center">
155 - <template #default="{ row }">
156 - <el-button type="primary" size="small" link @click="handleViewDetail(row)">
157 - 详情
158 - </el-button>
159 - </template>
160 - </el-table-column>
161 - </el-table>
162 -
163 <!-- 分页 --> 183 <!-- 分页 -->
164 <div class="pagination-wrapper"> 184 <div class="pagination-wrapper">
165 <div class="pagination-info"> 185 <div class="pagination-info">
166 共 {{ pagination.total }} 条,{{ pagination.pageSize }}/页 186 共 {{ pagination.total }} 条,{{ pagination.pageSize }}/页
167 </div> 187 </div>
168 - <el-pagination 188 + <div class="pagination-controls">
169 - v-model:current-page="pagination.pageNum" 189 + <button @click="handlePrevPage" :disabled="pagination.pageNum <= 1" class="page-btn">‹</button>
170 - v-model:page-size="pagination.pageSize" 190 + <button
171 - :page-sizes="[10, 20, 50, 100]" 191 + v-for="page in getPageNumbers()"
172 - :total="pagination.total" 192 + :key="page"
173 - layout="sizes, prev, pager, next" 193 + @click="handlePageChange(page)"
174 - @size-change="handleSizeChange" 194 + :class="['page-btn', { active: page === pagination.pageNum }]"
175 - @current-change="handleCurrentChange" 195 + >
176 - small 196 + {{ page }}
177 - /> 197 + </button>
198 + <button @click="handleNextPage" :disabled="pagination.pageNum >= getTotalPages()" class="page-btn">›</button>
199 + </div>
178 <div class="pagination-jump"> 200 <div class="pagination-jump">
179 前往 201 前往
180 - <el-input 202 + <input
181 v-model="jumpPage" 203 v-model="jumpPage"
182 - size="small" 204 + class="jump-input"
183 - style="width: 50px; margin: 0 8px;"
184 @keyup.enter="handleJumpPage" 205 @keyup.enter="handleJumpPage"
185 /> 206 />
186 207
...@@ -435,6 +456,8 @@ const searchForm = reactive<RebateSearchParams>({ ...@@ -435,6 +456,8 @@ const searchForm = reactive<RebateSearchParams>({
435 productCode: '', 456 productCode: '',
436 operateType: undefined, 457 operateType: undefined,
437 calcFlag: undefined, 458 calcFlag: undefined,
459 + auditStatus: undefined,
460 + dataSource: '',
438 rebateStartDate: '', 461 rebateStartDate: '',
439 rebateEndDate: '' 462 rebateEndDate: ''
440 }) 463 })
...@@ -730,15 +753,17 @@ const handleReset = () => { ...@@ -730,15 +753,17 @@ const handleReset = () => {
730 Object.assign(searchForm, { 753 Object.assign(searchForm, {
731 pageNum: 1, 754 pageNum: 1,
732 pageSize: 10, 755 pageSize: 10,
733 - rebateNo: undefined, 756 + rebateNo: '',
734 - dealerName: undefined, 757 + dealerCode: '',
735 - productName: undefined, 758 + dealerName: '',
736 - rebateType: undefined, 759 + productCode: '',
737 - status: undefined, 760 + operateType: undefined,
738 - applyStartTime: undefined, 761 + calcFlag: undefined,
739 - applyEndTime: undefined 762 + auditStatus: undefined,
763 + dataSource: '',
764 + rebateStartDate: '',
765 + rebateEndDate: ''
740 }) 766 })
741 - applyDateRange.value = null
742 pagination.pageNum = 1 767 pagination.pageNum = 1
743 getRebateList() 768 getRebateList()
744 } 769 }
...@@ -748,6 +773,104 @@ const handleRefresh = () => { ...@@ -748,6 +773,104 @@ const handleRefresh = () => {
748 getRebateList() 773 getRebateList()
749 } 774 }
750 775
776 +// 表格控制按钮
777 +const handleTableSearch = () => {
778 + handleSearch()
779 +}
780 +
781 +const handleTableRefresh = () => {
782 + handleRefresh()
783 +}
784 +
785 +const handleTableExport = () => {
786 + handleExport()
787 +}
788 +
789 +const handleTableViewToggle = () => {
790 + // 切换视图模式
791 + console.log('切换视图模式')
792 +}
793 +
794 +// 分页控制
795 +const handlePrevPage = () => {
796 + if (pagination.pageNum > 1) {
797 + pagination.pageNum--
798 + getRebateList()
799 + }
800 +}
801 +
802 +const handleNextPage = () => {
803 + if (pagination.pageNum < getTotalPages()) {
804 + pagination.pageNum++
805 + getRebateList()
806 + }
807 +}
808 +
809 +const handlePageChange = (page: number | string) => {
810 + if (typeof page === 'number') {
811 + pagination.pageNum = page
812 + getRebateList()
813 + }
814 +}
815 +
816 +const getPageNumbers = () => {
817 + const totalPages = getTotalPages()
818 + const current = pagination.pageNum
819 + const pages = []
820 +
821 + if (totalPages <= 7) {
822 + for (let i = 1; i <= totalPages; i++) {
823 + pages.push(i)
824 + }
825 + } else {
826 + if (current <= 4) {
827 + for (let i = 1; i <= 5; i++) {
828 + pages.push(i)
829 + }
830 + pages.push('...')
831 + pages.push(totalPages)
832 + } else if (current >= totalPages - 3) {
833 + pages.push(1)
834 + pages.push('...')
835 + for (let i = totalPages - 4; i <= totalPages; i++) {
836 + pages.push(i)
837 + }
838 + } else {
839 + pages.push(1)
840 + pages.push('...')
841 + for (let i = current - 1; i <= current + 1; i++) {
842 + pages.push(i)
843 + }
844 + pages.push('...')
845 + pages.push(totalPages)
846 + }
847 + }
848 +
849 + return pages
850 +}
851 +
852 +const getTotalPages = () => {
853 + return Math.ceil(pagination.total / pagination.pageSize)
854 +}
855 +
856 +// 状态样式类
857 +const getOperateTypeClass = (type: number) => {
858 + const classes = {
859 + 1: 'status-tag success',
860 + 2: 'status-tag warning',
861 + 3: 'status-tag danger'
862 + }
863 + return classes[type as keyof typeof classes] || 'status-tag'
864 +}
865 +
866 +const getCalcFlagClass = (flag: number) => {
867 + const classes = {
868 + 0: 'status-tag warning',
869 + 1: 'status-tag success'
870 + }
871 + return classes[flag as keyof typeof classes] || 'status-tag'
872 +}
873 +
751 // 分页变化 874 // 分页变化
752 const handleSizeChange = (size: number) => { 875 const handleSizeChange = (size: number) => {
753 pagination.pageSize = size 876 pagination.pageSize = size
...@@ -784,11 +907,11 @@ const handleViewDetail = async (row: Rebate) => { ...@@ -784,11 +907,11 @@ const handleViewDetail = async (row: Rebate) => {
784 const response = await rebateApi.getRebateById(row.rebateId) 907 const response = await rebateApi.getRebateById(row.rebateId)
785 console.log('详情接口响应:', response) 908 console.log('详情接口响应:', response)
786 909
787 - // 根据request.ts拦截器的处理,response.data已经是实际数据 910 + // 根据request.ts拦截器的处理,response直接就是数据对象
788 - if (response && response.data) { 911 + if (response) {
789 - rebateDetail.value = response.data 912 + rebateDetail.value = response as unknown as Rebate
790 detailDialogVisible.value = true 913 detailDialogVisible.value = true
791 - console.log('详情数据:', response.data) 914 + console.log('详情数据:', response)
792 } else { 915 } else {
793 ElMessage.error('获取返利详情失败') 916 ElMessage.error('获取返利详情失败')
794 } 917 }
...@@ -1478,23 +1601,57 @@ onMounted(async () => { ...@@ -1478,23 +1601,57 @@ onMounted(async () => {
1478 border-radius: 4px; 1601 border-radius: 4px;
1479 box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1); 1602 box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
1480 1603
1481 - .search-form {
1482 .search-row { 1604 .search-row {
1483 display: flex; 1605 display: flex;
1484 align-items: center; 1606 align-items: center;
1485 gap: 24px; 1607 gap: 24px;
1486 flex-wrap: wrap; 1608 flex-wrap: wrap;
1609 + margin-bottom: 12px;
1610 +
1611 + &:last-child {
1612 + margin-bottom: 0;
1613 + }
1487 1614
1488 .search-item { 1615 .search-item {
1489 display: flex; 1616 display: flex;
1490 align-items: center; 1617 align-items: center;
1491 gap: 8px; 1618 gap: 8px;
1492 1619
1493 - .search-label { 1620 + label {
1494 font-size: 14px; 1621 font-size: 14px;
1495 color: #333; 1622 color: #333;
1496 white-space: nowrap; 1623 white-space: nowrap;
1497 - min-width: 70px; 1624 + min-width: 80px;
1625 + }
1626 +
1627 + .search-input {
1628 + padding: 8px 12px;
1629 + border: 1px solid #ddd;
1630 + border-radius: 4px;
1631 + font-size: 14px;
1632 + width: 160px;
1633 + transition: border-color 0.3s;
1634 +
1635 + &:focus {
1636 + outline: none;
1637 + border-color: #409eff;
1638 + }
1639 + }
1640 +
1641 + .search-select {
1642 + padding: 8px 12px;
1643 + border: 1px solid #ddd;
1644 + border-radius: 4px;
1645 + font-size: 14px;
1646 + width: 120px;
1647 + background: white;
1648 + cursor: pointer;
1649 + transition: border-color 0.3s;
1650 +
1651 + &:focus {
1652 + outline: none;
1653 + border-color: #409eff;
1654 + }
1498 } 1655 }
1499 } 1656 }
1500 1657
...@@ -1502,6 +1659,96 @@ onMounted(async () => { ...@@ -1502,6 +1659,96 @@ onMounted(async () => {
1502 margin-left: auto; 1659 margin-left: auto;
1503 display: flex; 1660 display: flex;
1504 gap: 8px; 1661 gap: 8px;
1662 +
1663 + .search-btn, .reset-btn {
1664 + padding: 8px 16px;
1665 + border: 1px solid #ddd;
1666 + border-radius: 4px;
1667 + font-size: 14px;
1668 + cursor: pointer;
1669 + transition: all 0.3s;
1670 + background: white;
1671 +
1672 + &:hover {
1673 + background: #f5f7fa;
1674 + }
1675 +
1676 + &:disabled {
1677 + opacity: 0.6;
1678 + cursor: not-allowed;
1679 + }
1680 + }
1681 +
1682 + .search-btn {
1683 + background: #409eff;
1684 + color: white;
1685 + border-color: #409eff;
1686 +
1687 + &:hover {
1688 + background: #66b1ff;
1689 + }
1690 + }
1691 + }
1692 + }
1693 +}
1694 +
1695 +.action-section {
1696 + background: white;
1697 + padding: 12px 20px;
1698 + margin-bottom: 16px;
1699 + border-radius: 4px;
1700 + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
1701 +
1702 + .action-buttons {
1703 + display: flex;
1704 + gap: 12px;
1705 +
1706 + .action-btn {
1707 + padding: 8px 16px;
1708 + border: 1px solid #ddd;
1709 + border-radius: 4px;
1710 + font-size: 14px;
1711 + cursor: pointer;
1712 + transition: all 0.3s;
1713 + background: white;
1714 +
1715 + &:hover {
1716 + background: #f5f7fa;
1717 + }
1718 +
1719 + &:disabled {
1720 + opacity: 0.6;
1721 + cursor: not-allowed;
1722 + }
1723 +
1724 + &.primary {
1725 + background: #409eff;
1726 + color: white;
1727 + border-color: #409eff;
1728 +
1729 + &:hover {
1730 + background: #66b1ff;
1731 + }
1732 + }
1733 +
1734 + &.secondary {
1735 + background: #67c23a;
1736 + color: white;
1737 + border-color: #67c23a;
1738 +
1739 + &:hover {
1740 + background: #85ce61;
1741 + }
1742 + }
1743 +
1744 + &.danger {
1745 + background: #f56c6c;
1746 + color: white;
1747 + border-color: #f56c6c;
1748 +
1749 + &:hover {
1750 + background: #f78989;
1751 + }
1505 } 1752 }
1506 } 1753 }
1507 } 1754 }
...@@ -1580,55 +1827,107 @@ onMounted(async () => { ...@@ -1580,55 +1827,107 @@ onMounted(async () => {
1580 1827
1581 .table-section { 1828 .table-section {
1582 background: white; 1829 background: white;
1583 - border-radius: 8px; 1830 + border-radius: 4px;
1584 - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); 1831 + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
1585 overflow: hidden; 1832 overflow: hidden;
1586 1833
1587 .table-header { 1834 .table-header {
1588 display: flex; 1835 display: flex;
1589 - justify-content: space-between; 1836 + justify-content: flex-end;
1590 align-items: center; 1837 align-items: center;
1591 - padding: 20px 20px 0 20px; 1838 + padding: 12px 20px;
1592 - margin-bottom: 16px; 1839 + border-bottom: 1px solid #f0f0f0;
1840 + background: #fafafa;
1593 1841
1594 - .table-title { 1842 + .table-controls {
1595 - font-size: 16px; 1843 + display: flex;
1596 - font-weight: 500; 1844 + gap: 8px;
1597 - color: #333; 1845 +
1846 + .control-btn {
1847 + padding: 6px 12px;
1848 + border: 1px solid #ddd;
1849 + border-radius: 4px;
1850 + background: white;
1851 + cursor: pointer;
1852 + font-size: 14px;
1853 + transition: all 0.3s;
1854 +
1855 + &:hover {
1856 + background: #f5f7fa;
1857 + border-color: #409eff;
1858 + }
1859 + }
1598 } 1860 }
1861 + }
1862 +
1863 + .table-container {
1864 + position: relative;
1599 1865
1600 - .table-actions { 1866 + .loading-overlay {
1867 + position: absolute;
1868 + top: 0;
1869 + left: 0;
1870 + right: 0;
1871 + bottom: 0;
1872 + background: rgba(255, 255, 255, 0.8);
1601 display: flex; 1873 display: flex;
1602 align-items: center; 1874 align-items: center;
1603 - gap: 12px; 1875 + justify-content: center;
1876 + z-index: 10;
1604 1877
1605 - .table-info { 1878 + .loading-spinner {
1606 - font-size: 12px; 1879 + font-size: 14px;
1607 - color: #999; 1880 + color: #666;
1608 - }
1609 } 1881 }
1610 } 1882 }
1611 1883
1612 - .el-table { 1884 + .data-table {
1613 - border: none; 1885 + width: 100%;
1886 + border-collapse: collapse;
1887 + font-size: 14px;
1888 +
1889 + thead {
1890 + background: #fafafa;
1614 1891
1615 - :deep(.el-table__header) {
1616 th { 1892 th {
1617 - background-color: #fafafa; 1893 + padding: 12px 16px;
1618 - border: none; 1894 + text-align: left;
1619 font-weight: 500; 1895 font-weight: 500;
1620 color: #333; 1896 color: #333;
1897 + border-bottom: 1px solid #e0e0e0;
1898 + white-space: nowrap;
1621 } 1899 }
1622 } 1900 }
1623 1901
1624 - :deep(.el-table__body) { 1902 + tbody {
1625 - tr:hover > td { 1903 + tr {
1626 - background-color: #f5f7fa; 1904 + transition: background-color 0.3s;
1905 +
1906 + &:hover {
1907 + background: #f5f7fa;
1908 + }
1909 +
1910 + &:nth-child(even) {
1911 + background: #fafafa;
1912 + }
1913 +
1914 + &:nth-child(even):hover {
1915 + background: #f0f2f5;
1627 } 1916 }
1628 1917
1629 td { 1918 td {
1630 - border: none; 1919 + padding: 12px 16px;
1631 border-bottom: 1px solid #f0f0f0; 1920 border-bottom: 1px solid #f0f0f0;
1921 + vertical-align: middle;
1922 +
1923 + &.empty-data {
1924 + text-align: center;
1925 + color: #999;
1926 + font-style: italic;
1927 + padding: 40px;
1928 + }
1929 + }
1930 + }
1632 } 1931 }
1633 } 1932 }
1634 } 1933 }
...@@ -1646,15 +1945,100 @@ onMounted(async () => { ...@@ -1646,15 +1945,100 @@ onMounted(async () => {
1646 color: #666; 1945 color: #666;
1647 } 1946 }
1648 1947
1948 + .pagination-controls {
1949 + display: flex;
1950 + gap: 4px;
1951 + align-items: center;
1952 +
1953 + .page-btn {
1954 + padding: 6px 12px;
1955 + border: 1px solid #ddd;
1956 + border-radius: 4px;
1957 + background: white;
1958 + cursor: pointer;
1959 + font-size: 14px;
1960 + transition: all 0.3s;
1961 + min-width: 32px;
1962 +
1963 + &:hover:not(:disabled) {
1964 + background: #f5f7fa;
1965 + border-color: #409eff;
1966 + }
1967 +
1968 + &:disabled {
1969 + opacity: 0.5;
1970 + cursor: not-allowed;
1971 + }
1972 +
1973 + &.active {
1974 + background: #409eff;
1975 + color: white;
1976 + border-color: #409eff;
1977 + }
1978 + }
1979 + }
1980 +
1649 .pagination-jump { 1981 .pagination-jump {
1650 display: flex; 1982 display: flex;
1651 align-items: center; 1983 align-items: center;
1984 + gap: 8px;
1652 font-size: 14px; 1985 font-size: 14px;
1653 color: #666; 1986 color: #666;
1987 +
1988 + .jump-input {
1989 + width: 50px;
1990 + padding: 4px 8px;
1991 + border: 1px solid #ddd;
1992 + border-radius: 4px;
1993 + text-align: center;
1994 + font-size: 14px;
1995 +
1996 + &:focus {
1997 + outline: none;
1998 + border-color: #409eff;
1999 + }
2000 + }
1654 } 2001 }
1655 } 2002 }
1656 } 2003 }
1657 2004
2005 +.status-tag {
2006 + padding: 2px 8px;
2007 + border-radius: 12px;
2008 + font-size: 12px;
2009 + font-weight: 500;
2010 +
2011 + &.success {
2012 + background: #f0f9ff;
2013 + color: #67c23a;
2014 + }
2015 +
2016 + &.warning {
2017 + background: #fdf6ec;
2018 + color: #e6a23c;
2019 + }
2020 +
2021 + &.danger {
2022 + background: #fef0f0;
2023 + color: #f56c6c;
2024 + }
2025 +}
2026 +
2027 +.action-link {
2028 + color: #409eff;
2029 + text-decoration: none;
2030 + cursor: pointer;
2031 + font-size: 14px;
2032 + background: none;
2033 + border: none;
2034 + padding: 0;
2035 +
2036 + &:hover {
2037 + color: #66b1ff;
2038 + text-decoration: underline;
2039 + }
2040 +}
2041 +
1658 .amount-text { 2042 .amount-text {
1659 color: #f56c6c; 2043 color: #f56c6c;
1660 font-weight: 500; 2044 font-weight: 500;
......