feat: 1、新增水印文案自定义功能;2、input-item输入框组件新增清除功能(可用于快捷清除水印文案);3、偏好设置、主题切换、语言选择、是否全屏按钮新增动画效果 (#6800)

* feature: 新增水印文案自定义功能;

* chore: 偏好设置、主题切换、语言选择、是否全屏按钮新增动画效果
This commit is contained in:
zouawen 2025-10-07 06:15:41 +08:00 committed by GitHub
parent 33306a5aff
commit 2ce161e585
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 92 additions and 19 deletions

View File

@ -106,11 +106,16 @@ function handleMakeAll() {
notifications.value.forEach((item) => (item.isRead = true));
}
watch(
() => preferences.app.watermark,
async (enable) => {
() => ({
enable: preferences.app.watermark,
content: preferences.app.watermarkContent,
}),
async ({ enable, content }) => {
if (enable) {
await updateWatermark({
content: `${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,
content:
content ||
`${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,
});
} else {
destroyWatermark();

View File

@ -106,11 +106,16 @@ function handleMakeAll() {
notifications.value.forEach((item) => (item.isRead = true));
}
watch(
() => preferences.app.watermark,
async (enable) => {
() => ({
enable: preferences.app.watermark,
content: preferences.app.watermarkContent,
}),
async ({ enable, content }) => {
if (enable) {
await updateWatermark({
content: `${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,
content:
content ||
`${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,
});
} else {
destroyWatermark();

View File

@ -107,11 +107,16 @@ function handleMakeAll() {
}
watch(
() => preferences.app.watermark,
async (enable) => {
() => ({
enable: preferences.app.watermark,
content: preferences.app.watermarkContent,
}),
async ({ enable, content }) => {
if (enable) {
await updateWatermark({
content: `${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,
content:
content ||
`${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,
});
} else {
destroyWatermark();

View File

@ -85,3 +85,17 @@
.z-popup {
z-index: var(--popup-z-index);
}
@keyframes shrink {
0% {
transform: scale(1);
}
50% {
transform: scale(0.9);
}
100% {
transform: scale(1);
}
}

View File

@ -29,6 +29,7 @@ const defaultPreferences: Preferences = {
name: 'Vben Admin',
preferencesButtonPosition: 'auto',
watermark: false,
watermarkContent: '',
zIndex: 200,
},
breadcrumb: {

View File

@ -75,6 +75,10 @@ interface AppPreferences {
* @zh_CN
*/
watermark: boolean;
/**
* @zh_CN
*/
watermarkContent: string;
/** z-index */
zIndex: number;
}

View File

@ -21,7 +21,10 @@ isFullscreen.value = !!(
);
</script>
<template>
<VbenIconButton @click="toggle">
<VbenIconButton
class="hover:animate-[shrink_0.3s_ease-in-out]"
@click="toggle"
>
<Minimize v-if="isFullscreen" class="text-foreground size-4" />
<Maximize v-else class="text-foreground size-4" />
</VbenIconButton>

View File

@ -31,7 +31,7 @@ async function handleUpdate(value: string | undefined) {
:model-value="preferences.app.locale"
@update:model-value="handleUpdate"
>
<VbenIconButton>
<VbenIconButton class="hover:animate-[shrink_0.3s_ease-in-out]">
<Languages class="text-foreground size-4" />
</VbenIconButton>
</VbenDropdownRadioMenu>

View File

@ -2,6 +2,7 @@
import { SUPPORT_LANGUAGES } from '@vben/constants';
import { $t } from '@vben/locales';
import InputItem from '../input-item.vue';
import SelectItem from '../select-item.vue';
import SwitchItem from '../switch-item.vue';
@ -12,6 +13,7 @@ defineOptions({
const appLocale = defineModel<string>('appLocale');
const appDynamicTitle = defineModel<boolean>('appDynamicTitle');
const appWatermark = defineModel<boolean>('appWatermark');
const appWatermarkContent = defineModel<string>('appWatermarkContent');
const appEnableCheckUpdates = defineModel<boolean>('appEnableCheckUpdates');
</script>
@ -22,9 +24,23 @@ const appEnableCheckUpdates = defineModel<boolean>('appEnableCheckUpdates');
<SwitchItem v-model="appDynamicTitle">
{{ $t('preferences.dynamicTitle') }}
</SwitchItem>
<SwitchItem v-model="appWatermark">
<SwitchItem
v-model="appWatermark"
@update:model-value="
(val) => {
if (!val) appWatermarkContent = '';
}
"
>
{{ $t('preferences.watermark') }}
</SwitchItem>
<InputItem
v-if="appWatermark"
v-model="appWatermarkContent"
:placeholder="$t('preferences.watermarkContent')"
>
{{ $t('preferences.watermarkContent') }}
</InputItem>
<SwitchItem v-model="appEnableCheckUpdates">
{{ $t('preferences.checkUpdates') }}
</SwitchItem>

View File

@ -3,7 +3,7 @@ import type { SelectOption } from '@vben/types';
import { useSlots } from 'vue';
import { CircleHelp } from '@vben/icons';
import { CircleHelp, CircleX } from '@vben/icons';
import { Input, VbenTooltip } from '@vben-core/shadcn-ui';
@ -47,6 +47,17 @@ const slots = useSlots();
<slot name="tip"></slot>
</VbenTooltip>
</span>
<Input v-model="inputValue" class="h-8 w-[165px]" />
<div class="relative">
<Input
v-model="inputValue"
class="h-8 w-[165px]"
:placeholder="placeholder"
/>
<CircleX
v-if="inputValue"
class="hover:text-foreground text-foreground/60 absolute right-2 top-1/2 size-3 -translate-y-1/2 transform cursor-pointer"
@click="() => (inputValue = '')"
/>
</div>
</div>
</template>

View File

@ -13,7 +13,7 @@ function clearPreferencesAndLogout() {
</script>
<template>
<Preferences @clear-preferences-and-logout="clearPreferencesAndLogout">
<VbenIconButton>
<VbenIconButton class="hover:animate-[shrink_0.3s_ease-in-out]">
<Settings class="text-foreground size-4" />
</VbenIconButton>
</Preferences>

View File

@ -67,6 +67,7 @@ const appColorGrayMode = defineModel<boolean>('appColorGrayMode');
const appColorWeakMode = defineModel<boolean>('appColorWeakMode');
const appContentCompact = defineModel<ContentCompactType>('appContentCompact');
const appWatermark = defineModel<boolean>('appWatermark');
const appWatermarkContent = defineModel<string>('appWatermarkContent');
const appEnableCheckUpdates = defineModel<boolean>('appEnableCheckUpdates');
const appPreferencesButtonPosition = defineModel<PreferencesButtonPositionType>(
'appPreferencesButtonPosition',
@ -267,6 +268,7 @@ async function handleReset() {
v-model:app-enable-check-updates="appEnableCheckUpdates"
v-model:app-locale="appLocale"
v-model:app-watermark="appWatermark"
v-model:app-watermark-content="appWatermarkContent"
/>
</Block>

View File

@ -88,7 +88,7 @@ function toggleTheme(event: MouseEvent) {
:aria-label="theme"
:class="[`is-${theme}`]"
aria-live="polite"
class="theme-toggle cursor-pointer border-none bg-none"
class="theme-toggle cursor-pointer border-none bg-none hover:animate-[shrink_0.3s_ease-in-out]"
v-bind="bindProps"
@click.stop="toggleTheme"
>

View File

@ -37,6 +37,7 @@
"language": "Language",
"dynamicTitle": "Dynamic Title",
"watermark": "Watermark",
"watermarkContent": "Please input Watermark content",
"checkUpdates": "Periodic update check",
"position": {
"title": "Preferences Postion",

View File

@ -37,6 +37,7 @@
"language": "语言",
"dynamicTitle": "动态标题",
"watermark": "水印",
"watermarkContent": "请输入水印文案",
"checkUpdates": "定时检查更新",
"position": {
"title": "偏好设置位置",

View File

@ -122,11 +122,16 @@ function handleMakeAll() {
function handleClickLogo() {}
watch(
() => preferences.app.watermark,
async (enable) => {
() => ({
enable: preferences.app.watermark,
content: preferences.app.watermarkContent,
}),
async ({ enable, content }) => {
if (enable) {
await updateWatermark({
content: `${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,
content:
content ||
`${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,
});
} else {
destroyWatermark();