index.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <template>
  2. <a-list item-layout="vertical" :data-source="props.dataSource" :pagination="pagination" :loading="loading">
  3. <template #renderItem="{ item, index }">
  4. <a-list-item :key="index" class="xn-data-list-item">
  5. <a-list-item-meta class="xn-data-list-item-meta">
  6. <template #avatar>
  7. <a-avatar shape="square" :size="50">{{ index + 1 }}</a-avatar>
  8. </template>
  9. <template #title>
  10. <div class="xn-data-list-item-meta-title">
  11. <div class="xn-data-list-item-meta-title-prefix">
  12. <slot name="title-prefix" :record="item.record"></slot>
  13. </div>
  14. <a @click="clickTitle(item)">{{ item.title }}</a>
  15. <div class="xn-data-list-item-meta-title-suffix">
  16. <slot name="title-suffix" :record="item.record"></slot>
  17. </div>
  18. </div>
  19. </template>
  20. <template #description>
  21. <a-tooltip placement="top" v-for="description in item.descriptions">
  22. <template #title>
  23. <span>{{ description.title }}</span>
  24. </template>
  25. <a-tag>{{ description.content }}</a-tag>
  26. </a-tooltip>
  27. </template>
  28. </a-list-item-meta>
  29. <div class="xn-content" v-if="item.contents">
  30. <div class="xn-statistics" v-for="content in item.contents">
  31. <div class="xn-statistic-title">
  32. {{ content.title }}
  33. </div>
  34. <div class="xn-statistic-content">
  35. <span>{{ content.content }}</span>
  36. </div>
  37. </div>
  38. </div>
  39. <template #extra v-if="item.extra">
  40. <div class="xn-extra">
  41. <div class="xn-statistics">
  42. <div class="xn-statistic-title">{{ item.extra.title }}</div>
  43. <div class="xn-statistic-content">
  44. <span>{{ item.extra.content }}</span>
  45. </div>
  46. </div>
  47. </div>
  48. </template>
  49. <template #actions>
  50. <a-button type="link" @click="doAction(key, item)" v-for="{ key, label, icon, color } in props.actions">
  51. <template #icon>
  52. <component :is="icon" :style="{ color: color }" />
  53. </template>
  54. {{ label }}
  55. </a-button>
  56. </template>
  57. </a-list-item>
  58. </template>
  59. </a-list>
  60. </template>
  61. <script setup name="xnDataList">
  62. import { message } from 'ant-design-vue'
  63. const props = defineProps({
  64. // 数据源
  65. dataSource: {
  66. type: Array,
  67. required: true
  68. },
  69. // 分页
  70. page: {
  71. type: Object,
  72. required: true
  73. },
  74. // 动作
  75. actions: {
  76. type: Array,
  77. default: () => []
  78. },
  79. loading: {
  80. type: Boolean,
  81. default: false
  82. }
  83. })
  84. const emit = defineEmits(['title', 'action', 'page-change'])
  85. // 分页参数
  86. const { current, size, total } = toRefs(props.page)
  87. const pagination = reactive({
  88. onChange: (current) => {
  89. emit('page-change', current)
  90. },
  91. current: current,
  92. pageSize: size,
  93. total: total
  94. })
  95. // 出发 点击标题
  96. const clickTitle = (item) => {
  97. if (!item.record) {
  98. message.error('记录参数[record]错误')
  99. return
  100. }
  101. emit('title', { record: item.record })
  102. }
  103. // 触发 action
  104. const doAction = (key, item) => {
  105. if (!item.record) {
  106. message.error('记录参数[record]错误')
  107. return
  108. }
  109. emit('action', { key, record: item.record })
  110. }
  111. </script>
  112. <style lang="less" scoped>
  113. .xn-data-list-item {
  114. box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);
  115. padding: 12px 15px;
  116. margin-bottom: 10px;
  117. .xn-data-list-item-meta {
  118. align-items: center;
  119. padding-bottom: 15px;
  120. border-bottom: 1px solid #f0f0f0;
  121. .xn-data-list-item-meta-title {
  122. display: flex;
  123. align-items: center;
  124. .xn-data-list-item-meta-title-prefix {
  125. padding-left: 5px;
  126. }
  127. a {
  128. color: var(--text-color);
  129. transition: all 0.3s;
  130. padding: 0 5px;
  131. }
  132. .xn-data-list-item-meta-title-suffix {
  133. display: flex;
  134. flex: 1;
  135. justify-content: flex-end;
  136. }
  137. }
  138. }
  139. .xn-content {
  140. //box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.1);
  141. }
  142. .xn-extra {
  143. display: flex;
  144. align-items: center;
  145. height: 100%;
  146. }
  147. }
  148. .xn-statistics {
  149. display: inline-block;
  150. box-sizing: border-box;
  151. margin: 5px 20px;
  152. padding: 10px;
  153. color: var(--text-color);
  154. font-size: 14px;
  155. font-variant: tabular-nums;
  156. line-height: 1.5715;
  157. list-style: none;
  158. font-feature-settings: 'tnum';
  159. &:hover {
  160. box-shadow: var(--card-shadow);
  161. }
  162. .xn-statistic-title {
  163. margin-bottom: 4px;
  164. color: var(--text-color-secondary);
  165. font-size: 14px;
  166. }
  167. .xn-statistic-content {
  168. color: var(--heading-color);
  169. font-size: 15px;
  170. }
  171. }
  172. </style>