u
This commit is contained in:
1 parent
9c76e2769a
commit
f285ff776f
16 files changed
+884
-89
No files matched your search
@@ -76,7 +76,7 @@
|
|||||||
|
|
||||||
--ao-bg-color-component: #393939;
|
--ao-bg-color-component: #393939;
|
||||||
--ao-border-color-component: #5e5e5e;
|
--ao-border-color-component: #5e5e5e;
|
||||||
--ao-bg-color-secondarycomponent: #4b4b4b;
|
--ao-bg-color-secondarycomponent: #2c2c2c;
|
||||||
--ao-bg-color-secondarycomponent-hover: #5e5e5e;
|
--ao-bg-color-secondarycomponent-hover: #5e5e5e;
|
||||||
|
|
||||||
--ao-bg-color-mask: rgba(23, 23, 26, 0.6);
|
--ao-bg-color-mask: rgba(23, 23, 26, 0.6);
|
||||||
|
|||||||
@@ -77,7 +77,7 @@
|
|||||||
|
|
||||||
--ao-bg-color-component: #e8e8e8;
|
--ao-bg-color-component: #e8e8e8;
|
||||||
--ao-border-color-component: #ddd;
|
--ao-border-color-component: #ddd;
|
||||||
--ao-bg-color-secondarycomponent: #ddd;
|
--ao-bg-color-secondarycomponent: #f3f3f3;
|
||||||
--ao-bg-color-secondarycomponent-hover: #c6c6c6;
|
--ao-bg-color-secondarycomponent-hover: #c6c6c6;
|
||||||
|
|
||||||
--ao-bg-color-mask: rgba(29, 33, 41, 0.6);
|
--ao-bg-color-mask: rgba(29, 33, 41, 0.6);
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import type { VNode, VNodeChild } from 'vue'
|
||||||
|
import { Fragment } from 'vue'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断 vnode 是否匹配目标组件
|
||||||
|
* @param vnode VNode
|
||||||
|
* @param componentType 组件对象
|
||||||
|
* @param componentName 组件名称字符串(可选)
|
||||||
|
*/
|
||||||
|
function isTargetComponent(vnode: VNode, componentType: any, componentName?: string) {
|
||||||
|
if (!vnode)
|
||||||
|
return false
|
||||||
|
if (vnode.type === componentType)
|
||||||
|
return true
|
||||||
|
if (componentName && typeof vnode.type === 'object' && (vnode.type as any).name === componentName) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归获取指定组件的 props 和插槽函数(不执行函数 prop)
|
||||||
|
* @param nodes VNode 数组
|
||||||
|
* @param componentType 目标组件对象
|
||||||
|
* @param componentName 目标组件名称字符串(可选)
|
||||||
|
*/
|
||||||
|
export function getComponentInnerData(
|
||||||
|
nodes: VNode[],
|
||||||
|
componentType: any,
|
||||||
|
componentName?: string,
|
||||||
|
): { item: Record<string, any>, slots: Record<string, () => VNodeChild | VNodeChild[] | null> }[] {
|
||||||
|
const result: { item: Record<string, any>, slots: Record<string, () => VNodeChild | VNodeChild[] | null> }[] = []
|
||||||
|
|
||||||
|
function traverse(vnode: VNode) {
|
||||||
|
if (!vnode)
|
||||||
|
return
|
||||||
|
|
||||||
|
if (vnode.type === Fragment && Array.isArray(vnode.children)) {
|
||||||
|
vnode.children.forEach(child => traverse(child as VNode))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTargetComponent(vnode, componentType, componentName)) {
|
||||||
|
const item: Record<string, any> = {}
|
||||||
|
const slots: Record<string, () => VNodeChild | VNodeChild[] | null> = {}
|
||||||
|
|
||||||
|
if (vnode.props)
|
||||||
|
Object.assign(item, vnode.props)
|
||||||
|
|
||||||
|
if (vnode.children && typeof vnode.children === 'object' && !Array.isArray(vnode.children)) {
|
||||||
|
for (const key in vnode.children) {
|
||||||
|
const slotFn = vnode.children[key]
|
||||||
|
if (typeof slotFn === 'function') {
|
||||||
|
slots[key] = slotFn as () => VNodeChild | VNodeChild[] | null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push({ item, slots })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(vnode.children)) {
|
||||||
|
vnode.children.forEach(child => traverse(child as VNode))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes.forEach(traverse)
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -6,10 +6,14 @@ export { default as Checkbox } from './checkbox/checkbox'
|
|||||||
export { default as CheckboxGroup } from './checkbox/checkbox-group'
|
export { default as CheckboxGroup } from './checkbox/checkbox-group'
|
||||||
export { default as Collapse } from './collapse/collapse'
|
export { default as Collapse } from './collapse/collapse'
|
||||||
export { default as CollapseGroup } from './collapse/collapse-group'
|
export { default as CollapseGroup } from './collapse/collapse-group'
|
||||||
|
export { default as Descriptions } from './descriptions/descriptions'
|
||||||
|
export { default as DescriptionsGroup } from './descriptions/descriptions-group'
|
||||||
export { default as Drawer } from './drawer'
|
export { default as Drawer } from './drawer'
|
||||||
export { default as Group } from './group'
|
export { default as Group } from './group'
|
||||||
export { default as Icon } from './icon'
|
export { default as Icon } from './icon'
|
||||||
export { default as Input } from './input'
|
export { default as Input } from './input'
|
||||||
|
export { default as List } from './list/list'
|
||||||
|
export { default as ListItem } from './list/list-item'
|
||||||
export { default as Modal } from './modal'
|
export { default as Modal } from './modal'
|
||||||
export { default as Popconfirm } from './popconfirm'
|
export { default as Popconfirm } from './popconfirm'
|
||||||
export { default as Popup } from './popup'
|
export { default as Popup } from './popup'
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
// 示例数据
|
||||||
|
const demoData = ref([
|
||||||
|
{ label: '用户名', content: 'zhangsan', span: 1 },
|
||||||
|
{ label: '邮箱', content: 'zhangsan@example.com', span: 1 },
|
||||||
|
{ label: '手机号', content: '123456789', span: 1 },
|
||||||
|
{ label: '地址', content: '北京市海淀区中关村', span: 1 },
|
||||||
|
])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="demo-container">
|
||||||
|
<!-- 1. Row 布局 -->
|
||||||
|
<div class="demo-block">
|
||||||
|
<h3>Row 布局</h3>
|
||||||
|
<ADescriptionsGroup
|
||||||
|
:data="demoData"
|
||||||
|
layout="row"
|
||||||
|
title="Row Layout"
|
||||||
|
:columns="3"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 2. Row Vertical 布局 -->
|
||||||
|
<div class="demo-block">
|
||||||
|
<h3>Row Vertical 布局</h3>
|
||||||
|
<ADescriptionsGroup
|
||||||
|
:data="demoData"
|
||||||
|
layout="row-vertical"
|
||||||
|
title="Row Vertical Layout"
|
||||||
|
:columns="3"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 3. Column 布局 -->
|
||||||
|
<div class="demo-block">
|
||||||
|
<h3>Column 布局</h3>
|
||||||
|
<ADescriptionsGroup
|
||||||
|
:data="demoData"
|
||||||
|
layout="column"
|
||||||
|
title="Column Layout"
|
||||||
|
:columns="3"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 4. Column Vertical 布局 -->
|
||||||
|
<div class="demo-block">
|
||||||
|
<h3>Column Vertical 布局</h3>
|
||||||
|
<ADescriptionsGroup
|
||||||
|
:data="demoData"
|
||||||
|
layout="column-vertical"
|
||||||
|
title="Column Vertical Layout"
|
||||||
|
:columns="3"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 5. 单独使用 ADescriptions -->
|
||||||
|
<div class="demo-block">
|
||||||
|
<h3>ADescriptions 单独使用</h3>
|
||||||
|
<ADescriptionsGroup title="单独 Descriptions" :columns="3">
|
||||||
|
<ADescriptions label="用户名">
|
||||||
|
zhangsan
|
||||||
|
</ADescriptions>
|
||||||
|
<ADescriptions label="邮箱">
|
||||||
|
zhangsan@example.com
|
||||||
|
</ADescriptions>
|
||||||
|
<ADescriptions label="手机号">
|
||||||
|
123456789
|
||||||
|
</ADescriptions>
|
||||||
|
<ADescriptions label="地址">
|
||||||
|
<div style="background-color: red;">
|
||||||
|
测试
|
||||||
|
</div>
|
||||||
|
</ADescriptions>
|
||||||
|
</ADescriptionsGroup>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.demo-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 40px;
|
||||||
|
gap: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-block {
|
||||||
|
width: 80%;
|
||||||
|
max-width: 900px;
|
||||||
|
background: #fff;
|
||||||
|
padding: 20px 30px;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-block h3 {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+241
-25
@@ -1,11 +1,13 @@
|
|||||||
import type { PropType, VNode } from 'vue'
|
import type { PropType, VNode } from 'vue'
|
||||||
import { computed, defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
import { getPrefixCls } from '../_utils/getPrefixCls'
|
import { getPrefixCls } from '../_utils/getPrefixCls'
|
||||||
|
import { getComponentInnerData } from '../_utils/vnode'
|
||||||
|
import Descriptions from './descriptions'
|
||||||
|
|
||||||
interface DescriptionsData {
|
interface DescriptionsData {
|
||||||
label: string | VNode | (() => VNode)
|
label: string | VNode | (() => string | VNode)
|
||||||
content: string | VNode | (() => VNode)
|
content: string | VNode | (() => string | VNode)
|
||||||
span: number
|
span?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@@ -15,13 +17,17 @@ export default defineComponent({
|
|||||||
type: Array as PropType<DescriptionsData[]>,
|
type: Array as PropType<DescriptionsData[]>,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
title: {
|
header: {
|
||||||
type: [String, Object, Function] as PropType<string | VNode | (() => VNode)>,
|
type: [String, Object, Function] as PropType<string | VNode | (() => VNode)>,
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
type: String as PropType<'small' | 'medium' | 'large'>,
|
type: String as PropType<'small' | 'medium' | 'large'>,
|
||||||
default: 'medium',
|
default: 'medium',
|
||||||
},
|
},
|
||||||
|
tableLayout: {
|
||||||
|
type: String as PropType<'fixed' | 'auto'>,
|
||||||
|
default: 'fixed',
|
||||||
|
},
|
||||||
layout: {
|
layout: {
|
||||||
type: String as PropType<'row' | 'row-vertical' | 'column' | 'column-vertical'>,
|
type: String as PropType<'row' | 'row-vertical' | 'column' | 'column-vertical'>,
|
||||||
default: 'row',
|
default: 'row',
|
||||||
@@ -30,6 +36,28 @@ export default defineComponent({
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: 3,
|
default: 3,
|
||||||
},
|
},
|
||||||
|
border: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
colon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
labelClass: {
|
||||||
|
type: [String, Array, Object],
|
||||||
|
},
|
||||||
|
labelStyle: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
contentClass: {
|
||||||
|
type: [String, Array, Object],
|
||||||
|
},
|
||||||
|
contentStyle: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
class: {
|
class: {
|
||||||
type: [String, Array, Object],
|
type: [String, Array, Object],
|
||||||
default: '',
|
default: '',
|
||||||
@@ -40,36 +68,224 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
emits: [],
|
emits: [],
|
||||||
setup(props, { slots, emit }) {
|
setup(props, { slots }) {
|
||||||
const prefixCls = getPrefixCls('descriptions-group')
|
const prefixCls = getPrefixCls('descriptions')
|
||||||
const renderHeader = () => {
|
|
||||||
const title = slots.title
|
|
||||||
? slots.title()
|
|
||||||
: typeof props.title === 'function'
|
|
||||||
? props.title()
|
|
||||||
: props.title
|
|
||||||
|
|
||||||
return <div class={`${prefixCls}-header`}>{title}</div>
|
const renderLabel = (item: DescriptionsData) => {
|
||||||
|
if (typeof item.label === 'function')
|
||||||
|
return item.label()
|
||||||
|
return item.label
|
||||||
}
|
}
|
||||||
|
|
||||||
const childrenVNodes = computed(() => {
|
const renderContent = (item: DescriptionsData) => {
|
||||||
const nodes = slots.default?.() ?? []
|
if (typeof item.content === 'function')
|
||||||
return nodes.filter(node =>
|
return item.content()
|
||||||
node.type && (typeof node.type === 'string' || typeof node.type === 'object' || typeof node.type === 'function'),
|
return item.content
|
||||||
)
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const groupedData = computed(() => {
|
const getRows = () => {
|
||||||
c
|
const dataList: DescriptionsData[] = []
|
||||||
})
|
|
||||||
|
// 1️⃣ 构建基础数据列表
|
||||||
|
if (props.data && props.data.length) {
|
||||||
|
props.data.forEach((item) => {
|
||||||
|
dataList.push({
|
||||||
|
label: item.label,
|
||||||
|
content: item.content,
|
||||||
|
span: item.span ?? 1, // 默认 span = 1
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else if (slots.default) {
|
||||||
|
const childrenData = getComponentInnerData(slots.default(), Descriptions)
|
||||||
|
childrenData.forEach(({ item, slots }) => {
|
||||||
|
dataList.push({
|
||||||
|
label: slots.label ? slots.label() : item.label,
|
||||||
|
content: slots.content
|
||||||
|
? slots.content()
|
||||||
|
: slots.default
|
||||||
|
? slots.default()
|
||||||
|
: item.content,
|
||||||
|
span: item.span ?? 1,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2️⃣ 如果是列布局,直接一行返回
|
||||||
|
if (props.layout === 'column' || props.layout === 'column-vertical') {
|
||||||
|
return [dataList]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3️⃣ Row 布局按列分行
|
||||||
|
const res: DescriptionsData[][] = []
|
||||||
|
let temp: DescriptionsData[] = []
|
||||||
|
let currentSpan = 0
|
||||||
|
|
||||||
|
const addRow = () => {
|
||||||
|
if (temp.length) {
|
||||||
|
// 填充剩余列到最后一个 item
|
||||||
|
const restSpan = props.columns - currentSpan
|
||||||
|
if (restSpan > 0) {
|
||||||
|
const lastItem = temp[temp.length - 1]
|
||||||
|
lastItem.span = (lastItem.span ?? 1) + restSpan
|
||||||
|
}
|
||||||
|
res.push(temp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dataList.forEach((item) => {
|
||||||
|
const span = Math.min(item.span ?? 1, props.columns)
|
||||||
|
|
||||||
|
if (currentSpan + span > props.columns) {
|
||||||
|
addRow()
|
||||||
|
temp = []
|
||||||
|
currentSpan = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
temp.push({ ...item, span })
|
||||||
|
currentSpan += span
|
||||||
|
})
|
||||||
|
|
||||||
|
// 最后一行
|
||||||
|
addRow()
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
const label = (node: DescriptionsData) => {
|
||||||
|
const labelClass = [`${prefixCls}-label`]
|
||||||
|
|
||||||
|
let colspan = 1
|
||||||
|
|
||||||
|
// 水平布局下
|
||||||
|
if (props.layout === 'row') {
|
||||||
|
colspan = 1
|
||||||
|
}
|
||||||
|
else if (props.layout === 'row-vertical') {
|
||||||
|
colspan = node.span ?? 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<td
|
||||||
|
colspan={colspan}
|
||||||
|
class={[labelClass, props.labelClass]}
|
||||||
|
style={props.labelStyle}
|
||||||
|
>
|
||||||
|
{renderLabel(node)}
|
||||||
|
{props.colon ? ':' : null}
|
||||||
|
</td>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = (node: DescriptionsData) => {
|
||||||
|
const contentClass = [`${prefixCls}-content`]
|
||||||
|
|
||||||
|
let colspan = 1
|
||||||
|
if (props.layout === 'row') {
|
||||||
|
const span = node.span ?? 1
|
||||||
|
colspan = span * 2 - 1
|
||||||
|
}
|
||||||
|
else if (props.layout === 'row-vertical') {
|
||||||
|
colspan = node.span ?? 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<td
|
||||||
|
colspan={colspan}
|
||||||
|
class={[contentClass, props.contentClass]}
|
||||||
|
style={props.contentStyle}
|
||||||
|
>
|
||||||
|
{renderContent(node)}
|
||||||
|
</td>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const row = (data: DescriptionsData[]) => {
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
{
|
||||||
|
data.map(node => (
|
||||||
|
<>
|
||||||
|
{label(node)}
|
||||||
|
{content(node)}
|
||||||
|
</>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowVertical = (data: DescriptionsData[]) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<tr>{data.map(node => label(node))}</tr>
|
||||||
|
<tr>{data.map(node => content(node))}</tr>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const column = (data: DescriptionsData[]) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{data.map(node => (
|
||||||
|
<tr>
|
||||||
|
{label(node)}
|
||||||
|
{content(node)}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const columnVertical = (data: DescriptionsData[]) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{data.map(node => (
|
||||||
|
<>
|
||||||
|
<tr>{label(node)}</tr>
|
||||||
|
<tr>{content(node)}</tr>
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderHeader = () => {
|
||||||
|
const header = slots.header
|
||||||
|
? slots.header()
|
||||||
|
: typeof props.header === 'function'
|
||||||
|
? props.header()
|
||||||
|
: props.header
|
||||||
|
|
||||||
|
return <div class={`${prefixCls}-header`}>{header}</div>
|
||||||
|
}
|
||||||
|
|
||||||
const renderBody = () => {
|
const renderBody = () => {
|
||||||
return (
|
return (
|
||||||
<table class={[
|
<table class={[
|
||||||
`${prefixCls}-body`,
|
`${prefixCls}-body`,
|
||||||
|
`${prefixCls}-body-${props.tableLayout}`,
|
||||||
|
`${prefixCls}-size-${props.size}`,
|
||||||
|
{ [`${prefixCls}-body-border`]: props.border },
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
{getRows().map((item) => {
|
||||||
|
if (props.layout === 'row') {
|
||||||
|
return row(item)
|
||||||
|
}
|
||||||
|
else if (props.layout === 'row-vertical') {
|
||||||
|
return rowVertical(item)
|
||||||
|
}
|
||||||
|
else if (props.layout === 'column') {
|
||||||
|
return column(item)
|
||||||
|
}
|
||||||
|
else if (props.layout === 'column-vertical') {
|
||||||
|
return columnVertical(item)
|
||||||
|
}
|
||||||
|
// 默认 fallback
|
||||||
|
return row(item)
|
||||||
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
)
|
)
|
||||||
@@ -77,8 +293,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<div class={[prefixCls, props.class]} style={{ ...props.style }}>
|
<div class={[prefixCls, props.class]} style={{ ...props.style }}>
|
||||||
{renderHeader}
|
{renderHeader()}
|
||||||
{renderBody}
|
{renderBody()}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,16 +2,13 @@ import type { PropType, VNode } from 'vue'
|
|||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Descriptions',
|
name: 'AoDescriptions',
|
||||||
props: {
|
props: {
|
||||||
label: {
|
label: {
|
||||||
type: [String, Object, Function] as PropType<string | VNode | (() => VNode)>,
|
type: [String, Object, Function] as PropType<string | VNode | (() => string | VNode)>,
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
type: [String, Object, Function] as PropType<string | VNode | (() => VNode)>,
|
type: [String, Object, Function] as PropType<string | VNode | (() => string | VNode)>,
|
||||||
},
|
|
||||||
default: {
|
|
||||||
type: [String, Object, Function] as PropType<string | VNode | (() => VNode)>,
|
|
||||||
},
|
},
|
||||||
span: {
|
span: {
|
||||||
type: Number,
|
type: Number,
|
||||||
|
|||||||
@@ -4,4 +4,88 @@
|
|||||||
$descriptions-prefix: '#{$prefix}-descriptions';
|
$descriptions-prefix: '#{$prefix}-descriptions';
|
||||||
|
|
||||||
.#{$descriptions-prefix} {
|
.#{$descriptions-prefix} {
|
||||||
|
font-size: 14px;
|
||||||
|
color: $text-color-base;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
.#{$descriptions-prefix}-header {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: $text-color-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$descriptions-prefix}-body {
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 14px;
|
||||||
|
width: 100%;
|
||||||
|
&.#{$descriptions-prefix}-body-fixed {
|
||||||
|
table-layout: fixed;
|
||||||
|
}
|
||||||
|
&.#{$descriptions-prefix}-body-auto {
|
||||||
|
table-layout: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$descriptions-prefix}-label {
|
||||||
|
color: $text-color-placeholder;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$descriptions-prefix}-content {
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$descriptions-prefix}-size-small {
|
||||||
|
.#{$descriptions-prefix}-label,
|
||||||
|
.#{$descriptions-prefix}-content {
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$descriptions-prefix}-size-medium {
|
||||||
|
.#{$descriptions-prefix}-label,
|
||||||
|
.#{$descriptions-prefix}-content {
|
||||||
|
padding: 12px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$descriptions-prefix}-size-large {
|
||||||
|
.#{$descriptions-prefix}-label,
|
||||||
|
.#{$descriptions-prefix}-content {
|
||||||
|
padding: 18px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$descriptions-prefix}-body-border {
|
||||||
|
> tbody > tr > td {
|
||||||
|
border: 1px solid $border-color-component;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$descriptions-prefix}-label {
|
||||||
|
background-color: $bg-color-secondarycomponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.#{$descriptions-prefix}-size-small {
|
||||||
|
.#{$descriptions-prefix}-label,
|
||||||
|
.#{$descriptions-prefix}-content {
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.#{$descriptions-prefix}-size-medium {
|
||||||
|
.#{$descriptions-prefix}-label,
|
||||||
|
.#{$descriptions-prefix}-content {
|
||||||
|
padding: 12px 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.#{$descriptions-prefix}-size-large {
|
||||||
|
.#{$descriptions-prefix}-label,
|
||||||
|
.#{$descriptions-prefix}-content {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
@use './collapse/index.scss' as *;
|
@use './collapse/index.scss' as *;
|
||||||
@use './checkbox/index.scss' as *;
|
@use './checkbox/index.scss' as *;
|
||||||
@use './drawer/index.scss' as *;
|
@use './drawer/index.scss' as *;
|
||||||
|
@use './descriptions/index.scss' as *;
|
||||||
@use './group/index.scss' as *;
|
@use './group/index.scss' as *;
|
||||||
@use './icon/index.scss' as *;
|
@use './icon/index.scss' as *;
|
||||||
@use './input/index.scss' as *;
|
@use './input/index.scss' as *;
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
@use './tag/index.scss' as *;
|
@use './tag/index.scss' as *;
|
||||||
@use './textarea/index.scss' as *;
|
@use './textarea/index.scss' as *;
|
||||||
@use './tooltip/index.scss' as *;
|
@use './tooltip/index.scss' as *;
|
||||||
|
@use './list/index.scss' as *;
|
||||||
|
|
||||||
[class*='#{variables.$prefix}-'] {
|
[class*='#{variables.$prefix}-'] {
|
||||||
-webkit-box-sizing: border-box;
|
-webkit-box-sizing: border-box;
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
@use '../_styles/_variables.scss' as *;
|
||||||
|
@use 'sass:color';
|
||||||
|
|
||||||
|
$list-prefix: '#{$prefix}-list';
|
||||||
|
|
||||||
|
.#{$list-prefix} {
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
color: $text-color-base;
|
||||||
|
background: $bg-color-container;
|
||||||
|
.#{$list-prefix}-header,
|
||||||
|
.#{$list-prefix}-footer {
|
||||||
|
background: $bg-color-container;
|
||||||
|
padding: 12px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$list-prefix}-body {
|
||||||
|
overflow: auto;
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$list-prefix}-item {
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.#{$list-prefix}-item-prefix {
|
||||||
|
margin-right: 20px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$list-prefix}-item-content {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$list-prefix}-item-suffix {
|
||||||
|
margin-left: 20px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.#{$list-prefix}-separator {
|
||||||
|
.#{$list-prefix}-item::after {
|
||||||
|
background: $separator-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import type { PropType, VNode } from 'vue'
|
||||||
|
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'AoComponent',
|
||||||
|
props: {
|
||||||
|
prefix: {
|
||||||
|
type: [String, Object, Function] as PropType<string | VNode | (() => string | VNode)>,
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
type: [String, Object, Function] as PropType<string | VNode | (() => string | VNode)>,
|
||||||
|
},
|
||||||
|
suffix: {
|
||||||
|
type: [String, Object, Function] as PropType<string | VNode | (() => string | VNode)>,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
import type { PropType, VNode } from 'vue'
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import { getPrefixCls } from '../_utils/getPrefixCls'
|
||||||
|
import { getComponentInnerData } from '../_utils/vnode'
|
||||||
|
import ListItem from './list-item'
|
||||||
|
|
||||||
|
interface ListItemData {
|
||||||
|
prefix: string | VNode | (() => string | VNode)
|
||||||
|
content: string | VNode | (() => string | VNode)
|
||||||
|
suffix: string | VNode | (() => string | VNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'List',
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Array as PropType<ListItemData[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
type: [String, Object, Function] as PropType<string | VNode | (() => VNode)>,
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
type: [String, Object, Function] as PropType<string | VNode | (() => VNode)>,
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
type: [String, Object, Function] as PropType<string | VNode | (() => VNode)>,
|
||||||
|
},
|
||||||
|
separator: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
onScroll: {
|
||||||
|
type: Function as PropType<(options: { e: Event, scrollTop: number, scrollBottom: number }) => void>,
|
||||||
|
},
|
||||||
|
class: {
|
||||||
|
type: [String, Array, Object],
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: [],
|
||||||
|
setup(props, { slots }) {
|
||||||
|
const prefixCls = getPrefixCls('list')
|
||||||
|
|
||||||
|
const getRows = () => {
|
||||||
|
const dataList: ListItemData[] = []
|
||||||
|
|
||||||
|
// 1️⃣ 构建基础数据列表
|
||||||
|
if (props.data && props.data.length) {
|
||||||
|
props.data.forEach((item) => {
|
||||||
|
dataList.push({
|
||||||
|
prefix: item.prefix,
|
||||||
|
content: item.content,
|
||||||
|
suffix: item.suffix,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else if (slots.default) {
|
||||||
|
const childrenData = getComponentInnerData(slots.default(), ListItem)
|
||||||
|
childrenData.forEach(({ item, slots }) => {
|
||||||
|
dataList.push({
|
||||||
|
prefix: slots.prefix ? slots.prefix() : item.prefix,
|
||||||
|
content: slots.content
|
||||||
|
? slots.content()
|
||||||
|
: slots.default
|
||||||
|
? slots.default()
|
||||||
|
: item.content,
|
||||||
|
suffix: slots.suffix ? slots.suffix() : item.suffix,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataList
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderItemPrefix = (item: ListItemData) => {
|
||||||
|
if (typeof item.prefix === 'function')
|
||||||
|
return item.prefix()
|
||||||
|
return item.prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderItemContent = (item: ListItemData) => {
|
||||||
|
if (typeof item.content === 'function')
|
||||||
|
return item.content()
|
||||||
|
return item.content
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderItemSuffix = (item: ListItemData) => {
|
||||||
|
if (typeof item.suffix === 'function')
|
||||||
|
return item.suffix()
|
||||||
|
return item.suffix
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderHeader = () => {
|
||||||
|
const content = slots.header
|
||||||
|
? slots.header()
|
||||||
|
: typeof props.header === 'function'
|
||||||
|
? props.header()
|
||||||
|
: props.header
|
||||||
|
return content ? <div class={`${prefixCls}-header`}>{content}</div> : null
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleScroll = (e: Event) => {
|
||||||
|
const target = e.target as HTMLElement
|
||||||
|
const scrollTop = target.scrollTop
|
||||||
|
const scrollHeight = target.scrollHeight
|
||||||
|
const clientHeight = target.clientHeight
|
||||||
|
const scrollBottom = scrollHeight - scrollTop - clientHeight
|
||||||
|
|
||||||
|
// 触发滚动回调
|
||||||
|
props.onScroll?.({ e, scrollTop, scrollBottom })
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderBody = () => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
class={`${prefixCls}-body`}
|
||||||
|
onScroll={handleScroll}
|
||||||
|
>
|
||||||
|
<ul>
|
||||||
|
{getRows().map((item, index) => (
|
||||||
|
<li class={`${prefixCls}-item`} key={index}>
|
||||||
|
<div class={`${prefixCls}-item-prefix`}>{renderItemPrefix(item)}</div>
|
||||||
|
<div class={`${prefixCls}-item-content`}>{renderItemContent(item)}</div>
|
||||||
|
<div class={`${prefixCls}-item-suffix`}>{renderItemSuffix(item)}</div>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderFooter = () => {
|
||||||
|
const content = slots.footer
|
||||||
|
? slots.footer()
|
||||||
|
: typeof props.footer === 'function'
|
||||||
|
? props.footer()
|
||||||
|
: props.footer
|
||||||
|
return content ? <div class={`${prefixCls}-footer`}>{content}</div> : null
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => (
|
||||||
|
<div
|
||||||
|
class={[
|
||||||
|
prefixCls,
|
||||||
|
props.class,
|
||||||
|
props.separator ? `${prefixCls}-separator` : '',
|
||||||
|
]}
|
||||||
|
style={{ ...props.style }}
|
||||||
|
>
|
||||||
|
{renderHeader()}
|
||||||
|
{renderBody()}
|
||||||
|
{renderFooter()}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -43,3 +43,15 @@ $spin-prefix: #{$prefix}-spin;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.#{$spin-prefix}-horizontal {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px; // 图标和 tip 之间间距
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$spin-prefix}-vertical {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px; // 图标和 tip 之间间距
|
||||||
|
}
|
||||||
@@ -1,24 +1,40 @@
|
|||||||
import type { PropType, VNode } from 'vue'
|
import type { PropType, VNode } from 'vue'
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent, onUnmounted, ref } from 'vue'
|
||||||
import { getPrefixCls } from '../_utils/getPrefixCls'
|
import { getPrefixCls } from '../_utils/getPrefixCls'
|
||||||
import Icon from '../icon'
|
import Icon from '../icon'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Spin',
|
name: 'Spin',
|
||||||
props: {
|
props: {
|
||||||
loading: { type: Boolean, default: false },
|
loading: {
|
||||||
opacity: { type: Number as PropType<number>, default: 0.6 },
|
type: Boolean,
|
||||||
rounded: { type: Boolean, default: true },
|
default: false,
|
||||||
icon: { type: String as PropType<string>, default: 'mingcute:loading-line' },
|
},
|
||||||
size: { type: Number as PropType<number>, default: 16 },
|
icon: {
|
||||||
rotate: { type: Number as PropType<number>, default: 360 },
|
type: String as PropType<string>,
|
||||||
|
default: 'mingcute:loading-fill',
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: Number as PropType<number>,
|
||||||
|
default: 16,
|
||||||
|
},
|
||||||
tip: {
|
tip: {
|
||||||
type: [String, Object, Function] as unknown as () => string | VNode | (() => VNode),
|
type: [String, Object, Function] as PropType<string | VNode | (() => VNode)>,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
tipPosition: {
|
||||||
|
type: String as PropType<'top' | 'right' | 'bottom' | 'left'>,
|
||||||
|
default: 'bottom',
|
||||||
|
},
|
||||||
|
delay: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setup(props, { slots }) {
|
setup(props, { slots }) {
|
||||||
const prefixCls = getPrefixCls('spin')
|
const prefixCls = getPrefixCls('spin')
|
||||||
|
const showLoading = ref(false)
|
||||||
|
let timer: number | null = null
|
||||||
|
|
||||||
const renderTip = () => {
|
const renderTip = () => {
|
||||||
if (slots.tip)
|
if (slots.tip)
|
||||||
@@ -28,51 +44,72 @@ export default defineComponent({
|
|||||||
return props.tip
|
return props.tip
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
// 每次渲染时处理 delay
|
||||||
const tipContent = renderTip()
|
const updateShowLoading = () => {
|
||||||
|
if (timer)
|
||||||
if (!props.loading || !slots.default) {
|
clearTimeout(timer)
|
||||||
// loading 为 false 时的结构
|
if (props.loading) {
|
||||||
return (
|
if (props.delay > 0) {
|
||||||
<div
|
timer = window.setTimeout(() => {
|
||||||
class={[
|
showLoading.value = true
|
||||||
prefixCls,
|
}, props.delay)
|
||||||
tipContent ? `${prefixCls}-has-tip` : '',
|
}
|
||||||
]}
|
else {
|
||||||
>
|
showLoading.value = true
|
||||||
<Icon
|
}
|
||||||
icon={props.icon}
|
|
||||||
size={props.size}
|
|
||||||
class={`${prefixCls}-icon`}
|
|
||||||
spin
|
|
||||||
/>
|
|
||||||
{tipContent && <div class={`${prefixCls}-tip`}>{tipContent}</div>}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
showLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// loading 为 true 时的结构
|
onUnmounted(() => {
|
||||||
return (
|
if (timer)
|
||||||
<div
|
clearTimeout(timer)
|
||||||
class={[
|
})
|
||||||
prefixCls,
|
|
||||||
`${prefixCls}-loading`,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{slots.default()}
|
|
||||||
|
|
||||||
<div class={`${prefixCls}-mask`}>
|
return () => {
|
||||||
<div class={`${prefixCls}-mask-inner`}>
|
// 更新延迟显示状态
|
||||||
<Icon
|
updateShowLoading()
|
||||||
icon={props.icon}
|
|
||||||
size={props.size}
|
const tipContent = renderTip()
|
||||||
spin
|
const isHorizontal = props.tipPosition === 'left' || props.tipPosition === 'right'
|
||||||
class={`${prefixCls}-icon`}
|
const containerClass = [
|
||||||
/>
|
prefixCls,
|
||||||
{tipContent && <div class={`${prefixCls}-tip`}>{tipContent}</div>}
|
tipContent ? `${prefixCls}-has-tip` : '',
|
||||||
|
tipContent ? `${prefixCls}-tip-${props.tipPosition}` : '',
|
||||||
|
]
|
||||||
|
|
||||||
|
const tipNode = tipContent ? <div class={`${prefixCls}-tip`}>{tipContent}</div> : null
|
||||||
|
const iconNode = <Icon icon={props.icon} size={props.size} spin class={`${prefixCls}-icon`} />
|
||||||
|
|
||||||
|
const content = isHorizontal
|
||||||
|
? (
|
||||||
|
<div class={`${prefixCls}-horizontal`}>
|
||||||
|
{props.tipPosition === 'left' && tipNode}
|
||||||
|
{iconNode}
|
||||||
|
{props.tipPosition === 'right' && tipNode}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
|
: (
|
||||||
|
<div class={`${prefixCls}-vertical`}>
|
||||||
|
{props.tipPosition === 'top' && tipNode}
|
||||||
|
{iconNode}
|
||||||
|
{props.tipPosition === 'bottom' && tipNode}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={containerClass} style={{ position: 'relative' }}>
|
||||||
|
{/* 默认内容立即渲染 */}
|
||||||
|
{slots.default && slots.default()}
|
||||||
|
|
||||||
|
{/* 延迟显示的 loading 遮罩 */}
|
||||||
|
{showLoading.value && (
|
||||||
|
<div class={`${prefixCls}-mask`}>
|
||||||
|
<div class={`${prefixCls}-mask-inner`}>{content}</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,35 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
const items = Array.from({ length: 10 }, (_, i) => ({
|
||||||
|
prefix: `图标${i + 1}`,
|
||||||
|
content: `这是内容${i + 1}`,
|
||||||
|
suffix: `操作${i + 1}`,
|
||||||
|
}))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="main">
|
||||||
content
|
<AList header="列表 Header" footer="列表 Footer" style="width: 1000px;height:400px">
|
||||||
|
<AListItem v-for="(item, index) in items" :key="index">
|
||||||
<t-descriptions-item label="Name">
|
<template #prefix>
|
||||||
TDesign
|
{{ item.prefix }}
|
||||||
</t-descriptions-item>
|
</template>
|
||||||
|
{{ item.content }}
|
||||||
|
<template #suffix>
|
||||||
|
{{ item.suffix }}
|
||||||
|
</template>
|
||||||
|
</AListItem>
|
||||||
|
</AList>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.main {
|
||||||
|
height: 800px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #eeeeee;
|
||||||
|
flex-direction: column;
|
||||||
|
gap:16px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -16,10 +16,15 @@ declare module 'vue' {
|
|||||||
ACollapse: typeof import('@ao/ao-design')['Collapse']
|
ACollapse: typeof import('@ao/ao-design')['Collapse']
|
||||||
ACollapseGroup: typeof import('@ao/ao-design')['CollapseGroup']
|
ACollapseGroup: typeof import('@ao/ao-design')['CollapseGroup']
|
||||||
AConfigProvider: typeof import('@ao/ao-design')['ConfigProvider']
|
AConfigProvider: typeof import('@ao/ao-design')['ConfigProvider']
|
||||||
|
ADescriptions: typeof import('@ao/ao-design')['Descriptions']
|
||||||
|
'ADescriptions.Item': typeof import('@ao/ao-design')['Descriptions.Item']
|
||||||
|
ADescriptionsGroup: typeof import('@ao/ao-design')['DescriptionsGroup']
|
||||||
ADrawer: typeof import('@ao/ao-design')['Drawer']
|
ADrawer: typeof import('@ao/ao-design')['Drawer']
|
||||||
AGroup: typeof import('@ao/ao-design')['Group']
|
AGroup: typeof import('@ao/ao-design')['Group']
|
||||||
AIcon: typeof import('@ao/ao-design')['Icon']
|
AIcon: typeof import('@ao/ao-design')['Icon']
|
||||||
AInput: typeof import('@ao/ao-design')['Input']
|
AInput: typeof import('@ao/ao-design')['Input']
|
||||||
|
AList: typeof import('@ao/ao-design')['List']
|
||||||
|
AListItem: typeof import('@ao/ao-design')['ListItem']
|
||||||
ALoading: typeof import('@ao/ao-design')['Loading']
|
ALoading: typeof import('@ao/ao-design')['Loading']
|
||||||
AMessage: typeof import('@ao/ao-design')['Message']
|
AMessage: typeof import('@ao/ao-design')['Message']
|
||||||
AModal: typeof import('@ao/ao-design')['Modal']
|
AModal: typeof import('@ao/ao-design')['Modal']
|
||||||
|
|||||||
Reference in new issue
Block a user