This commit is contained in:
xingyu4j
2025-11-24 11:47:31 +08:00
185 changed files with 2651 additions and 939 deletions

View File

@@ -71,17 +71,10 @@ const modelValue = defineModel({ default: '', type: String });
const visible = ref(false);
const currentSelect = ref('');
const currentPage = ref(1);
const keyword = ref('');
const keywordDebounce = refDebounced(keyword, 300);
const innerIcons = ref<string[]>([]);
/* 当检索关键词变化时,重置分页 */
watch(keywordDebounce, () => {
currentPage.value = 1;
setCurrentPage(1);
});
watchDebounced(
() => props.prefix,
async (prefix) => {
@@ -122,7 +115,7 @@ const showList = computed(() => {
);
});
const { paginationList, total, setCurrentPage } = usePagination(
const { paginationList, total, setCurrentPage, currentPage } = usePagination(
showList,
props.pageSize,
);
@@ -145,7 +138,6 @@ const handleClick = (icon: string) => {
};
const handlePageChange = (page: number) => {
currentPage.value = page;
setCurrentPage(page);
};

View File

@@ -55,16 +55,12 @@ function handleClick(event: MouseEvent) {
return;
}
const param: JsonViewerValue = {
path: '',
value: '',
depth: 0,
el: event.target,
path: pathNode.getAttribute('path') || '',
depth: Number(pathNode.getAttribute('depth')) || 0,
value: event.target.textContent || undefined,
};
param.path = pathNode.getAttribute('path') || '';
param.depth = Number(pathNode.getAttribute('depth')) || 0;
param.value = event.target.textContent || undefined;
param.value = JSON.parse(param.value);
emit('valueClick', param);
}

View File

@@ -618,13 +618,11 @@ const stickStyles = computed(() => (stick: string) => {
const stickStyle = {
width: `${stickSize.value / parentScaleX.value}px`,
height: `${stickSize.value / parentScaleY.value}px`,
[styleMapping.y[stick[0] as 'b' | 'm' | 't'] as 'height' | 'width']:
`${stickSize.value / parentScaleX.value / -2}px`,
[styleMapping.x[stick[1] as 'l' | 'm' | 'r'] as 'height' | 'width']:
`${stickSize.value / parentScaleX.value / -2}px`,
};
stickStyle[
styleMapping.y[stick[0] as 'b' | 'm' | 't'] as 'height' | 'width'
] = `${stickSize.value / parentScaleX.value / -2}px`;
stickStyle[
styleMapping.x[stick[1] as 'l' | 'm' | 'r'] as 'height' | 'width'
] = `${stickSize.value / parentScaleX.value / -2}px`;
return stickStyle;
});

View File

@@ -2,3 +2,4 @@ export * from './about';
export * from './authentication';
export * from './dashboard';
export * from './fallback';
export * from './profile';

View File

@@ -0,0 +1,56 @@
<script setup lang="ts">
import type { Recordable } from '@vben/types';
import type { VbenFormSchema } from '@vben-core/form-ui';
import { computed, reactive } from 'vue';
import { useVbenForm } from '@vben-core/form-ui';
import { VbenButton } from '@vben-core/shadcn-ui';
interface Props {
formSchema?: VbenFormSchema[];
}
const props = withDefaults(defineProps<Props>(), {
formSchema: () => [],
});
const emit = defineEmits<{
submit: [Recordable<any>];
}>();
const [Form, formApi] = useVbenForm(
reactive({
commonConfig: {
// 所有表单项
componentProps: {
class: 'w-full',
},
},
layout: 'horizontal',
schema: computed(() => props.formSchema),
showDefaultActions: false,
}),
);
async function handleSubmit() {
const { valid } = await formApi.validate();
const values = await formApi.getValues();
if (valid) {
emit('submit', values);
}
}
defineExpose({
getFormApi: () => formApi,
});
</script>
<template>
<div @keydown.enter.prevent="handleSubmit">
<Form />
<VbenButton type="submit" class="mt-4" @click="handleSubmit">
更新基本信息
</VbenButton>
</div>
</template>

View File

@@ -0,0 +1,6 @@
export { default as ProfileBaseSetting } from './base-setting.vue';
export { default as ProfileNotificationSetting } from './notification-setting.vue';
export { default as ProfilePasswordSetting } from './password-setting.vue';
export { default as Profile } from './profile.vue';
export { default as ProfileSecuritySetting } from './security-setting.vue';
export type * from './types';

View File

@@ -0,0 +1,53 @@
<script setup lang="ts">
import type { Recordable } from '@vben/types';
import type { SettingProps } from './types';
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
Switch,
} from '@vben-core/shadcn-ui';
withDefaults(defineProps<SettingProps>(), {
formSchema: () => [],
});
const emit = defineEmits<{
change: [Recordable<any>];
}>();
function handleChange(fieldName: string, value: boolean) {
emit('change', { fieldName, value });
}
</script>
<template>
<Form class="space-y-8">
<div class="space-y-4">
<template v-for="item in formSchema" :key="item.fieldName">
<FormField type="checkbox" :name="item.fieldName">
<FormItem
class="flex flex-row items-center justify-between rounded-lg border p-4"
>
<div class="space-y-0.5">
<FormLabel class="text-base"> {{ item.label }} </FormLabel>
<FormDescription>
{{ item.description }}
</FormDescription>
</div>
<FormControl>
<Switch
:model-value="item.value"
@update:model-value="handleChange(item.fieldName, $event)"
/>
</FormControl>
</FormItem>
</FormField>
</template>
</div>
</Form>
</template>

