Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions frontend/src/global/use-logo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ export const useLogo = async () => {
globalStore.themeConfig.loginBackground = res.data?.loginBackground;
globalStore.themeConfig.loginBtnLinkColor = res.data?.loginBtnLinkColor;
globalStore.themeConfig.favicon = res.data.favicon;
try {
globalStore.watermark = JSON.parse(res.data.watermark);
} catch {
globalStore.watermark = null;
}
}

const link = (document.querySelector("link[rel*='icon']") || document.createElement('link')) as HTMLLinkElement;
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/lang/modules/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1590,6 +1590,17 @@ const message = {
userChangeHelper: 'Changing the panel user will log you out. Continue?',
passwd: 'Panel password',
emailHelper: 'For password retrieval',
watermark: 'Watermark Settings',
watermarkContent: 'Watermark Content',
contentHelper: 'Use {0} to represent the current node name and node IP',
watermarkColor: 'Watermark Color',
watermarkFont: 'Watermark Font Size',
watermarkHeight: 'Watermark Height',
watermarkWidth: 'Watermark Width',
watermarkRotate: 'Rotation Angle',
watermarkGap: 'Spacing',
watermarkCloseHelper: 'Are you sure you want to turn off the system watermark settings?',
watermarkOpenHelper: 'Are you sure you want to save the current system watermark settings?',
title: 'Panel alias',
panelPort: 'Panel port',
titleHelper:
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/lang/modules/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1535,6 +1535,17 @@ const message = {
userChangeHelper: 'パネルユーザーを変更すると、ログアウトします。続く?',
passwd: 'パネルパスワード',
emailHelper: 'パスワード取得用',
watermark: '透かし設定',
watermarkContent: '透かし内容',
contentHelper: '{0} を使用して現在のノード名とノードIPを表す',
watermarkColor: '透かしの色',
watermarkFont: '透かしのフォントサイズ',
watermarkHeight: '透かしの高さ',
watermarkWidth: '透かしの幅',
watermarkRotate: '回転角度',
watermarkGap: '間隔',
watermarkCloseHelper: 'システムの透かし設定を無効にしてもよろしいですか?',
watermarkOpenHelper: '現在のシステム透かし設定を保存してもよろしいですか?',
title: 'パネルエイリアス',
panelPort: 'パネルポート',
titleHelper: '英語、漢字、数字、スペース、および一般的な特殊文字を含む3~30文字の長さをサポートします',
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/lang/modules/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1519,6 +1519,17 @@ const message = {
userChangeHelper: '패널 사용자를 변경하면 로그아웃됩니다. 계속하시겠습니까?',
passwd: '패널 비밀번호',
emailHelper: '비밀번호 복구용',
watermark: '워터마크 설정',
watermarkContent: '워터마크 내용',
contentHelper: '{0}을 사용하여 현재 노드 이름과 노드 IP를 나타냅니다',
watermarkColor: '워터마크 색상',
watermarkFont: '워터마크 글꼴 크기',
watermarkHeight: '워터마크 높이',
watermarkWidth: '워터마크 너비',
watermarkRotate: '회전 각도',
watermarkGap: '간격',
watermarkCloseHelper: '시스템 워터마크 설정을 해제하시겠습니까?',
watermarkOpenHelper: '현재 시스템 워터마크 설정을 저장하시겠습니까?',
title: '패널 별칭',
panelPort: '패널 포트',
titleHelper: '영문자, 한자, 숫자, 공백, 일반 특수 문자를 포함하여 3~30자의 길이를 지원합니다.',
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/lang/modules/ms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1579,6 +1579,17 @@ const message = {
userChangeHelper: 'Menukar pengguna panel akan menyebabkan anda log keluar. Teruskan?',
passwd: 'Kata laluan panel',
emailHelper: 'Untuk pemulihan kata laluan',
watermark: 'Tetapan Tanda Air',
watermarkContent: 'Kandungan Tanda Air',
contentHelper: 'Gunakan {0} untuk mewakili nama nod semasa dan IP nod',
watermarkColor: 'Warna Tanda Air',
watermarkFont: 'Saiz Fon Tanda Air',
watermarkHeight: 'Ketinggian Tanda Air',
watermarkWidth: 'Lebar Tanda Air',
watermarkRotate: 'Sudut Putaran',
watermarkGap: 'Jarak',
watermarkCloseHelper: 'Adakah anda pasti ingin mematikan tetapan tanda air sistem?',
watermarkOpenHelper: 'Adakah anda pasti ingin menyimpan tetapan tanda air sistem semasa?',
title: 'Alias panel',
panelPort: 'Port panel',
titleHelper:
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/lang/modules/pt-br.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1566,6 +1566,17 @@ const message = {
userChangeHelper: 'Alterar o usuário do painel irá desconectá-lo. Continuar?',
passwd: 'Senha do painel',
emailHelper: 'Para recuperação de senha',
watermark: 'Configurações de Marca d Água',
watermarkContent: 'Conteúdo da Marca d Água',
contentHelper: 'Use {0} para representar o nome do nó atual e o IP do nó',
watermarkColor: 'Cor da Marca d Água',
watermarkFont: 'Tamanho da Fonte da Marca d Água',
watermarkHeight: 'Altura da Marca d Água',
watermarkWidth: 'Largura da Marca d Água',
watermarkRotate: 'Ângulo de Rotação',
watermarkGap: 'Espaçamento',
watermarkCloseHelper: 'Tem certeza de que deseja desativar as configurações de marca d água do sistema?',
watermarkOpenHelper: 'Tem certeza de que deseja salvar as configurações atuais de marca d água do sistema?',
title: 'Alias do painel',
panelPort: 'Porta do painel',
titleHelper:
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/lang/modules/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1568,6 +1568,17 @@ const message = {
userChangeHelper: 'Изменение пользователя панели приведет к выходу из системы. Продолжить?',
passwd: 'Пароль панели',
emailHelper: 'Для восстановления пароля',
watermark: 'Настройки Водяного Знака',
watermarkContent: 'Содержимое Водяного Знака',
contentHelper: 'Используйте {0} для обозначения текущего имени узла и IP-адреса узла',
watermarkColor: 'Цвет Водяного Знака',
watermarkFont: 'Размер Шрифта Водяного Знака',
watermarkHeight: 'Высота Водяного Знака',
watermarkWidth: 'Ширина Водяного Знака',
watermarkRotate: 'Угол Поворота',
watermarkGap: 'Интервал',
watermarkCloseHelper: 'Вы уверены, что хотите отключить настройки системного водяного знака?',
watermarkOpenHelper: 'Вы уверены, что хотите сохранить текущие настройки системного водяного знака?',
title: 'Псевдоним панели',
panelPort: 'Порт панели',
titleHelper:
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/lang/modules/tr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1608,6 +1608,17 @@ const message = {
userChangeHelper: 'Panel kullanıcısını değiştirmek sizi oturumdan çıkaracak. Devam etmek istiyor musunuz?',
passwd: 'Panel parolası',
emailHelper: 'Parola kurtarma için',
watermark: 'Filigran Ayarları',
watermarkContent: 'Filigran İçeriği',
contentHelper: 'Mevcut düğüm adını ve düğüm IP sini temsil etmek için {0} kullanın',
watermarkColor: 'Filigran Rengi',
watermarkFont: 'Filigran Yazı Tipi Boyutu',
watermarkHeight: 'Filigran Yüksekliği',
watermarkWidth: 'Filigran Genişliği',
watermarkRotate: 'Döndürme Açısı',
watermarkGap: 'Aralık',
watermarkCloseHelper: 'Sistem filigran ayarlarını kapatmak istediğinizden emin misiniz?',
watermarkOpenHelper: 'Mevcut sistem filigran ayarlarını kaydetmek istediğinizden emin misiniz?',
title: 'Panel takma adı',
panelPort: 'Panel portu',
titleHelper:
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/lang/modules/zh-Hant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,17 @@ const message = {
userChangeHelper: '修改面板用户将退出登录,是否继续?',
passwd: '面板密码',
emailHelper: '用於密碼找回',
watermark: '浮水印設定',
watermarkContent: '浮水印內容',
contentHelper: '使用 {0} 作為目前節點名稱和節點 IP',
watermarkColor: '浮水印顏色',
watermarkFont: '浮水印字型大小',
watermarkHeight: '浮水印高度',
watermarkWidth: '浮水印寬度',
watermarkRotate: '旋轉角度',
watermarkGap: '間距',
watermarkCloseHelper: '是否確認關閉系統浮水印設定?',
watermarkOpenHelper: '是否確認儲存目前系統浮水印設定?',
title: '面板別名',
panelPort: '面板端口',
titleHelper: '支援長度 3 至 30 的英文字母、中文、數字、空格和常見的特殊符號。',
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/lang/modules/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1509,6 +1509,17 @@ const message = {
userChangeHelper: '修改面板用户将退出登陆,是否继续?',
passwd: '面板密码',
emailHelper: '用于密码找回',
watermark: '水印设置',
watermarkContent: '水印内容',
contentHelper: '使用 {0} 作为当前节点名称和节点 IP',
watermarkColor: '水印颜色',
watermarkFont: '水印字号',
watermarkHeight: '水印高度',
watermarkWidth: '水印宽度',
watermarkRotate: '旋转角',
watermarkGap: '间距',
watermarkCloseHelper: '是否确认关闭系统水印设置',
watermarkOpenHelper: '是否确认保存当前系统水印设置',
title: '面板别名',
titleHelper: '支持长度3-30的英文、中文、数字、空格和常见的特殊字符',
panelPort: '面板端口',
Expand Down
25 changes: 24 additions & 1 deletion frontend/src/layout/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,20 @@
<div class="main-container">
<mobile-header v-if="classObj.mobile" />
<Tabs v-if="classObj.openMenuTabs" />
<app-main :keep-alive="classObj.openMenuTabs ? tabsStore.cachedTabs : null" class="app-main" />
<el-watermark
v-if="globalStore.isMasterProductPro && globalStore.watermark"
class="app-main"
:content="loadContent()"
:font="{
fontSize: globalStore.watermark.fontSize,
color: globalStore.watermark.color,
}"
:rotate="globalStore.watermark.rotate"
:gap="[globalStore.watermark.gap, globalStore.watermark.gap]"
>
<app-main :keep-alive="classObj.openMenuTabs ? tabsStore.cachedTabs : null" />
</el-watermark>
<app-main class="app-main" v-else :keep-alive="classObj.openMenuTabs ? tabsStore.cachedTabs : null" />
<Footer class="app-footer" v-if="!globalStore.isFullScreen" />
<TaskList ref="taskListRef" />
</div>
Expand All @@ -44,6 +57,7 @@ import { useRoute, useRouter } from 'vue-router';
import { loadMasterProductProFromDB, loadProductProFromDB } from '@/utils/xpack';
import { useTheme } from '@/global/use-theme';
import TaskList from '@/components/task-list/index.vue';
import i18n from '@/lang';
const { switchTheme } = useTheme();

useResize();
Expand Down Expand Up @@ -84,6 +98,15 @@ const handleCollapse = () => {
menuStore.setCollapse();
};

const loadContent = () => {
let itemName = globalStore.watermark.content.replaceAll(
'${nodeName}',
globalStore.currentNode === 'local' ? i18n.global.t('xpack.node.master') : globalStore.currentNode,
);
itemName = itemName.replaceAll('${nodeAddr}', globalStore.currentNodeAddr);
return itemName;
};

watch(
() => globalStore.isLoading,
() => {
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/store/interface/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ export interface ThemeConfigProp {
themeColor: string;
}

export interface Watermark {
color: string,
fontSize: number,
content: string,
rotate: number,
gap: number,
}

export interface GlobalState {
isLoading: boolean;
loadingText: string;
Expand All @@ -26,6 +34,7 @@ export interface GlobalState {
themeConfig: ThemeConfigProp;
isFullScreen: boolean;
openMenuTabs: boolean;
watermark: Watermark;
isOnRestart: boolean;
agreeLicense: boolean;
hasNewVersion: boolean;
Expand Down
1 change: 1 addition & 0 deletions frontend/src/store/modules/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const GlobalStore = defineStore({
loginBgType: '',
loginBtnLinkColor: '',
},
watermark: null,
openMenuTabs: false,
isFullScreen: false,
isOnRestart: false,
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/utils/xpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export function resetXSetting() {
globalStore.themeConfig.logo = '';
globalStore.themeConfig.logoWithText = '';
globalStore.themeConfig.favicon = '';
globalStore.watermark = null;
}

export function initFavicon() {
Expand Down Expand Up @@ -119,6 +120,11 @@ export async function getXpackSettingForTheme() {
if (res2.data?.theme) {
globalStore.themeConfig.theme = res2.data.theme;
}
try {
globalStore.watermark = JSON.parse(res2.data.watermark);
} catch {
globalStore.watermark = null;
}
} else {
resetXSetting();
}
Expand Down
52 changes: 52 additions & 0 deletions frontend/src/views/setting/panel/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,24 @@
</el-radio-group>
</el-form-item>

<el-form-item :label="$t('setting.watermark')" v-if="isMasterProductPro" prop="watermark">
<el-radio-group class="w-full" @change="onChangeWatermark" v-model="form.watermarkItem">
<el-radio-button value="Enable">
<span>{{ $t('commons.button.enable') }}</span>
</el-radio-button>
<el-radio-button value="Disable">
<span>{{ $t('commons.button.disable') }}</span>
</el-radio-button>
</el-radio-group>
<div v-if="form.watermarkItem === 'Enable'">
<div>
<el-button link type="primary" @click="onChangeWatermark">
{{ $t('commons.button.view') }}
</el-button>
</div>
</div>
</el-form-item>

<el-form-item :label="$t('setting.title')" prop="panelName">
<el-input disabled v-model="form.panelName">
<template #append>
Expand Down Expand Up @@ -198,6 +216,7 @@
<Timeout ref="timeoutRef" @search="search()" />
<HideMenu ref="hideMenuRef" @search="search()" />
<ThemeColor ref="themeColorRef" />
<Watermark ref="watermarkRef" @search="search()" />
</div>
</template>

Expand All @@ -217,6 +236,7 @@ import { MsgSuccess } from '@/utils/message';
import ThemeColor from '@/views/setting/panel/theme-color/index.vue';
import ApiInterface from '@/views/setting/panel/api-interface/index.vue';
import Password from '@/views/setting/panel/password/index.vue';
import Watermark from '@/views/setting/panel/watermark/index.vue';
import UserName from '@/views/setting/panel/username/index.vue';
import Timeout from '@/views/setting/panel/timeout/index.vue';
import PanelName from '@/views/setting/panel/name/index.vue';
Expand Down Expand Up @@ -253,6 +273,8 @@ const form = reactive({
sessionTimeout: 0,
panelName: '',
theme: '',
watermark: '',
watermarkItem: '',
themeColor: {} as ThemeColor,
menuTabs: '',
language: '',
Expand Down Expand Up @@ -286,6 +308,7 @@ const systemIPRef = ref();
const proxyRef = ref();
const timeoutRef = ref();
const hideMenuRef = ref();
const watermarkRef = ref();
const themeColorRef = ref();
const apiInterfaceRef = ref();
const unset = ref(i18n.global.t('setting.unSetting'));
Expand Down Expand Up @@ -347,6 +370,8 @@ const search = async () => {
: '{"light":"#005eeb","dark":"#F0BE96"}';
globalStore.themeConfig.theme = form.theme;
form.proxyDocker = xpackRes.data.proxyDocker;
form.watermark = xpackRes.data.watermark;
form.watermarkItem = xpackRes.data.watermark ? 'Enable' : 'Disable';
}
} else {
globalStore.themeConfig.theme = form.theme;
Expand Down Expand Up @@ -389,6 +414,33 @@ const onChangeThemeColor = () => {
themeColorRef.value.acceptParams({ themeColor: themeColor, theme: globalStore.themeConfig.theme });
};

const onChangeWatermark = async () => {
if (form.watermarkItem === 'Enable') {
watermarkRef.value.acceptParams(form.watermark);
return;
}
ElMessageBox.confirm(i18n.global.t('setting.watermarkCloseHelper'), i18n.global.t('setting.watermark'), {
confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'),
})
.then(async () => {
loading.value = true;
await updateXpackSettingByKey('Watermark', '')
.then(() => {
loading.value = false;
globalStore.watermark = null;
search();
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {
loading.value = false;
});
})
.catch(() => {
form.watermarkItem = 'Enable';
});
};

const onChangeApiInterfaceStatus = async () => {
if (form.apiInterfaceStatus === 'Enable') {
apiInterfaceRef.value.acceptParams({
Expand Down
Loading
Loading