chore: 升级 shadcn-vue 组件到v4最新版 (#7972)

* fix: useStore is deprecated

* chore: update deps

* feat: 升级shadcn-ui v4

* fix: workbench style

* feat: 升级shadcn-ui v4 step2

* feat: 升级shadcn-ui v4 step3

* chore: 升级shadcn v4

* fix: pagination

* fix: dark style

* fix: doc import

* feat: 增加详情组件,参考 antdv-next

* docs: descriptions docs

* docs: Browser Support

* feat: add table action

* feat: icon use vbenIcon

* fix: type error

* fix: dropdown popConfirm

* feat: 使用默认的文字交互

* feat: 优化渲染性能
This commit is contained in:
xingyu
2026-05-31 15:18:46 +08:00
committed by GitHub
parent 108d7ff335
commit 04fbb7a556
239 changed files with 6015 additions and 3205 deletions

View File

@@ -3,8 +3,8 @@ import { h } from 'vue';
import { alert, prompt, useAlertContext, VbenButton } from '@vben/common-ui';
import { BadgeJapaneseYen } from '@lucide/vue';
import { Input, RadioGroup, Select } from 'antdv-next';
import { BadgeJapaneseYen } from 'lucide-vue-next';
function showPrompt() {
prompt({

View File

@@ -0,0 +1,18 @@
<script lang="ts" setup>
import { VbenDescriptions } from '@vben/common-ui';
const items = [
{ content: 'Vben', label: '用户名' },
{ content: '13800138000', label: '手机号' },
{ content: '中国 · 杭州', label: '居住地' },
{ content: '前端工程师', label: '职位' },
{
content: '这是一段较长的备注信息,用于演示跨列展示。',
label: '备注',
span: 3,
},
];
</script>
<template>
<VbenDescriptions :items="items" />
</template>

View File

@@ -0,0 +1,22 @@
<script lang="ts" setup>
import { VbenDescriptions } from '@vben/common-ui';
const items = [
{ content: 'Vben', label: '用户名' },
{ content: '13800138000', label: '手机号' },
{ content: '正常', label: '状态' },
{ content: '中国 · 杭州', label: '居住地' },
{
content: '浙江省杭州市西湖区某某街道某某小区 1 幢 2 单元',
label: '地址',
span: 3,
},
];
</script>
<template>
<VbenDescriptions bordered title="用户信息" :items="items">
<template #extra>
<span style="color: #1677ff; cursor: pointer">编辑</span>
</template>
</VbenDescriptions>
</template>

View File

@@ -0,0 +1,17 @@
<script lang="ts" setup>
import { VbenDescriptions, VbenDescriptionsItem } from '@vben/common-ui';
</script>
<template>
<!-- 通过子组件 VbenDescriptionsItem 声明列表项 -->
<VbenDescriptions bordered :column="2">
<VbenDescriptionsItem label="用户名">Vben</VbenDescriptionsItem>
<VbenDescriptionsItem label="状态">
<span style="color: #52c41a"> 正常</span>
</VbenDescriptionsItem>
<VbenDescriptionsItem label="备注" :span="2">
<template #content>
<span style="color: #888">通过 #content 插槽自定义内容</span>
</template>
</VbenDescriptionsItem>
</VbenDescriptions>
</template>

View File

@@ -0,0 +1,35 @@
<script lang="ts" setup>
import { VbenDescriptions } from '@vben/common-ui';
const items = [
{ content: 'Vben', label: '用户名' },
{ content: '13800138000', label: '手机号' },
{ content: '中国 · 杭州', label: '居住地' },
{ content: '前端工程师', label: '职位' },
];
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 16px">
<VbenDescriptions
size="small"
bordered
title="Small"
:column="2"
:items="items"
/>
<VbenDescriptions
size="middle"
bordered
title="Middle"
:column="2"
:items="items"
/>
<VbenDescriptions
size="large"
bordered
title="Large"
:column="2"
:items="items"
/>
</div>
</template>

View File

@@ -0,0 +1,15 @@
<script lang="ts" setup>
import { VbenDescriptions } from '@vben/common-ui';
const items = [
{ content: '1', label: 'A' },
{ content: '2span: 2', label: 'B', span: 2 },
{ content: '3', label: 'C' },
{ content: '占满当前行剩余空间', label: 'Dspan: filled', span: 'filled' },
{ content: '5', label: 'E' },
];
</script>
<template>
<!-- 列数随断点变化xs 1 sm 2 md 及以上 3 -->
<VbenDescriptions bordered :column="{ md: 3, sm: 2, xs: 1 }" :items="items" />
</template>

View File

@@ -0,0 +1,13 @@
<script lang="ts" setup>
import { VbenDescriptions } from '@vben/common-ui';
const items = [
{ content: 'Vben', label: '用户名' },
{ content: '13800138000', label: '手机号' },
{ content: '中国 · 杭州', label: '居住地' },
{ content: '这是一段较长的备注信息。', label: '备注', span: 3 },
];
</script>
<template>
<VbenDescriptions bordered layout="vertical" :items="items" />
</template>

View File

@@ -0,0 +1,28 @@
<script lang="ts" setup>
import type { ActionItem } from '@vben/common-ui';
import { ref } from 'vue';
import { VbenTableAction } from '@vben/common-ui';
const last = ref('无');
const actions: ActionItem[] = [
{ key: 'edit', onClick: () => (last.value = '编辑'), text: '编辑' },
{ key: 'detail', onClick: () => (last.value = '详情'), text: '详情' },
{
danger: true,
key: 'delete',
onClick: () => (last.value = '删除'),
text: '删除',
},
];
</script>
<template>
<div>
<VbenTableAction :actions="actions" align="start" divider />
<p style="margin-top: 8px; font-size: 13px; opacity: 0.7">
最近点击{{ last }}
</p>
</div>
</template>

View File

@@ -0,0 +1,44 @@
<script lang="ts" setup>
import type { ActionItem } from '@vben/common-ui';
import { ref } from 'vue';
import { VbenTableAction } from '@vben/common-ui';
const last = ref('无');
const actions: ActionItem[] = [
{ key: 'edit', onClick: () => (last.value = '编辑'), text: '编辑' },
];
const dropdownActions: ActionItem[] = [
{ key: 'copy', onClick: () => (last.value = '复制'), text: '复制' },
{ key: 'export', onClick: () => (last.value = '导出'), text: '导出' },
{
danger: true,
key: 'remove',
// 下拉项同样支持气泡确认
popConfirm: {
cancelText: '取消',
confirm: () => (last.value = '已移除'),
okText: '确认',
title: '确定移除吗?',
},
text: '移除',
},
];
</script>
<template>
<div>
<VbenTableAction
:actions="actions"
:dropdown-actions="dropdownActions"
align="start"
divider
more-text="更多"
/>
<p style="margin-top: 8px; font-size: 13px; opacity: 0.7">
最近点击{{ last }}
</p>
</div>
</template>

View File

@@ -0,0 +1,28 @@
<script lang="ts" setup>
import type { ActionItem } from '@vben/common-ui';
import { VbenTableAction } from '@vben/common-ui';
// 模拟当前用户拥有的权限码
const allow = new Set(['user:detail', 'user:edit']);
function hasPermission(auth?: string | string[]) {
if (!auth) return true;
const codes = Array.isArray(auth) ? auth : [auth];
return codes.some((code) => allow.has(code));
}
const actions: ActionItem[] = [
{ auth: 'user:edit', key: 'edit', text: '编辑' },
{ auth: 'user:detail', key: 'detail', text: '详情' },
// 无 user:delete 权限,按钮被隐藏
{ auth: 'user:delete', danger: true, key: 'delete', text: '删除(无权限)' },
];
</script>
<template>
<VbenTableAction
:actions="actions"
:has-permission="hasPermission"
align="start"
/>
</template>

View File

@@ -0,0 +1,32 @@
<script lang="ts" setup>
import type { ActionItem } from '@vben/common-ui';
import { ref } from 'vue';
import { VbenTableAction } from '@vben/common-ui';
const last = ref('无');
const actions: ActionItem[] = [
{ key: 'edit', onClick: () => (last.value = '编辑'), text: '编辑' },
{
danger: true,
key: 'delete',
popConfirm: {
cancelText: '取消',
confirm: () => (last.value = '已删除'),
okText: '确认',
title: '确定删除这一行吗?',
},
text: '删除',
},
];
</script>
<template>
<div>
<VbenTableAction :actions="actions" align="start" />
<p style="margin-top: 8px; font-size: 13px; opacity: 0.7">
最近操作{{ last }}
</p>
</div>
</template>

View File

@@ -0,0 +1,17 @@
<script lang="ts" setup>
import type { ActionItem } from '@vben/common-ui';
import { VbenTableAction } from '@vben/common-ui';
const actions: ActionItem[] = [
{ key: 'edit', text: '编辑', tooltip: '编辑这一行' },
{
key: 'detail',
text: '详情',
tooltip: { content: '查看详情', side: 'top' },
},
];
</script>
<template>
<VbenTableAction :actions="actions" align="start" />
</template>