index.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. <template>
  2. <fieldset class="g-fieldset app-table-details" :style="fieldsetStyle">
  3. <legend class="g-fieldset__legend" v-if="title">
  4. <slot name="title">
  5. {{ title }}
  6. </slot>
  7. </legend>
  8. <table class="app-table-details__table" cellspacing="0" cellpadding="0" :style="tableStyle">
  9. <tbody>
  10. <tr v-for="(items, i) in cellGroup" :key="i">
  11. <template v-for="(item, n) in items" :key="n">
  12. <th :style="labelStyle">
  13. <slot :name="item.prop + 'Label'">
  14. {{ item.formatLabel ? item.formatLabel(data[item.prop]) : item.label }}
  15. </slot>
  16. </th>
  17. <td :colspan="(items.length - 1) === n ? (column * 2 - items.length * 2) + 1 : 1"
  18. :style="valueStyle">
  19. <slot :name="item.prop" :value="data[item.prop]">
  20. {{ handleValue(item) }}
  21. </slot>
  22. </td>
  23. </template>
  24. </tr>
  25. </tbody>
  26. </table>
  27. <slot></slot>
  28. </fieldset>
  29. </template>
  30. <script lang="ts" setup>
  31. import { PropType, computed } from 'vue'
  32. import { handleNoneValue } from '@/filters'
  33. import { CellProp } from './types'
  34. const props = defineProps({
  35. title: String,
  36. data: {
  37. type: Object,
  38. default: () => ({})
  39. },
  40. cellProps: {
  41. type: Array as PropType<CellProp[]>,
  42. required: true
  43. },
  44. column: {
  45. type: Number,
  46. default: 1
  47. },
  48. width: {
  49. type: [String, Number],
  50. default: '100%'
  51. },
  52. // 标签宽度
  53. labelWidth: {
  54. type: Number,
  55. default: 0
  56. },
  57. // 标签对齐方式
  58. labelAlign: {
  59. type: String as PropType<'left' | 'center' | 'right'>,
  60. default: 'right'
  61. },
  62. // 边框大小
  63. borderWidth: {
  64. type: Number,
  65. default: 0
  66. },
  67. // 边框颜色
  68. borderColor: {
  69. type: String,
  70. default: '#213141'
  71. },
  72. })
  73. const cellGroup = computed(() => {
  74. // const result = []
  75. // let index = 0
  76. // // 一维数组转换成二维数组
  77. // while (index < props.cellProps.length) {
  78. // const rows = props.cellProps.slice(index, index += props.column)
  79. // result.push(rows)
  80. // }
  81. return props.cellProps.reduce<CellProp[][]>((pre, cur) => {
  82. if (cur.show === undefined || cur.show) {
  83. const rows = pre[pre.length - 1] // 获取上一组元素
  84. if (rows) {
  85. const cell = rows[rows.length - 1] // 获取最后一个元素
  86. if (cell.entireRow || cur.entireRow || rows.length === props.column) {
  87. pre[pre.length] = [cur]
  88. } else {
  89. rows.push(cur)
  90. }
  91. } else {
  92. pre[0] = [cur]
  93. }
  94. }
  95. return pre
  96. }, [])
  97. })
  98. const fieldsetStyle = computed(() => props.title ? {} : {
  99. borderWidth: 0,
  100. padding: 0
  101. })
  102. const tableStyle = computed(() => ({
  103. width: typeof props.width === 'number' ? props.width + 'px' : props.width
  104. }))
  105. const valueStyle = computed(() => ({
  106. borderWidth: props.borderWidth + 'px',
  107. borderColor: props.borderColor
  108. }))
  109. const labelStyle = computed(() => ({
  110. width: props.labelWidth ? props.labelWidth + 'px' : 'fit-content',
  111. textAlign: props.labelAlign,
  112. ...valueStyle.value
  113. }))
  114. const handleValue = (cell: CellProp) => {
  115. const value = props.data[cell.prop]
  116. const formattedValue = cell.formatValue ? cell.formatValue(value) : value
  117. if (Number.isFinite(formattedValue) && cell.decimal) {
  118. return formattedValue.toFixed(cell.decimal)
  119. }
  120. return handleNoneValue(formattedValue)
  121. }
  122. </script>
  123. <style lang="less">
  124. @import './index.less';
  125. </style>