feat(project): 添加vben5前端
This commit is contained in:
36
Yi.Vben5.Vue3/docs/src/demos/vben-alert/alert/index.vue
Normal file
36
Yi.Vben5.Vue3/docs/src/demos/vben-alert/alert/index.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<script lang="ts" setup>
|
||||
import { h } from 'vue';
|
||||
|
||||
import { alert, VbenButton } from '@vben/common-ui';
|
||||
|
||||
import { Result } from 'ant-design-vue';
|
||||
|
||||
function showAlert() {
|
||||
alert('This is an alert message');
|
||||
}
|
||||
|
||||
function showIconAlert() {
|
||||
alert({
|
||||
content: 'This is an alert message with icon',
|
||||
icon: 'success',
|
||||
});
|
||||
}
|
||||
|
||||
function showCustomAlert() {
|
||||
alert({
|
||||
buttonAlign: 'center',
|
||||
content: h(Result, {
|
||||
status: 'success',
|
||||
subTitle: '已成功创建订单。订单ID:2017182818828182881',
|
||||
title: '操作成功',
|
||||
}),
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="flex gap-4">
|
||||
<VbenButton @click="showAlert">Alert</VbenButton>
|
||||
<VbenButton @click="showIconAlert">Alert With Icon</VbenButton>
|
||||
<VbenButton @click="showCustomAlert">Alert With Custom Content</VbenButton>
|
||||
</div>
|
||||
</template>
|
||||
75
Yi.Vben5.Vue3/docs/src/demos/vben-alert/confirm/index.vue
Normal file
75
Yi.Vben5.Vue3/docs/src/demos/vben-alert/confirm/index.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<script lang="ts" setup>
|
||||
import { h, ref } from 'vue';
|
||||
|
||||
import { alert, confirm, VbenButton } from '@vben/common-ui';
|
||||
|
||||
import { Checkbox, message } from 'ant-design-vue';
|
||||
|
||||
function showConfirm() {
|
||||
confirm('This is an alert message')
|
||||
.then(() => {
|
||||
alert('Confirmed');
|
||||
})
|
||||
.catch(() => {
|
||||
alert('Canceled');
|
||||
});
|
||||
}
|
||||
|
||||
function showIconConfirm() {
|
||||
confirm({
|
||||
content: 'This is an alert message with icon',
|
||||
icon: 'success',
|
||||
});
|
||||
}
|
||||
|
||||
function showfooterConfirm() {
|
||||
const checked = ref(false);
|
||||
confirm({
|
||||
cancelText: '不要虾扯蛋',
|
||||
confirmText: '是的,我们都是NPC',
|
||||
content:
|
||||
'刚才发生的事情,为什么我似乎早就经历过一般?\n我甚至能在事情发生过程中潜意识里预知到接下来会发生什么。\n\n听起来挺玄乎的,你有过这种感觉吗?',
|
||||
footer: () =>
|
||||
h(
|
||||
Checkbox,
|
||||
{
|
||||
checked: checked.value,
|
||||
class: 'flex-1',
|
||||
'onUpdate:checked': (v) => (checked.value = v),
|
||||
},
|
||||
'不再提示',
|
||||
),
|
||||
icon: 'question',
|
||||
title: '未解之谜',
|
||||
}).then(() => {
|
||||
if (checked.value) {
|
||||
message.success('我不会再拿这个问题烦你了');
|
||||
} else {
|
||||
message.info('下次还要继续问你哟');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showAsyncConfirm() {
|
||||
confirm({
|
||||
beforeClose({ isConfirm }) {
|
||||
if (isConfirm) {
|
||||
// 这里可以执行一些异步操作。如果最终返回了false,将阻止关闭弹窗
|
||||
return new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
}
|
||||
},
|
||||
content: 'This is an alert message with async confirm',
|
||||
icon: 'success',
|
||||
}).then(() => {
|
||||
alert('Confirmed');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="flex gap-4">
|
||||
<VbenButton @click="showConfirm">Confirm</VbenButton>
|
||||
<VbenButton @click="showIconConfirm">Confirm With Icon</VbenButton>
|
||||
<VbenButton @click="showfooterConfirm">Confirm With Footer</VbenButton>
|
||||
<VbenButton @click="showAsyncConfirm">Async Confirm</VbenButton>
|
||||
</div>
|
||||
</template>
|
||||
118
Yi.Vben5.Vue3/docs/src/demos/vben-alert/prompt/index.vue
Normal file
118
Yi.Vben5.Vue3/docs/src/demos/vben-alert/prompt/index.vue
Normal file
@@ -0,0 +1,118 @@
|
||||
<script lang="ts" setup>
|
||||
import { h } from 'vue';
|
||||
|
||||
import { alert, prompt, useAlertContext, VbenButton } from '@vben/common-ui';
|
||||
|
||||
import { Input, RadioGroup, Select } from 'ant-design-vue';
|
||||
import { BadgeJapaneseYen } from 'lucide-vue-next';
|
||||
|
||||
function showPrompt() {
|
||||
prompt({
|
||||
content: '请输入一些东西',
|
||||
})
|
||||
.then((val) => {
|
||||
alert(`已收到你的输入:${val}`);
|
||||
})
|
||||
.catch(() => {
|
||||
alert('Canceled');
|
||||
});
|
||||
}
|
||||
|
||||
function showSlotsPrompt() {
|
||||
prompt({
|
||||
component: () => {
|
||||
// 获取弹窗上下文。注意:只能在setup或者函数式组件中调用
|
||||
const { doConfirm } = useAlertContext();
|
||||
return h(
|
||||
Input,
|
||||
{
|
||||
onKeydown(e: KeyboardEvent) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
// 调用弹窗提供的确认方法
|
||||
doConfirm();
|
||||
}
|
||||
},
|
||||
placeholder: '请输入',
|
||||
prefix: '充值金额:',
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
addonAfter: () => h(BadgeJapaneseYen),
|
||||
},
|
||||
);
|
||||
},
|
||||
content:
|
||||
'此弹窗演示了如何使用自定义插槽,并且可以使用useAlertContext获取到弹窗的上下文。\n在输入框中按下回车键会触发确认操作。',
|
||||
icon: 'question',
|
||||
modelPropName: 'value',
|
||||
}).then((val) => {
|
||||
if (val) alert(`你输入的是${val}`);
|
||||
});
|
||||
}
|
||||
|
||||
function showSelectPrompt() {
|
||||
prompt({
|
||||
component: Select,
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: 'Option A', value: 'Option A' },
|
||||
{ label: 'Option B', value: 'Option B' },
|
||||
{ label: 'Option C', value: 'Option C' },
|
||||
],
|
||||
placeholder: '请选择',
|
||||
// 弹窗会设置body的pointer-events为none,这回影响下拉框的点击事件
|
||||
popupClassName: 'pointer-events-auto',
|
||||
},
|
||||
content: '此弹窗演示了如何使用component传递自定义组件',
|
||||
icon: 'question',
|
||||
modelPropName: 'value',
|
||||
}).then((val) => {
|
||||
if (val) {
|
||||
alert(`你选择了${val}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function showAsyncPrompt() {
|
||||
prompt({
|
||||
async beforeClose(scope) {
|
||||
if (scope.isConfirm) {
|
||||
if (scope.value) {
|
||||
// 模拟异步操作,如果不成功,可以返回false
|
||||
await sleep(2000);
|
||||
} else {
|
||||
alert('请选择一个选项');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
component: RadioGroup,
|
||||
componentProps: {
|
||||
class: 'flex flex-col',
|
||||
options: [
|
||||
{ label: 'Option 1', value: 'option1' },
|
||||
{ label: 'Option 2', value: 'option2' },
|
||||
{ label: 'Option 3', value: 'option3' },
|
||||
],
|
||||
},
|
||||
content: '选择一个选项后再点击[确认]',
|
||||
icon: 'question',
|
||||
modelPropName: 'value',
|
||||
}).then((val) => {
|
||||
alert(`${val} 已设置。`);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="flex gap-4">
|
||||
<VbenButton @click="showPrompt">Prompt</VbenButton>
|
||||
<VbenButton @click="showSlotsPrompt"> Prompt With slots </VbenButton>
|
||||
<VbenButton @click="showSelectPrompt">Prompt With Select</VbenButton>
|
||||
<VbenButton @click="showAsyncPrompt">Prompt With Async</VbenButton>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,100 @@
|
||||
<script lang="ts" setup>
|
||||
import { ApiComponent } from '@vben/common-ui';
|
||||
|
||||
import { Cascader } from 'ant-design-vue';
|
||||
|
||||
const treeData: Record<string, any> = [
|
||||
{
|
||||
label: '浙江',
|
||||
value: 'zhejiang',
|
||||
children: [
|
||||
{
|
||||
value: 'hangzhou',
|
||||
label: '杭州',
|
||||
children: [
|
||||
{
|
||||
value: 'xihu',
|
||||
label: '西湖',
|
||||
},
|
||||
{
|
||||
value: 'sudi',
|
||||
label: '苏堤',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'jiaxing',
|
||||
label: '嘉兴',
|
||||
children: [
|
||||
{
|
||||
value: 'wuzhen',
|
||||
label: '乌镇',
|
||||
},
|
||||
{
|
||||
value: 'meihuazhou',
|
||||
label: '梅花洲',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'zhoushan',
|
||||
label: '舟山',
|
||||
children: [
|
||||
{
|
||||
value: 'putuoshan',
|
||||
label: '普陀山',
|
||||
},
|
||||
{
|
||||
value: 'taohuadao',
|
||||
label: '桃花岛',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '江苏',
|
||||
value: 'jiangsu',
|
||||
children: [
|
||||
{
|
||||
value: 'nanjing',
|
||||
label: '南京',
|
||||
children: [
|
||||
{
|
||||
value: 'zhonghuamen',
|
||||
label: '中华门',
|
||||
},
|
||||
{
|
||||
value: 'zijinshan',
|
||||
label: '紫金山',
|
||||
},
|
||||
{
|
||||
value: 'yuhuatai',
|
||||
label: '雨花台',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 模拟请求接口
|
||||
*/
|
||||
function fetchApi(): Promise<Record<string, any>> {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(treeData);
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<ApiComponent
|
||||
:api="fetchApi"
|
||||
:component="Cascader"
|
||||
:immediate="false"
|
||||
children-field="children"
|
||||
loading-slot="suffixIcon"
|
||||
visible-event="onDropdownVisibleChange"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { VbenCountToAnimator } from '@vben/common-ui';
|
||||
</script>
|
||||
<template>
|
||||
<VbenCountToAnimator :duration="3000" :end-val="30000" :start-val="1" />
|
||||
</template>
|
||||
@@ -0,0 +1,12 @@
|
||||
<script lang="ts" setup>
|
||||
import { VbenCountToAnimator } from '@vben/common-ui';
|
||||
</script>
|
||||
<template>
|
||||
<VbenCountToAnimator
|
||||
:duration="3000"
|
||||
:end-val="2000000"
|
||||
:start-val="1"
|
||||
prefix="$"
|
||||
separator="/"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,45 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
|
||||
|
||||
const list = ref<number[]>([]);
|
||||
|
||||
const [Drawer, drawerApi] = useVbenDrawer({
|
||||
onCancel() {
|
||||
drawerApi.close();
|
||||
},
|
||||
onConfirm() {
|
||||
console.log('onConfirm');
|
||||
},
|
||||
onOpenChange(isOpen) {
|
||||
if (isOpen) {
|
||||
handleUpdate(10);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function handleUpdate(len: number) {
|
||||
drawerApi.setState({ loading: true });
|
||||
setTimeout(() => {
|
||||
list.value = Array.from({ length: len }, (_v, k) => k + 1);
|
||||
drawerApi.setState({ loading: false });
|
||||
}, 2000);
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Drawer title="自动计算高度">
|
||||
<div
|
||||
v-for="item in list"
|
||||
:key="item"
|
||||
class="even:bg-heavy bg-muted flex-center h-[220px] w-full"
|
||||
>
|
||||
{{ item }}
|
||||
</div>
|
||||
<template #prepend-footer>
|
||||
<VbenButton type="link" @click="handleUpdate(6)">
|
||||
点击更新数据
|
||||
</VbenButton>
|
||||
</template>
|
||||
</Drawer>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
|
||||
|
||||
import ExtraDrawer from './drawer.vue';
|
||||
|
||||
const [Drawer, drawerApi] = useVbenDrawer({
|
||||
// 连接抽离的组件
|
||||
connectedComponent: ExtraDrawer,
|
||||
});
|
||||
|
||||
function open() {
|
||||
drawerApi.open();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Drawer />
|
||||
<VbenButton @click="open">Open</VbenButton>
|
||||
</div>
|
||||
</template>
|
||||
11
Yi.Vben5.Vue3/docs/src/demos/vben-drawer/basic/index.vue
Normal file
11
Yi.Vben5.Vue3/docs/src/demos/vben-drawer/basic/index.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
|
||||
|
||||
const [Drawer, drawerApi] = useVbenDrawer();
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<VbenButton @click="() => drawerApi.open()">Open</VbenButton>
|
||||
<Drawer class="w-[600px]" title="基础示例"> drawer content </Drawer>
|
||||
</div>
|
||||
</template>
|
||||
26
Yi.Vben5.Vue3/docs/src/demos/vben-drawer/dynamic/drawer.vue
Normal file
26
Yi.Vben5.Vue3/docs/src/demos/vben-drawer/dynamic/drawer.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
|
||||
|
||||
const [Drawer, drawerApi] = useVbenDrawer({
|
||||
onCancel() {
|
||||
drawerApi.close();
|
||||
},
|
||||
onConfirm() {
|
||||
console.info('onConfirm');
|
||||
},
|
||||
title: '动态修改配置示例',
|
||||
});
|
||||
|
||||
function handleUpdateTitle() {
|
||||
drawerApi.setState({ title: '内部动态标题' });
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Drawer>
|
||||
<div class="flex-col-center">
|
||||
<VbenButton class="mb-3" type="primary" @click="handleUpdateTitle()">
|
||||
内部动态修改标题
|
||||
</VbenButton>
|
||||
</div>
|
||||
</Drawer>
|
||||
</template>
|
||||
29
Yi.Vben5.Vue3/docs/src/demos/vben-drawer/dynamic/index.vue
Normal file
29
Yi.Vben5.Vue3/docs/src/demos/vben-drawer/dynamic/index.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
|
||||
|
||||
import ExtraDrawer from './drawer.vue';
|
||||
|
||||
const [Drawer, drawerApi] = useVbenDrawer({
|
||||
// 连接抽离的组件
|
||||
connectedComponent: ExtraDrawer,
|
||||
});
|
||||
|
||||
function open() {
|
||||
drawerApi.open();
|
||||
}
|
||||
|
||||
function handleUpdateTitle() {
|
||||
drawerApi.setState({ title: '外部动态标题' }).open();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Drawer />
|
||||
|
||||
<VbenButton @click="open">Open</VbenButton>
|
||||
<VbenButton class="ml-2" type="primary" @click="handleUpdateTitle">
|
||||
从外部修改标题并打开
|
||||
</VbenButton>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenDrawer } from '@vben/common-ui';
|
||||
|
||||
const [Drawer] = useVbenDrawer();
|
||||
</script>
|
||||
<template>
|
||||
<Drawer title="组件抽离示例"> extra drawer content </Drawer>
|
||||
</template>
|
||||
21
Yi.Vben5.Vue3/docs/src/demos/vben-drawer/extra/index.vue
Normal file
21
Yi.Vben5.Vue3/docs/src/demos/vben-drawer/extra/index.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
|
||||
|
||||
import ExtraDrawer from './drawer.vue';
|
||||
|
||||
const [Drawer, drawerApi] = useVbenDrawer({
|
||||
// 连接抽离的组件
|
||||
connectedComponent: ExtraDrawer,
|
||||
});
|
||||
|
||||
function open() {
|
||||
drawerApi.open();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Drawer />
|
||||
<VbenButton @click="open">Open</VbenButton>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,26 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { useVbenDrawer } from '@vben/common-ui';
|
||||
|
||||
const data = ref();
|
||||
|
||||
const [Drawer, drawerApi] = useVbenDrawer({
|
||||
onCancel() {
|
||||
drawerApi.close();
|
||||
},
|
||||
onConfirm() {
|
||||
console.info('onConfirm');
|
||||
},
|
||||
onOpenChange(isOpen: boolean) {
|
||||
if (isOpen) {
|
||||
data.value = drawerApi.getData<Record<string, any>>();
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<Drawer title="数据共享示例">
|
||||
<div class="flex-col-center">外部传递数据: {{ data }}</div>
|
||||
</Drawer>
|
||||
</template>
|
||||
@@ -0,0 +1,27 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
|
||||
|
||||
import ExtraDrawer from './drawer.vue';
|
||||
|
||||
const [Drawer, drawerApi] = useVbenDrawer({
|
||||
// 连接抽离的组件
|
||||
connectedComponent: ExtraDrawer,
|
||||
});
|
||||
|
||||
function open() {
|
||||
drawerApi
|
||||
.setData({
|
||||
content: '外部传递的数据 content',
|
||||
payload: '外部传递的数据 payload',
|
||||
})
|
||||
.open();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Drawer />
|
||||
|
||||
<VbenButton @click="open">Open</VbenButton>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,16 @@
|
||||
<script lang="ts" setup>
|
||||
import { EllipsisText } from '@vben/common-ui';
|
||||
|
||||
const text = `
|
||||
Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。
|
||||
`;
|
||||
</script>
|
||||
<template>
|
||||
<EllipsisText :line="2" :tooltip-when-ellipsis="true">
|
||||
{{ text }}
|
||||
</EllipsisText>
|
||||
|
||||
<EllipsisText :line="3" :tooltip-when-ellipsis="true">
|
||||
{{ text }}
|
||||
</EllipsisText>
|
||||
</template>
|
||||
@@ -0,0 +1,10 @@
|
||||
<script lang="ts" setup>
|
||||
import { EllipsisText } from '@vben/common-ui';
|
||||
|
||||
const text = `
|
||||
Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。
|
||||
`;
|
||||
</script>
|
||||
<template>
|
||||
<EllipsisText :line="3" expand>{{ text }}</EllipsisText>
|
||||
</template>
|
||||
@@ -0,0 +1,10 @@
|
||||
<script lang="ts" setup>
|
||||
import { EllipsisText } from '@vben/common-ui';
|
||||
|
||||
const text = `
|
||||
Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈,可以作为项目的启动模版,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 vue3、vite、ts 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。
|
||||
`;
|
||||
</script>
|
||||
<template>
|
||||
<EllipsisText :max-width="500">{{ text }}</EllipsisText>
|
||||
</template>
|
||||
@@ -0,0 +1,14 @@
|
||||
<script lang="ts" setup>
|
||||
import { EllipsisText } from '@vben/common-ui';
|
||||
</script>
|
||||
<template>
|
||||
<EllipsisText :max-width="240">
|
||||
住在我心里孤独的 孤独的海怪 痛苦之王 开始厌倦 深海的光 停滞的海浪
|
||||
<template #tooltip>
|
||||
<div style="text-align: center">
|
||||
《秦皇岛》<br />住在我心里孤独的<br />孤独的海怪 痛苦之王<br />开始厌倦
|
||||
深海的光 停滞的海浪
|
||||
</div>
|
||||
</template>
|
||||
</EllipsisText>
|
||||
</template>
|
||||
236
Yi.Vben5.Vue3/docs/src/demos/vben-form/api/index.vue
Normal file
236
Yi.Vben5.Vue3/docs/src/demos/vben-form/api/index.vue
Normal file
@@ -0,0 +1,236 @@
|
||||
<script lang="ts" setup>
|
||||
import { Button, message, Space } from 'ant-design-vue';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
|
||||
const [BaseForm, formApi] = useVbenForm({
|
||||
// 所有表单项共用,可单独在表单内覆盖
|
||||
commonConfig: {
|
||||
// 所有表单项
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
},
|
||||
// 使用 tailwindcss grid布局
|
||||
// 提交函数
|
||||
handleSubmit: onSubmit,
|
||||
// 垂直布局,label和input在不同行,值为vertical
|
||||
layout: 'horizontal',
|
||||
// 水平布局,label和input在同一行
|
||||
schema: [
|
||||
{
|
||||
// 组件需要在 #/adapter.ts内注册,并加上类型
|
||||
component: 'Input',
|
||||
// 对应组件的参数
|
||||
componentProps: {
|
||||
placeholder: '请输入用户名',
|
||||
},
|
||||
// 字段名
|
||||
fieldName: 'field1',
|
||||
// 界面显示的label
|
||||
label: 'field1',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
filterOption: true,
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
placeholder: '请选择',
|
||||
showSearch: true,
|
||||
},
|
||||
fieldName: 'fieldOptions',
|
||||
label: '下拉选',
|
||||
},
|
||||
],
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-2',
|
||||
});
|
||||
|
||||
function onSubmit(values: Record<string, any>) {
|
||||
message.success({
|
||||
content: `form values: ${JSON.stringify(values)}`,
|
||||
});
|
||||
}
|
||||
|
||||
function handleClick(
|
||||
action:
|
||||
| 'batchAddSchema'
|
||||
| 'batchDeleteSchema'
|
||||
| 'disabled'
|
||||
| 'hiddenAction'
|
||||
| 'hiddenResetButton'
|
||||
| 'hiddenSubmitButton'
|
||||
| 'labelWidth'
|
||||
| 'resetDisabled'
|
||||
| 'resetLabelWidth'
|
||||
| 'showAction'
|
||||
| 'showResetButton'
|
||||
| 'showSubmitButton'
|
||||
| 'updateActionAlign'
|
||||
| 'updateResetButton'
|
||||
| 'updateSchema'
|
||||
| 'updateSubmitButton',
|
||||
) {
|
||||
switch (action) {
|
||||
case 'batchAddSchema': {
|
||||
formApi.setState((prev) => {
|
||||
const currentSchema = prev?.schema ?? [];
|
||||
const newSchema = [];
|
||||
for (let i = 0; i < 2; i++) {
|
||||
newSchema.push({
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
fieldName: `field${i}${Date.now()}`,
|
||||
label: `field+`,
|
||||
});
|
||||
}
|
||||
return {
|
||||
schema: [...currentSchema, ...newSchema],
|
||||
};
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'batchDeleteSchema': {
|
||||
formApi.setState((prev) => {
|
||||
const currentSchema = prev?.schema ?? [];
|
||||
return {
|
||||
schema: currentSchema.slice(0, -2),
|
||||
};
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'disabled': {
|
||||
formApi.setState({ commonConfig: { disabled: true } });
|
||||
break;
|
||||
}
|
||||
case 'hiddenAction': {
|
||||
formApi.setState({ showDefaultActions: false });
|
||||
break;
|
||||
}
|
||||
case 'hiddenResetButton': {
|
||||
formApi.setState({ resetButtonOptions: { show: false } });
|
||||
break;
|
||||
}
|
||||
case 'hiddenSubmitButton': {
|
||||
formApi.setState({ submitButtonOptions: { show: false } });
|
||||
break;
|
||||
}
|
||||
case 'labelWidth': {
|
||||
formApi.setState({
|
||||
commonConfig: {
|
||||
labelWidth: 150,
|
||||
},
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'resetDisabled': {
|
||||
formApi.setState({ commonConfig: { disabled: false } });
|
||||
break;
|
||||
}
|
||||
case 'resetLabelWidth': {
|
||||
formApi.setState({
|
||||
commonConfig: {
|
||||
labelWidth: 100,
|
||||
},
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'showAction': {
|
||||
formApi.setState({ showDefaultActions: true });
|
||||
break;
|
||||
}
|
||||
case 'showResetButton': {
|
||||
formApi.setState({ resetButtonOptions: { show: true } });
|
||||
break;
|
||||
}
|
||||
case 'showSubmitButton': {
|
||||
formApi.setState({ submitButtonOptions: { show: true } });
|
||||
break;
|
||||
}
|
||||
case 'updateActionAlign': {
|
||||
formApi.setState({
|
||||
// 可以自行调整class
|
||||
actionWrapperClass: 'text-center',
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'updateResetButton': {
|
||||
formApi.setState({
|
||||
resetButtonOptions: { disabled: true },
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'updateSchema': {
|
||||
formApi.updateSchema([
|
||||
{
|
||||
componentProps: {
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
value: '2',
|
||||
},
|
||||
{
|
||||
label: '选项3',
|
||||
value: '3',
|
||||
},
|
||||
],
|
||||
},
|
||||
fieldName: 'fieldOptions',
|
||||
},
|
||||
]);
|
||||
message.success('字段 `fieldOptions` 下拉选项更新成功。');
|
||||
break;
|
||||
}
|
||||
case 'updateSubmitButton': {
|
||||
formApi.setState({
|
||||
submitButtonOptions: { loading: true },
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Space class="mb-5 flex-wrap">
|
||||
<Button @click="handleClick('updateSchema')">updateSchema</Button>
|
||||
<Button @click="handleClick('labelWidth')">更改labelWidth</Button>
|
||||
<Button @click="handleClick('resetLabelWidth')">还原labelWidth</Button>
|
||||
<Button @click="handleClick('disabled')">禁用表单</Button>
|
||||
<Button @click="handleClick('resetDisabled')">解除禁用</Button>
|
||||
<Button @click="handleClick('hiddenAction')">隐藏操作按钮</Button>
|
||||
<Button @click="handleClick('showAction')">显示操作按钮</Button>
|
||||
<Button @click="handleClick('hiddenResetButton')">隐藏重置按钮</Button>
|
||||
<Button @click="handleClick('showResetButton')">显示重置按钮</Button>
|
||||
<Button @click="handleClick('hiddenSubmitButton')">隐藏提交按钮</Button>
|
||||
<Button @click="handleClick('showSubmitButton')">显示提交按钮</Button>
|
||||
<Button @click="handleClick('updateResetButton')">修改重置按钮</Button>
|
||||
<Button @click="handleClick('updateSubmitButton')">修改提交按钮</Button>
|
||||
<Button @click="handleClick('updateActionAlign')">
|
||||
调整操作按钮位置
|
||||
</Button>
|
||||
<Button @click="handleClick('batchAddSchema')"> 批量添加表单项 </Button>
|
||||
<Button @click="handleClick('batchDeleteSchema')">
|
||||
批量删除表单项
|
||||
</Button>
|
||||
</Space>
|
||||
<BaseForm />
|
||||
</div>
|
||||
</template>
|
||||
231
Yi.Vben5.Vue3/docs/src/demos/vben-form/basic/index.vue
Normal file
231
Yi.Vben5.Vue3/docs/src/demos/vben-form/basic/index.vue
Normal file
@@ -0,0 +1,231 @@
|
||||
<script lang="ts" setup>
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
|
||||
const [BaseForm] = useVbenForm({
|
||||
// 所有表单项共用,可单独在表单内覆盖
|
||||
commonConfig: {
|
||||
// 所有表单项
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
},
|
||||
// 提交函数
|
||||
handleSubmit: onSubmit,
|
||||
// 垂直布局,label和input在不同行,值为vertical
|
||||
// 水平布局,label和input在同一行
|
||||
layout: 'horizontal',
|
||||
schema: [
|
||||
{
|
||||
// 组件需要在 #/adapter.ts内注册,并加上类型
|
||||
component: 'Input',
|
||||
// 对应组件的参数
|
||||
componentProps: {
|
||||
placeholder: '请输入用户名',
|
||||
},
|
||||
// 字段名
|
||||
fieldName: 'username',
|
||||
// 界面显示的label
|
||||
label: '字符串',
|
||||
},
|
||||
{
|
||||
component: 'InputPassword',
|
||||
componentProps: {
|
||||
placeholder: '请输入密码',
|
||||
},
|
||||
fieldName: 'password',
|
||||
label: '密码',
|
||||
},
|
||||
{
|
||||
component: 'InputNumber',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
fieldName: 'number',
|
||||
label: '数字(带后缀)',
|
||||
suffix: () => '¥',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
filterOption: true,
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
placeholder: '请选择',
|
||||
showSearch: true,
|
||||
},
|
||||
fieldName: 'options',
|
||||
label: '下拉选',
|
||||
},
|
||||
{
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
},
|
||||
fieldName: 'radioGroup',
|
||||
label: '单选组',
|
||||
},
|
||||
{
|
||||
component: 'Radio',
|
||||
fieldName: 'radio',
|
||||
label: '',
|
||||
renderComponentContent: () => {
|
||||
return {
|
||||
default: () => ['Radio'],
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'CheckboxGroup',
|
||||
componentProps: {
|
||||
name: 'cname',
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
},
|
||||
fieldName: 'checkboxGroup',
|
||||
label: '多选组',
|
||||
},
|
||||
{
|
||||
component: 'Checkbox',
|
||||
fieldName: 'checkbox',
|
||||
label: '',
|
||||
renderComponentContent: () => {
|
||||
return {
|
||||
default: () => ['我已阅读并同意'],
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'Mentions',
|
||||
componentProps: {
|
||||
options: [
|
||||
{
|
||||
label: 'afc163',
|
||||
value: 'afc163',
|
||||
},
|
||||
{
|
||||
label: 'zombieJ',
|
||||
value: 'zombieJ',
|
||||
},
|
||||
],
|
||||
placeholder: '请输入',
|
||||
},
|
||||
fieldName: 'mentions',
|
||||
label: '提及',
|
||||
},
|
||||
{
|
||||
component: 'Rate',
|
||||
fieldName: 'rate',
|
||||
label: '评分',
|
||||
},
|
||||
{
|
||||
component: 'Switch',
|
||||
componentProps: {
|
||||
class: 'w-auto',
|
||||
},
|
||||
fieldName: 'switch',
|
||||
label: '开关',
|
||||
},
|
||||
{
|
||||
component: 'DatePicker',
|
||||
fieldName: 'datePicker',
|
||||
label: '日期选择框',
|
||||
},
|
||||
{
|
||||
component: 'RangePicker',
|
||||
fieldName: 'rangePicker',
|
||||
label: '范围选择器',
|
||||
},
|
||||
{
|
||||
component: 'TimePicker',
|
||||
fieldName: 'timePicker',
|
||||
label: '时间选择框',
|
||||
},
|
||||
{
|
||||
component: 'TreeSelect',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请选择',
|
||||
showSearch: true,
|
||||
treeData: [
|
||||
{
|
||||
label: 'root 1',
|
||||
value: 'root 1',
|
||||
children: [
|
||||
{
|
||||
label: 'parent 1',
|
||||
value: 'parent 1',
|
||||
children: [
|
||||
{
|
||||
label: 'parent 1-0',
|
||||
value: 'parent 1-0',
|
||||
children: [
|
||||
{
|
||||
label: 'my leaf',
|
||||
value: 'leaf1',
|
||||
},
|
||||
{
|
||||
label: 'your leaf',
|
||||
value: 'leaf2',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'parent 1-1',
|
||||
value: 'parent 1-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'parent 2',
|
||||
value: 'parent 2',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
treeNodeFilterProp: 'label',
|
||||
},
|
||||
fieldName: 'treeSelect',
|
||||
label: '树选择',
|
||||
},
|
||||
],
|
||||
wrapperClass: 'grid-cols-1',
|
||||
});
|
||||
|
||||
function onSubmit(values: Record<string, any>) {
|
||||
message.success({
|
||||
content: `form values: ${JSON.stringify(values)}`,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BaseForm />
|
||||
</template>
|
||||
68
Yi.Vben5.Vue3/docs/src/demos/vben-form/custom/index.vue
Normal file
68
Yi.Vben5.Vue3/docs/src/demos/vben-form/custom/index.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<script lang="ts" setup>
|
||||
import { h } from 'vue';
|
||||
|
||||
import { Input, message } from 'ant-design-vue';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
|
||||
const [Form] = useVbenForm({
|
||||
// 所有表单项共用,可单独在表单内覆盖
|
||||
commonConfig: {
|
||||
// 所有表单项
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
labelClass: 'w-2/6',
|
||||
},
|
||||
// 提交函数
|
||||
handleSubmit: onSubmit,
|
||||
// 垂直布局,label和input在不同行,值为vertical
|
||||
// 水平布局,label和input在同一行
|
||||
layout: 'horizontal',
|
||||
schema: [
|
||||
{
|
||||
// 组件需要在 #/adapter.ts内注册,并加上类型
|
||||
component: 'Input',
|
||||
fieldName: 'field',
|
||||
label: '自定义后缀',
|
||||
suffix: () => h('span', { class: 'text-red-600' }, '元'),
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'field1',
|
||||
label: '自定义组件slot',
|
||||
renderComponentContent: () => ({
|
||||
prefix: () => 'prefix',
|
||||
suffix: () => 'suffix',
|
||||
}),
|
||||
},
|
||||
{
|
||||
component: h(Input, { placeholder: '请输入' }),
|
||||
fieldName: 'field2',
|
||||
label: '自定义组件',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'field3',
|
||||
label: '自定义组件(slot)',
|
||||
rules: 'required',
|
||||
},
|
||||
],
|
||||
wrapperClass: 'grid-cols-1',
|
||||
});
|
||||
|
||||
function onSubmit(values: Record<string, any>) {
|
||||
message.success({
|
||||
content: `form values: ${JSON.stringify(values)}`,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form>
|
||||
<template #field3="slotProps">
|
||||
<Input placeholder="请输入" v-bind="slotProps" />
|
||||
</template>
|
||||
</Form>
|
||||
</template>
|
||||
168
Yi.Vben5.Vue3/docs/src/demos/vben-form/dynamic/index.vue
Normal file
168
Yi.Vben5.Vue3/docs/src/demos/vben-form/dynamic/index.vue
Normal file
@@ -0,0 +1,168 @@
|
||||
<script lang="ts" setup>
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
|
||||
const [Form] = useVbenForm({
|
||||
// 提交函数
|
||||
handleSubmit: onSubmit,
|
||||
schema: [
|
||||
{
|
||||
component: 'Input',
|
||||
defaultValue: 'hidden value',
|
||||
dependencies: {
|
||||
show: false,
|
||||
// 随意一个字段改变时,都会触发
|
||||
triggerFields: ['field1Switch'],
|
||||
},
|
||||
fieldName: 'hiddenField',
|
||||
label: '隐藏字段',
|
||||
},
|
||||
{
|
||||
component: 'Switch',
|
||||
defaultValue: true,
|
||||
fieldName: 'field1Switch',
|
||||
help: '通过Dom控制销毁',
|
||||
label: '显示字段1',
|
||||
},
|
||||
{
|
||||
component: 'Switch',
|
||||
defaultValue: true,
|
||||
fieldName: 'field2Switch',
|
||||
help: '通过css控制隐藏',
|
||||
label: '显示字段2',
|
||||
},
|
||||
{
|
||||
component: 'Switch',
|
||||
fieldName: 'field3Switch',
|
||||
label: '禁用字段3',
|
||||
},
|
||||
{
|
||||
component: 'Switch',
|
||||
fieldName: 'field4Switch',
|
||||
label: '字段4必填',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
if(values) {
|
||||
return !!values.field1Switch;
|
||||
},
|
||||
// 只有指定的字段改变时,才会触发
|
||||
triggerFields: ['field1Switch'],
|
||||
},
|
||||
// 字段名
|
||||
fieldName: 'field1',
|
||||
// 界面显示的label
|
||||
label: '字段1',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
show(values) {
|
||||
return !!values.field2Switch;
|
||||
},
|
||||
triggerFields: ['field2Switch'],
|
||||
},
|
||||
fieldName: 'field2',
|
||||
label: '字段2',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
disabled(values) {
|
||||
return !!values.field3Switch;
|
||||
},
|
||||
triggerFields: ['field3Switch'],
|
||||
},
|
||||
fieldName: 'field3',
|
||||
label: '字段3',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
required(values) {
|
||||
return !!values.field4Switch;
|
||||
},
|
||||
triggerFields: ['field4Switch'],
|
||||
},
|
||||
fieldName: 'field4',
|
||||
label: '字段4',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
rules(values) {
|
||||
if (values.field1 === '123') {
|
||||
return 'required';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
triggerFields: ['field1'],
|
||||
},
|
||||
fieldName: 'field5',
|
||||
help: '当字段1的值为`123`时,必填',
|
||||
label: '动态rules',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
class: 'w-full',
|
||||
filterOption: true,
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
placeholder: '请选择',
|
||||
showSearch: true,
|
||||
},
|
||||
dependencies: {
|
||||
componentProps(values) {
|
||||
if (values.field2 === '123') {
|
||||
return {
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
value: '2',
|
||||
},
|
||||
{
|
||||
label: '选项3',
|
||||
value: '3',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
return {};
|
||||
},
|
||||
triggerFields: ['field2'],
|
||||
},
|
||||
fieldName: 'field6',
|
||||
help: '当字段2的值为`123`时,更改下拉选项',
|
||||
label: '动态配置',
|
||||
},
|
||||
],
|
||||
// 大屏一行显示3个,中屏一行显示2个,小屏一行显示1个
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-2',
|
||||
});
|
||||
|
||||
function onSubmit(values: Record<string, any>) {
|
||||
message.success({
|
||||
content: `form values: ${JSON.stringify(values)}`,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form />
|
||||
</template>
|
||||
94
Yi.Vben5.Vue3/docs/src/demos/vben-form/query/index.vue
Normal file
94
Yi.Vben5.Vue3/docs/src/demos/vben-form/query/index.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<script lang="ts" setup>
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
|
||||
const [QueryForm] = useVbenForm({
|
||||
// 默认展开
|
||||
collapsed: false,
|
||||
// 所有表单项共用,可单独在表单内覆盖
|
||||
commonConfig: {
|
||||
// 所有表单项
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
},
|
||||
// 提交函数
|
||||
handleSubmit: onSubmit,
|
||||
// 垂直布局,label和input在不同行,值为vertical
|
||||
// 水平布局,label和input在同一行
|
||||
layout: 'horizontal',
|
||||
schema: [
|
||||
{
|
||||
// 组件需要在 #/adapter.ts内注册,并加上类型
|
||||
component: 'Input',
|
||||
// 对应组件的参数
|
||||
componentProps: {
|
||||
placeholder: '请输入用户名',
|
||||
},
|
||||
// 字段名
|
||||
fieldName: 'username',
|
||||
// 界面显示的label
|
||||
label: '字符串',
|
||||
},
|
||||
{
|
||||
component: 'InputPassword',
|
||||
componentProps: {
|
||||
placeholder: '请输入密码',
|
||||
},
|
||||
fieldName: 'password',
|
||||
label: '密码',
|
||||
},
|
||||
{
|
||||
component: 'InputNumber',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
fieldName: 'number',
|
||||
label: '数字(带后缀)',
|
||||
suffix: () => '¥',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
filterOption: true,
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
placeholder: '请选择',
|
||||
showSearch: true,
|
||||
},
|
||||
fieldName: 'options',
|
||||
label: '下拉选',
|
||||
},
|
||||
{
|
||||
component: 'DatePicker',
|
||||
fieldName: 'datePicker',
|
||||
label: '日期选择框',
|
||||
},
|
||||
],
|
||||
// 是否可展开
|
||||
showCollapseButton: true,
|
||||
submitButtonOptions: {
|
||||
content: '查询',
|
||||
},
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-2',
|
||||
});
|
||||
function onSubmit(values: Record<string, any>) {
|
||||
message.success({
|
||||
content: `form values: ${JSON.stringify(values)}`,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<QueryForm />
|
||||
</template>
|
||||
189
Yi.Vben5.Vue3/docs/src/demos/vben-form/rules/index.vue
Normal file
189
Yi.Vben5.Vue3/docs/src/demos/vben-form/rules/index.vue
Normal file
@@ -0,0 +1,189 @@
|
||||
<script lang="ts" setup>
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import { useVbenForm, z } from '#/adapter/form';
|
||||
|
||||
const [Form] = useVbenForm({
|
||||
// 所有表单项共用,可单独在表单内覆盖
|
||||
commonConfig: {
|
||||
// 所有表单项
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
},
|
||||
},
|
||||
// 提交函数
|
||||
handleSubmit: onSubmit,
|
||||
// 垂直布局,label和input在不同行,值为vertical
|
||||
// 水平布局,label和input在同一行
|
||||
layout: 'horizontal',
|
||||
schema: [
|
||||
{
|
||||
// 组件需要在 #/adapter.ts内注册,并加上类型
|
||||
component: 'Input',
|
||||
// 对应组件的参数
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
// 字段名
|
||||
fieldName: 'field1',
|
||||
// 界面显示的label
|
||||
label: '字段1',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
defaultValue: '默认值',
|
||||
fieldName: 'field2',
|
||||
label: '默认值(必填)',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
fieldName: 'field3',
|
||||
label: '默认值(非必填)',
|
||||
rules: z.string().default('默认值').optional(),
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
fieldName: 'field31',
|
||||
label: '自定义信息',
|
||||
rules: z.string().min(1, { message: '最少输入1个字符' }),
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
// 对应组件的参数
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
// 字段名
|
||||
fieldName: 'field4',
|
||||
// 界面显示的label
|
||||
label: '邮箱',
|
||||
rules: z.string().email('请输入正确的邮箱'),
|
||||
},
|
||||
{
|
||||
component: 'InputNumber',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
fieldName: 'number',
|
||||
label: '数字',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
filterOption: true,
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
placeholder: '请选择',
|
||||
showSearch: true,
|
||||
},
|
||||
defaultValue: undefined,
|
||||
fieldName: 'options',
|
||||
label: '下拉选',
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
},
|
||||
fieldName: 'radioGroup',
|
||||
label: '单选组',
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
component: 'CheckboxGroup',
|
||||
componentProps: {
|
||||
name: 'cname',
|
||||
options: [
|
||||
{
|
||||
label: '选项1',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '选项2',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
},
|
||||
fieldName: 'checkboxGroup',
|
||||
label: '多选组',
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
component: 'Checkbox',
|
||||
fieldName: 'checkbox',
|
||||
label: '',
|
||||
renderComponentContent: () => {
|
||||
return {
|
||||
default: () => ['我已阅读并同意'],
|
||||
};
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
component: 'DatePicker',
|
||||
defaultValue: undefined,
|
||||
fieldName: 'datePicker',
|
||||
label: '日期选择框',
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
component: 'RangePicker',
|
||||
defaultValue: undefined,
|
||||
fieldName: 'rangePicker',
|
||||
label: '区间选择框',
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
component: 'InputPassword',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
fieldName: 'password',
|
||||
label: '密码',
|
||||
rules: 'required',
|
||||
},
|
||||
],
|
||||
wrapperClass: 'grid-cols-1',
|
||||
});
|
||||
|
||||
function onSubmit(values: Record<string, any>) {
|
||||
message.success({
|
||||
content: `form values: ${JSON.stringify(values)}`,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form />
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenModal, VbenButton } from '@vben/common-ui';
|
||||
|
||||
import ExtraModal from './modal.vue';
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
// 连接抽离的组件
|
||||
connectedComponent: ExtraModal,
|
||||
});
|
||||
|
||||
function openModal() {
|
||||
modalApi.open();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Modal />
|
||||
<VbenButton @click="openModal">Open</VbenButton>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,45 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { useVbenModal, VbenButton } from '@vben/common-ui';
|
||||
|
||||
const list = ref<number[]>([]);
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
onCancel() {
|
||||
modalApi.close();
|
||||
},
|
||||
onConfirm() {
|
||||
console.log('onConfirm');
|
||||
},
|
||||
onOpenChange(isOpen) {
|
||||
if (isOpen) {
|
||||
handleUpdate(10);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function handleUpdate(len: number) {
|
||||
modalApi.setState({ loading: true });
|
||||
setTimeout(() => {
|
||||
list.value = Array.from({ length: len }, (_v, k) => k + 1);
|
||||
modalApi.setState({ loading: false });
|
||||
}, 2000);
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Modal title="自动计算高度">
|
||||
<div
|
||||
v-for="item in list"
|
||||
:key="item"
|
||||
class="even:bg-heavy bg-muted flex-center h-[220px] w-full"
|
||||
>
|
||||
{{ item }}
|
||||
</div>
|
||||
<template #prepend-footer>
|
||||
<VbenButton type="link" @click="handleUpdate(6)">
|
||||
点击更新数据
|
||||
</VbenButton>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
11
Yi.Vben5.Vue3/docs/src/demos/vben-modal/basic/index.vue
Normal file
11
Yi.Vben5.Vue3/docs/src/demos/vben-modal/basic/index.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenModal, VbenButton } from '@vben/common-ui';
|
||||
|
||||
const [Modal, modalApi] = useVbenModal();
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<VbenButton @click="() => modalApi.open()">Open</VbenButton>
|
||||
<Modal class="w-[600px]" title="基础示例"> modal content </Modal>
|
||||
</div>
|
||||
</template>
|
||||
21
Yi.Vben5.Vue3/docs/src/demos/vben-modal/draggable/index.vue
Normal file
21
Yi.Vben5.Vue3/docs/src/demos/vben-modal/draggable/index.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenModal, VbenButton } from '@vben/common-ui';
|
||||
|
||||
import ExtraModal from './modal.vue';
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
// 连接抽离的组件
|
||||
connectedComponent: ExtraModal,
|
||||
});
|
||||
|
||||
function openModal() {
|
||||
modalApi.open();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Modal />
|
||||
<VbenButton @click="openModal">Open</VbenButton>
|
||||
</div>
|
||||
</template>
|
||||
10
Yi.Vben5.Vue3/docs/src/demos/vben-modal/draggable/modal.vue
Normal file
10
Yi.Vben5.Vue3/docs/src/demos/vben-modal/draggable/modal.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
const [Modal] = useVbenModal({
|
||||
draggable: true,
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<Modal title="拖拽示例"> modal content </Modal>
|
||||
</template>
|
||||
29
Yi.Vben5.Vue3/docs/src/demos/vben-modal/dynamic/index.vue
Normal file
29
Yi.Vben5.Vue3/docs/src/demos/vben-modal/dynamic/index.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenModal, VbenButton } from '@vben/common-ui';
|
||||
|
||||
import ExtraModal from './modal.vue';
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
// 连接抽离的组件
|
||||
connectedComponent: ExtraModal,
|
||||
});
|
||||
|
||||
function openModal() {
|
||||
modalApi.open();
|
||||
}
|
||||
|
||||
function handleUpdateTitle() {
|
||||
modalApi.setState({ title: '外部动态标题' }).open();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Modal />
|
||||
|
||||
<VbenButton @click="openModal">Open</VbenButton>
|
||||
<VbenButton class="ml-2" type="primary" @click="handleUpdateTitle">
|
||||
从外部修改标题并打开
|
||||
</VbenButton>
|
||||
</div>
|
||||
</template>
|
||||
38
Yi.Vben5.Vue3/docs/src/demos/vben-modal/dynamic/modal.vue
Normal file
38
Yi.Vben5.Vue3/docs/src/demos/vben-modal/dynamic/modal.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenModal, VbenButton } from '@vben/common-ui';
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
draggable: true,
|
||||
onCancel() {
|
||||
modalApi.close();
|
||||
},
|
||||
onConfirm() {
|
||||
console.info('onConfirm');
|
||||
},
|
||||
title: '动态修改配置示例',
|
||||
});
|
||||
|
||||
const state = modalApi.useStore();
|
||||
|
||||
function handleUpdateTitle() {
|
||||
modalApi.setState({ title: '内部动态标题' });
|
||||
}
|
||||
|
||||
function handleToggleFullscreen() {
|
||||
modalApi.setState((prev) => {
|
||||
return { ...prev, fullscreen: !prev.fullscreen };
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Modal>
|
||||
<div class="flex-col-center">
|
||||
<VbenButton class="mb-3" type="primary" @click="handleUpdateTitle()">
|
||||
内部动态修改标题
|
||||
</VbenButton>
|
||||
<VbenButton class="mb-3" @click="handleToggleFullscreen()">
|
||||
{{ state.fullscreen ? '退出全屏' : '打开全屏' }}
|
||||
</VbenButton>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
21
Yi.Vben5.Vue3/docs/src/demos/vben-modal/extra/index.vue
Normal file
21
Yi.Vben5.Vue3/docs/src/demos/vben-modal/extra/index.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenModal, VbenButton } from '@vben/common-ui';
|
||||
|
||||
import ExtraModal from './modal.vue';
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
// 连接抽离的组件
|
||||
connectedComponent: ExtraModal,
|
||||
});
|
||||
|
||||
function openModal() {
|
||||
modalApi.open();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Modal />
|
||||
<VbenButton @click="openModal">Open</VbenButton>
|
||||
</div>
|
||||
</template>
|
||||
8
Yi.Vben5.Vue3/docs/src/demos/vben-modal/extra/modal.vue
Normal file
8
Yi.Vben5.Vue3/docs/src/demos/vben-modal/extra/modal.vue
Normal file
@@ -0,0 +1,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
const [Modal] = useVbenModal();
|
||||
</script>
|
||||
<template>
|
||||
<Modal title="组件抽离示例"> extra modal content </Modal>
|
||||
</template>
|
||||
@@ -0,0 +1,27 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVbenModal, VbenButton } from '@vben/common-ui';
|
||||
|
||||
import ExtraModal from './modal.vue';
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
// 连接抽离的组件
|
||||
connectedComponent: ExtraModal,
|
||||
});
|
||||
|
||||
function openModal() {
|
||||
modalApi
|
||||
.setData({
|
||||
content: '外部传递的数据 content',
|
||||
payload: '外部传递的数据 payload',
|
||||
})
|
||||
.open();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Modal />
|
||||
|
||||
<VbenButton @click="openModal">Open</VbenButton>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,26 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
|
||||
const data = ref();
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
onCancel() {
|
||||
modalApi.close();
|
||||
},
|
||||
onConfirm() {
|
||||
console.info('onConfirm');
|
||||
},
|
||||
onOpenChange(isOpen: boolean) {
|
||||
if (isOpen) {
|
||||
data.value = modalApi.getData<Record<string, any>>();
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<Modal title="数据共享示例">
|
||||
<div class="flex-col-center">外部传递数据: {{ data }}</div>
|
||||
</Modal>
|
||||
</template>
|
||||
85
Yi.Vben5.Vue3/docs/src/demos/vben-vxe-table/basic/index.vue
Normal file
85
Yi.Vben5.Vue3/docs/src/demos/vben-vxe-table/basic/index.vue
Normal file
@@ -0,0 +1,85 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
import { Button, message } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
|
||||
import { MOCK_TABLE_DATA } from '../table-data';
|
||||
|
||||
interface RowType {
|
||||
address: string;
|
||||
age: number;
|
||||
id: number;
|
||||
name: string;
|
||||
nickname: string;
|
||||
role: string;
|
||||
}
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ title: '序号', type: 'seq', width: 50 },
|
||||
{ field: 'name', title: 'Name' },
|
||||
{ field: 'age', sortable: true, title: 'Age' },
|
||||
{ field: 'nickname', title: 'Nickname' },
|
||||
{ field: 'role', title: 'Role' },
|
||||
{ field: 'address', showOverflow: true, title: 'Address' },
|
||||
],
|
||||
data: MOCK_TABLE_DATA,
|
||||
pagerConfig: {
|
||||
enabled: false,
|
||||
},
|
||||
sortConfig: {
|
||||
multiple: true,
|
||||
},
|
||||
};
|
||||
|
||||
const gridEvents: VxeGridListeners<RowType> = {
|
||||
cellClick: ({ row }) => {
|
||||
message.info(`cell-click: ${row.name}`);
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({ gridEvents, gridOptions });
|
||||
|
||||
const showBorder = gridApi.useStore((state) => state.gridOptions?.border);
|
||||
const showStripe = gridApi.useStore((state) => state.gridOptions?.stripe);
|
||||
|
||||
function changeBorder() {
|
||||
gridApi.setGridOptions({
|
||||
border: !showBorder.value,
|
||||
});
|
||||
}
|
||||
|
||||
function changeStripe() {
|
||||
gridApi.setGridOptions({
|
||||
stripe: !showStripe.value,
|
||||
});
|
||||
}
|
||||
|
||||
function changeLoading() {
|
||||
gridApi.setLoading(true);
|
||||
setTimeout(() => {
|
||||
gridApi.setLoading(false);
|
||||
}, 2000);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- 此处的`vp-raw` 是为了适配文档的展示效果,实际使用时不需要 -->
|
||||
<div class="vp-raw w-full">
|
||||
<Grid>
|
||||
<template #toolbar-tools>
|
||||
<Button class="mr-2" type="primary" @click="changeBorder">
|
||||
{{ showBorder ? '隐藏' : '显示' }}边框
|
||||
</Button>
|
||||
<Button class="mr-2" type="primary" @click="changeLoading">
|
||||
显示loading
|
||||
</Button>
|
||||
<Button class="mr-2" type="primary" @click="changeStripe">
|
||||
{{ showStripe ? '隐藏' : '显示' }}斑马纹
|
||||
</Button>
|
||||
</template>
|
||||
</Grid>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,105 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
import { Button, Image, Switch, Tag } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
|
||||
import { getExampleTableApi } from '../mock-api';
|
||||
|
||||
interface RowType {
|
||||
category: string;
|
||||
color: string;
|
||||
id: string;
|
||||
imageUrl: string;
|
||||
open: boolean;
|
||||
price: string;
|
||||
productName: string;
|
||||
releaseDate: string;
|
||||
status: 'error' | 'success' | 'warning';
|
||||
}
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
checkboxConfig: {
|
||||
highlight: true,
|
||||
labelField: 'name',
|
||||
},
|
||||
columns: [
|
||||
{ title: '序号', type: 'seq', width: 50 },
|
||||
{ field: 'category', title: 'Category', width: 100 },
|
||||
{
|
||||
field: 'imageUrl',
|
||||
slots: { default: 'image-url' },
|
||||
title: 'Image',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
cellRender: { name: 'CellImage' },
|
||||
field: 'imageUrl2',
|
||||
title: 'Render Image',
|
||||
width: 130,
|
||||
},
|
||||
{
|
||||
field: 'open',
|
||||
slots: { default: 'open' },
|
||||
title: 'Open',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
slots: { default: 'status' },
|
||||
title: 'Status',
|
||||
width: 100,
|
||||
},
|
||||
{ field: 'color', title: 'Color', width: 100 },
|
||||
{ field: 'productName', title: 'Product Name', width: 200 },
|
||||
{ field: 'price', title: 'Price', width: 100 },
|
||||
{
|
||||
field: 'releaseDate',
|
||||
formatter: 'formatDateTime',
|
||||
title: 'Date',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
cellRender: { name: 'CellLink', props: { text: '编辑' } },
|
||||
field: 'action',
|
||||
fixed: 'right',
|
||||
title: '操作',
|
||||
width: 120,
|
||||
},
|
||||
],
|
||||
keepSource: true,
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }) => {
|
||||
return await getExampleTableApi({
|
||||
page: page.currentPage,
|
||||
MaxResultCount: page.pageSize,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid] = useVbenVxeGrid({ gridOptions });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vp-raw w-full">
|
||||
<Grid>
|
||||
<template #image-url="{ row }">
|
||||
<Image :src="row.imageUrl" height="30" width="30" />
|
||||
</template>
|
||||
<template #open="{ row }">
|
||||
<Switch v-model:checked="row.open" />
|
||||
</template>
|
||||
<template #status="{ row }">
|
||||
<Tag :color="row.color">{{ row.status }}</Tag>
|
||||
</template>
|
||||
<template #action>
|
||||
<Button type="link">编辑</Button>
|
||||
</template>
|
||||
</Grid>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,55 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
|
||||
import { getExampleTableApi } from '../mock-api';
|
||||
|
||||
interface RowType {
|
||||
category: string;
|
||||
color: string;
|
||||
id: string;
|
||||
price: string;
|
||||
productName: string;
|
||||
releaseDate: string;
|
||||
}
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ title: '序号', type: 'seq', width: 50 },
|
||||
{ editRender: { name: 'input' }, field: 'category', title: 'Category' },
|
||||
{ editRender: { name: 'input' }, field: 'color', title: 'Color' },
|
||||
{
|
||||
editRender: { name: 'input' },
|
||||
field: 'productName',
|
||||
title: 'Product Name',
|
||||
},
|
||||
{ field: 'price', title: 'Price' },
|
||||
{ field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },
|
||||
],
|
||||
editConfig: {
|
||||
mode: 'cell',
|
||||
trigger: 'click',
|
||||
},
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }) => {
|
||||
return await getExampleTableApi({
|
||||
page: page.currentPage,
|
||||
MaxResultCount: page.pageSize,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
showOverflow: true,
|
||||
};
|
||||
|
||||
const [Grid] = useVbenVxeGrid({ gridOptions });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vp-raw w-full">
|
||||
<Grid />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,92 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
import { Button, message } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
|
||||
import { getExampleTableApi } from '../mock-api';
|
||||
|
||||
interface RowType {
|
||||
category: string;
|
||||
color: string;
|
||||
id: string;
|
||||
price: string;
|
||||
productName: string;
|
||||
releaseDate: string;
|
||||
}
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ title: '序号', type: 'seq', width: 50 },
|
||||
{ editRender: { name: 'input' }, field: 'category', title: 'Category' },
|
||||
{ editRender: { name: 'input' }, field: 'color', title: 'Color' },
|
||||
{
|
||||
editRender: { name: 'input' },
|
||||
field: 'productName',
|
||||
title: 'Product Name',
|
||||
},
|
||||
{ field: 'price', title: 'Price' },
|
||||
{ field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },
|
||||
{ slots: { default: 'action' }, title: '操作' },
|
||||
],
|
||||
editConfig: {
|
||||
mode: 'row',
|
||||
trigger: 'click',
|
||||
},
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }) => {
|
||||
return await getExampleTableApi({
|
||||
page: page.currentPage,
|
||||
MaxResultCount: page.pageSize,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
showOverflow: true,
|
||||
};
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
|
||||
|
||||
function hasEditStatus(row: RowType) {
|
||||
return gridApi.grid?.isEditByRow(row);
|
||||
}
|
||||
|
||||
function editRowEvent(row: RowType) {
|
||||
gridApi.grid?.setEditRow(row);
|
||||
}
|
||||
|
||||
async function saveRowEvent(row: RowType) {
|
||||
await gridApi.grid?.clearEdit();
|
||||
|
||||
gridApi.setLoading(true);
|
||||
setTimeout(() => {
|
||||
gridApi.setLoading(false);
|
||||
message.success({
|
||||
content: `保存成功!category=${row.category}`,
|
||||
});
|
||||
}, 600);
|
||||
}
|
||||
|
||||
const cancelRowEvent = (_row: RowType) => {
|
||||
gridApi.grid?.clearEdit();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vp-raw w-full">
|
||||
<Grid>
|
||||
<template #action="{ row }">
|
||||
<template v-if="hasEditStatus(row)">
|
||||
<Button type="link" @click="saveRowEvent(row)">保存</Button>
|
||||
<Button type="link" @click="cancelRowEvent(row)">取消</Button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Button type="link" @click="editRowEvent(row)">编辑</Button>
|
||||
</template>
|
||||
</template>
|
||||
</Grid>
|
||||
</div>
|
||||
</template>
|
||||
67
Yi.Vben5.Vue3/docs/src/demos/vben-vxe-table/fixed/index.vue
Normal file
67
Yi.Vben5.Vue3/docs/src/demos/vben-vxe-table/fixed/index.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
import { Button } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
|
||||
import { getExampleTableApi } from '../mock-api';
|
||||
|
||||
interface RowType {
|
||||
category: string;
|
||||
color: string;
|
||||
id: string;
|
||||
price: string;
|
||||
productName: string;
|
||||
releaseDate: string;
|
||||
}
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ fixed: 'left', title: '序号', type: 'seq', width: 50 },
|
||||
{ field: 'category', title: 'Category', width: 300 },
|
||||
{ field: 'color', title: 'Color', width: 300 },
|
||||
{ field: 'productName', title: 'Product Name', width: 300 },
|
||||
{ field: 'price', title: 'Price', width: 300 },
|
||||
{
|
||||
field: 'releaseDate',
|
||||
formatter: 'formatDateTime',
|
||||
title: 'DateTime',
|
||||
width: 500,
|
||||
},
|
||||
{
|
||||
field: 'action',
|
||||
fixed: 'right',
|
||||
slots: { default: 'action' },
|
||||
title: '操作',
|
||||
width: 120,
|
||||
},
|
||||
],
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }) => {
|
||||
return await getExampleTableApi({
|
||||
page: page.currentPage,
|
||||
MaxResultCount: page.pageSize,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
isHover: true,
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid] = useVbenVxeGrid({ gridOptions });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vp-raw w-full">
|
||||
<Grid>
|
||||
<template #action>
|
||||
<Button type="link">编辑</Button>
|
||||
</template>
|
||||
</Grid>
|
||||
</div>
|
||||
</template>
|
||||
127
Yi.Vben5.Vue3/docs/src/demos/vben-vxe-table/form/index.vue
Normal file
127
Yi.Vben5.Vue3/docs/src/demos/vben-vxe-table/form/index.vue
Normal file
@@ -0,0 +1,127 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VbenFormProps } from '#/adapter/form';
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
|
||||
import { getExampleTableApi } from '../mock-api';
|
||||
|
||||
interface RowType {
|
||||
category: string;
|
||||
color: string;
|
||||
id: string;
|
||||
price: string;
|
||||
productName: string;
|
||||
releaseDate: string;
|
||||
}
|
||||
|
||||
const formOptions: VbenFormProps = {
|
||||
// 默认展开
|
||||
collapsed: false,
|
||||
schema: [
|
||||
{
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: 'Please enter category',
|
||||
},
|
||||
defaultValue: '1',
|
||||
fieldName: 'category',
|
||||
label: 'Category',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: 'Please enter productName',
|
||||
},
|
||||
fieldName: 'productName',
|
||||
label: 'ProductName',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: 'Please enter price',
|
||||
},
|
||||
fieldName: 'price',
|
||||
label: 'Price',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
options: [
|
||||
{
|
||||
label: 'Color1',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: 'Color2',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
placeholder: '请选择',
|
||||
},
|
||||
fieldName: 'color',
|
||||
label: 'Color',
|
||||
},
|
||||
{
|
||||
component: 'DatePicker',
|
||||
fieldName: 'datePicker',
|
||||
label: 'Date',
|
||||
},
|
||||
],
|
||||
// 控制表单是否显示折叠按钮
|
||||
showCollapseButton: true,
|
||||
submitButtonOptions: {
|
||||
content: '查询',
|
||||
},
|
||||
// 是否在字段值改变时提交表单
|
||||
submitOnChange: false,
|
||||
// 按下回车时是否提交表单
|
||||
submitOnEnter: false,
|
||||
};
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
checkboxConfig: {
|
||||
highlight: true,
|
||||
labelField: 'name',
|
||||
},
|
||||
columns: [
|
||||
{ title: '序号', type: 'seq', width: 50 },
|
||||
{ align: 'left', title: 'Name', type: 'checkbox', width: 100 },
|
||||
{ field: 'category', title: 'Category' },
|
||||
{ field: 'color', title: 'Color' },
|
||||
{ field: 'productName', title: 'Product Name' },
|
||||
{ field: 'price', title: 'Price' },
|
||||
{ field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },
|
||||
],
|
||||
keepSource: true,
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
message.success(`Query params: ${JSON.stringify(formValues)}`);
|
||||
return await getExampleTableApi({
|
||||
page: page.currentPage,
|
||||
MaxResultCount: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
toolbarConfig: {
|
||||
// 是否显示搜索表单控制按钮
|
||||
// @ts-ignore 正式环境时有完整的类型声明
|
||||
search: true,
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid] = useVbenVxeGrid({ formOptions, gridOptions });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vp-raw w-full">
|
||||
<Grid />
|
||||
</div>
|
||||
</template>
|
||||
36
Yi.Vben5.Vue3/docs/src/demos/vben-vxe-table/mock-api.ts
Normal file
36
Yi.Vben5.Vue3/docs/src/demos/vben-vxe-table/mock-api.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { MOCK_API_DATA } from './table-data';
|
||||
|
||||
export namespace DemoTableApi {
|
||||
export interface PageFetchParams {
|
||||
[key: string]: any;
|
||||
page: number;
|
||||
MaxResultCount: number;
|
||||
}
|
||||
}
|
||||
|
||||
export function sleep(time = 1000) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(true);
|
||||
}, time);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取示例表格数据
|
||||
*/
|
||||
async function getExampleTableApi(params: DemoTableApi.PageFetchParams) {
|
||||
return new Promise<{ items: any; total: number }>((resolve) => {
|
||||
const { page, MaxResultCount } = params;
|
||||
const items = MOCK_API_DATA.slice((page - 1) * MaxResultCount, page * MaxResultCount);
|
||||
|
||||
sleep(1000).then(() => {
|
||||
resolve({
|
||||
total: items.length,
|
||||
items,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export { getExampleTableApi };
|
||||
112
Yi.Vben5.Vue3/docs/src/demos/vben-vxe-table/remote/index.vue
Normal file
112
Yi.Vben5.Vue3/docs/src/demos/vben-vxe-table/remote/index.vue
Normal file
@@ -0,0 +1,112 @@
|
||||
<script lang="ts" setup>
|
||||
import type { DemoTableApi } from '../mock-api';
|
||||
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
import { Button } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
|
||||
import { MOCK_API_DATA } from '../table-data';
|
||||
|
||||
interface RowType {
|
||||
category: string;
|
||||
color: string;
|
||||
id: string;
|
||||
price: string;
|
||||
productName: string;
|
||||
releaseDate: string;
|
||||
}
|
||||
|
||||
// 数据实例
|
||||
// const MOCK_TREE_TABLE_DATA = [
|
||||
// {
|
||||
// date: '2020-08-01',
|
||||
// id: 10_000,
|
||||
// name: 'Test1',
|
||||
// parentId: null,
|
||||
// size: 1024,
|
||||
// type: 'mp3',
|
||||
// },
|
||||
// ]
|
||||
|
||||
const sleep = (time = 1000) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(true);
|
||||
}, time);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取示例表格数据
|
||||
*/
|
||||
async function getExampleTableApi(params: DemoTableApi.PageFetchParams) {
|
||||
return new Promise<{ items: any; total: number }>((resolve) => {
|
||||
const { page, MaxResultCount } = params;
|
||||
const items = MOCK_API_DATA.slice((page - 1) * MaxResultCount, page * MaxResultCount);
|
||||
|
||||
sleep(1000).then(() => {
|
||||
resolve({
|
||||
total: items.length,
|
||||
items,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
checkboxConfig: {
|
||||
highlight: true,
|
||||
labelField: 'name',
|
||||
},
|
||||
columns: [
|
||||
{ title: '序号', type: 'seq', width: 50 },
|
||||
{ align: 'left', title: 'Name', type: 'checkbox', width: 100 },
|
||||
{ field: 'category', title: 'Category' },
|
||||
{ field: 'color', title: 'Color' },
|
||||
{ field: 'productName', title: 'Product Name' },
|
||||
{ field: 'price', title: 'Price' },
|
||||
{ field: 'releaseDate', formatter: 'formatDateTime', title: 'DateTime' },
|
||||
],
|
||||
exportConfig: {},
|
||||
// height: 'auto', // 如果设置为 auto,则必须确保存在父节点且不允许存在相邻元素,否则会出现高度闪动问题
|
||||
keepSource: true,
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }) => {
|
||||
return await getExampleTableApi({
|
||||
page: page.currentPage,
|
||||
MaxResultCount: page.pageSize,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
toolbarConfig: {
|
||||
custom: true,
|
||||
export: true,
|
||||
// import: true,
|
||||
refresh: true,
|
||||
zoom: true,
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
gridOptions,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vp-raw w-full">
|
||||
<Grid>
|
||||
<template #toolbar-tools>
|
||||
<Button class="mr-2" type="primary" @click="() => gridApi.query()">
|
||||
刷新当前页面
|
||||
</Button>
|
||||
<Button type="primary" @click="() => gridApi.reload()">
|
||||
刷新并返回第一页
|
||||
</Button>
|
||||
</template>
|
||||
</Grid>
|
||||
</div>
|
||||
</template>
|
||||
384
Yi.Vben5.Vue3/docs/src/demos/vben-vxe-table/table-data.ts
Normal file
384
Yi.Vben5.Vue3/docs/src/demos/vben-vxe-table/table-data.ts
Normal file
@@ -0,0 +1,384 @@
|
||||
interface TableRowData {
|
||||
address: string;
|
||||
age: number;
|
||||
id: number;
|
||||
name: string;
|
||||
nickname: string;
|
||||
role: string;
|
||||
}
|
||||
|
||||
const roles = ['User', 'Admin', 'Manager', 'Guest'];
|
||||
|
||||
export const MOCK_TABLE_DATA: TableRowData[] = (() => {
|
||||
const data: TableRowData[] = [];
|
||||
for (let i = 0; i < 10; i++) {
|
||||
data.push({
|
||||
address: `New York${i}`,
|
||||
age: i + 1,
|
||||
id: i,
|
||||
name: `Test${i}`,
|
||||
nickname: `Test${i}`,
|
||||
role: roles[Math.floor(Math.random() * roles.length)] as string,
|
||||
});
|
||||
}
|
||||
return data;
|
||||
})();
|
||||
|
||||
export const MOCK_TREE_TABLE_DATA = [
|
||||
{
|
||||
date: '2020-08-01',
|
||||
id: 10_000,
|
||||
name: 'Test1',
|
||||
parentId: null,
|
||||
size: 1024,
|
||||
type: 'mp3',
|
||||
},
|
||||
{
|
||||
date: '2021-04-01',
|
||||
id: 10_050,
|
||||
name: 'Test2',
|
||||
parentId: null,
|
||||
size: 0,
|
||||
type: 'mp4',
|
||||
},
|
||||
{
|
||||
date: '2020-03-01',
|
||||
id: 24_300,
|
||||
name: 'Test3',
|
||||
parentId: 10_050,
|
||||
size: 1024,
|
||||
type: 'avi',
|
||||
},
|
||||
{
|
||||
date: '2021-04-01',
|
||||
id: 20_045,
|
||||
name: 'Test4',
|
||||
parentId: 24_300,
|
||||
size: 600,
|
||||
type: 'html',
|
||||
},
|
||||
{
|
||||
date: '2021-04-01',
|
||||
id: 10_053,
|
||||
name: 'Test5',
|
||||
parentId: 24_300,
|
||||
size: 0,
|
||||
type: 'avi',
|
||||
},
|
||||
{
|
||||
date: '2021-10-01',
|
||||
id: 24_330,
|
||||
name: 'Test6',
|
||||
parentId: 10_053,
|
||||
size: 25,
|
||||
type: 'txt',
|
||||
},
|
||||
{
|
||||
date: '2020-01-01',
|
||||
id: 21_011,
|
||||
name: 'Test7',
|
||||
parentId: 10_053,
|
||||
size: 512,
|
||||
type: 'pdf',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 22_200,
|
||||
name: 'Test8',
|
||||
parentId: 10_053,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2020-11-01',
|
||||
id: 23_666,
|
||||
name: 'Test9',
|
||||
parentId: null,
|
||||
size: 2048,
|
||||
type: 'xlsx',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 23_677,
|
||||
name: 'Test10',
|
||||
parentId: 23_666,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 23_671,
|
||||
name: 'Test11',
|
||||
parentId: 23_677,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 23_672,
|
||||
name: 'Test12',
|
||||
parentId: 23_677,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 23_688,
|
||||
name: 'Test13',
|
||||
parentId: 23_666,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 23_681,
|
||||
name: 'Test14',
|
||||
parentId: 23_688,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 23_682,
|
||||
name: 'Test15',
|
||||
parentId: 23_688,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2020-10-01',
|
||||
id: 24_555,
|
||||
name: 'Test16',
|
||||
parentId: null,
|
||||
size: 224,
|
||||
type: 'avi',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 24_566,
|
||||
name: 'Test17',
|
||||
parentId: 24_555,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
{
|
||||
date: '2021-06-01',
|
||||
id: 24_577,
|
||||
name: 'Test18',
|
||||
parentId: 24_555,
|
||||
size: 1024,
|
||||
type: 'js',
|
||||
},
|
||||
];
|
||||
|
||||
export const MOCK_API_DATA = [
|
||||
{
|
||||
available: true,
|
||||
category: 'Computers',
|
||||
color: 'purple',
|
||||
currency: 'NAD',
|
||||
description:
|
||||
'Ergonomic executive chair upholstered in bonded black leather and PVC padded seat and back for all-day comfort and support',
|
||||
id: '45a613df-227a-4907-a89f-4a7f1252ca0c',
|
||||
imageUrl: 'https://avatars.githubusercontent.com/u/62715097',
|
||||
imageUrl2: 'https://avatars.githubusercontent.com/u/75395683',
|
||||
inProduction: false,
|
||||
open: true,
|
||||
price: '48.89',
|
||||
productName: 'Handcrafted Steel Salad',
|
||||
quantity: 70,
|
||||
rating: 3.780_582_329_574_367,
|
||||
releaseDate: '2024-09-09T04:06:57.793Z',
|
||||
status: 'error',
|
||||
tags: ['Bespoke', 'Handmade', 'Luxurious'],
|
||||
weight: 1.031_015_671_912_002_5,
|
||||
},
|
||||
{
|
||||
available: true,
|
||||
category: 'Toys',
|
||||
color: 'green',
|
||||
currency: 'CZK',
|
||||
description:
|
||||
'The Nagasaki Lander is the trademarked name of several series of Nagasaki sport bikes, that started with the 1984 ABC800J',
|
||||
id: 'd02e5ee9-bc98-4de2-98fa-25a6567ecc19',
|
||||
imageUrl: 'https://avatars.githubusercontent.com/u/51512330',
|
||||
imageUrl2: 'https://avatars.githubusercontent.com/u/58698113',
|
||||
inProduction: false,
|
||||
open: false,
|
||||
price: '68.15',
|
||||
productName: 'Generic Cotton Gloves',
|
||||
quantity: 3,
|
||||
rating: 1.681_749_367_682_703_3,
|
||||
releaseDate: '2024-06-16T09:00:36.806Z',
|
||||
status: 'warning',
|
||||
tags: ['Rustic', 'Handcrafted', 'Recycled'],
|
||||
weight: 9.601_076_149_300_575,
|
||||
},
|
||||
{
|
||||
available: true,
|
||||
category: 'Beauty',
|
||||
color: 'teal',
|
||||
currency: 'OMR',
|
||||
description:
|
||||
'The Apollotech B340 is an affordable wireless mouse with reliable connectivity, 12 months battery life and modern design',
|
||||
id: '2b72521c-225c-4e64-8030-611b76b10b37',
|
||||
imageUrl: 'https://avatars.githubusercontent.com/u/50300075',
|
||||
imageUrl2: 'https://avatars.githubusercontent.com/u/36541691',
|
||||
inProduction: true,
|
||||
open: true,
|
||||
price: '696.94',
|
||||
productName: 'Gorgeous Soft Ball',
|
||||
quantity: 50,
|
||||
rating: 2.361_581_777_372_057_5,
|
||||
releaseDate: '2024-06-03T13:24:19.809Z',
|
||||
status: 'warning',
|
||||
tags: ['Gorgeous', 'Ergonomic', 'Licensed'],
|
||||
weight: 8.882_340_049_286_19,
|
||||
},
|
||||
{
|
||||
available: true,
|
||||
category: 'Games',
|
||||
color: 'silver',
|
||||
currency: 'SOS',
|
||||
description:
|
||||
'Carbonite web goalkeeper gloves are ergonomically designed to give easy fit',
|
||||
id: 'bafab694-3801-452c-b102-9eb519bd1143',
|
||||
imageUrl: 'https://avatars.githubusercontent.com/u/89827115',
|
||||
imageUrl2: 'https://avatars.githubusercontent.com/u/55952747',
|
||||
inProduction: false,
|
||||
open: false,
|
||||
price: '553.84',
|
||||
productName: 'Bespoke Soft Computer',
|
||||
quantity: 29,
|
||||
rating: 2.176_412_873_760_271_7,
|
||||
releaseDate: '2024-09-17T12:16:27.034Z',
|
||||
status: 'error',
|
||||
tags: ['Elegant', 'Rustic', 'Recycled'],
|
||||
weight: 9.653_285_869_978_038,
|
||||
},
|
||||
{
|
||||
available: true,
|
||||
category: 'Toys',
|
||||
color: 'indigo',
|
||||
currency: 'BIF',
|
||||
description:
|
||||
'Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals',
|
||||
id: 'bf6dea6b-2a55-441d-8773-937e03d99389',
|
||||
imageUrl: 'https://avatars.githubusercontent.com/u/21431092',
|
||||
imageUrl2: 'https://avatars.githubusercontent.com/u/3771350',
|
||||
inProduction: true,
|
||||
open: true,
|
||||
price: '237.39',
|
||||
productName: 'Handcrafted Cotton Mouse',
|
||||
quantity: 54,
|
||||
rating: 4.363_265_388_265_461,
|
||||
releaseDate: '2023-10-23T13:42:34.947Z',
|
||||
status: 'error',
|
||||
tags: ['Unbranded', 'Handmade', 'Generic'],
|
||||
weight: 9.513_203_612_535_571,
|
||||
},
|
||||
{
|
||||
available: false,
|
||||
category: 'Tools',
|
||||
color: 'violet',
|
||||
currency: 'TZS',
|
||||
description:
|
||||
'New ABC 13 9370, 13.3, 5th Gen CoreA5-8250U, 8GB RAM, 256GB SSD, power UHD Graphics, OS 10 Home, OS Office A & J 2016',
|
||||
id: '135ba6ab-32ee-4989-8189-5cfa658ef970',
|
||||
imageUrl: 'https://avatars.githubusercontent.com/u/29946092',
|
||||
imageUrl2: 'https://avatars.githubusercontent.com/u/23842994',
|
||||
inProduction: false,
|
||||
open: false,
|
||||
price: '825.25',
|
||||
productName: 'Awesome Bronze Ball',
|
||||
quantity: 94,
|
||||
rating: 4.251_159_804_726_753,
|
||||
releaseDate: '2023-12-30T07:31:43.464Z',
|
||||
status: 'warning',
|
||||
tags: ['Handmade', 'Elegant', 'Unbranded'],
|
||||
weight: 2.247_473_385_732_636_8,
|
||||
},
|
||||
{
|
||||
available: true,
|
||||
category: 'Automotive',
|
||||
color: 'teal',
|
||||
currency: 'BOB',
|
||||
description: 'The Football Is Good For Training And Recreational Purposes',
|
||||
id: '652ef256-7d4e-48b7-976c-7afaa781ea92',
|
||||
imageUrl: 'https://avatars.githubusercontent.com/u/2531904',
|
||||
imageUrl2: 'https://avatars.githubusercontent.com/u/15215990',
|
||||
inProduction: false,
|
||||
open: false,
|
||||
price: '780.49',
|
||||
productName: 'Oriental Rubber Pants',
|
||||
quantity: 70,
|
||||
rating: 2.636_323_417_377_916,
|
||||
releaseDate: '2024-02-23T23:30:49.628Z',
|
||||
status: 'success',
|
||||
tags: ['Unbranded', 'Elegant', 'Unbranded'],
|
||||
weight: 4.812_965_858_018_838,
|
||||
},
|
||||
{
|
||||
available: false,
|
||||
category: 'Garden',
|
||||
color: 'plum',
|
||||
currency: 'LRD',
|
||||
description:
|
||||
'The slim & simple Maple Gaming Keyboard from Dev Byte comes with a sleek body and 7- Color RGB LED Back-lighting for smart functionality',
|
||||
id: '3ea24798-6589-40cc-85f0-ab78752244a0',
|
||||
imageUrl: 'https://avatars.githubusercontent.com/u/23165285',
|
||||
imageUrl2: 'https://avatars.githubusercontent.com/u/14595665',
|
||||
inProduction: false,
|
||||
open: true,
|
||||
price: '583.85',
|
||||
productName: 'Handcrafted Concrete Hat',
|
||||
quantity: 15,
|
||||
rating: 1.371_600_527_752_802_7,
|
||||
releaseDate: '2024-03-02T19:40:50.255Z',
|
||||
status: 'error',
|
||||
tags: ['Rustic', 'Sleek', 'Ergonomic'],
|
||||
weight: 4.926_949_366_405_728_4,
|
||||
},
|
||||
{
|
||||
available: false,
|
||||
category: 'Industrial',
|
||||
color: 'salmon',
|
||||
currency: 'AUD',
|
||||
description:
|
||||
'The Apollotech B340 is an affordable wireless mouse with reliable connectivity, 12 months battery life and modern design',
|
||||
id: '997113dd-f6e4-4acc-9790-ef554c7498d1',
|
||||
imageUrl: 'https://avatars.githubusercontent.com/u/49021914',
|
||||
imageUrl2: 'https://avatars.githubusercontent.com/u/4690621',
|
||||
inProduction: true,
|
||||
open: false,
|
||||
price: '67.99',
|
||||
productName: 'Generic Rubber Bacon',
|
||||
quantity: 68,
|
||||
rating: 4.129_840_682_128_08,
|
||||
releaseDate: '2023-12-17T01:40:25.415Z',
|
||||
status: 'error',
|
||||
tags: ['Oriental', 'Small', 'Handcrafted'],
|
||||
weight: 1.080_114_331_801_906_4,
|
||||
},
|
||||
{
|
||||
available: false,
|
||||
category: 'Tools',
|
||||
color: 'sky blue',
|
||||
currency: 'NOK',
|
||||
description:
|
||||
'The Nagasaki Lander is the trademarked name of several series of Nagasaki sport bikes, that started with the 1984 ABC800J',
|
||||
id: 'f697a250-6cb2-46c8-b0f7-871ab1f2fa8d',
|
||||
imageUrl: 'https://avatars.githubusercontent.com/u/95928385',
|
||||
imageUrl2: 'https://avatars.githubusercontent.com/u/47588244',
|
||||
inProduction: false,
|
||||
open: false,
|
||||
price: '613.89',
|
||||
productName: 'Gorgeous Frozen Ball',
|
||||
quantity: 55,
|
||||
rating: 1.646_947_205_998_534_6,
|
||||
releaseDate: '2024-10-13T12:31:04.929Z',
|
||||
status: 'warning',
|
||||
tags: ['Handmade', 'Unbranded', 'Unbranded'],
|
||||
weight: 9.430_690_557_758_114,
|
||||
},
|
||||
];
|
||||
80
Yi.Vben5.Vue3/docs/src/demos/vben-vxe-table/tree/index.vue
Normal file
80
Yi.Vben5.Vue3/docs/src/demos/vben-vxe-table/tree/index.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
import { Button } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
|
||||
import { MOCK_TREE_TABLE_DATA } from '../table-data';
|
||||
|
||||
interface RowType {
|
||||
date: string;
|
||||
id: number;
|
||||
name: string;
|
||||
parentId: null | number;
|
||||
size: number;
|
||||
type: string;
|
||||
}
|
||||
|
||||
// 数据实例
|
||||
// const MOCK_TREE_TABLE_DATA = [
|
||||
// {
|
||||
// date: '2020-08-01',
|
||||
// id: 10_000,
|
||||
// name: 'Test1',
|
||||
// parentId: null,
|
||||
// size: 1024,
|
||||
// type: 'mp3',
|
||||
// },
|
||||
// {
|
||||
// date: '2021-04-01',
|
||||
// id: 10_050,
|
||||
// name: 'Test2',
|
||||
// parentId: 10_000,
|
||||
// size: 0,
|
||||
// type: 'mp4',
|
||||
// },
|
||||
// ];
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ type: 'seq', width: 70 },
|
||||
{ field: 'name', minWidth: 300, title: 'Name', treeNode: true },
|
||||
{ field: 'size', title: 'Size' },
|
||||
{ field: 'type', title: 'Type' },
|
||||
{ field: 'date', title: 'Date' },
|
||||
],
|
||||
data: MOCK_TREE_TABLE_DATA,
|
||||
pagerConfig: {
|
||||
enabled: false,
|
||||
},
|
||||
treeConfig: {
|
||||
parentField: 'parentId',
|
||||
rowField: 'id',
|
||||
transform: true,
|
||||
},
|
||||
};
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
|
||||
|
||||
const expandAll = () => {
|
||||
gridApi.grid?.setAllTreeExpand(true);
|
||||
};
|
||||
|
||||
const collapseAll = () => {
|
||||
gridApi.grid?.setAllTreeExpand(false);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vp-raw h-[300px] w-full">
|
||||
<Grid>
|
||||
<template #toolbar-tools>
|
||||
<Button class="mr-2" type="primary" @click="expandAll">
|
||||
展开全部
|
||||
</Button>
|
||||
<Button type="primary" @click="collapseAll"> 折叠全部 </Button>
|
||||
</template>
|
||||
</Grid>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,64 @@
|
||||
<script lang="ts" setup>
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
|
||||
interface RowType {
|
||||
id: number;
|
||||
name: string;
|
||||
role: string;
|
||||
sex: string;
|
||||
}
|
||||
|
||||
const gridOptions: VxeGridProps<RowType> = {
|
||||
columns: [
|
||||
{ type: 'seq', width: 70 },
|
||||
{ field: 'name', title: 'Name' },
|
||||
{ field: 'role', title: 'Role' },
|
||||
{ field: 'sex', title: 'Sex' },
|
||||
],
|
||||
data: [],
|
||||
height: 'auto',
|
||||
pagerConfig: {
|
||||
enabled: false,
|
||||
},
|
||||
scrollY: {
|
||||
enabled: true,
|
||||
gt: 0,
|
||||
},
|
||||
showOverflow: true,
|
||||
};
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
|
||||
|
||||
// 模拟行数据
|
||||
const loadList = (size = 200) => {
|
||||
try {
|
||||
const dataList: RowType[] = [];
|
||||
for (let i = 0; i < size; i++) {
|
||||
dataList.push({
|
||||
id: 10_000 + i,
|
||||
name: `Test${i}`,
|
||||
role: 'Developer',
|
||||
sex: '男',
|
||||
});
|
||||
}
|
||||
gridApi.setGridOptions({ data: dataList });
|
||||
} catch (error) {
|
||||
console.error('Failed to load data:', error);
|
||||
// Implement user-friendly error handling
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
loadList(1000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vp-raw h-[500px] w-full">
|
||||
<Grid />
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user