cwg-tabel.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. <template>
  2. <view class="table-container">
  3. <!-- 表格 -->
  4. <uni-table :type="selectionType" :border="false" @selection-change="handleSelectionChange">
  5. <uni-tr class="tabel-header">
  6. <uni-th v-for="column in columns" :key="column.prop" :align="column.align || 'center'"
  7. :width="column.width || '50'" :class="[
  8. headerClass
  9. ]" :style="getHeaderStyle(column)">
  10. <view class="header-content">
  11. {{ column.label }}
  12. <view v-if="column.sortable" class="sort-icon">
  13. <uni-icons :type="getSortIcon(column)" :size="14" color="#999" />
  14. </view>
  15. </view>
  16. </uni-th>
  17. <uni-th v-if="showOperation" align="center" :width="operationWidth" :style="getOperationHeaderStyle()">
  18. {{ t('common.operation') }}
  19. </uni-th>
  20. </uni-tr>
  21. <template v-for="(row, rowIndex) in tableData" :key="rowIndex">
  22. <uni-tr>
  23. <uni-td v-for="column in columns" :key="column.prop" :align="column.align || 'center'"
  24. :class="getCellClass(column, row)" :style="getCellStyle(column, row)">
  25. <!-- 自定义渲染插槽 -->
  26. <slot v-if="column.slot" :name="column.slot" :row="row" :column="column" :index="rowIndex">
  27. {{ row[column.prop] }}
  28. </slot>
  29. <!-- 标签类型渲染 -->
  30. <uni-tag v-else-if="column.type === 'tag'" :text="formatTagText(row[column.prop], column)"
  31. :type="formatTagType(row[column.prop], column)" size="small" />
  32. <!-- 文件类型渲染 -->
  33. <view v-else-if="column.type === 'file'">
  34. <cwg-file :path="row[column.prop]" />
  35. </view>
  36. <!-- 默认文本渲染 -->
  37. <template v-else>{{ formatCellValue(row[column.prop], column, row) }}</template>
  38. </uni-td>
  39. <!-- 操作按钮 -->
  40. <uni-td v-if="showOperation" align="center">
  41. <view class="operation-btns">
  42. <template v-for="(action, index) in operationActions" :key="index">
  43. <button v-if="showAction(action, row)" class="btn" size="mini"
  44. :type="action.type || 'default'" @click="handleAction(action, row)">
  45. <cwg-icon :name="action.icon" :size="16" color="#fff" v-if="action.icon" />
  46. {{ action.text }}
  47. </button>
  48. </template>
  49. </view>
  50. </uni-td>
  51. </uni-tr>
  52. <!-- 展开行 - 这里是您要放置 expand 插槽的地方 -->
  53. <uni-tr v-if="expandedRows[rowIndex]" class="expand-row">
  54. <uni-td :colspan="columnSpan" class="expand-cell">
  55. <slot name="expand" :row="row" :rowIndex="rowIndex">
  56. <view class="default-expand-content">
  57. <text class="no-content">暂无展开内容</text>
  58. </view>
  59. </slot>
  60. </uni-td>
  61. </uni-tr>
  62. </template>
  63. <!-- 空数据提示 -->
  64. <uni-tr v-if="tableData.length === 0">
  65. <uni-td :colspan="columnSpan" align="center">
  66. <view class="empty-data">
  67. <uni-icons type="info" size="30" color="#999"></uni-icons>
  68. <text class="empty-text">暂无数据</text>
  69. </view>
  70. </uni-td>
  71. </uni-tr>
  72. </uni-table>
  73. <!-- 分页组件 -->
  74. <view class="pagination-container" v-if="showPagination && tableData.length > 0">
  75. <view class="pagination-info">
  76. <text>共 {{ pagination.total }} 条记录</text>
  77. <view v-if="showPageSize" class="page-size-select">
  78. <text>每页显示</text>
  79. <picker @change="handlePageSizeChange" :value="pageSizeIndex" :range="pageSizes">
  80. <view class="page-size-value">{{ pagination.pageSize }}条/页</view>
  81. </picker>
  82. </view>
  83. </view>
  84. <view class="pagination">
  85. <view class="page-item prev" :class="{ disabled: pagination.current === 1 }"
  86. @click="handlePageChange('prev')">
  87. <uni-icons type="arrowleft" size="16" color="#666"></uni-icons>
  88. <text>上一页</text>
  89. </view>
  90. <view class="page-numbers">
  91. <view v-for="page in visiblePages" :key="page" class="page-number"
  92. :class="{ active: pagination.current === page }" @click="handlePageChange(page)">
  93. {{ page }}
  94. </view>
  95. </view>
  96. <view class="page-item next" :class="{ disabled: pagination.current === pagination.pages }"
  97. @click="handlePageChange('next')">
  98. <text>下一页</text>
  99. <uni-icons type="arrowright" size="16" color="#666"></uni-icons>
  100. </view>
  101. </view>
  102. </view>
  103. </view>
  104. </template>
  105. <script setup>
  106. import { ref, computed, watch, onMounted } from 'vue'
  107. const props = defineProps({
  108. // 表格列配置
  109. columns: {
  110. type: Array,
  111. required: true,
  112. default: () => []
  113. },
  114. // API 请求函数
  115. api: {
  116. type: Function,
  117. required: true
  118. },
  119. // 查询参数
  120. queryParams: {
  121. type: Object,
  122. default: () => ({})
  123. },
  124. // 是否立即加载
  125. immediate: {
  126. type: Boolean,
  127. default: true
  128. },
  129. // 选择类型:'selection' | null
  130. selectionType: {
  131. type: String,
  132. default: null
  133. },
  134. // 是否显示操作列
  135. showOperation: {
  136. type: Boolean,
  137. default: false
  138. },
  139. // 操作按钮配置
  140. operationActions: {
  141. type: Array,
  142. default: () => [
  143. { text: '编辑', type: 'primary', action: 'edit', icon: 'crm-puls' },
  144. { text: '删除', type: 'warn', action: 'delete', icon: 'crm-delete' },
  145. { text: '查看', type: 'default', action: 'view', icon: 'view' }
  146. ]
  147. },
  148. // 是否显示底部操作栏
  149. showBottomActions: {
  150. type: Boolean,
  151. default: false
  152. },
  153. // 底部操作按钮
  154. bottomActions: {
  155. type: Array,
  156. default: () => []
  157. },
  158. // 是否显示每页条数选择
  159. showPageSize: {
  160. type: Boolean,
  161. default: true
  162. },
  163. // 是否显示分页
  164. showPagination: {
  165. type: Boolean,
  166. default: true
  167. },
  168. // 每页条数选项
  169. pageSizes: {
  170. type: Array,
  171. default: () => [10, 20, 30, 50, 100]
  172. },
  173. // 默认每页条数
  174. defaultPageSize: {
  175. type: Number,
  176. default: 10
  177. },
  178. // ========== 表头样式自定义 ==========
  179. // 表头背景色
  180. headerBackground: {
  181. type: String,
  182. default: 'var(--color-slate-200)'
  183. },
  184. // 表头文字颜色
  185. headerColor: {
  186. type: String,
  187. default: 'var(--color-slate-800)'
  188. },
  189. // 表头字体大小
  190. headerFontSize: {
  191. type: [String, Number],
  192. default: '14rpx'
  193. },
  194. // 表头字体粗细
  195. headerFontWeight: {
  196. type: [String, Number],
  197. default: 600
  198. },
  199. // 表头高度
  200. headerHeight: {
  201. type: [String, Number],
  202. default: '40rpx'
  203. },
  204. // 表头自定义类名
  205. headerClass: {
  206. type: [String, Array],
  207. default: ''
  208. },
  209. // 表头自定义样式对象
  210. headerStyle: {
  211. type: Object,
  212. default: () => ({})
  213. },
  214. // 是否固定表头
  215. stickyHeader: {
  216. type: Boolean,
  217. default: true
  218. },
  219. // 表头固定时的偏移量
  220. stickyOffset: {
  221. type: [String, Number],
  222. default: '0'
  223. }
  224. })
  225. const emit = defineEmits([
  226. 'selection-change',
  227. 'action-click',
  228. 'bottom-action-click',
  229. 'page-change',
  230. 'load-success',
  231. 'load-error'
  232. ])
  233. // 展开行状态
  234. const expandedRows = ref({})
  235. // 切换行展开状态
  236. const toggleRowExpand = (rowIndex) => {
  237. const key = rowIndex
  238. if (expandedRows.value[key]) {
  239. expandedRows.value[key] = false
  240. } else {
  241. expandedRows.value = {}
  242. expandedRows.value[key] = true
  243. }
  244. emit('expand-change', { rowIndex, expanded: expandedRows.value[key] })
  245. }
  246. // 表格数据
  247. const tableData = ref([])
  248. const selectedItems = ref([])
  249. // 分页参数
  250. const pagination = ref({
  251. current: 1,
  252. pageSize: props.defaultPageSize,
  253. total: 0,
  254. pages: 0
  255. })
  256. // 加载状态
  257. const loading = ref(false)
  258. // 计算列跨度
  259. const columnSpan = computed(() => {
  260. let span = props.columns.length
  261. if (props.showOperation) span += 1
  262. return span
  263. })
  264. // 计算每页条数索引
  265. const pageSizeIndex = computed(() => {
  266. return props.pageSizes.indexOf(pagination.value.pageSize)
  267. })
  268. // 计算显示的页码
  269. const visiblePages = computed(() => {
  270. const maxVisible = 5
  271. const half = Math.floor(maxVisible / 2)
  272. let start = Math.max(1, pagination.value.current - half)
  273. let end = Math.min(pagination.value.pages, start + maxVisible - 1)
  274. if (end - start + 1 < maxVisible) {
  275. start = Math.max(1, end - maxVisible + 1)
  276. }
  277. return Array.from({ length: end - start + 1 }, (_, i) => start + i)
  278. })
  279. // 监听查询参数变化
  280. watch(() => props.queryParams, () => {
  281. refreshTable()
  282. }, { deep: true })
  283. // ========== 表头样式计算 ==========
  284. // 获取表头样式
  285. const getHeaderStyle = (column) => {
  286. const baseStyle = {
  287. backgroundColor: props.headerBackground,
  288. color: props.headerColor,
  289. fontSize: typeof props.headerFontSize === 'number' ? props.headerFontSize + 'rpx' : props.headerFontSize,
  290. fontWeight: props.headerFontWeight,
  291. height: typeof props.headerHeight === 'number' ? props.headerHeight + 'rpx' : props.headerHeight,
  292. lineHeight: typeof props.headerHeight === 'number' ? props.headerHeight + 'rpx' : props.headerHeight,
  293. ...props.headerStyle
  294. }
  295. // 固定表头
  296. if (props.stickyHeader) {
  297. baseStyle.position = 'sticky'
  298. baseStyle.top = props.stickyOffset
  299. baseStyle.zIndex = 100
  300. }
  301. // 列自定义样式
  302. if (column.headerStyle) {
  303. Object.assign(baseStyle, column.headerStyle)
  304. }
  305. return baseStyle
  306. }
  307. // 获取操作列表头样式
  308. const getOperationHeaderStyle = () => {
  309. return {
  310. backgroundColor: props.headerBackground,
  311. color: props.headerColor,
  312. fontSize: typeof props.headerFontSize === 'number' ? props.headerFontSize + 'px' : props.headerFontSize,
  313. fontWeight: props.headerFontWeight,
  314. height: typeof props.headerHeight === 'number' ? props.headerHeight + 'px' : props.headerHeight,
  315. lineHeight: typeof props.headerHeight === 'number' ? props.headerHeight + 'px' : props.headerHeight,
  316. position: props.stickyHeader ? 'sticky' : 'static',
  317. top: props.stickyHeader ? props.stickyOffset : 'auto',
  318. zIndex: props.stickyHeader ? 100 : 'auto'
  319. }
  320. }
  321. // 获取单元格样式
  322. const getCellStyle = (column, row) => {
  323. const style = {}
  324. if (column.cellStyle) {
  325. if (typeof column.cellStyle === 'function') {
  326. Object.assign(style, column.cellStyle({ row, column }))
  327. } else {
  328. Object.assign(style, column.cellStyle)
  329. }
  330. }
  331. return style
  332. }
  333. // 获取单元格类名
  334. const getCellClass = (column, row) => {
  335. const classes = []
  336. if (column.cellClass) {
  337. if (typeof column.cellClass === 'function') {
  338. const result = column.cellClass({ row, column })
  339. if (result) {
  340. if (Array.isArray(result)) {
  341. classes.push(...result)
  342. } else {
  343. classes.push(result)
  344. }
  345. }
  346. } else {
  347. classes.push(column.cellClass)
  348. }
  349. }
  350. return classes.join(' ')
  351. }
  352. // 加载数据
  353. const loadData = async () => {
  354. if (loading.value) return
  355. loading.value = true
  356. try {
  357. const params = {
  358. page: {
  359. current: pagination.value.current,
  360. size: pagination.value.pageSize
  361. },
  362. ...props.queryParams
  363. }
  364. const res = await props.api(params)
  365. // 处理不同的API返回格式
  366. if (res.code === 200 || res.code === 0) {
  367. const data = res.data || res
  368. // 支持不同的分页数据结构
  369. if (Array.isArray(data)) {
  370. tableData.value = data
  371. pagination.value.total = data.length
  372. pagination.value.pages = 1
  373. } else if (data.list || data.records) {
  374. tableData.value = data.list || data.records
  375. pagination.value.total = data.total || data.list?.length || 0
  376. pagination.value.pages = data.pages || Math.ceil(pagination.value.total / pagination.value.pageSize)
  377. } else {
  378. tableData.value = []
  379. }
  380. emit('load-success', res)
  381. } else {
  382. throw new Error(res.message || '加载失败')
  383. }
  384. } catch (error) {
  385. console.error('表格数据加载失败:', error)
  386. uni.showToast({
  387. title: error.message || '加载失败',
  388. icon: 'none'
  389. })
  390. emit('load-error', error)
  391. } finally {
  392. loading.value = false
  393. }
  394. }
  395. // 刷新表格
  396. const refreshTable = () => {
  397. pagination.value.current = 1
  398. loadData()
  399. }
  400. // 重新加载
  401. const reload = () => {
  402. loadData()
  403. }
  404. // 分页变化
  405. const handlePageChange = (page) => {
  406. if (page === 'prev') {
  407. if (pagination.value.current > 1) {
  408. pagination.value.current--
  409. } else {
  410. return
  411. }
  412. } else if (page === 'next') {
  413. if (pagination.value.current < pagination.value.pages) {
  414. pagination.value.current++
  415. } else {
  416. return
  417. }
  418. } else {
  419. pagination.value.current = page
  420. }
  421. loadData()
  422. emit('page-change', pagination.value)
  423. }
  424. // 每页条数变化
  425. const handlePageSizeChange = (e) => {
  426. const size = props.pageSizes[e.detail.value]
  427. pagination.value.pageSize = size
  428. pagination.value.current = 1
  429. loadData()
  430. }
  431. // 选择变化
  432. const handleSelectionChange = (e) => {
  433. selectedItems.value = e.detail.value
  434. emit('selection-change', selectedItems.value)
  435. }
  436. // 操作按钮点击
  437. const handleAction = (action, row) => {
  438. emit('action-click', { action: action.action, row, original: action })
  439. }
  440. // 底部操作点击
  441. const handleBottomAction = (action) => {
  442. emit('bottom-action-click', action)
  443. }
  444. // 判断是否显示操作按钮
  445. const showAction = (action, row) => {
  446. if (action.show) {
  447. return action.show(row)
  448. }
  449. return true
  450. }
  451. // 格式化单元格值
  452. const formatCellValue = (value, column, row) => {
  453. if (column.formatter) {
  454. return column.formatter({ value, row })
  455. }
  456. if (column.type === 'date' && value) {
  457. return formatDate(value, column.dateFormat || 'YYYY-MM-DD HH:mm:ss')
  458. }
  459. if (value === null || value === undefined) {
  460. return '-'
  461. }
  462. return value
  463. }
  464. // 格式化标签文本
  465. const formatTagText = (value, column) => {
  466. if (column.tagMap && column.tagMap[value]) {
  467. return column.tagMap[value]
  468. }
  469. return value || '-'
  470. }
  471. // 格式化标签类型
  472. const formatTagType = (value, column) => {
  473. if (column.tagTypeMap && column.tagTypeMap[value]) {
  474. return column.tagTypeMap[value]
  475. }
  476. return 'default'
  477. }
  478. // 格式化日期
  479. const formatDate = (date, format) => {
  480. if (!date) return '-'
  481. const d = new Date(date)
  482. const year = d.getFullYear()
  483. const month = String(d.getMonth() + 1).padStart(2, '0')
  484. const day = String(d.getDate()).padStart(2, '0')
  485. const hour = String(d.getHours()).padStart(2, '0')
  486. const minute = String(d.getMinutes()).padStart(2, '0')
  487. const second = String(d.getSeconds()).padStart(2, '0')
  488. return format
  489. .replace('YYYY', year)
  490. .replace('MM', month)
  491. .replace('DD', day)
  492. .replace('HH', hour)
  493. .replace('mm', minute)
  494. .replace('ss', second)
  495. }
  496. // 预览图片
  497. const handlePreviewImage = (url) => {
  498. uni.previewImage({
  499. urls: [url]
  500. })
  501. }
  502. // 获取选中项
  503. const getSelectedItems = () => {
  504. return selectedItems.value
  505. }
  506. // 清空选中
  507. const clearSelection = () => {
  508. selectedItems.value = []
  509. }
  510. // 暴露方法给父组件
  511. defineExpose({
  512. refreshTable,
  513. reload,
  514. getSelectedItems,
  515. clearSelection,
  516. loadData,
  517. tableData,
  518. toggleRowExpand,
  519. pagination
  520. })
  521. // 初始化加载
  522. onMounted(() => {
  523. if (props.immediate) {
  524. loadData()
  525. }
  526. })
  527. </script>
  528. <style scoped lang="scss">
  529. @import "@/uni.scss";
  530. .table-container {
  531. width: 100%;
  532. overflow-x: auto;
  533. /* 关键:横向滚动 */
  534. -webkit-overflow-scrolling: touch;
  535. /* 流畅滚动 */
  536. max-height: calc(100vh - 209px);
  537. overflow: hidden;
  538. color: var(--color-slate-800);
  539. :deep(.uni-table-scroll) {
  540. width: 100%;
  541. max-height: calc(100vh - 375px);
  542. overflow: auto;
  543. }
  544. :deep(.uni-table) {
  545. min-height: px2rpx(100) !important;
  546. .uni-table-th {
  547. position: sticky;
  548. top: 0;
  549. z-index: 100;
  550. transition: all 0.3s;
  551. .header-content {
  552. display: flex;
  553. align-items: center;
  554. justify-content: center;
  555. gap: 4px;
  556. .sort-icon {
  557. display: inline-flex;
  558. cursor: pointer;
  559. .uni-icons {
  560. transition: all 0.3s;
  561. }
  562. }
  563. }
  564. &.sortable {
  565. cursor: pointer;
  566. &:hover {
  567. .sort-icon .uni-icons {
  568. color: var(--color-primary) !important;
  569. }
  570. }
  571. }
  572. &::after {
  573. display: none;
  574. }
  575. }
  576. .uni-table-tr {
  577. border-bottom: 5px solid var(--color-slate-200) !important;
  578. &:last-child {
  579. border-bottom: none !important;
  580. }
  581. }
  582. .uni-table-th,
  583. .uni-table-td {
  584. padding: px2rpx(12) px2rpx(20);
  585. color: var(--color-slate-800);
  586. box-sizing: border-box;
  587. }
  588. .uni-table-td {
  589. word-break: break-word;
  590. }
  591. .expand-cell {
  592. padding: 0 !important;
  593. }
  594. }
  595. }
  596. .table-image {
  597. width: px2rpx(30);
  598. height: px2rpx(30);
  599. border-radius: px2rpx(8);
  600. }
  601. .operation-btns {
  602. display: flex;
  603. gap: px2rpx(10);
  604. justify-content: center;
  605. flex-wrap: wrap;
  606. }
  607. .btn {
  608. margin: 0 px2rpx(4);
  609. font-size: px2rpx(16);
  610. padding: 0 px2rpx(20);
  611. height: px2rpx(36);
  612. border-radius: none;
  613. display: flex;
  614. align-items: center;
  615. justify-content: center;
  616. cursor: pointer;
  617. transition: all 0.3s;
  618. &:hover {
  619. opacity: 0.8;
  620. }
  621. &:active {
  622. transform: scale(0.95);
  623. }
  624. }
  625. .empty-data {
  626. display: flex;
  627. flex-direction: column;
  628. align-items: center;
  629. justify-content: center;
  630. padding: px2rpx(30) 0;
  631. }
  632. .empty-text {
  633. margin-top: px2rpx(20);
  634. font-size: px2rpx(16);
  635. color: #999;
  636. }
  637. .bottom-actions {
  638. margin: px2rpx(30) px2rpx(20);
  639. display: flex;
  640. justify-content: space-between;
  641. align-items: center;
  642. }
  643. .left-actions,
  644. .right-actions {
  645. display: flex;
  646. gap: px2rpx(20);
  647. }
  648. /* 分页样式 */
  649. .pagination-container {
  650. margin: px2rpx(20) px2rpx(20);
  651. display: flex;
  652. align-items: center;
  653. justify-content: flex-end;
  654. gap: px2rpx(20);
  655. .pagination {
  656. display: flex;
  657. align-items: center;
  658. padding: px2rpx(10);
  659. }
  660. .page-item {
  661. display: flex;
  662. align-items: center;
  663. padding: 0 px2rpx(12);
  664. height: px2rpx(30);
  665. background-color: var(--color-white);
  666. border: 1px solid #dcdfe6;
  667. border-radius: px2rpx(8);
  668. font-size: px2rpx(16);
  669. color: #606266;
  670. cursor: pointer;
  671. transition: all 0.3s;
  672. margin: 0 px2rpx(6);
  673. }
  674. .page-item.prev {
  675. margin-right: px2rpx(10);
  676. }
  677. .page-item.next {
  678. margin-left: px2rpx(10);
  679. }
  680. .page-item:not(.disabled):hover {
  681. color: #007aff;
  682. border-color: #007aff;
  683. }
  684. .page-item.disabled {
  685. opacity: 0.5;
  686. cursor: not-allowed;
  687. pointer-events: none;
  688. }
  689. .page-numbers {
  690. display: flex;
  691. gap: px2rpx(8);
  692. }
  693. .page-number {
  694. display: flex;
  695. align-items: center;
  696. justify-content: center;
  697. min-width: px2rpx(40);
  698. height: px2rpx(30);
  699. padding: 0 px2rpx(4);
  700. background-color: var(--color-white);
  701. border-radius: px2rpx(8);
  702. font-size: px2rpx(16);
  703. color: #606266;
  704. cursor: pointer;
  705. transition: all 0.3s;
  706. }
  707. .page-number:hover {
  708. color: #007aff;
  709. border-color: #007aff;
  710. }
  711. .page-number.active {
  712. background-color: #007aff;
  713. border-color: #007aff;
  714. color: #fff;
  715. }
  716. .pagination-info {
  717. display: flex;
  718. align-items: center;
  719. gap: px2rpx(30);
  720. font-size: px2rpx(16);
  721. color: #909399;
  722. }
  723. .page-size-select {
  724. display: flex;
  725. align-items: center;
  726. gap: px2rpx(10);
  727. }
  728. .page-size-value {
  729. padding: px2rpx(6) px2rpx(20);
  730. border: 1px solid #dcdfe6;
  731. border-radius: px2rpx(8);
  732. color: #606266;
  733. }
  734. }
  735. @media screen and (max-width: 768px) {
  736. .pagination {
  737. flex-wrap: wrap;
  738. justify-content: center;
  739. }
  740. .page-item {
  741. padding: 0 px2rpx(16);
  742. }
  743. .page-number {
  744. min-width: px2rpx(60);
  745. }
  746. .pagination-info {
  747. flex-direction: column;
  748. gap: px2rpx(10);
  749. }
  750. }
  751. </style>