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