View File

@@ -0,0 +1,56 @@
<script setup lang="ts">
import type { Recordable } from '@vben/types';
import type { VbenFormSchema } from '@vben-core/form-ui';
import { computed, reactive } from 'vue';
import { useVbenForm } from '@vben-core/form-ui';
import { VbenButton } from '@vben-core/shadcn-ui';
interface Props {
formSchema?: VbenFormSchema[];
}
const props = withDefaults(defineProps<Props>(), {
formSchema: () => [],
});
const emit = defineEmits<{
submit: [Recordable<any>];
}>();
const [Form, formApi] = useVbenForm(
reactive({
commonConfig: {
// 所有表单项
componentProps: {
class: 'w-full',
},
},
layout: 'horizontal',
schema: computed(() => props.formSchema),
showDefaultActions: false,
}),
);
async function handleSubmit() {
const { valid } = await formApi.validate();
const values = await formApi.getValues();
if (valid) {
emit('submit', values);
}
}
defineExpose({
getFormApi: () => formApi,
});
</script>
<template>
<div>
<Form />
<VbenButton type="submit" class="mt-4" @click="handleSubmit">
更新密码
</VbenButton>
</div>
</template>

View File

@@ -0,0 +1,62 @@
<script setup lang="ts">
import type { Props } from './types';
import { preferences } from '@vben-core/preferences';
import {
Card,
Separator,
Tabs,
TabsList,
TabsTrigger,
VbenAvatar,
} from '@vben-core/shadcn-ui';
import { Page } from '../../components';
defineOptions({
name: 'ProfileUI',
});
withDefaults(defineProps<Props>(), {
title: '关于项目',
tabs: () => [],
});
const tabsValue = defineModel<string>('modelValue');
</script>
<template>
<Page auto-content-height>
<div class="flex h-full w-full">
<Card class="w-1/6 flex-none">
<div class="mt-4 flex h-40 flex-col items-center justify-center gap-4">
<VbenAvatar
:src="userInfo?.avatar ?? preferences.app.defaultAvatar"
class="size-20"
/>
<span class="text-lg font-semibold">
{{ userInfo?.realName ?? '' }}
</span>
<span class="text-foreground/80 text-sm">
{{ userInfo?.username ?? '' }}
</span>
</div>
<Separator class="my-4" />
<Tabs v-model="tabsValue" orientation="vertical" class="m-4">
<TabsList class="bg-card grid w-full grid-cols-1">
<TabsTrigger
v-for="tab in tabs"
:key="tab.value"
:value="tab.value"
class="data-[state=active]:bg-primary data-[state=active]:text-primary-foreground h-12 justify-start"
>
{{ tab.label }}
</TabsTrigger>
</TabsList>
</Tabs>
</Card>
<Card class="ml-4 w-5/6 flex-auto p-8">
<slot name="content"></slot>
</Card>
</div>
</Page>
</template>

View File

@@ -0,0 +1,53 @@
<script setup lang="ts">
import type { Recordable } from '@vben/types';
import type { SettingProps } from './types';
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
Switch,
} from '@vben-core/shadcn-ui';
withDefaults(defineProps<SettingProps>(), {
formSchema: () => [],
});
const emit = defineEmits<{
change: [Recordable<any>];
}>();
function handleChange(fieldName: string, value: boolean) {
emit('change', { fieldName, value });
}
</script>
<template>
<Form class="space-y-8">
<div class="space-y-4">
<template v-for="item in formSchema" :key="item.fieldName">
<FormField type="checkbox" :name="item.fieldName">
<FormItem
class="flex flex-row items-center justify-between rounded-lg border p-4"
>
<div class="space-y-0.5">
<FormLabel class="text-base"> {{ item.label }} </FormLabel>
<FormDescription>
{{ item.description }}
</FormDescription>
</div>
<FormControl>
<Switch
:model-value="item.value"
@update:model-value="handleChange(item.fieldName, $event)"
/>
</FormControl>
</FormItem>
</FormField>
</template>
</div>
</Form>
</template>

View File

@@ -0,0 +1,21 @@
import type { BasicUserInfo } from '@vben/types';
export interface Props {
title?: string;
userInfo: BasicUserInfo | null;
tabs: {
label: string;
value: string;
}[];
}
export interface FormSchemaItem {
description: string;
fieldName: string;
label: string;
value: boolean;
}
export interface SettingProps {
formSchema: FormSchemaItem[];
}