Descriptions.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <script lang="ts" name="Descriptions" setup>
  2. import { PropType } from 'vue'
  3. import dayjs from 'dayjs'
  4. import { useDesign } from '@/hooks/web/useDesign'
  5. import { propTypes } from '@/utils/propTypes'
  6. import { useAppStore } from '@/store/modules/app'
  7. import { DescriptionsSchema } from '@/types/descriptions'
  8. const appStore = useAppStore()
  9. const mobile = computed(() => appStore.getMobile)
  10. const attrs = useAttrs()
  11. const slots = useSlots()
  12. const props = defineProps({
  13. title: propTypes.string.def(''),
  14. message: propTypes.string.def(''),
  15. collapse: propTypes.bool.def(true),
  16. columns: propTypes.number.def(1),
  17. schema: {
  18. type: Array as PropType<DescriptionsSchema[]>,
  19. default: () => []
  20. },
  21. data: {
  22. type: Object as PropType<any>,
  23. default: () => ({})
  24. }
  25. })
  26. const { getPrefixCls } = useDesign()
  27. const prefixCls = getPrefixCls('descriptions')
  28. const getBindValue = computed(() => {
  29. const delArr: string[] = ['title', 'message', 'collapse', 'schema', 'data', 'class']
  30. const obj = { ...attrs, ...props }
  31. for (const key in obj) {
  32. if (delArr.indexOf(key) !== -1) {
  33. delete obj[key]
  34. }
  35. }
  36. return obj
  37. })
  38. const getBindItemValue = (item: DescriptionsSchema) => {
  39. const delArr: string[] = ['field']
  40. const obj = { ...item }
  41. for (const key in obj) {
  42. if (delArr.indexOf(key) !== -1) {
  43. delete obj[key]
  44. }
  45. }
  46. return obj
  47. }
  48. // 折叠
  49. const show = ref(true)
  50. const toggleClick = () => {
  51. if (props.collapse) {
  52. show.value = !unref(show)
  53. }
  54. }
  55. </script>
  56. <template>
  57. <div
  58. :class="[
  59. prefixCls,
  60. 'bg-[var(--el-color-white)] dark:(bg-[var(--el-bg-color)] border-[var(--el-border-color)] border-1px)'
  61. ]"
  62. >
  63. <div
  64. v-if="title"
  65. :class="[
  66. `${prefixCls}-header`,
  67. 'h-50px flex justify-between items-center border-bottom-1 border-solid border-[var(--tags-view-border-color)] px-10px cursor-pointer dark:border-[var(--el-border-color)]'
  68. ]"
  69. @click="toggleClick"
  70. >
  71. <div :class="[`${prefixCls}-header__title`, 'relative font-18px font-bold ml-10px']">
  72. <div class="flex items-center">
  73. {{ title }}
  74. <ElTooltip v-if="message" :content="message" placement="right">
  75. <Icon class="ml-5px" icon="ep:warning" />
  76. </ElTooltip>
  77. </div>
  78. </div>
  79. <Icon v-if="collapse" :icon="show ? 'ep:arrow-down' : 'ep:arrow-up'" />
  80. </div>
  81. <ElCollapseTransition>
  82. <div v-show="show" :class="[`${prefixCls}-content`, 'p-10px']">
  83. <ElDescriptions
  84. :column="props.columns"
  85. :direction="mobile ? 'vertical' : 'horizontal'"
  86. border
  87. v-bind="getBindValue"
  88. >
  89. <template v-if="slots['extra']" #extra>
  90. <slot name="extra"></slot>
  91. </template>
  92. <ElDescriptionsItem
  93. v-for="item in schema"
  94. :key="item.field"
  95. min-width="80"
  96. v-bind="getBindItemValue(item)"
  97. >
  98. <template #label>
  99. <slot
  100. :name="`${item.field}-label`"
  101. :row="{
  102. label: item.label
  103. }"
  104. >{{ item.label }}
  105. </slot>
  106. </template>
  107. <template #default>
  108. <slot v-if="item.dateFormat">
  109. {{
  110. data[item.field] !== null ? dayjs(data[item.field]).format(item.dateFormat) : ''
  111. }}
  112. </slot>
  113. <slot v-else-if="item.dictType">
  114. <DictTag :type="item.dictType" :value="data[item.field] + ''" />
  115. </slot>
  116. <slot v-else :name="item.field" :row="data">{{ data[item.field] }}</slot>
  117. </template>
  118. </ElDescriptionsItem>
  119. </ElDescriptions>
  120. </div>
  121. </ElCollapseTransition>
  122. </div>
  123. </template>
  124. <style lang="scss" scoped>
  125. $prefix-cls: #{$namespace}-descriptions;
  126. .#{$prefix-cls}-header {
  127. &__title {
  128. &::after {
  129. position: absolute;
  130. top: 3px;
  131. left: -10px;
  132. width: 4px;
  133. height: 70%;
  134. background: var(--el-color-primary);
  135. content: '';
  136. }
  137. }
  138. }
  139. .#{$prefix-cls}-content {
  140. :deep(.#{$elNamespace}-descriptions__cell) {
  141. width: 0;
  142. }
  143. }
  144. </style>