xto-fronted 0.9.8 → 0.9.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/TableActions.vue.d.ts +11 -0
- package/dist/{index-DMUFTG7s.js → index-B1Mm04GL.js} +1 -1
- package/dist/{index-BK1apsCp.js → index-BXcy4Waf.js} +1 -1
- package/dist/{index-BVJQ19TI.js → index-CEMQH6PX.js} +1 -1
- package/dist/{index-DaMmGfCF.js → index-ChjL51Io.js} +1 -1
- package/dist/{index-BWXq-6ka.js → index-DJkhFYHs.js} +1082 -1012
- package/dist/index.d.ts +1 -0
- package/dist/index.js +82 -81
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/assets/styles/index.scss +3 -2
- package/src/components/TableActions.vue +142 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* TableActions 表格行内操作区
|
|
4
|
+
*
|
|
5
|
+
* 统一列表页「操作」列的排版。行内操作不该用实心按钮:同一个文案,实心按钮
|
|
6
|
+
* 比文字链宽近一倍(实心有 padding 10px 20px + 边框,text 变体左右 padding 为 0),
|
|
7
|
+
* 且一片实心色块会压过行数据本身。操作列一旦被撑到换行,整张表的行高就跟着翻倍。
|
|
8
|
+
*
|
|
9
|
+
* 组件做三件事:
|
|
10
|
+
* 1. 内部的 x-button 一律降级为文字链(type=text / size=small),页面不用改写法;
|
|
11
|
+
* 原本是 danger 的保持红色文字,不会退化成实心红块
|
|
12
|
+
* 2. 不换行(nowrap)+ 统一间距,行高恒定
|
|
13
|
+
* 3. 超过 max 个时,其余收进「更多」下拉
|
|
14
|
+
*
|
|
15
|
+
* 用法:
|
|
16
|
+
* <x-table-column label="操作" width="220" fixed="right">
|
|
17
|
+
* <TableActions :max="3">
|
|
18
|
+
* <x-button type="primary" @click="edit(row)">编辑</x-button>
|
|
19
|
+
* <x-button type="danger" @click="del(row)">删除</x-button>
|
|
20
|
+
* </TableActions>
|
|
21
|
+
* </x-table-column>
|
|
22
|
+
*/
|
|
23
|
+
import { cloneVNode, computed, Comment, useSlots, type VNode } from 'vue'
|
|
24
|
+
import { Icon } from '@xto/base'
|
|
25
|
+
import { Dropdown, DropdownMenu, DropdownItem } from '@xto/navigation'
|
|
26
|
+
|
|
27
|
+
defineOptions({
|
|
28
|
+
name: 'TableActions'
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const props = withDefaults(
|
|
32
|
+
defineProps<{
|
|
33
|
+
/** 超过该数量时,其余收进「更多」下拉;0 表示不折叠 */
|
|
34
|
+
max?: number
|
|
35
|
+
/** 按钮间距(px) */
|
|
36
|
+
gap?: number
|
|
37
|
+
}>(),
|
|
38
|
+
{
|
|
39
|
+
max: 0,
|
|
40
|
+
gap: 8
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
const slots = useSlots() as unknown as { default?: () => VNode[] }
|
|
45
|
+
|
|
46
|
+
/** 把行内按钮统一成文字链;danger 保持红色语义 */
|
|
47
|
+
const normalize = (v: VNode): VNode => {
|
|
48
|
+
const p = (v.props || {}) as Record<string, any>
|
|
49
|
+
const isDanger = p.type === 'danger' || p.danger === true || p.danger === ''
|
|
50
|
+
const merged: Record<string, any> = { type: 'text', size: 'small' }
|
|
51
|
+
if (isDanger) {
|
|
52
|
+
// danger 不是 x-button 的 prop,直接用 class 上色(避免渲染成实心红块)
|
|
53
|
+
merged.class = [p.class, 'table-actions__danger']
|
|
54
|
+
}
|
|
55
|
+
return cloneVNode(v, merged)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const items = computed<VNode[]>(() =>
|
|
59
|
+
(slots.default?.() ?? [])
|
|
60
|
+
.filter((v: VNode) => v.type && v.type !== Comment && typeof v.type !== 'symbol')
|
|
61
|
+
.map(normalize)
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
const folded = computed(() => props.max > 0 && items.value.length > props.max)
|
|
65
|
+
const visible = computed(() =>
|
|
66
|
+
folded.value ? items.value.slice(0, Math.max(1, props.max - 1)) : items.value
|
|
67
|
+
)
|
|
68
|
+
const overflow = computed(() => (folded.value ? items.value.slice(Math.max(1, props.max - 1)) : []))
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<template>
|
|
72
|
+
<div v-if="items.length" class="table-actions" :style="{ gap: `${gap}px` }">
|
|
73
|
+
<component :is="v" v-for="(v, i) in visible" :key="i" />
|
|
74
|
+
|
|
75
|
+
<Dropdown v-if="overflow.length" trigger="click" placement="bottom-end">
|
|
76
|
+
<x-button type="text" size="small" class="table-actions__more">
|
|
77
|
+
更多
|
|
78
|
+
<Icon name="caret-down" :size="12" />
|
|
79
|
+
</x-button>
|
|
80
|
+
<template #dropdown>
|
|
81
|
+
<DropdownMenu>
|
|
82
|
+
<DropdownItem v-for="(v, i) in overflow" :key="i" :command="i">
|
|
83
|
+
<component :is="v" />
|
|
84
|
+
</DropdownItem>
|
|
85
|
+
</DropdownMenu>
|
|
86
|
+
</template>
|
|
87
|
+
</Dropdown>
|
|
88
|
+
</div>
|
|
89
|
+
</template>
|
|
90
|
+
|
|
91
|
+
<style lang="scss" scoped>
|
|
92
|
+
.table-actions {
|
|
93
|
+
display: inline-flex;
|
|
94
|
+
align-items: center;
|
|
95
|
+
// 行高恒定的关键:任何情况下都不换行
|
|
96
|
+
white-space: nowrap;
|
|
97
|
+
|
|
98
|
+
// 文字链左右 padding 为 0,靠 gap 拉开间距
|
|
99
|
+
:deep(.x-button + .x-button) {
|
|
100
|
+
margin-left: 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 兜底:按钮常被 x-popconfirm / x-tooltip 等包一层,上面按 props 归一化够不到,
|
|
104
|
+
// 这里再用样式把实心变体压成文字链(:deep 后特异性高于 .x-button--xxx,无需 !important)
|
|
105
|
+
:deep(.x-button--primary),
|
|
106
|
+
:deep(.x-button--success),
|
|
107
|
+
:deep(.x-button--warning),
|
|
108
|
+
:deep(.x-button--info) {
|
|
109
|
+
color: var(--xto-color-primary, #4f46e5);
|
|
110
|
+
background-color: transparent;
|
|
111
|
+
border-color: transparent;
|
|
112
|
+
padding-left: 0;
|
|
113
|
+
padding-right: 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
:deep(.x-button--danger),
|
|
117
|
+
:deep(.x-button.table-actions__danger) {
|
|
118
|
+
color: var(--xto-color-danger, #f53f3f);
|
|
119
|
+
background-color: transparent;
|
|
120
|
+
border-color: transparent;
|
|
121
|
+
padding-left: 0;
|
|
122
|
+
padding-right: 0;
|
|
123
|
+
|
|
124
|
+
&:hover,
|
|
125
|
+
&:focus {
|
|
126
|
+
color: var(--xto-color-danger-light-3, #f87b7b);
|
|
127
|
+
background-color: transparent;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
&__more {
|
|
132
|
+
display: inline-flex;
|
|
133
|
+
align-items: center;
|
|
134
|
+
gap: 2px;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// 「更多」下拉里每项独占一行、左对齐
|
|
139
|
+
:global(.x-dropdown__menu .x-dropdown-menu__item) {
|
|
140
|
+
line-height: 1.2;
|
|
141
|
+
}
|
|
142
|
+
</style>
|
package/src/index.ts
CHANGED
|
@@ -112,6 +112,7 @@ export { default as Tabs } from './components/Layout/Tabs.vue'
|
|
|
112
112
|
export { default as Footer } from './components/Layout/Footer.vue'
|
|
113
113
|
export { default as FilterBar } from './components/FilterBar.vue'
|
|
114
114
|
export { default as TableCard } from './components/TableCard.vue'
|
|
115
|
+
export { default as TableActions } from './components/TableActions.vue'
|
|
115
116
|
|
|
116
117
|
// 错误页面组件
|
|
117
118
|
export { default as Login } from './views/login/index.vue'
|