mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-02 15:30:25 +08:00
feat: i18n
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"@vueuse/core": "^11.1.0",
|
||||
"@vueuse/core": "^11.2.0",
|
||||
"asciinema-player": "^3.8.1",
|
||||
"axios": "^1.6.2",
|
||||
"clipboard": "^2.0.11",
|
||||
@@ -19,7 +19,7 @@
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"echarts": "^5.5.1",
|
||||
"element-plus": "^2.8.6",
|
||||
"element-plus": "^2.8.8",
|
||||
"js-base64": "^3.7.7",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"lodash": "^4.17.21",
|
||||
@@ -28,7 +28,7 @@
|
||||
"monaco-sql-languages": "^0.12.2",
|
||||
"monaco-themes": "^0.4.4",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.2.5",
|
||||
"pinia": "^2.2.6",
|
||||
"qrcode.vue": "^3.5.1",
|
||||
"screenfull": "^6.0.2",
|
||||
"sortablejs": "^1.15.3",
|
||||
@@ -36,7 +36,8 @@
|
||||
"sql-formatter": "^15.4.5",
|
||||
"trzsz": "^1.1.5",
|
||||
"uuid": "^9.0.1",
|
||||
"vue": "^3.5.12",
|
||||
"vue": "^3.5.13",
|
||||
"vue-i18n": "^10.0.4",
|
||||
"vue-router": "^4.4.5",
|
||||
"xterm": "^5.3.0",
|
||||
"xterm-addon-fit": "^0.8.0",
|
||||
@@ -51,16 +52,16 @@
|
||||
"@types/sortablejs": "^1.15.8",
|
||||
"@typescript-eslint/eslint-plugin": "^6.7.4",
|
||||
"@typescript-eslint/parser": "^6.7.4",
|
||||
"@vitejs/plugin-vue": "^5.1.4",
|
||||
"@vue/compiler-sfc": "^3.5.12",
|
||||
"@vitejs/plugin-vue": "^5.2.0",
|
||||
"@vue/compiler-sfc": "^3.5.13",
|
||||
"code-inspector-plugin": "^0.4.5",
|
||||
"dotenv": "^16.3.1",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-plugin-vue": "^9.28.0",
|
||||
"prettier": "^3.2.5",
|
||||
"sass": "^1.80.5",
|
||||
"sass": "^1.80.6",
|
||||
"typescript": "^5.6.3",
|
||||
"vite": "^5.4.10",
|
||||
"vite": "^5.4.11",
|
||||
"vue-eslint-parser": "^9.4.3"
|
||||
},
|
||||
"browserslist": [
|
||||
@@ -68,4 +69,4 @@
|
||||
"last 2 versions",
|
||||
"not dead"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
<template>
|
||||
<div class="h100">
|
||||
<el-watermark
|
||||
:zIndex="10000000"
|
||||
:width="210"
|
||||
v-if="themeConfig.isWatermark"
|
||||
:font="{ color: 'rgba(180, 180, 180, 0.3)' }"
|
||||
:content="themeConfig.watermarkText"
|
||||
class="h100"
|
||||
>
|
||||
<router-view v-show="themeConfig.lockScreenTime !== 0" />
|
||||
</el-watermark>
|
||||
<router-view v-if="!themeConfig.isWatermark" v-show="themeConfig.lockScreenTime !== 0" />
|
||||
<el-config-provider :size="getGlobalComponentSize" :locale="getGlobalI18n">
|
||||
<div class="h100">
|
||||
<el-watermark
|
||||
:zIndex="10000000"
|
||||
:width="210"
|
||||
v-if="themeConfig.isWatermark"
|
||||
:font="{ color: 'rgba(180, 180, 180, 0.3)' }"
|
||||
:content="themeConfig.watermarkText"
|
||||
class="h100"
|
||||
>
|
||||
<router-view v-show="themeConfig.lockScreenTime !== 0" />
|
||||
</el-watermark>
|
||||
<router-view v-if="!themeConfig.isWatermark" v-show="themeConfig.lockScreenTime !== 0" />
|
||||
|
||||
<LockScreen v-if="themeConfig.isLockScreen" />
|
||||
<Setings ref="setingsRef" v-show="themeConfig.lockScreenTime !== 0" />
|
||||
</div>
|
||||
<LockScreen v-if="themeConfig.isLockScreen" />
|
||||
<Setings ref="setingsRef" v-show="themeConfig.lockScreenTime !== 0" />
|
||||
</div>
|
||||
</el-config-provider>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="app">
|
||||
import { ref, onMounted, onUnmounted, nextTick, watch } from 'vue';
|
||||
import { ref, onMounted, onUnmounted, nextTick, watch, computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
@@ -26,6 +28,10 @@ import LockScreen from '@/layout/lockScreen/index.vue';
|
||||
import Setings from '@/layout/navBars/breadcrumb/setings.vue';
|
||||
import mittBus from '@/common/utils/mitt';
|
||||
import { useIntervalFn } from '@vueuse/core';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import EnumValue from './common/Enum';
|
||||
import { I18nEnum } from './common/commonEnum';
|
||||
import { saveThemeConfig } from './common/utils/storage';
|
||||
|
||||
const setingsRef = ref();
|
||||
const route = useRoute();
|
||||
@@ -33,6 +39,9 @@ const route = useRoute();
|
||||
const themeConfigStores = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(themeConfigStores);
|
||||
|
||||
// 定义变量内容
|
||||
const { locale, t } = useI18n();
|
||||
|
||||
// 布局配置弹窗打开
|
||||
const openSetingsDrawer = () => {
|
||||
setingsRef.value.openDrawer();
|
||||
@@ -67,6 +76,31 @@ watch(
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => themeConfig.value.globalI18n,
|
||||
(val) => {
|
||||
locale.value = val;
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
themeConfig,
|
||||
(val) => {
|
||||
saveThemeConfig(val);
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// 获取全局组件大小
|
||||
const getGlobalComponentSize = computed(() => {
|
||||
return themeConfig.value.globalComponentSize;
|
||||
});
|
||||
|
||||
// 获取全局 i18n
|
||||
const getGlobalI18n = computed(() => {
|
||||
return EnumValue.getEnumByValue(I18nEnum, locale.value)?.extra.el;
|
||||
});
|
||||
|
||||
// 刷新水印时间
|
||||
const { pause, resume } = useIntervalFn(() => {
|
||||
if (!themeConfig.value.isWatermark) {
|
||||
@@ -96,7 +130,7 @@ watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
nextTick(() => {
|
||||
document.title = `${route.meta.title} - ${themeConfig.value.globalTitle}` || themeConfig.value.globalTitle;
|
||||
document.title = `${t((route.meta.title as string) || '')} - ${themeConfig.value.globalTitle}` || themeConfig.value.globalTitle;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,107 +1,121 @@
|
||||
{
|
||||
"id": "3953964",
|
||||
"name": "mayfly-go",
|
||||
"font_family": "iconfont",
|
||||
"css_prefix_text": "icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "23957582",
|
||||
"name": "MongoDB",
|
||||
"font_class": "mongo",
|
||||
"unicode": "e646",
|
||||
"unicode_decimal": 58950
|
||||
},
|
||||
{
|
||||
"icon_id": "4969649",
|
||||
"name": "Redis",
|
||||
"font_class": "op-redis",
|
||||
"unicode": "e728",
|
||||
"unicode_decimal": 59176
|
||||
},
|
||||
{
|
||||
"icon_id": "22442993",
|
||||
"name": "PostgreSQL",
|
||||
"font_class": "op-postgres",
|
||||
"unicode": "e8b7",
|
||||
"unicode_decimal": 59575
|
||||
},
|
||||
{
|
||||
"icon_id": "12295203",
|
||||
"name": "达梦数据库",
|
||||
"font_class": "db-dm",
|
||||
"unicode": "e6f0",
|
||||
"unicode_decimal": 59120
|
||||
},
|
||||
{
|
||||
"icon_id": "10055634",
|
||||
"name": "云数据库MongoDB",
|
||||
"font_class": "op-mongo",
|
||||
"unicode": "e7d7",
|
||||
"unicode_decimal": 59351
|
||||
},
|
||||
{
|
||||
"icon_id": "10055642",
|
||||
"name": "云数据库 RDS MySQL",
|
||||
"font_class": "op-mysql",
|
||||
"unicode": "e7d8",
|
||||
"unicode_decimal": 59352
|
||||
},
|
||||
{
|
||||
"icon_id": "3876165",
|
||||
"name": "redis",
|
||||
"font_class": "redis",
|
||||
"unicode": "e619",
|
||||
"unicode_decimal": 58905
|
||||
},
|
||||
{
|
||||
"icon_id": "25271976",
|
||||
"name": "oracle",
|
||||
"font_class": "oracle",
|
||||
"unicode": "e507",
|
||||
"unicode_decimal": 58631
|
||||
},
|
||||
{
|
||||
"icon_id": "8105644",
|
||||
"name": "mariadb",
|
||||
"font_class": "mariadb",
|
||||
"unicode": "e513",
|
||||
"unicode_decimal": 58643
|
||||
},
|
||||
{
|
||||
"icon_id": "13601813",
|
||||
"name": "sqlite",
|
||||
"font_class": "sqlite",
|
||||
"unicode": "e546",
|
||||
"unicode_decimal": 58694
|
||||
},
|
||||
{
|
||||
"icon_id": "29340317",
|
||||
"name": "temp-mssql",
|
||||
"font_class": "MSSQLNATIVE",
|
||||
"unicode": "e600",
|
||||
"unicode_decimal": 58880
|
||||
},
|
||||
{
|
||||
"icon_id": "7699332",
|
||||
"name": "gaussdb",
|
||||
"font_class": "gauss",
|
||||
"unicode": "e683",
|
||||
"unicode_decimal": 59011
|
||||
},
|
||||
{
|
||||
"icon_id": "34836637",
|
||||
"name": "kingbase",
|
||||
"font_class": "kingbase",
|
||||
"unicode": "e882",
|
||||
"unicode_decimal": 59522
|
||||
},
|
||||
{
|
||||
"icon_id": "33047500",
|
||||
"name": "vastbase",
|
||||
"font_class": "vastbase",
|
||||
"unicode": "e62b",
|
||||
"unicode_decimal": 58923
|
||||
}
|
||||
]
|
||||
}
|
||||
"id": "3953964",
|
||||
"name": "mayfly-go",
|
||||
"font_family": "iconfont",
|
||||
"css_prefix_text": "icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "2967035",
|
||||
"name": "符号-英文",
|
||||
"font_class": "fuhao-yingwen",
|
||||
"unicode": "e712",
|
||||
"unicode_decimal": 59154
|
||||
},
|
||||
{
|
||||
"icon_id": "26283783",
|
||||
"name": "符号-中文",
|
||||
"font_class": "fuhao-zhongwen",
|
||||
"unicode": "e603",
|
||||
"unicode_decimal": 58883
|
||||
},
|
||||
{
|
||||
"icon_id": "23957582",
|
||||
"name": "MongoDB",
|
||||
"font_class": "mongo",
|
||||
"unicode": "e646",
|
||||
"unicode_decimal": 58950
|
||||
},
|
||||
{
|
||||
"icon_id": "4969649",
|
||||
"name": "Redis",
|
||||
"font_class": "op-redis",
|
||||
"unicode": "e728",
|
||||
"unicode_decimal": 59176
|
||||
},
|
||||
{
|
||||
"icon_id": "22442993",
|
||||
"name": "PostgreSQL",
|
||||
"font_class": "op-postgres",
|
||||
"unicode": "e8b7",
|
||||
"unicode_decimal": 59575
|
||||
},
|
||||
{
|
||||
"icon_id": "12295203",
|
||||
"name": "达梦数据库",
|
||||
"font_class": "db-dm",
|
||||
"unicode": "e6f0",
|
||||
"unicode_decimal": 59120
|
||||
},
|
||||
{
|
||||
"icon_id": "10055634",
|
||||
"name": "云数据库MongoDB",
|
||||
"font_class": "op-mongo",
|
||||
"unicode": "e7d7",
|
||||
"unicode_decimal": 59351
|
||||
},
|
||||
{
|
||||
"icon_id": "10055642",
|
||||
"name": "云数据库 RDS MySQL",
|
||||
"font_class": "op-mysql",
|
||||
"unicode": "e7d8",
|
||||
"unicode_decimal": 59352
|
||||
},
|
||||
{
|
||||
"icon_id": "3876165",
|
||||
"name": "redis",
|
||||
"font_class": "redis",
|
||||
"unicode": "e619",
|
||||
"unicode_decimal": 58905
|
||||
},
|
||||
{
|
||||
"icon_id": "25271976",
|
||||
"name": "oracle",
|
||||
"font_class": "oracle",
|
||||
"unicode": "e507",
|
||||
"unicode_decimal": 58631
|
||||
},
|
||||
{
|
||||
"icon_id": "8105644",
|
||||
"name": "mariadb",
|
||||
"font_class": "mariadb",
|
||||
"unicode": "e513",
|
||||
"unicode_decimal": 58643
|
||||
},
|
||||
{
|
||||
"icon_id": "13601813",
|
||||
"name": "sqlite",
|
||||
"font_class": "sqlite",
|
||||
"unicode": "e546",
|
||||
"unicode_decimal": 58694
|
||||
},
|
||||
{
|
||||
"icon_id": "29340317",
|
||||
"name": "temp-mssql",
|
||||
"font_class": "MSSQLNATIVE",
|
||||
"unicode": "e600",
|
||||
"unicode_decimal": 58880
|
||||
},
|
||||
{
|
||||
"icon_id": "7699332",
|
||||
"name": "gaussdb",
|
||||
"font_class": "gauss",
|
||||
"unicode": "e683",
|
||||
"unicode_decimal": 59011
|
||||
},
|
||||
{
|
||||
"icon_id": "34836637",
|
||||
"name": "kingbase",
|
||||
"font_class": "kingbase",
|
||||
"unicode": "e882",
|
||||
"unicode_decimal": 59522
|
||||
},
|
||||
{
|
||||
"icon_id": "33047500",
|
||||
"name": "vastbase",
|
||||
"font_class": "vastbase",
|
||||
"unicode": "e62b",
|
||||
"unicode_decimal": 58923
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,13 @@
|
||||
import EnumValue from './Enum';
|
||||
// element plus 自带国际化
|
||||
import zhcnLocale from 'element-plus/es/locale/lang/zh-cn';
|
||||
import enLocale from 'element-plus/es/locale/lang/en';
|
||||
|
||||
// i18n
|
||||
export const I18nEnum = {
|
||||
ZhCn: EnumValue.of('zh-cn', '简体中文').setExtra({ icon: 'iconfont icon-fuhao-zhongwen', el: zhcnLocale }),
|
||||
En: EnumValue.of('en', 'English').setExtra({ icon: 'iconfont icon-fuhao-yingwen', el: enLocale }),
|
||||
};
|
||||
|
||||
// 资源类型
|
||||
export const ResourceTypeEnum = {
|
||||
|
||||
@@ -6,6 +6,7 @@ export default {
|
||||
otpVerify: (param: any) => request.post('/auth/accounts/otp-verify', param),
|
||||
getPublicKey: () => request.get('/common/public-key'),
|
||||
getConfigValue: (params: any) => request.get('/sys/configs/value', params),
|
||||
getServerConf: () => request.get('/sys/configs/server'),
|
||||
oauth2LoginConfig: () => request.get('/auth/oauth2-config'),
|
||||
changePwd: (param: any) => request.post('/sys/accounts/change-pwd', param),
|
||||
captcha: () => request.get('/sys/captcha'),
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { i18n } from '@/i18n';
|
||||
|
||||
export const AccountUsernamePattern = {
|
||||
pattern: /^[a-zA-Z0-9_]{5,20}$/g,
|
||||
message: '只允许输入5-20位大小写字母、数字、_-.:',
|
||||
pattern: /^[a-zA-Z0-9_]{5,16}$/g,
|
||||
message: i18n.global.t('system.account.usernamePatternErrMsg'),
|
||||
};
|
||||
|
||||
export const ResourceCodePattern = {
|
||||
pattern: /^[a-zA-Z0-9_\-.:]{1,32}$/g,
|
||||
message: '只允许输入1-32位大小写字母、数字、_-.:',
|
||||
message: i18n.global.t('system.menu.resourceCodePatternErrMsg'),
|
||||
};
|
||||
|
||||
@@ -73,6 +73,15 @@ export async function getMachineConfig(): Promise<any> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统服务启动配置
|
||||
*
|
||||
* @returns 配置信息
|
||||
*/
|
||||
export async function getServerConf(): Promise<any> {
|
||||
return openApi.getServerConf();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统配置值
|
||||
*
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import { getLocal } from '@/common/utils/storage';
|
||||
|
||||
// 全局组件大小
|
||||
export const globalComponentSize = getLocal('themeConfig')?.globalComponentSize;
|
||||
@@ -69,7 +69,7 @@ export function convertToBytes(sizeStr: string) {
|
||||
* @returns
|
||||
*/
|
||||
export function formatTime(time: number, unit: string = 's') {
|
||||
const units = {
|
||||
const units: any = {
|
||||
y: 31536000,
|
||||
M: 2592000,
|
||||
d: 86400,
|
||||
|
||||
@@ -177,3 +177,40 @@ export function isPrefixSubsequence(prefix: string, targetTemplate: string) {
|
||||
// 如果prefix的所有字符都被找到,返回true
|
||||
return i === prefix.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机密码
|
||||
* @param length 密码长度
|
||||
*/
|
||||
export function randomPassword(length = 10) {
|
||||
const lowerCase = 'abcdefghijklmnopqrstuvwxyz';
|
||||
const upperCase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
const numbers = '0123456789';
|
||||
const specialChars = '!@#$%^&*()-_=+[]{}|;:,.<>?';
|
||||
|
||||
// 确保每个类别至少包含一个字符
|
||||
let password = [getRandomChar(lowerCase), getRandomChar(upperCase), getRandomChar(numbers), getRandomChar(specialChars)];
|
||||
|
||||
// 剩余字符从所有字符集中随机选择
|
||||
const allChars = lowerCase + upperCase + numbers + specialChars;
|
||||
for (let i = 4; i < length; i++) {
|
||||
password.push(getRandomChar(allChars));
|
||||
}
|
||||
|
||||
// 打乱数组顺序以增加随机性
|
||||
shuffleArray(password);
|
||||
|
||||
return password.join('');
|
||||
}
|
||||
|
||||
function getRandomChar(charSet: string) {
|
||||
const randomIndex = Math.floor(Math.random() * charSet.length);
|
||||
return charSet[randomIndex];
|
||||
}
|
||||
|
||||
function shuffleArray(array: string[]) {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[array[i], array[j]] = [array[j], array[i]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
:is="`el-option`"
|
||||
v-for="(col, index) in item.options"
|
||||
:key="index"
|
||||
:label="col[fieldNames.label]"
|
||||
:label="$t(col[fieldNames.label])"
|
||||
:value="col[fieldNames.value]"
|
||||
></component>
|
||||
</template>
|
||||
@@ -28,6 +28,9 @@
|
||||
<script setup lang="ts" name="SearchFormItem">
|
||||
import { computed } from 'vue';
|
||||
import { SearchItem } from '../index';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
interface SearchFormItemProps {
|
||||
item: SearchItem;
|
||||
@@ -70,7 +73,7 @@ const handleEvents = computed(() => {
|
||||
// 处理默认 placeholder
|
||||
const placeholder = computed(() => {
|
||||
const search = props.item;
|
||||
const label = search.label;
|
||||
const label = t(search.label);
|
||||
if (['datetimerange', 'daterange', 'monthrange'].includes(search?.props?.type) || search?.props?.isRange) {
|
||||
return {
|
||||
rangeSeparator: search?.props?.rangeSeparator ?? '至',
|
||||
@@ -78,7 +81,9 @@ const placeholder = computed(() => {
|
||||
endPlaceholder: search?.props?.endPlaceholder ?? '结束时间',
|
||||
};
|
||||
}
|
||||
const placeholder = search?.props?.placeholder ?? (search?.type?.includes('input') ? `请输入${label}` : `请选择${label}`);
|
||||
return { placeholder };
|
||||
|
||||
const placeholder =
|
||||
search?.props?.placeholder ?? (search?.type?.includes('input') ? t('common.pleaseInput', { label }) : t('common.pleaseSelect', { label }));
|
||||
return { placeholder: t(placeholder) };
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
@click="onCurrentContextmenuClick(v)"
|
||||
>
|
||||
<SvgIcon :name="v.icon" />
|
||||
<span>{{ v.txt }}</span>
|
||||
<span>{{ $t(v.txt) }}</span>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
<template>
|
||||
<div class="crontab">
|
||||
<el-tabs v-model="state.activeName" @tab-change="changeTab(state.activeName)" type="border-card">
|
||||
<el-tab-pane label="秒" name="second" v-if="shouldHide('second')">
|
||||
<el-tab-pane :label="$t('components.crontab.second')" name="second" v-if="shouldHide('second')">
|
||||
<CrontabSecond :cron="crontabValueObj" ref="secondRef" />
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="分钟" name="min" v-if="shouldHide('min')">
|
||||
<el-tab-pane :label="$t('components.crontab.minute')" name="min" v-if="shouldHide('min')">
|
||||
<CrontabMin :cron="crontabValueObj" ref="minRef" />
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="小时" name="hour" v-if="shouldHide('hour')">
|
||||
<el-tab-pane :label="$t('components.crontab.hour')" name="hour" v-if="shouldHide('hour')">
|
||||
<CrontabHour :cron="crontabValueObj" ref="hourRef" />
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="日" name="day" v-if="shouldHide('day')">
|
||||
<el-tab-pane :label="$t('components.crontab.day')" name="day" v-if="shouldHide('day')">
|
||||
<CrontabDay :cron="crontabValueObj" ref="dayRef" />
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="月" name="mouth" v-if="shouldHide('mouth')">
|
||||
<el-tab-pane :label="$t('components.crontab.month')" name="mouth" v-if="shouldHide('mouth')">
|
||||
<CrontabMouth :cron="crontabValueObj" ref="mouthRef" />
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="周" name="week" v-if="shouldHide('week')">
|
||||
<el-tab-pane :label="$t('components.crontab.week')" name="week" v-if="shouldHide('week')">
|
||||
<CrontabWeek :cron="crontabValueObj" ref="weekRef" />
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="年" name="year" v-if="shouldHide('year')">
|
||||
<el-tab-pane :label="$t('components.crontab.year')" name="year" v-if="shouldHide('year')">
|
||||
<CrontabYear :cron="crontabValueObj" ref="yearRef" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<div class="popup-main">
|
||||
<div class="popup-result">
|
||||
<p class="title">时间表达式</p>
|
||||
<p class="title">{{ $t('components.crontab.timeExpression') }}</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="item of tabTitles" width="40" :key="item">{{ item }}</th>
|
||||
<th>crontab完整表达式</th>
|
||||
<th>{{ $t('components.crontab.crontabCompleteExpression') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -73,9 +73,9 @@
|
||||
<CrontabResult :ex="crontabValueString"></CrontabResult>
|
||||
|
||||
<div class="pop_btn">
|
||||
<el-button size="small" @click="hidePopup">取消</el-button>
|
||||
<el-button size="small" type="warning" @click="clearCron">重置</el-button>
|
||||
<el-button size="small" type="primary" @click="submitFill">确定</el-button>
|
||||
<el-button size="small" @click="hidePopup">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button size="small" type="warning" @click="clearCron">{{ $t('common.reset') }}</el-button>
|
||||
<el-button size="small" type="primary" @click="submitFill">{{ $t('common.confirm') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,42 +1,45 @@
|
||||
<template>
|
||||
<el-form size="small">
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="1"> 日,允许的通配符[, - * / L M] </el-radio>
|
||||
<el-radio v-model="radioValue" :label="1"> {{ $t('components.crontab.day') }},{{ $t('components.crontab.dayCrontype1') }} </el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="2"> 不指定 </el-radio>
|
||||
<el-radio v-model="radioValue" :label="2"> {{ $t('components.crontab.crontype2') }} </el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="3">
|
||||
周期从
|
||||
<el-input-number v-model="cycle01" :min="0" :max="31" /> - <el-input-number v-model="cycle02" :min="0" :max="31" /> 日
|
||||
{{ $t('components.crontab.crontype3') }}
|
||||
<el-input-number v-model="cycle01" :min="0" :max="31" /> - <el-input-number v-model="cycle02" :min="0" :max="31" />
|
||||
{{ $t('components.crontab.day') }}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="4">
|
||||
从
|
||||
<el-input-number v-model="average01" :min="0" :max="31" /> 号开始,每 <el-input-number v-model="average02" :min="0" :max="31" /> 日执行一次
|
||||
{{ $t('components.crontab.crontypeFrom') }}
|
||||
<el-input-number v-model="average01" :min="0" :max="31" /> {{ $t('components.crontab.crontypeStartDay') }},
|
||||
{{ $t('components.crontab.crontypeEvery') }} <el-input-number v-model="average02" :min="0" :max="31" />
|
||||
{{ $t('components.crontab.crontypeExecDay') }}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<!-- <el-form-item>
|
||||
<el-radio v-model="radioValue" :label="5">
|
||||
每月
|
||||
<el-input-number v-model="workday" :min="0" :max="31" /> 号最近的那个工作日
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="6"> 本月最后一天 </el-radio>
|
||||
<el-radio v-model="radioValue" :label="6"> {{ $t('components.crontab.monthLastDay') }} </el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<div class="flex-align-center w100">
|
||||
<el-radio v-model="radioValue" :label="7" class="mr5"> 指定 </el-radio>
|
||||
<el-select @click="radioValue = 7" class="w100" clearable v-model="checkboxList" placeholder="可多选" multiple>
|
||||
<el-radio v-model="radioValue" :label="7" class="mr5"> {{ $t('components.crontab.appoint') }} </el-radio>
|
||||
<el-select @click="radioValue = 7" class="w100" clearable v-model="checkboxList" multiple>
|
||||
<el-option v-for="item in 31" :key="item" :value="`${item}`">{{ item }}</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
<template>
|
||||
<el-form size="small">
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="1"> 小时,允许的通配符[, - * /] </el-radio>
|
||||
<el-radio v-model="radioValue" :label="1"> {{ $t('components.crontab.hour') }},{{ $t('components.crontab.hourCronType1') }} </el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="2">
|
||||
周期从
|
||||
<el-input-number v-model="cycle01" :min="0" :max="60" /> - <el-input-number v-model="cycle02" :min="0" :max="60" /> 小时
|
||||
{{ $t('components.crontab.crontype3') }}
|
||||
<el-input-number v-model="cycle01" :min="0" :max="60" /> - <el-input-number v-model="cycle02" :min="0" :max="60" />
|
||||
{{ $t('components.crontab.hour') }}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="3">
|
||||
从
|
||||
<el-input-number v-model="average01" :min="0" :max="60" /> 小时开始,每 <el-input-number v-model="average02" :min="0" :max="60" /> 小时执行一次
|
||||
{{ $t('components.crontab.crontypeFrom') }}
|
||||
<el-input-number v-model="average01" :min="0" :max="60" /> {{ $t('components.crontab.crontypeStartHour') }},
|
||||
{{ $t('components.crontab.crontypeEvery') }} <el-input-number v-model="average02" :min="0" :max="60" />
|
||||
{{ $t('components.crontab.crontypeExecHour') }}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<div class="flex-align-center w100">
|
||||
<el-radio v-model="radioValue" :label="4" class="mr5"> 指定 </el-radio>
|
||||
<el-select @click="radioValue = 4" class="w100" clearable v-model="checkboxList" placeholder="可多选" multiple>
|
||||
<el-radio v-model="radioValue" :label="4" class="mr5"> {{ $t('components.crontab.appoint') }} </el-radio>
|
||||
<el-select @click="radioValue = 4" class="w100" clearable v-model="checkboxList" multiple>
|
||||
<el-option v-for="item in 60" :key="item" :value="`${item - 1}`">{{ item - 1 }}</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<el-input v-model="cron" placeholder="可点击左边按钮配置">
|
||||
<el-input v-model="cron" :placeholder="$t('components.crontab.crontabInputPlaceholder')">
|
||||
<template #prepend>
|
||||
<el-button @click="showCron = true" icon="Pointer"></el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-dialog title="生成 cron" v-model="showCron" width="600px">
|
||||
<el-dialog :title="$t('components.crontab.crontabTitle')" v-model="showCron" width="660px">
|
||||
<Crontab :expression="cron" @hide="showCron = false" @fill="(ex: any) => (cron = ex)" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
<template>
|
||||
<el-form size="small">
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="1"> 分钟,允许的通配符[, - * /] </el-radio>
|
||||
<el-radio v-model="radioValue" :label="1"> {{ $t('components.crontab.minute') }},{{ $t('components.crontab.hourCronType1') }} </el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="2">
|
||||
周期从
|
||||
<el-input-number v-model="cycle01" :min="0" :max="60" /> - <el-input-number v-model="cycle02" :min="0" :max="60" /> 分钟
|
||||
{{ $t('components.crontab.crontype3') }}
|
||||
<el-input-number v-model="cycle01" :min="0" :max="60" /> - <el-input-number v-model="cycle02" :min="0" :max="60" />
|
||||
{{ $t('components.crontab.minute') }}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="3">
|
||||
从
|
||||
<el-input-number v-model="average01" :min="0" :max="60" /> 分钟开始,每 <el-input-number v-model="average02" :min="0" :max="60" /> 分钟执行一次
|
||||
{{ $t('components.crontab.crontypeFrom') }}
|
||||
<el-input-number v-model="average01" :min="0" :max="60" /> {{ $t('components.crontab.crontypeStartMin') }},
|
||||
{{ $t('components.crontab.crontypeEvery') }} <el-input-number v-model="average02" :min="0" :max="60" />
|
||||
{{ $t('components.crontab.crontypeExecMin') }}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<div class="flex-align-center w100">
|
||||
<el-radio v-model="radioValue" :label="4" class="mr5"> 指定 </el-radio>
|
||||
<el-select @click="radioValue = 4" class="w100" clearable v-model="checkboxList" placeholder="可多选" multiple>
|
||||
<el-radio v-model="radioValue" :label="4" class="mr5"> {{ $t('components.crontab.appoint') }} </el-radio>
|
||||
<el-select @click="radioValue = 4" class="w100" clearable v-model="checkboxList" multiple>
|
||||
<el-option v-for="item in 60" :key="item" :value="`${item - 1}`">{{ item - 1 }}</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
<template>
|
||||
<el-form size="small">
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="1"> 月,允许的通配符[, - * /] </el-radio>
|
||||
<el-radio v-model="radioValue" :label="1"> {{ $t('components.crontab.month') }},{{ $t('components.crontab.hourCronType1') }} </el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="2">
|
||||
周期从
|
||||
<el-input-number v-model="cycle01" :min="1" :max="12" /> - <el-input-number v-model="cycle02" :min="1" :max="12" /> 月
|
||||
{{ $t('components.crontab.crontype3') }}
|
||||
<el-input-number v-model="cycle01" :min="1" :max="12" /> - <el-input-number v-model="cycle02" :min="1" :max="12" />
|
||||
{{ $t('components.crontab.month') }}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="3">
|
||||
从
|
||||
<el-input-number v-model="average01" :min="1" :max="12" /> 月开始,每 <el-input-number v-model="average02" :min="1" :max="12" /> 月月执行一次
|
||||
{{ $t('components.crontab.crontypeFrom') }}
|
||||
<el-input-number v-model="average01" :min="1" :max="12" /> {{ $t('components.crontab.crontypeStartMonth') }},
|
||||
{{ $t('components.crontab.crontypeEvery') }}
|
||||
<el-input-number v-model="average02" :min="1" :max="12" /> {{ $t('components.crontab.crontypeExecMonth') }}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<div class="flex-align-center w100">
|
||||
<el-radio v-model="radioValue" :label="4" class="mr5"> 指定 </el-radio>
|
||||
<el-select @click="radioValue = 4" class="w100" clearable v-model="checkboxList" placeholder="可多选" multiple>
|
||||
<el-radio v-model="radioValue" :label="4" class="mr5"> {{ $t('components.crontab.appoint') }} </el-radio>
|
||||
<el-select @click="radioValue = 4" class="w100" clearable v-model="checkboxList" multiple>
|
||||
<el-option v-for="item in 12" :key="item" :value="`${item}`">{{ item }}</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="popup-result">
|
||||
<p class="title">最近5次运行时间</p>
|
||||
<p class="title">{{ $t('components.crontab.last5runTimes') }}</p>
|
||||
<ul class="popup-result-scroll">
|
||||
<template v-if="isShow">
|
||||
<li v-for="item in resultList" :key="item">{{ item }}</li>
|
||||
</template>
|
||||
<li v-else>计算结果中...</li>
|
||||
<li v-else>{{ $t('components.crontab.calculationing') }}...</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
<template>
|
||||
<el-form size="small">
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="1"> 秒,允许的通配符[, - * /] </el-radio>
|
||||
<el-radio v-model="radioValue" :label="1"> {{ $t('components.crontab.second') }},{{ $t('components.crontab.hourCronType1') }} </el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="2">
|
||||
周期从
|
||||
<el-input-number v-model="cycle01" :min="0" :max="60" /> - <el-input-number v-model="cycle02" :min="0" :max="60" /> 秒
|
||||
{{ $t('components.crontab.crontype3') }}
|
||||
<el-input-number v-model="cycle01" :min="0" :max="60" /> - <el-input-number v-model="cycle02" :min="0" :max="60" />
|
||||
{{ $t('components.crontab.second') }}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="3">
|
||||
从
|
||||
<el-input-number v-model="average01" :min="0" :max="60" /> 秒开始,每 <el-input-number v-model="average02" :min="0" :max="60" /> 秒执行一次
|
||||
{{ $t('components.crontab.crontypeFrom') }}
|
||||
<el-input-number v-model="average01" :min="0" :max="60" /> {{ $t('components.crontab.crontypeStartSecond') }},
|
||||
{{ $t('components.crontab.crontypeEvery') }}<el-input-number v-model="average02" :min="0" :max="60" />
|
||||
{{ $t('components.crontab.crontypeExecSecond') }}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<div class="flex-align-center w100">
|
||||
<el-radio v-model="radioValue" :label="4" class="mr5"> 指定 </el-radio>
|
||||
<el-select @click="radioValue = 4" class="w100" clearable v-model="checkboxList" placeholder="可多选" multiple>
|
||||
<el-radio v-model="radioValue" :label="4" class="mr5"> {{ $t('components.crontab.appoint') }} </el-radio>
|
||||
<el-select @click="radioValue = 4" class="w100" clearable v-model="checkboxList" multiple>
|
||||
<el-option v-for="item in 60" :key="item" :value="`${item - 1}`">{{ item - 1 }}</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
<template>
|
||||
<el-form size="small">
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="1"> 周,允许的通配符[, - * / L #] </el-radio>
|
||||
<el-radio v-model="radioValue" :label="1"> {{ $t('components.crontab.weekCronType1') }} </el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="2"> 不指定 </el-radio>
|
||||
<el-radio v-model="radioValue" :label="2"> {{ $t('components.crontab.crontype2') }} </el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio v-model="radioValue" :label="3">
|
||||
周期从星期
|
||||
{{ $t('components.crontab.crontype3') }}
|
||||
<el-input-number v-model="cycle01" :min="1" :max="7" /> -
|
||||
<el-input-number v-model="cycle02" :min="1" :max="7" />
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<!-- <el-form-item>
|
||||
<el-radio v-model="radioValue" :label="4">
|
||||
第
|
||||
<el-input-number v-model="average01" :min="1" :max="4" /> 周的星期
|
||||
@@ -29,13 +29,13 @@
|
||||
本月最后一个星期
|
||||
<el-input-number v-model="weekday" :min="1" :max="7" />
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
|
||||
<el-form-item>
|
||||
<div class="flex-align-center w100">
|
||||
<el-radio v-model="radioValue" :label="6" class="mr5"> 指定 </el-radio>
|
||||
<el-select @click="radioValue = 6" class="w100" clearable v-model="checkboxList" placeholder="可多选" multiple>
|
||||
<el-option v-for="(item, index) of weekList" :label="item" :key="index" :value="`${index + 1}`">{{ item }}</el-option>
|
||||
<el-radio v-model="radioValue" :label="6" class="mr5"> {{ $t('components.crontab.appoint') }} </el-radio>
|
||||
<el-select @click="radioValue = 6" class="w100" clearable v-model="checkboxList" multiple>
|
||||
<el-option v-for="(item, index) of weekList" :label="item" :key="index" :value="`${index + 1}`">{{ $t(item) }}</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</el-form-item>
|
||||
@@ -56,7 +56,15 @@ const state = reactive({
|
||||
average01: 1,
|
||||
average02: 1,
|
||||
checkboxList: [] as any,
|
||||
weekList: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
|
||||
weekList: [
|
||||
'components.crontab.monday',
|
||||
'components.crontab.tuesday',
|
||||
'components.crontab.wednesday',
|
||||
'components.crontab.thursday',
|
||||
'components.crontab.friday',
|
||||
'components.crontab.saturday',
|
||||
'components.crontab.sunday',
|
||||
],
|
||||
});
|
||||
|
||||
const { radioValue, cycle01, cycle02, average01, average02, checkboxList, weekday, weekList } = toRefs(state);
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<el-form size="small">
|
||||
<el-form-item>
|
||||
<el-radio :label="1" v-model="radioValue"> 不填,允许的通配符[, - * /] </el-radio>
|
||||
<el-radio :label="1" v-model="radioValue"> {{ $t('components.crontab.hourCronType1') }} </el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio :label="2" v-model="radioValue"> 每年 </el-radio>
|
||||
<el-radio :label="2" v-model="radioValue"> {{ $t('components.crontab.yearly') }} </el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-radio :label="3" v-model="radioValue">
|
||||
周期从
|
||||
{{ $t('components.crontab.crontype3') }}
|
||||
<el-input-number v-model="cycle01" :min="fullYear" /> -
|
||||
<el-input-number v-model="cycle02" :min="fullYear" />
|
||||
</el-radio>
|
||||
@@ -18,15 +18,17 @@
|
||||
|
||||
<el-form-item>
|
||||
<el-radio :label="4" v-model="radioValue">
|
||||
从
|
||||
<el-input-number v-model="average01" :min="fullYear" /> 年开始,每 <el-input-number v-model="average02" :min="fullYear" /> 年执行一次
|
||||
{{ $t('components.crontab.crontypeFrom') }}
|
||||
<el-input-number v-model="average01" :min="fullYear" /> {{ $t('components.crontab.crontypeStartYear') }},
|
||||
{{ $t('components.crontab.crontypeEvery') }}
|
||||
<el-input-number v-model="average02" :min="fullYear" /> {{ $t('components.crontab.crontypeExecYear') }}
|
||||
</el-radio>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<div class="flex-align-center w100">
|
||||
<el-radio v-model="radioValue" :label="5" class="mr5"> 指定 </el-radio>
|
||||
<el-select @click="radioValue = 5" class="w100" clearable v-model="checkboxList" placeholder="可多选" multiple>
|
||||
<el-radio v-model="radioValue" :label="5" class="mr5"> {{ $t('components.crontab.appoint') }} </el-radio>
|
||||
<el-select @click="radioValue = 5" class="w100" clearable v-model="checkboxList" multiple>
|
||||
<el-option v-for="item in 9" :key="item" :value="`${item - 1 + fullYear}`" :label="item - 1 + fullYear" />
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
<template>
|
||||
<div class="dynamic-form">
|
||||
<el-form v-bind="$attrs" ref="formRef" :model="modelValue" label-width="auto">
|
||||
<el-form-item v-for="item in props.formItems as any" :key="item.name" :prop="item.model" :label="item.name" :required="item.required ?? true">
|
||||
<el-input v-if="!item.options" v-model="modelValue[item.model]" :placeholder="item.placeholder" autocomplete="off" clearable></el-input>
|
||||
<el-form-item v-for="item in props.formItems as any" :key="item.name" :prop="item.model" :label="$t(item.name)" :required="item.required ?? true">
|
||||
<el-input v-if="!item.options" v-model="modelValue[item.model]" :placeholder="$t(item.placeholder)" autocomplete="off" clearable></el-input>
|
||||
|
||||
<el-select v-else v-model="modelValue[item.model]" :placeholder="item.placeholder" filterable autocomplete="off" clearable style="width: 100%">
|
||||
<el-select
|
||||
v-else
|
||||
v-model="modelValue[item.model]"
|
||||
:placeholder="$t(item.placeholder)"
|
||||
filterable
|
||||
autocomplete="off"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option v-for="option in item.options.split(',')" :key="option" :label="option" :value="option" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<template #footer>
|
||||
<span>
|
||||
<slot name="btns">
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="confirm">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm">{{ $t('common.confirm') }}</el-button>
|
||||
</slot>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
<template>
|
||||
<div class="dynamic-form-edit w100">
|
||||
<el-table :data="formItems" stripe class="w100" empty-text="暂无表单项">
|
||||
<el-table :data="formItems" stripe class="w100">
|
||||
<el-table-column prop="name" label="model" min-width="100px">
|
||||
<template #header>
|
||||
<el-button class="ml0" type="primary" circle size="small" icon="Plus" @click="addItem()"> </el-button>
|
||||
<span class="ml10">model</span>
|
||||
<span class="ml10">model field</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row['model']" placeholder="字段model" clearable> </el-input>
|
||||
<el-input v-model="scope.row['model']" :placeholder="$t('components.df.fieldModelPlaceholder')" clearable> </el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="name" label="label" min-width="100px">
|
||||
<el-table-column prop="name" :label="$t('components.df.fieldLabel')" min-width="100px">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row['name']" placeholder="字段title" clearable> </el-input>
|
||||
<el-input v-model="scope.row['name']" clearable> </el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="placeholder" label="字段说明" min-width="140px">
|
||||
<el-table-column prop="placeholder" :label="$t('components.df.fieldPlaceholder')" min-width="140px">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row['placeholder']" placeholder="字段说明" clearable> </el-input>
|
||||
<el-input v-model="scope.row['placeholder']" clearable> </el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="options" label="可选值" min-width="140px">
|
||||
<el-table-column prop="options" :label="$t('components.df.optionalValues')" min-width="140px">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row['options']" placeholder="可选值 ,分割" clearable> </el-input>
|
||||
<el-input v-model="scope.row['options']" :placeholder="$t('components.df.optionalValuesPlaceholder')" clearable> </el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="required" label="必填" min-width="40px">
|
||||
<el-table-column prop="required" :label="$t('components.df.required')" min-width="65px">
|
||||
<template #default="scope">
|
||||
<el-checkbox v-model="scope.row['required']" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" wdith="20px">
|
||||
<el-table-column :label="$t('common.operation')" wdith="20px">
|
||||
<template #default="scope">
|
||||
<el-button type="danger" @click="deleteItem(scope.$index)" icon="delete" plain></el-button>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<el-select v-bind="$attrs" v-model="modelValue">
|
||||
<el-option v-for="item in props.enums" :key="item.value" :label="item.label" :value="item.value"> </el-option>
|
||||
<el-option v-for="item in props.enums" :key="item.value" :label="$t(item.label)" :value="item.value"> </el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-tag :disable-transitions="true" v-bind="$attrs" :type="type" :color="color" effect="plain">{{ enumLabel }}</el-tag>
|
||||
<el-tag :disable-transitions="true" v-bind="$attrs" :type="type" :color="color" effect="plain">{{ $t(enumLabel) }}</el-tag>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
<div>
|
||||
<transition name="el-zoom-in-top">
|
||||
<!-- 查询表单 -->
|
||||
<SearchForm v-if="isShowSearch" :items="tableSearchItems" v-model="queryForm" :search="search" :reset="reset" :search-col="searchCol">
|
||||
<SearchForm v-if="isShowSearch" :items="tableSearchItems" v-model="queryForm" :search="search"
|
||||
:reset="reset" :search-col="searchCol">
|
||||
<!-- 遍历父组件传入的 solts 透传给子组件 -->
|
||||
<template v-for="(_, key) in useSlots()" v-slot:[key]>
|
||||
<slot :name="key"></slot>
|
||||
@@ -27,54 +28,45 @@
|
||||
<SvgIcon :size="16" name="CaretBottom" class="mr4 mt6 simple-search-form-btn" />
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item
|
||||
v-for="searchItem in searchItems"
|
||||
:key="searchItem.prop"
|
||||
@click="changeSimpleFormItem(searchItem)"
|
||||
>
|
||||
{{ searchItem.label }}
|
||||
<el-dropdown-item v-for="searchItem in searchItems"
|
||||
:key="searchItem.prop" @click="changeSimpleFormItem(searchItem)">
|
||||
{{ $t(searchItem.label) }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
|
||||
<div class="simple-search-form-label mt5">
|
||||
<el-text truncated tag="b">{{ `${nowSearchItem?.label} : ` }}</el-text>
|
||||
<el-text truncated tag="b">{{ `${$t(nowSearchItem?.label)} : ` }}</el-text>
|
||||
</div>
|
||||
|
||||
<el-form-item style="width: 200px" :key="nowSearchItem.prop">
|
||||
<SearchFormItem
|
||||
@keyup.enter.native="searchFormItemKeyUpEnter"
|
||||
v-if="!nowSearchItem.slot"
|
||||
:item="nowSearchItem"
|
||||
v-model="queryForm[nowSearchItem.prop]"
|
||||
/>
|
||||
<SearchFormItem @keyup.enter.native="searchFormItemKeyUpEnter"
|
||||
v-if="!nowSearchItem.slot" :item="nowSearchItem"
|
||||
v-model="queryForm[nowSearchItem.prop]" />
|
||||
|
||||
<slot @keyup.enter.native="searchFormItemKeyUpEnter" v-else :name="nowSearchItem.slot"></slot>
|
||||
<slot @keyup.enter.native="searchFormItemKeyUpEnter" v-else
|
||||
:name="nowSearchItem.slot">
|
||||
</slot>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<el-button v-if="showToolButton('search') && searchItems?.length" icon="Search" circle @click="search" />
|
||||
<el-button v-if="showToolButton('search') && searchItems?.length" icon="Search"
|
||||
circle @click="search" />
|
||||
|
||||
<!-- <el-button v-if="showToolButton('refresh')" icon="Refresh" circle @click="execQuery()" /> -->
|
||||
|
||||
<el-button
|
||||
v-if="showToolButton('search') && searchItems?.length > 1"
|
||||
:icon="isShowSearch ? 'ArrowDown' : 'ArrowUp'"
|
||||
circle
|
||||
@click="isShowSearch = !isShowSearch"
|
||||
/>
|
||||
<el-button v-if="showToolButton('search') && searchItems?.length > 1"
|
||||
:icon="isShowSearch ? 'ArrowDown' : 'ArrowUp'" circle
|
||||
@click="isShowSearch = !isShowSearch" />
|
||||
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
title="表格配置"
|
||||
popper-style="max-height: 550px; overflow: auto; max-width: 450px"
|
||||
width="auto"
|
||||
trigger="click"
|
||||
>
|
||||
<el-popover placement="bottom" title="表格配置"
|
||||
popper-style="max-height: 550px; overflow: auto; max-width: 450px" width="auto"
|
||||
trigger="click">
|
||||
<div v-for="(item, index) in tableColumns" :key="index">
|
||||
<el-checkbox v-model="item.show" :label="item.label" :true-value="true" :false-value="false" />
|
||||
<el-checkbox v-model="item.show" :label="item.label" :true-value="true"
|
||||
:false-value="false" />
|
||||
</div>
|
||||
<template #reference>
|
||||
<el-button icon="Operation" circle :size="props.size"></el-button>
|
||||
@@ -86,33 +78,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
v-bind="$attrs"
|
||||
:max-height="tableMaxHeight"
|
||||
@selection-change="handleSelectionChange"
|
||||
:data="tableData"
|
||||
highlight-current-row
|
||||
v-loading="loading"
|
||||
:size="props.size as any"
|
||||
:border="border"
|
||||
>
|
||||
<el-table ref="tableRef" v-bind="$attrs" :max-height="tableMaxHeight"
|
||||
@selection-change="handleSelectionChange" :data="tableData" highlight-current-row
|
||||
v-loading="loading" :size="props.size as any" :border="border">
|
||||
<el-table-column v-if="props.showSelection" :selectable="selectable" type="selection" width="40" />
|
||||
|
||||
<template v-for="(item, index) in tableColumns">
|
||||
<el-table-column
|
||||
:key="index"
|
||||
v-if="item.show"
|
||||
:prop="item.prop"
|
||||
:label="item.label"
|
||||
:fixed="item.fixed"
|
||||
:align="item.align"
|
||||
:show-overflow-tooltip="item.showOverflowTooltip"
|
||||
:min-width="item.minWidth"
|
||||
:sortable="item.sortable || false"
|
||||
:type="item.type"
|
||||
:width="item.width"
|
||||
>
|
||||
<el-table-column :key="index" v-if="item.show" :prop="item.prop" :label="$t(item.label)"
|
||||
:fixed="item.fixed" :align="item.align" :show-overflow-tooltip="item.showOverflowTooltip"
|
||||
:min-width="item.minWidth" :sortable="item.sortable || false" :type="item.type"
|
||||
:width="item.width">
|
||||
<!-- 插槽:预留功能 -->
|
||||
<template #default="scope" v-if="item.slot">
|
||||
<slot :name="item.slotName ? item.slotName : item.prop" :data="scope.row"></slot>
|
||||
@@ -120,29 +95,21 @@
|
||||
|
||||
<!-- 枚举类型使用tab展示 -->
|
||||
<template #default="scope" v-else-if="item.type == 'tag'">
|
||||
<enum-tag :size="props.size" :enums="item.typeParam" :value="item.getValueByData(scope.row)"></enum-tag>
|
||||
<enum-tag :size="props.size" :enums="item.typeParam"
|
||||
:value="item.getValueByData(scope.row)"></enum-tag>
|
||||
</template>
|
||||
|
||||
<template #default="scope" v-else>
|
||||
<!-- 配置了美化文本按钮以及文本内容大于指定长度,则显示美化按钮 -->
|
||||
<el-popover
|
||||
v-if="item.isBeautify && item.getValueByData(scope.row)?.length > 35"
|
||||
effect="light"
|
||||
trigger="click"
|
||||
placement="top"
|
||||
width="600px"
|
||||
>
|
||||
<el-popover v-if="item.isBeautify && item.getValueByData(scope.row)?.length > 35"
|
||||
effect="light" trigger="click" placement="top" width="600px">
|
||||
<template #default>
|
||||
<el-input :autosize="{ minRows: 3, maxRows: 15 }" disabled v-model="formatVal" type="textarea" />
|
||||
<el-input :autosize="{ minRows: 3, maxRows: 15 }" disabled v-model="formatVal"
|
||||
type="textarea" />
|
||||
</template>
|
||||
<template #reference>
|
||||
<el-link
|
||||
@click="formatText(item.getValueByData(scope.row))"
|
||||
:underline="false"
|
||||
type="success"
|
||||
icon="MagicStick"
|
||||
class="mr5"
|
||||
></el-link>
|
||||
<el-link @click="formatText(item.getValueByData(scope.row))" :underline="false"
|
||||
type="success" icon="MagicStick" class="mr5"></el-link>
|
||||
</template>
|
||||
</el-popover>
|
||||
|
||||
@@ -154,17 +121,10 @@
|
||||
</div>
|
||||
|
||||
<el-row v-if="props.pageable" class="mt20" type="flex" justify="end">
|
||||
<el-pagination
|
||||
:small="props.size == 'small'"
|
||||
@current-change="pageNumChange"
|
||||
@size-change="pageSizeChange"
|
||||
style="text-align: right"
|
||||
layout="prev, pager, next, total, sizes"
|
||||
:total="total"
|
||||
v-model:current-page="queryForm.pageNum"
|
||||
v-model:page-size="queryForm.pageSize"
|
||||
:page-sizes="pageSizes"
|
||||
/>
|
||||
<el-pagination :small="props.size == 'small'" @current-change="pageNumChange"
|
||||
@size-change="pageSizeChange" style="text-align: right" layout="prev, pager, next, total, sizes"
|
||||
:total="total" v-model:current-page="queryForm.pageNum" v-model:page-size="queryForm.pageSize"
|
||||
:page-sizes="pageSizes" />
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
@@ -185,6 +145,7 @@ import SvgIcon from '@/components/svgIcon/index.vue';
|
||||
import { usePageTable } from '@/hooks/usePageTable';
|
||||
import { ElTable } from 'element-plus';
|
||||
|
||||
|
||||
const emit = defineEmits(['update:selectionData', 'pageSizeChange', 'pageNumChange']);
|
||||
|
||||
export interface PageTableProps {
|
||||
@@ -377,6 +338,7 @@ defineExpose({
|
||||
// 表格 header 样式
|
||||
.table-header {
|
||||
width: 100%;
|
||||
|
||||
.header-button-lf {
|
||||
float: left;
|
||||
}
|
||||
@@ -445,7 +407,7 @@ defineExpose({
|
||||
// }
|
||||
|
||||
// 设置 el-table 中 header 文字不换行,并省略
|
||||
.el-table__header .el-table__cell > .cell {
|
||||
.el-table__header .el-table__cell>.cell {
|
||||
// white-space: nowrap;
|
||||
white-space: wrap;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import EnumValue from '@/common/Enum';
|
||||
import { formatDate } from '@/common/utils/format';
|
||||
import { getValueByPath } from '@/common/utils/object';
|
||||
import { getTextWidth } from '@/common/utils/string';
|
||||
import { i18n } from '@/i18n';
|
||||
|
||||
export class TableColumn {
|
||||
/**
|
||||
@@ -183,7 +184,7 @@ export class TableColumn {
|
||||
*/
|
||||
isEnum(enums: any): TableColumn {
|
||||
this.setFormatFunc((data: any, prop: string) => {
|
||||
return EnumValue.getLabelByValue(enums, getValueByPath(data, prop));
|
||||
return i18n.global.t(EnumValue.getLabelByValue(enums, getValueByPath(data, prop)));
|
||||
});
|
||||
return this;
|
||||
}
|
||||
@@ -243,7 +244,7 @@ export class TableColumn {
|
||||
// 需要加上表格的内间距等,视情况加
|
||||
const contentWidth: number = getTextWidth(maxWidthText) + 30;
|
||||
// 获取label的宽度,取较大的宽度
|
||||
const columnWidth: number = getTextWidth(label) + 60;
|
||||
const columnWidth: number = getTextWidth(i18n.global.t(label)) + 60;
|
||||
const flexWidth: number = contentWidth > columnWidth ? contentWidth : columnWidth;
|
||||
// 设置上限与累加需要额外增加的宽度
|
||||
this.minWidth = (flexWidth > 400 ? 400 : flexWidth) + this.addWidth;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<el-input v-model="state.modelValue" type="textarea" :rows="20" />
|
||||
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="onsubmit">确 定</el-button>
|
||||
<el-button type="primary" @click="onsubmit">{{ $t('common.confirm') }}</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
@@ -22,6 +22,9 @@ import { TerminalStatus } from './common';
|
||||
import { useEventListener } from '@vueuse/core';
|
||||
import themes from './themes';
|
||||
import { TrzszFilter } from 'trzsz';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
// mounted时,是否执行init方法
|
||||
@@ -166,7 +169,7 @@ function initSocket() {
|
||||
|
||||
// 监听socket错误信息
|
||||
socket.onerror = (e: Event) => {
|
||||
term.writeln('\r\n\x1b[31m提示: 连接错误...');
|
||||
term.writeln(`\r\n\x1b[31m${t('components.terminal.connErrMsg')}`);
|
||||
state.status = TerminalStatus.Error;
|
||||
console.log('连接错误', e);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div>
|
||||
<div class="terminal-dialog-container" v-for="openTerminal of terminals" :key="openTerminal.terminalId">
|
||||
<el-dialog
|
||||
title="SSH终端"
|
||||
title="SSH Terminal"
|
||||
v-model="openTerminal.visible"
|
||||
top="32px"
|
||||
class="terminal-dialog"
|
||||
@@ -26,11 +26,13 @@
|
||||
|
||||
<!-- 右侧 -->
|
||||
<div class="title-right-fixed">
|
||||
<el-popconfirm @confirm="reConnect(openTerminal.terminalId)" title="确认重新连接?">
|
||||
<el-popconfirm @confirm="reConnect(openTerminal.terminalId)" :title="$t('components.terminal.connConfirm')">
|
||||
<template #reference>
|
||||
<div class="mr15 pointer">
|
||||
<el-tag v-if="openTerminal.status == TerminalStatus.Connected" type="success" effect="light" round> 已连接 </el-tag>
|
||||
<el-tag v-else type="danger" effect="light" round> 未连接 </el-tag>
|
||||
<el-tag v-if="openTerminal.status == TerminalStatus.Connected" type="success" effect="light" round>
|
||||
{{ $t('components.terminal.connected') }}
|
||||
</el-tag>
|
||||
<el-tag v-else type="danger" effect="light" round> {{ $t('components.terminal.notConn') }} </el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
@@ -39,8 +41,8 @@
|
||||
<template #reference>
|
||||
<SvgIcon name="QuestionFilled" :size="20" class="pointer-icon mr10" />
|
||||
</template>
|
||||
<div>ctrl | command + f (搜索)</div>
|
||||
<div class="mt5">点击连接状态可重连</div>
|
||||
<div>ctrl | command + f ({{ $t('components.terminal.search') }})</div>
|
||||
<div class="mt5">{{ $t('components.terminal.reConnTips') }}</div>
|
||||
</el-popover>
|
||||
|
||||
<SvgIcon
|
||||
@@ -49,12 +51,24 @@
|
||||
@click="minimize(openTerminal.terminalId)"
|
||||
:size="20"
|
||||
class="pointer-icon mr10"
|
||||
title="最小化"
|
||||
:title="$t('components.terminal.minimize')"
|
||||
/>
|
||||
|
||||
<SvgIcon name="FullScreen" @click="handlerFullScreen(openTerminal)" :size="20" class="pointer-icon mr10" title="全屏|退出全屏" />
|
||||
<SvgIcon
|
||||
name="FullScreen"
|
||||
@click="handlerFullScreen(openTerminal)"
|
||||
:size="20"
|
||||
class="pointer-icon mr10"
|
||||
:title="$t('components.terminal.fullScreenTitle')"
|
||||
/>
|
||||
|
||||
<SvgIcon name="Close" class="pointer-icon" @click="close(openTerminal.terminalId)" title="关闭" :size="20" />
|
||||
<SvgIcon
|
||||
name="Close"
|
||||
class="pointer-icon"
|
||||
@click="close(openTerminal.terminalId)"
|
||||
:title="$t('components.terminal.close')"
|
||||
:size="20"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -30,7 +30,7 @@ import EnumTag from '@/components/enumtag/EnumTag.vue';
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: '日志',
|
||||
default: 'Log',
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div id="search-card" v-show="search.visible" @keydown.esc="closeSearch">
|
||||
<el-card title="搜索" size="small">
|
||||
<el-card :title="$t('components.terminal.search')" size="small">
|
||||
<!-- 搜索框 -->
|
||||
<el-input
|
||||
class="search-input"
|
||||
ref="searchInputRef"
|
||||
placeholder="请输入查找内容,回车搜索"
|
||||
:placeholder="$t('components.terminal.serachPlaceholder')"
|
||||
v-model="search.value"
|
||||
@keyup.enter.native="searchKeywords(true)"
|
||||
clearable
|
||||
@@ -15,24 +15,30 @@
|
||||
<div class="search-options">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-checkbox class="usn" v-model="search.regex"> 正则匹配 </el-checkbox>
|
||||
<el-checkbox class="usn" v-model="search.regex"> {{ $t('components.terminal.regexMatch') }} </el-checkbox>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-checkbox class="usn" v-model="search.words"> 单词全匹配 </el-checkbox>
|
||||
<el-checkbox class="usn" v-model="search.words"> {{ $t('components.terminal.fullWordMatching') }} </el-checkbox>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-checkbox class="usn" v-model="search.matchCase"> 区分大小写 </el-checkbox>
|
||||
<el-checkbox class="usn" v-model="search.matchCase"> {{ $t('components.terminal.caseSensitive') }} </el-checkbox>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-checkbox class="usn" v-model="search.incremental"> 增量查找 </el-checkbox>
|
||||
<el-checkbox class="usn" v-model="search.incremental"> {{ $t('components.terminal.incrementalSearch') }} </el-checkbox>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<!-- 按钮 -->
|
||||
<div class="search-buttons">
|
||||
<el-button class="terminal-search-button search-button-prev" type="primary" size="small" @click="searchKeywords(false)"> 上一个 </el-button>
|
||||
<el-button class="terminal-search-button search-button-next" type="primary" size="small" @click="searchKeywords(true)"> 下一个 </el-button>
|
||||
<el-button class="terminal-search-button search-button-next" type="primary" size="small" @click="closeSearch"> 关闭 </el-button>
|
||||
<el-button class="terminal-search-button search-button-prev" type="primary" size="small" @click="searchKeywords(false)">
|
||||
{{ $t('components.terminal.previous') }}}}
|
||||
</el-button>
|
||||
<el-button class="terminal-search-button search-button-next" type="primary" size="small" @click="searchKeywords(true)">
|
||||
{{ $t('components.terminal.next') }}}}
|
||||
</el-button>
|
||||
<el-button class="terminal-search-button search-button-next" type="primary" size="small" @click="closeSearch">
|
||||
{{ $t('components.terminal.close') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
@@ -41,6 +47,9 @@
|
||||
import { ref, toRefs, nextTick, reactive } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { SearchAddon, ISearchOptions } from 'xterm-addon-search';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
searchAddon: {
|
||||
@@ -101,7 +110,7 @@ function searchKeywords(direction: any) {
|
||||
res = props.searchAddon?.findPrevious(state.search.value, getSearchOptions(option));
|
||||
}
|
||||
if (!res) {
|
||||
ElMessage.info('未查询到匹配项');
|
||||
ElMessage.info(t('components.terminal.noMatchMsg'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ export enum TerminalStatus {
|
||||
}
|
||||
|
||||
export const TerminalStatusEnum = {
|
||||
Error: EnumValue.of(TerminalStatus.Error, '连接出错').setExtra({ iconColor: 'var(--el-color-error)' }),
|
||||
NoConnected: EnumValue.of(TerminalStatus.NoConnected, '未连接').setExtra({ iconColor: 'var(--el-color-primary)' }),
|
||||
Connected: EnumValue.of(TerminalStatus.Connected, '连接成功').setExtra({ iconColor: 'var(--el-color-success)' }),
|
||||
Disconnected: EnumValue.of(TerminalStatus.Disconnected, '连接失败').setExtra({ iconColor: 'var(--el-color-error)' }),
|
||||
Error: EnumValue.of(TerminalStatus.Error, 'components.terminal.connError').setExtra({ iconColor: 'var(--el-color-error)' }),
|
||||
NoConnected: EnumValue.of(TerminalStatus.NoConnected, 'components.terminal.notConn').setExtra({ iconColor: 'var(--el-color-primary)' }),
|
||||
Connected: EnumValue.of(TerminalStatus.Connected, 'components.terminal.connSuccess').setExtra({ iconColor: 'var(--el-color-success)' }),
|
||||
Disconnected: EnumValue.of(TerminalStatus.Disconnected, 'components.terminal.connFail').setExtra({ iconColor: 'var(--el-color-error)' }),
|
||||
};
|
||||
|
||||
94
frontend/src/hooks/useI18n.ts
Normal file
94
frontend/src/hooks/useI18n.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { i18n } from '@/i18n';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
|
||||
/**
|
||||
* rule message 提示输入字段名
|
||||
* @param label 字段名称key
|
||||
* @returns
|
||||
*/
|
||||
export function useI18nPleaseInput(labelI18nKey: string) {
|
||||
const t = i18n.global.t;
|
||||
return t('common.pleaseInput', { label: t(labelI18nKey) });
|
||||
}
|
||||
|
||||
/**
|
||||
* rule message 提示选择字段名
|
||||
* @param label 字段名称key
|
||||
* @returns
|
||||
*/
|
||||
export function useI18nPleaseSelect(labelI18nKey: string) {
|
||||
const t = i18n.global.t;
|
||||
return t('common.pleaseSelect', { label: t(labelI18nKey) });
|
||||
}
|
||||
|
||||
/**
|
||||
* 提示确认删除
|
||||
* @param name 删除对象名称
|
||||
* @returns
|
||||
*/
|
||||
export async function useI18nDeleteConfirm(name: string = '') {
|
||||
return useI18nConfirm('common.deleteConfirm', { name });
|
||||
}
|
||||
|
||||
/**
|
||||
* 提示确认信息
|
||||
* @param i18nKey i18n msg key
|
||||
* @param value i18n msg value
|
||||
* @returns
|
||||
*/
|
||||
export async function useI18nConfirm(i18nKey: string = '', value = {}) {
|
||||
const t = i18n.global.t;
|
||||
return ElMessageBox.confirm(t(i18nKey, value), t('common.hint'), {
|
||||
confirmButtonText: t('common.confirm'),
|
||||
cancelButtonText: t('common.cancel'),
|
||||
type: 'warning',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 表单校验
|
||||
* @param formRef 表单ref
|
||||
* @param callback 校验通过回调
|
||||
* @returns
|
||||
*/
|
||||
export async function useI18nFormValidate(formRef: any) {
|
||||
const t = i18n.global.t;
|
||||
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
ElMessage.error(t('common.formValidationError'));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export function useI18nCreateTitle(i18nKey: string) {
|
||||
const t = i18n.global.t;
|
||||
return t('common.createTitle', { name: t(i18nKey) });
|
||||
}
|
||||
|
||||
export function useI18nEditTitle(i18nKey: string) {
|
||||
const t = i18n.global.t;
|
||||
return t('common.editTitle', { name: t(i18nKey) });
|
||||
}
|
||||
|
||||
export function useI18nDetailTitle(i18nKey: string) {
|
||||
const t = i18n.global.t;
|
||||
return t('common.detailTitle', { name: t(i18nKey) });
|
||||
}
|
||||
|
||||
export function useI18nOperateSuccessMsg() {
|
||||
const t = i18n.global.t;
|
||||
ElMessage.success(t('common.operateSuccess'));
|
||||
}
|
||||
|
||||
export function useI18nSaveSuccessMsg() {
|
||||
const t = i18n.global.t;
|
||||
ElMessage.success(t('common.saveSuccess'));
|
||||
}
|
||||
|
||||
export function useI18nDeleteSuccessMsg() {
|
||||
const t = i18n.global.t;
|
||||
ElMessage.success(t('common.deleteSuccess'));
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import config from '@/common/config';
|
||||
import { unref } from 'vue';
|
||||
import { URL_401 } from '@/router/staticRouter';
|
||||
import openApi from '@/common/openApi';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
|
||||
const baseUrl: string = config.baseApiUrl;
|
||||
|
||||
@@ -27,7 +28,11 @@ const useCustomFetch = createFetch({
|
||||
headers.set('Authorization', token);
|
||||
headers.set('ClientId', getClientId());
|
||||
}
|
||||
|
||||
const themeConfig = useThemeConfig().themeConfig;
|
||||
|
||||
headers.set('Content-Type', 'application/json');
|
||||
headers.set('Accept-Language', themeConfig?.globalI18n);
|
||||
options.headers = headers;
|
||||
|
||||
return { options };
|
||||
@@ -89,7 +94,7 @@ export function useApiFetch<T>(api: Api, params: any = null, reqOptions: Request
|
||||
|
||||
return {
|
||||
execute: async function () {
|
||||
return execUaf(uaf);
|
||||
return execCustomFetch(uaf);
|
||||
},
|
||||
isFetching: uaf.isFetching,
|
||||
data: uaf.data,
|
||||
@@ -100,7 +105,7 @@ export function useApiFetch<T>(api: Api, params: any = null, reqOptions: Request
|
||||
let refreshingToken = false;
|
||||
let queue: any[] = [];
|
||||
|
||||
async function execUaf(uaf: any) {
|
||||
async function execCustomFetch(uaf: any) {
|
||||
try {
|
||||
await uaf.execute(true);
|
||||
} catch (e: any) {
|
||||
@@ -146,7 +151,7 @@ async function execUaf(uaf: any) {
|
||||
// 请求加入队列等待, 防止并发多次请求refreshToken
|
||||
return new Promise((resolve) => {
|
||||
queue.push(() => {
|
||||
resolve(execUaf(uaf));
|
||||
resolve(execCustomFetch(uaf));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -170,7 +175,7 @@ async function execUaf(uaf: any) {
|
||||
queue = [];
|
||||
}
|
||||
|
||||
await execUaf(uaf);
|
||||
await execCustomFetch(uaf);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
445
frontend/src/i18n/en/common.ts
Normal file
445
frontend/src/i18n/en/common.ts
Normal file
@@ -0,0 +1,445 @@
|
||||
// 定义内容
|
||||
export default {
|
||||
common: {
|
||||
create: 'Create',
|
||||
edit: 'Edit',
|
||||
delete: 'Delete',
|
||||
detail: 'Details',
|
||||
add: 'Add',
|
||||
save: 'Save',
|
||||
remove: 'Remove',
|
||||
confirm: 'Confirm',
|
||||
cancel: 'Cancel',
|
||||
submit: 'Submit',
|
||||
operation: 'Operations',
|
||||
name: 'Name',
|
||||
code: 'Code',
|
||||
remark: 'Remark',
|
||||
status: 'Status',
|
||||
username: 'Username',
|
||||
role: 'Role',
|
||||
msg: 'Message',
|
||||
type: 'Type',
|
||||
time: 'Time',
|
||||
account: 'Account',
|
||||
password: 'Password',
|
||||
createTime: 'Create Time',
|
||||
creator: 'Creator',
|
||||
updateTime: 'Update Time',
|
||||
modifier: 'Modifier',
|
||||
keyword: 'Keyword',
|
||||
path: 'Path',
|
||||
tag: 'Tag',
|
||||
more: 'More',
|
||||
enable: 'Enable',
|
||||
disable: 'Disable',
|
||||
hint: 'Hint',
|
||||
yes: 'Yes',
|
||||
no: 'No',
|
||||
refresh: 'Refresh',
|
||||
basic: 'Basic',
|
||||
other: 'Other',
|
||||
reset: 'Reset',
|
||||
success: 'Success',
|
||||
fail: 'Fail',
|
||||
previousStep: 'Previous Step',
|
||||
nextStep: 'Next Step',
|
||||
copy: 'Copy',
|
||||
pleaseInput: 'Please enter {label}',
|
||||
pleaseSelect: 'Please select {label}',
|
||||
formValidationError: 'Please fill in the form information correctly',
|
||||
createTitle: 'Create {name}',
|
||||
editTitle: 'Edit {name}',
|
||||
detailTitle: '{name} Details',
|
||||
deleteConfirm: 'This operation will delete [{name}]. Do you want to continue?',
|
||||
saveSuccess: 'save successfully',
|
||||
deleteSuccess: 'delete successfully',
|
||||
operateSuccess: 'operate successfully',
|
||||
},
|
||||
layout: {
|
||||
user: {
|
||||
title0: 'Component size',
|
||||
langSwitch: 'Language switching',
|
||||
menuSearch: 'Menu search',
|
||||
layoutConf: 'Layout configuration',
|
||||
news: 'news',
|
||||
fullScreenOn: 'Full screen on',
|
||||
fullScreenOff: 'Full screen off',
|
||||
dropdownLarge: 'large',
|
||||
dropdownDefault: 'default',
|
||||
dropdownSmall: 'small',
|
||||
index: 'Home Page',
|
||||
personalCenter: 'Personal Center',
|
||||
logout: 'Log out',
|
||||
dropdown6: 'Code warehouse',
|
||||
searchPlaceholder: 'Menu search',
|
||||
newTitle: 'Notice',
|
||||
newBtn: 'All read',
|
||||
newGo: 'Go to the notification center',
|
||||
newDesc: 'No notice',
|
||||
logOutTitle: 'Tips',
|
||||
logOutMessage: 'This operation will log out. Do you want to continue?',
|
||||
logOutExit: 'Exiting',
|
||||
logoutSuccess: 'Safe exit successful!',
|
||||
},
|
||||
tagsView: {
|
||||
refresh: 'Refresh',
|
||||
close: 'Close',
|
||||
closeOther: 'Close Other',
|
||||
closeAll: 'Close All',
|
||||
fullscreen: 'Fullscreen',
|
||||
closeFullscreen: 'Close Fullscreen',
|
||||
},
|
||||
notFound: {
|
||||
title: 'Wrong address input, please re-enter the address~',
|
||||
msg: 'You can check the web address first, and then re-enter or give us feedback.',
|
||||
backHomepage: 'Back to home page',
|
||||
},
|
||||
noAccess: {
|
||||
title: 'You are not authorized to operate~',
|
||||
loginAgain: 'Login again',
|
||||
},
|
||||
config: {
|
||||
configTitle: 'Layout configuration',
|
||||
terminalTheme: 'Terminal Themes',
|
||||
theme: 'Theme',
|
||||
custom: 'Custom',
|
||||
fontColor: 'Font Color',
|
||||
backgroundColor: 'Background Color',
|
||||
cursorColor: 'Cursor Color',
|
||||
fontSize: 'Font Size',
|
||||
fontWeight: 'Font Weight',
|
||||
editorSetting: 'Editor Settings',
|
||||
globalSetting: 'Global Settings',
|
||||
pagesize: 'Page Size',
|
||||
globalTheme: 'Global Themes',
|
||||
twoTopTitle: 'top bar set up',
|
||||
|
||||
menuSetting: 'Menu set up',
|
||||
menuBar: 'Menu background',
|
||||
menuBarFontColor: 'Menu default font color',
|
||||
menuBarActiveColor: 'Menu Highlight Color',
|
||||
isMenuBarColorGradual: 'Menu gradient',
|
||||
|
||||
twoColumnsTitle: 'Columns set up',
|
||||
twoTopBar: 'Top bar background',
|
||||
twoTopBarColor: 'Top bar default font color',
|
||||
twoIsTopBarColorGradual: 'Top bar gradient',
|
||||
|
||||
twoColumnsMenuBar: 'Column menu background',
|
||||
twoColumnsMenuBarColor: 'Default font color bar menu',
|
||||
twoIsColumnsMenuBarColorGradual: 'Column gradient',
|
||||
twoIsColumnsMenuHoverPreload: 'Column Menu Hover Preload',
|
||||
|
||||
interfaceSetting: 'Interface settings',
|
||||
isCollapse: 'Menu horizontal collapse',
|
||||
isUniqueOpened: 'Menu accordion',
|
||||
isFixedHeader: 'Fixed header',
|
||||
isClassicSplitMenu: 'Classic layout split menu',
|
||||
isLockScreen: 'Open the lock screen',
|
||||
lockScreenTime: 'screen locking(s/s)',
|
||||
interfaceDisplay: 'Interface display',
|
||||
isShowLogo: 'Sidebar logo',
|
||||
isBreadcrumb: 'Open breadcrumb',
|
||||
isBreadcrumbIcon: 'Open breadcrumb icon',
|
||||
isTagsview: 'Open tagsview',
|
||||
isTagsviewIcon: 'Open tagsview Icon',
|
||||
isCacheTagsView: 'Enable tagsview cache',
|
||||
isSortableTagsView: 'Enable tagsview drag',
|
||||
isShareTagsView: 'Enable tagsview sharing',
|
||||
isFooter: 'Open footer',
|
||||
isGrayscale: 'Grey model',
|
||||
isInvert: 'Color weak mode',
|
||||
isDark: 'Dark Mode',
|
||||
isWartermark: 'Turn on watermark',
|
||||
wartermarkText: 'Watermark copy',
|
||||
otherSetting: 'Other settings',
|
||||
tagsStyle: 'Tagsview style',
|
||||
animation: 'Page animation',
|
||||
columnsAsideStyle: 'Column style',
|
||||
columnsAsideLayout: 'Column layout',
|
||||
layoutSwitch: 'Layout switch',
|
||||
defaults: 'One',
|
||||
classic: 'Two',
|
||||
transverse: 'Three',
|
||||
columns: 'Four',
|
||||
},
|
||||
},
|
||||
staticRoutes: {
|
||||
signIn: 'signIn',
|
||||
notFound: 'notFound',
|
||||
noPower: 'noPower',
|
||||
},
|
||||
upgrade: {
|
||||
title: 'New version',
|
||||
msg: 'The new version is available, please update it now! Dont worry, the update is fast!',
|
||||
desc: 'Prompt: Update will restore the default configuration',
|
||||
btnOne: 'Cruel refusal',
|
||||
btnTwo: 'Update now',
|
||||
btnTwoLoading: 'Updating',
|
||||
},
|
||||
menu: {
|
||||
index: 'Home Page',
|
||||
personalCenter: 'Personal Center',
|
||||
|
||||
tag: 'Tag',
|
||||
tagTree: 'Tag Tree',
|
||||
tagSave: 'Save Tag',
|
||||
tagDelete: 'Delete Tag',
|
||||
authorization: 'Authorization',
|
||||
authorizationBase: 'Base Permission',
|
||||
authorizationSave: 'Save Authorization',
|
||||
authorizationDelete: 'Delete Authorization',
|
||||
team: 'Team',
|
||||
teamSave: 'Save Team',
|
||||
teamDelete: 'Delete Team',
|
||||
teamMemberAdd: 'Add Member',
|
||||
teamMemberDelete: 'Delete Member',
|
||||
teamTagSave: 'Save Team Tag',
|
||||
|
||||
machine: 'Machine',
|
||||
machineOp: 'Machine Operation',
|
||||
machineOpBase: 'Base Permission',
|
||||
machineList: 'Machine List',
|
||||
machineBase: 'Base Permission',
|
||||
machineCreate: 'Create Machine',
|
||||
machineEdit: 'Edit Machine',
|
||||
machineDelete: 'Delete Machine',
|
||||
machineTerminal: 'Machine Terminal',
|
||||
machineFileConf: 'File',
|
||||
machineFileConfCreate: 'File-Add Config',
|
||||
machineFileConfDelete: 'File-Delete Config',
|
||||
machineFileCreate: 'File-Create',
|
||||
machineFileDelete: 'File-Delete',
|
||||
machineFileWrite: 'File-Write',
|
||||
machineFileUpload: 'File-Upload',
|
||||
machineScript: 'Script',
|
||||
machineScriptSave: 'Script-Save',
|
||||
machineScriptDelete: 'Script-Delete',
|
||||
machineScriptRun: 'Script-Run',
|
||||
machineKillprocess: 'Kill Process',
|
||||
machineCronJob: 'Cron Job',
|
||||
machineCronJobSvae: 'Cron Job-Save',
|
||||
machineCronJobDelete: 'Cron Job-Delete',
|
||||
machineSecurityConfig: 'Security Config',
|
||||
machineSecurityCmdSvae: 'Cmd Config-Save',
|
||||
machineSecurityCmdDelete: 'Cmd Config-Delete',
|
||||
|
||||
dbms: 'DBMS',
|
||||
dbDataOp: 'Data Operation',
|
||||
dbDataOpBase: 'Base Permission',
|
||||
dbDataOpSqlScriptRun: 'SQL Script Run',
|
||||
dbInstance: 'DB Instance',
|
||||
dbInstanceBase: 'Base Permission',
|
||||
dbInstanceSave: 'Save Instance',
|
||||
dbInstanceDelete: 'Delete Instance',
|
||||
dbBase: 'Db Base Permission',
|
||||
dbSave: 'Save Db',
|
||||
dbDelete: 'Delete Db',
|
||||
dbDataSync: 'Data Sync',
|
||||
dbDataSyncBase: 'Base Permission',
|
||||
dbDataSyncSave: 'Save Sync Task',
|
||||
dbDataSyncDelete: 'Delete Sync Task',
|
||||
dbDataSyncChangeStatus: 'Enable/Disable Sync Task',
|
||||
dbDataSyncLog: 'Sync Log',
|
||||
dbTransfer: 'DB Transfer',
|
||||
dbTransferBase: 'Base Permission',
|
||||
dbTransferSave: 'Save Transfer Task',
|
||||
dbTransferDelete: 'Delete Transfer Task',
|
||||
dbTransferChangeStatus: 'Enable/Disable Transfer Task',
|
||||
dbTransferRun: 'Run Transfer Task',
|
||||
dbTransferRunLog: 'Transfer Log',
|
||||
dbTransferFileShow: 'ransfer File-Show',
|
||||
dbTransferFileDelete: 'Transfer File-Delete',
|
||||
dbTransferFileDownload: 'Transfer File-Download',
|
||||
dbTransferFileRun: 'Transfer File-Run',
|
||||
|
||||
redis: 'Redis',
|
||||
redisDataOp: 'Data Operation',
|
||||
redisDataOpBase: 'Base Permission',
|
||||
redisDataOpSave: 'Save Data',
|
||||
redisDataOpDelete: 'Delete Data',
|
||||
redisManage: 'Redis Manage',
|
||||
redisManageBase: 'Base Permission',
|
||||
|
||||
mongo: 'Mongo',
|
||||
mongoDataOp: 'Data Operation',
|
||||
mongoDataOpBase: 'Base Permission',
|
||||
mongoDataOpSave: 'Save Data',
|
||||
mongoDataOpDelete: 'Delete Data',
|
||||
mongoManage: 'Mongo Manage',
|
||||
mongoManageBase: 'Base Permission',
|
||||
|
||||
flow: 'Flow',
|
||||
myTask: 'My Task',
|
||||
myFlow: 'My Flow',
|
||||
flowProcDef: 'Process Define',
|
||||
flowProcDefSave: 'Save Process Define',
|
||||
flowProcDefDelete: 'Delete Process Define',
|
||||
|
||||
system: 'System',
|
||||
menuPermission: 'Menu & Permission',
|
||||
menuPermissionBase: 'Base Permission',
|
||||
menuPermissionAdd: 'Add Menu Permission',
|
||||
menuPermissionEdit: 'Edit Menu Permission',
|
||||
menuPermissionDelete: 'Delete Menu Permission',
|
||||
menuPermissionEnableDisable: 'Enable/Disable Menu Permission',
|
||||
account: 'Account',
|
||||
accountBase: 'Base Permission',
|
||||
accountAdd: 'Add Account',
|
||||
accountEdit: 'Edit Account',
|
||||
accountDelete: 'Delete Account',
|
||||
accountEnableDisable: 'Enable/Disable Account',
|
||||
accountRoleAllocation: 'Role Allocation',
|
||||
role: 'Role',
|
||||
roleBase: 'Base Permission',
|
||||
roleAdd: 'Add Role',
|
||||
roleEdit: 'Edit Role',
|
||||
roleDelete: 'Delete Role',
|
||||
roleMenuPermissionAllocation: 'Menu & Permission Allocation',
|
||||
sysConf: 'System Config',
|
||||
sysConfBase: 'Base Permission',
|
||||
sysConfSave: 'Save System Config',
|
||||
opLog: 'Operation Log',
|
||||
opLogBase: 'Base Permission',
|
||||
|
||||
noPagePermission: 'No Page Permission',
|
||||
authcertShowciphertext: 'Show Ciphertext',
|
||||
},
|
||||
home: {
|
||||
personalInfo: 'Personal Information',
|
||||
welcomeMsg: `Hello, {name}, no matter how bad life gets, it doesn't prevent me from getting better!`,
|
||||
lastLoginIp: 'Last Login Ip',
|
||||
lastLoginTime: 'Last Login Time',
|
||||
msgNotify: 'Message Notification',
|
||||
noOpRecord: 'No operation record',
|
||||
msgTypeLogin: 'Login',
|
||||
msgTypeNotify: 'Notify',
|
||||
},
|
||||
personal: {
|
||||
updateInfo: 'Update Information',
|
||||
basicInfo: 'Basic Information',
|
||||
inputNewPasswordPlaceholder: 'Enter a new password',
|
||||
updatePersonalInfo: 'Updating Personal Information',
|
||||
accountInfo: 'Account Information',
|
||||
currentStatus: 'Current Status',
|
||||
boundUp: 'Bound up',
|
||||
notBound: 'Not bound',
|
||||
immediateBinding: 'Immediate binding',
|
||||
unbundle: 'Unbundle',
|
||||
updateSuccess: 'Update successfully',
|
||||
bindingSuccess: 'Binding successfully',
|
||||
unbundleSuccess: 'Unbundle successfully',
|
||||
},
|
||||
login: {
|
||||
accountPasswordLogin: 'Account Password Login',
|
||||
thirdPartyLogin: 'Third Party login',
|
||||
ldapLogin: 'LDAP Login',
|
||||
inputUsernamePlaceholder: 'Please enter your username',
|
||||
inputPasswordPlaceholder: 'Please enter your password',
|
||||
inputCaptchaPlaceholder: 'Please enter the verification code',
|
||||
login: 'Login',
|
||||
loginFailTip: 'Tip: If you fail to log in more than {loginFailCount} times, you will not be allowed to log in again for {loginFailMin} minutes',
|
||||
loginSuccessTip: 'welcome back!',
|
||||
changePassword: 'Change Password',
|
||||
oldPassword: 'Old Password',
|
||||
newPassword: 'New Password',
|
||||
inputNewPasswordPlaceholder: 'Please enter a new password',
|
||||
passwordRuleTip: 'Must be at least 8 characters long and contain upper/lower case + number + special symbol',
|
||||
passwordChangeSuccessTip: 'The password has been changed successfully, and the new password has been filled in the login password box',
|
||||
otpValidation: 'OTP validation',
|
||||
qrCode: 'QR code',
|
||||
enterOtpCodeTip: 'Enter the authorization code shown in the Token APP',
|
||||
inputOtpCodePlaceholder: 'Please enter the OTP authorization code',
|
||||
updateBasicInfo: 'Modifying basic information',
|
||||
name: 'Name',
|
||||
inputNamePlaceholder: 'Please enter your name',
|
||||
},
|
||||
components: {
|
||||
df: {
|
||||
fieldModelPlaceholder: 'The field associated with model',
|
||||
fieldLabel: 'label',
|
||||
fieldPlaceholder: 'placeholder',
|
||||
optionalValues: 'Optional values',
|
||||
optionalValuesPlaceholder: 'Optional values, use, split',
|
||||
required: 'Required',
|
||||
},
|
||||
terminal: {
|
||||
connError: 'Connection error',
|
||||
notConn: 'Not connected',
|
||||
connSuccess: 'be connected successfully',
|
||||
connFail: 'connection fail',
|
||||
connErrMsg: 'Tip: Connection error...',
|
||||
connConfirm: 'Are you sure to reconnect?',
|
||||
connected: 'Connected',
|
||||
search: 'Search',
|
||||
reConnTips: 'Click the connection status to reconnect',
|
||||
minimize: 'Minimize',
|
||||
fullScreenTitle: 'Full screen | Exits from full screen',
|
||||
close: 'Close',
|
||||
|
||||
serachPlaceholder: 'Please enter the search content, press enter search',
|
||||
regexMatch: 'Regex Match',
|
||||
fullWordMatching: 'Full Word Matching',
|
||||
caseSensitive: 'Case Sensitive',
|
||||
incrementalSearch: 'Incremental Search',
|
||||
previous: 'Previous',
|
||||
next: 'Next',
|
||||
noMatchMsg: 'No matching item is found',
|
||||
},
|
||||
crontab: {
|
||||
crontabInputPlaceholder: 'Click the left button to configure',
|
||||
crontabTitle: 'Generate cron',
|
||||
second: 'Second',
|
||||
minute: 'Minute',
|
||||
hour: 'Hour',
|
||||
day: 'Day',
|
||||
month: 'Month',
|
||||
week: 'Week',
|
||||
year: 'Year',
|
||||
timeExpression: 'Time Expression',
|
||||
crontabCompleteExpression: 'Crontab Complete Expression',
|
||||
|
||||
dayCrontype1: 'Allowed wildcard [, - * / L M]',
|
||||
crontype2: 'Not specify',
|
||||
crontype3: 'Cycle from',
|
||||
|
||||
crontypeFrom: 'Starting on the',
|
||||
crontypeEvery: 'It is executed every',
|
||||
appoint: 'Appoint',
|
||||
|
||||
crontypeStartDay: 'th',
|
||||
crontypeExecDay: 'days',
|
||||
monthLastDay: 'Last day of the month',
|
||||
|
||||
hourCronType1: 'Allowed wildcard [, - * /]',
|
||||
crontypeStartHour: "o 'clock",
|
||||
crontypeExecHour: 'hours',
|
||||
|
||||
crontypeStartMin: 'minutes',
|
||||
crontypeExecMin: 'minutes',
|
||||
|
||||
crontypeStartSecond: 'seconds',
|
||||
crontypeExecSecond: 'seconds',
|
||||
|
||||
crontypeStartMonth: 'months',
|
||||
crontypeExecMonth: 'months',
|
||||
|
||||
yearly: 'Yearly',
|
||||
crontypeStartYear: 'years',
|
||||
crontypeExecYear: 'years',
|
||||
|
||||
weekCronType1: 'Allowed wildcard [, - * / L #]',
|
||||
monday: 'Monday',
|
||||
tuesday: 'Tuesday',
|
||||
wednesday: 'Wednesday',
|
||||
thursday: 'Thursday',
|
||||
friday: 'Friday',
|
||||
saturday: 'Saturday',
|
||||
sunday: 'Sunday',
|
||||
|
||||
last5runTimes: 'Last 5 running times',
|
||||
calculationing: 'In the calculation result',
|
||||
},
|
||||
},
|
||||
};
|
||||
207
frontend/src/i18n/en/db.ts
Normal file
207
frontend/src/i18n/en/db.ts
Normal file
@@ -0,0 +1,207 @@
|
||||
export default {
|
||||
db: {
|
||||
// db instance
|
||||
dbManage: 'DB Management',
|
||||
port: 'Port',
|
||||
connParam: 'Connection Params',
|
||||
keywordPlaceholder: 'host / name / code',
|
||||
acName: 'Credential',
|
||||
dbInst: 'DB Instance',
|
||||
manageDbTitle: 'Manage the [{instName}] database',
|
||||
sqlitePathPlaceholder: 'Please enter the absolute address of the sqlite file on the server',
|
||||
connParamPlaceholder: 'Other connection parameters of the form key1=value1&key2=value2',
|
||||
connSuccess: 'be connected successfully',
|
||||
showDb: 'View DB',
|
||||
db: 'Database',
|
||||
dbFilterPlaceholder: 'DB name: Input filterable',
|
||||
sqlRecord: 'SQL records',
|
||||
dump: 'Export',
|
||||
dumpContent: 'Export Content',
|
||||
structure: 'Structure',
|
||||
data: 'Data',
|
||||
extName: 'Ext Name',
|
||||
dbFilterPlacehoder: 'Filter by database name',
|
||||
allDb: 'All DB',
|
||||
dumpDb: 'Export DB',
|
||||
getDbMode: 'Get DB Mode',
|
||||
noDumpDbMsg: 'Add the database you want to export',
|
||||
allSelect: 'check all',
|
||||
selectDbPlacehoder: '',
|
||||
|
||||
// db
|
||||
dbInstInfo: 'DB Instance Info',
|
||||
newQuery: 'New Query',
|
||||
locationTagTree: 'Navigate to the specified position in the left tree',
|
||||
dbShowSetting: 'DB View Setting',
|
||||
showFieldComments: 'Show column comment',
|
||||
autoLocationTagTree: 'Automatically locate the tree nodes',
|
||||
cacheTableInfo: 'Cache table information -[If not enabled, get table information in real time]',
|
||||
dbName: 'DB Name',
|
||||
table: 'Table',
|
||||
createTable: 'Create Table',
|
||||
tableOp: 'Table Operation',
|
||||
copyTable: 'Copy Table',
|
||||
renameTable: 'Rename',
|
||||
editTable: 'Edit',
|
||||
delTable: 'Delete Table',
|
||||
close: 'Close',
|
||||
closeOther: 'Close Other',
|
||||
noDbInstMsg: 'Select the database instance and the corresponding schema',
|
||||
query: 'Query',
|
||||
nQuery: 'NewQuery',
|
||||
renamePrompt: 'Rename table 【{db}.{tableName}】',
|
||||
noChange: 'No change',
|
||||
isCopyTableData: 'Do you copy data?',
|
||||
execSuccess: 'Successful execution',
|
||||
execFail: 'Execution failure',
|
||||
sqlScriptRun: 'Run SQL Script',
|
||||
saveSql: 'Save SQL',
|
||||
execInfo: 'Execution info',
|
||||
result: 'Result',
|
||||
times: 'times',
|
||||
resultSet: 'Result Set',
|
||||
tableDataEmptyTextTips:
|
||||
'tips: Single table query at the beginning of select * or click the default query data of the table name, double-click the data online modification',
|
||||
noSelctRunSqlMsg: 'Select the sql you want to execute',
|
||||
enterExecRemarkTips: 'Please enter remark',
|
||||
execRemarkPlaceholder: 'Enter the remark to execute the sql',
|
||||
currentSqlTabIsRunning: 'The current result set tab is being executed, please use the new TAB to execute',
|
||||
sqlCannotEmpty: 'sql content cannot be empty',
|
||||
enterSqlScriptNameTips: 'Please enter the SQL script name',
|
||||
scriptFileUploadRunning: `'{filename}' is being uploaded for execution, please pay attention to the result notification`,
|
||||
runSql: 'Run SQL',
|
||||
newTabRunSql: 'NewTab Run SQL',
|
||||
formatSql: 'Format SQL',
|
||||
|
||||
execTime: 'execution time',
|
||||
oneClickCopy: 'One click copy',
|
||||
asc: 'Asc',
|
||||
desc: 'Desc',
|
||||
fixed: 'Fixed',
|
||||
cancelFiexd: 'Cancel Fixed',
|
||||
formView: 'Form View',
|
||||
genJson: 'Generating JSON',
|
||||
exportCsv: 'Export CSV',
|
||||
exportSql: 'Export SQL',
|
||||
onlySelectOneData: 'Only one row can be selected',
|
||||
|
||||
editField: 'Edit field',
|
||||
valueTypeNoMatch: 'The input does not match the type',
|
||||
|
||||
tableFieldConf: 'Table field Configuration',
|
||||
columnFilterPlaceholder: 'Enter column name or remark filter',
|
||||
selectAll: 'Select All',
|
||||
submitUpdate: 'Submit changes',
|
||||
cancelUpdate: 'Cancel changes',
|
||||
autoCompleteColumnPlaceholder:
|
||||
'Select a column or enter a SQL conditional expression and press Enter or click the query icon to filter the results. The input can be prompted by the field name',
|
||||
selectColumn: 'Select Column',
|
||||
columnName: 'Column Name',
|
||||
homePage: 'Home Page',
|
||||
previousPage: 'Previous Page',
|
||||
rowsPage: 'rows/page',
|
||||
rows: 'rows',
|
||||
conditionInputDialogTitle: 'Enter the value of [{columnName}]',
|
||||
addDataDialogTitle: 'Add `{tableName}` table data',
|
||||
|
||||
exportContent: 'Export Content',
|
||||
selectExportTable: 'Select the table you want to export first',
|
||||
tableNamePlaceholder: 'Table name: Input filterable',
|
||||
comment: 'Comment',
|
||||
commentPlaceholder: 'Comment: Input filterable',
|
||||
dataSize: 'Data Size',
|
||||
indexSize: 'Index Size',
|
||||
column: 'Column',
|
||||
index: 'Index',
|
||||
nullable: 'Nullable',
|
||||
seqInIndex: 'Sequence number',
|
||||
|
||||
// DbSqlExecLog
|
||||
selectDbPlaceholder: 'Please select database',
|
||||
restoreSql: 'Restore SQL',
|
||||
stmtType: 'Statement type',
|
||||
execUser: 'Executor',
|
||||
execRes: 'Result',
|
||||
oldValue: 'Old Value',
|
||||
|
||||
// db transfer
|
||||
pleaseSetting: 'Please set',
|
||||
log: 'Logs',
|
||||
stop: 'Stop',
|
||||
run: 'Run',
|
||||
file: 'File',
|
||||
taskName: 'Task Name',
|
||||
srcDb: 'Source DB',
|
||||
runState: 'Run State',
|
||||
createDbTransferDialogTitle: 'Added DB transfer task (transfer does not change the source DB)',
|
||||
editDbTransferDialogTitle: 'Modify the DB transfer task (transfer does not change the source DB)',
|
||||
stopConfirm: 'Sure to stop?',
|
||||
runConfirm: 'Sure to run?',
|
||||
transferFileManage: 'Transfer file management',
|
||||
dbFileType: 'DB dialect file',
|
||||
targetDb: 'Target DB',
|
||||
fileDbType: 'SQL Dialect',
|
||||
transferFileRunDialogTitle: 'Specify the database to execute the sql file',
|
||||
targetDbTypeSelectError: 'Please select [{dbType}] database',
|
||||
cronAble: 'Timed transfer',
|
||||
transferMode: 'Transfer Mode',
|
||||
transfer2Db: 'Transfer to DB',
|
||||
transfer2File: 'Transfer to File',
|
||||
fileSaveDays: 'File retention days',
|
||||
transferStrategy: 'Transfer Strategy',
|
||||
day: 'Day',
|
||||
transferFull: 'Full',
|
||||
transferIncrement: 'Increment(not yet available)',
|
||||
nameCase: 'Convert',
|
||||
none: 'None',
|
||||
lower: 'Lower',
|
||||
upper: 'Upper',
|
||||
dbObj: 'DB',
|
||||
allTable: 'All Table',
|
||||
custom: 'Custom',
|
||||
noTransferTableMsg: 'Select the table you want to transfer',
|
||||
|
||||
// dbSync
|
||||
recentState: 'Recent task status',
|
||||
dbSync: 'Data Synchronism',
|
||||
realTime: 'Real Time',
|
||||
noRealTime: 'Non-real time',
|
||||
srcDataSql: 'Source Data SQL',
|
||||
targetDbTable: 'Target Db table',
|
||||
pageSize: 'Page Size',
|
||||
pageSizePlaceholder: 'Size of data per page queried when synchronizing data',
|
||||
updateField: 'Update Field',
|
||||
updateFieldTips: 'The current maximum value of this field will be included when querying the data source, with aliases such as t.reate_time',
|
||||
updateFiledPlaceholder: 'The current maximum value of this field will be included when querying the data source',
|
||||
updateFieldValue: 'Update Field Value',
|
||||
updateFieldValueTips:
|
||||
'The record updates the current value of the field, such as: current time, current date, etc., and the next time the data is queried, the value condition will be added',
|
||||
updateFieldValuePlaceholder: 'Update the current maximum value of the field',
|
||||
fieldValueSrc: 'Source of values',
|
||||
fieldValueSrcTips:
|
||||
'The field name of the updated value is taken from the query result. The default is the same as the updated field. If the query result specifies a field alias and is inconsistent with the original updated field, the field value is the current updated value',
|
||||
fieldValueSrcPlaceholder: 'Update the value source',
|
||||
fieldMap: 'Field Mapping',
|
||||
srcField: 'Source Field',
|
||||
targetField: 'Target Field',
|
||||
sqlPreview: 'SQL Preview',
|
||||
selectSql: 'Select SQL',
|
||||
insertSql: 'Insert SQL',
|
||||
keyDuplicateStrategy: 'Key Duplicate Strategy',
|
||||
fieldMapError: 'There are duplicate target fields in the field map, please check',
|
||||
noDataSqlMsg: 'Please enter data sql',
|
||||
notSelectSql: 'sql statement error, please enter the select statement',
|
||||
notOneSql: 'sql statement error, please enter a single query statement',
|
||||
notColumnSql: 'No field found. Check your sql',
|
||||
|
||||
// enums
|
||||
getDbNamesModeAuto: 'Real-time get db',
|
||||
getDbNamesModeAssign: 'Specifying the db name',
|
||||
|
||||
ignore: 'Ignore',
|
||||
replate: 'Replate',
|
||||
|
||||
running: 'Running',
|
||||
waitRun: 'Wait Run',
|
||||
},
|
||||
};
|
||||
90
frontend/src/i18n/en/flow.ts
Normal file
90
frontend/src/i18n/en/flow.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
export default {
|
||||
flow: {
|
||||
// procdef
|
||||
approvalNode: 'Approval Node',
|
||||
procdef: 'Process Definition',
|
||||
triggeringCondition: 'Condition',
|
||||
triggeringConditionTips: 'go template syntax. If the output is 1, the approval process is triggered',
|
||||
conditionPlaceholder: 'Trigger condition, return value =1, means to trigger the approval process',
|
||||
conditionDefault: `{{/* DBMS- Run Sql rules The param parameter is described as follows */}}
|
||||
{{/* stmtType: select / read / insert / update / delete / ddl ; */}}
|
||||
{{ if eq .bizType "db_sql_exec_flow"}}
|
||||
{{/* Enable process approval when select and read statements are not available */}}
|
||||
{{ if and (ne .param.stmtType "select") (ne .param.stmtType "read") }}
|
||||
1
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* Redis-Run Cmd rules; param: parameter is described as follows */}}
|
||||
{{/* cmdType: read(Read cmd) / write(Write cmd); */}}
|
||||
{{/* cmd: get/set/hset... */}}
|
||||
{{ if eq .bizType "redis_run_cmd_flow"}}
|
||||
{{ if eq .param.cmdType "write" }}
|
||||
1
|
||||
{{ end }}
|
||||
{{ end }}`,
|
||||
nodeName: 'Node Name',
|
||||
nodeNameTips: 'Click the specified node to drag and drop sort',
|
||||
auditor: 'Auditor',
|
||||
tasksNotEmpty: 'Please improve the task of the approval node',
|
||||
tasksNoComplete: 'Please complete the task information of the {index} th approval node',
|
||||
// procdef status enum
|
||||
enable: 'Enable',
|
||||
disable: 'Disable',
|
||||
|
||||
// procinst
|
||||
startProcess: 'Start Process',
|
||||
cancelProcessConfirm: 'Confirm canceling the process?',
|
||||
bizType: 'Business Type',
|
||||
bizKey: 'Business Key',
|
||||
initiator: 'Initiator',
|
||||
procdefName: 'Process Name',
|
||||
bizStatus: 'Business Status',
|
||||
startingTime: 'Starting Time',
|
||||
endTime: 'End Time',
|
||||
duration: 'Duration',
|
||||
proc: 'Process',
|
||||
bizInfo: 'Business Information',
|
||||
approvalNodeNotExist: 'There is no approval node',
|
||||
resourceNotExistFlow: 'This resource does not require an approval operation',
|
||||
procinstFormError: 'Please fill in the information correctly',
|
||||
procinstStartSuccess: 'Process initiated successfully',
|
||||
// db run sql flow biz
|
||||
runSql: 'Run SQL',
|
||||
selectDbPlaceholder: 'Please select database',
|
||||
// redis run cmd flow biz
|
||||
runCmd: 'Rum Cmd',
|
||||
selectRedisPlaceholder: 'Select the Redis instance and db',
|
||||
cmdPlaceholder: `For example: SET 'key' 'value'; Multiple commands; segmentation`,
|
||||
// ProcinstStatusEnum
|
||||
active: 'Active',
|
||||
completed: 'Completed',
|
||||
suspended: 'Suspended',
|
||||
terminated: 'Terminated',
|
||||
cancelled: 'Cancelled',
|
||||
handleResult: 'Result of handling',
|
||||
runResult: 'Result of execution',
|
||||
// ProcinstBizStatus
|
||||
waitHandle: 'Pending',
|
||||
handleSuccess: 'Success',
|
||||
handleFail: 'Fail',
|
||||
noHandle: 'No processing',
|
||||
// ProcinstTaskStatus
|
||||
waitProcess: 'Waiting',
|
||||
pass: 'Pass',
|
||||
reject: 'Reject',
|
||||
back: 'Back',
|
||||
canceled: 'Canceled',
|
||||
// FlowBizType
|
||||
dbSqlExec: 'DBMS-Run SQL',
|
||||
redisRunCmd: 'Redis-Run Cmd',
|
||||
|
||||
// task
|
||||
audit: 'Audit',
|
||||
procinstStatus: 'Process status',
|
||||
taskStatus: 'Task status',
|
||||
taskName: 'Task Name',
|
||||
taskBeginTime: 'Begin Time',
|
||||
flowAudit: 'Approval Process',
|
||||
},
|
||||
};
|
||||
134
frontend/src/i18n/en/machine.ts
Normal file
134
frontend/src/i18n/en/machine.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
export default {
|
||||
machine: {
|
||||
keywordPlaceholder: 'ip / Name / Code',
|
||||
acName: 'Credential',
|
||||
runningStat: 'Running Status',
|
||||
fs: 'Disk (mount point => available/total)',
|
||||
memberInfo: 'Memory (available/total)',
|
||||
cpuInfo: 'CPU (free)',
|
||||
file: 'File',
|
||||
directory: 'Directory',
|
||||
folder: 'Folder',
|
||||
script: 'Script',
|
||||
process: 'Process',
|
||||
terminalPlayback: 'Terminal Playback',
|
||||
createMachine: 'Create Machine',
|
||||
editMachine: 'Edit Machine',
|
||||
reConnTips: 'Are you sure to reconnect?',
|
||||
clickReConn: 'Click to reconnect',
|
||||
port: 'Port',
|
||||
sshTunnel: 'SSH Tunnel',
|
||||
newOpenTabTerminalTips: 'Hold down ctrl to open a new TAB',
|
||||
newTab: 'New TAB',
|
||||
openTerminal: 'Open Terminal',
|
||||
newTabOpenTerminal: 'Open Terminal(New TAB)',
|
||||
fileManage: 'File Manage',
|
||||
scriptManage: 'Script Manage',
|
||||
machineState: 'Machine State',
|
||||
remoteFileDesktopManage: 'Remote desktop file management', // Remote desktop file management
|
||||
remoteDesktop: 'Remote Desktop',
|
||||
protocol: 'Protocol',
|
||||
ipAndPort: 'ip and port',
|
||||
connSuccess: 'be connected successfully',
|
||||
noAcErrMsg: 'Please complete the voucher account information',
|
||||
|
||||
// MachineRec
|
||||
playback: 'Playback',
|
||||
cmd: 'Command',
|
||||
execCmdRecord: 'Executive command record',
|
||||
execTime: 'Execution time',
|
||||
operator: 'Operator',
|
||||
beginTime: 'Begin Time',
|
||||
endTime: 'End Time',
|
||||
|
||||
// MachineStats
|
||||
basicInfo: 'basic information',
|
||||
hostname: 'Hostname',
|
||||
runTime: 'Run Time',
|
||||
totalTask: 'Total Task',
|
||||
runningTask: 'Running Task',
|
||||
load: 'Load',
|
||||
disk: 'Disk',
|
||||
mountPoint: 'Mount Point',
|
||||
available: 'Available',
|
||||
used: 'Used',
|
||||
networkCard: 'Network Card',
|
||||
receive: 'Receive',
|
||||
send: 'Send',
|
||||
memory: 'Memory',
|
||||
cpuUsageRate: 'Cpu Usage Rate',
|
||||
|
||||
// process
|
||||
processName: 'Process Name',
|
||||
selectSortType: 'Please select a sort type',
|
||||
selectProcessNum: 'Please select the number of processes',
|
||||
cpuDesc: 'CUP descending',
|
||||
memDesc: 'Memory descending',
|
||||
virtualMemory: 'Virtual Memory',
|
||||
fixedMemory: 'Fixed Memory',
|
||||
procState: 'process state',
|
||||
startTime: 'Start Time',
|
||||
procCpuRunTime: 'The actual CPU time used by the process',
|
||||
killProcConfirm: 'Are you sure to terminate the process?',
|
||||
kill: 'Kill',
|
||||
|
||||
// script
|
||||
execute: 'Execute',
|
||||
scriptParam: 'Script Param',
|
||||
execResult: 'result of execution',
|
||||
execCompleted: 'execution is completed',
|
||||
scriptParamTips1: '1. You can use {{.model}} as a placeholder in the script content',
|
||||
scriptParamTips2: '2. When executing the script, you can enter the corresponding form content to replace the placeholder',
|
||||
scriptResultEnumResult: 'Have result',
|
||||
scriptResultEnumNoResult: 'No result',
|
||||
scriptResultEnumRealTime: 'Real-time',
|
||||
scriptTypeEnumPrivate: 'Private',
|
||||
scriptTypeEnumPublic: 'Public',
|
||||
|
||||
// security
|
||||
cmdConfig: 'Command Config',
|
||||
filterCmds: 'Filter command',
|
||||
relateMachine: 'Associated machine',
|
||||
newCmd: 'New Command',
|
||||
cmdPlaceholder: 'Enter the command regular expression',
|
||||
|
||||
// cronjob
|
||||
cronjob: 'Cronjob',
|
||||
machineCode: 'Machine Code',
|
||||
cronjobRunning: 'Running',
|
||||
cronjobNoRun: 'Not Run',
|
||||
cronjobRun: 'Execute',
|
||||
cronJobExecStatusEnumSuccess: 'Success',
|
||||
cronJobExecStatusEnumFail: 'Fail',
|
||||
cronjobExecResult: 'Execute Result',
|
||||
cronjobExecTime: 'Execute Time',
|
||||
cronjobExecRecord: 'Record of execution',
|
||||
runSuccess: 'Executed successfully',
|
||||
cronjobRunState: 'Run State',
|
||||
execResRecordType: 'Result record type',
|
||||
cronExpression: 'Cron Expression',
|
||||
|
||||
// file
|
||||
upload: 'Upload',
|
||||
download: 'Download',
|
||||
copy: 'Copy',
|
||||
move: 'Move',
|
||||
paste: 'Paste',
|
||||
fileNameFilterPlaceholder: 'Name: Input filterable',
|
||||
calculate: 'Calculate',
|
||||
modificationTime: 'Modify Time',
|
||||
attribute: 'Attribute',
|
||||
user: 'User',
|
||||
group: 'Group',
|
||||
renameTips: 'rename: Double-click the file name cell and then press Ente',
|
||||
fileDetail: 'File Details',
|
||||
createFile: 'Create File',
|
||||
pasteSuccess: 'Paste successfully',
|
||||
sameDirNoPaste: 'Can not paste in the same directory',
|
||||
renameSuccess: 'Rename successfully',
|
||||
newFileNameNotEmpty: 'he new name cannot be empty',
|
||||
fileTooLargeTips: 'The file is too large, please download and use it',
|
||||
uploadSuccess: 'Upload successfully',
|
||||
fileExceedsSysConf: 'The uploaded file exceeds the system configuration [{uploadMaxFileSize}]',
|
||||
},
|
||||
};
|
||||
44
frontend/src/i18n/en/mongo.ts
Normal file
44
frontend/src/i18n/en/mongo.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
export default {
|
||||
mongo: {
|
||||
mongo: 'MongoDB',
|
||||
db: 'DB',
|
||||
keywordPlaceholder: 'host / name / code',
|
||||
connUrl: 'Connection URL',
|
||||
|
||||
dbList: 'DB List',
|
||||
isEmpty: 'Is Empty',
|
||||
deleteDbConfirm: 'Make sure to delete the db?',
|
||||
coll: 'Collection',
|
||||
deleteCollConfirm: 'Are you sure to delete the collection??',
|
||||
collState: 'Collection State',
|
||||
createDbAndColl: 'Crate DB & Collection',
|
||||
dbName: 'DB Name',
|
||||
collName: 'Collection Name',
|
||||
createColl: 'Create Collection',
|
||||
collTitle: '`{dbName}` Collection',
|
||||
|
||||
template: 'Template',
|
||||
cmdTemplatePlaceholder: 'Select command template',
|
||||
moreCmdTips: 'Select more commands to view ',
|
||||
usersInfoDesc: 'Get user information',
|
||||
createUserDesc: 'Create a new user',
|
||||
grantRolesToUserDesc: 'Grants additional roles to the user',
|
||||
dropUserDesc: 'Drop User',
|
||||
roleInfoDesc: 'Get Role Information',
|
||||
createRoleDesc: 'Create Role',
|
||||
runSuccess: 'Run successfully',
|
||||
|
||||
queryParam: 'query parameter',
|
||||
queryParamPlaceholder: 'Click to enter the corresponding search conditions',
|
||||
deleteDocConfirm: 'Are you sure to delete the document?',
|
||||
doc: 'Document',
|
||||
findParamErrMsg: 'The filter or sort field json string value is incorrect. Note: The json key requires double quotes',
|
||||
docErrMsg: 'The document content is incorrect and cannot be parsed into a json object',
|
||||
insertSuccess: 'Insert successfully',
|
||||
insertFail: 'Insert failure',
|
||||
idNotExist: 'The _id attribute for the document does not exist',
|
||||
modifyFail: 'fail to modify',
|
||||
deleteFail: 'fail to delete',
|
||||
docParse2jsonFail: 'Parsing the document content into a json object failed',
|
||||
},
|
||||
};
|
||||
66
frontend/src/i18n/en/redis.ts
Normal file
66
frontend/src/i18n/en/redis.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
export default {
|
||||
redis: {
|
||||
standaloneInfo: 'Standalone',
|
||||
clusterInfo: 'Cluster',
|
||||
node: 'Node',
|
||||
clusterIpTips:
|
||||
'p:port1@port2 :port1 indicates the port through which the redis server communicates with clients, and port2 indicates the port through which nodes in the cluster communicate',
|
||||
masterSlaveRelationTips: `If the node is slave and the master node is known, it is the ID of the master node. Otherwise, the symbol '-'`,
|
||||
configEpochTips:
|
||||
'The epoch value of a node (or the epoch value of its primary node if the node is a slave node). Each time a node fails to switch, a new, unique, increasing epoch is created.',
|
||||
keywordPlaceholder: 'host / name / code',
|
||||
hostTips: `Enter host:port; The sentinel mode is mastername=sentinelhost:port. If the cluster or sentinels need multiple nodes, they can be separated by ','`,
|
||||
nodePassword: 'Node Password',
|
||||
sentinelHostErr: 'Sentinel model host for: mastername = sentinelhost: sentinelport mode',
|
||||
delimiter: 'Delimiter',
|
||||
keyMatchTips: 'match supports * obfuscated key, enter search',
|
||||
loadMore: 'Load More',
|
||||
addKey: 'Adding key',
|
||||
newTabOpen: 'New tab opens',
|
||||
redisSelectErr: 'Select redis first',
|
||||
flushDbTips: 'Make sure to clear all keys of the [{db}] library?',
|
||||
keyNotEmpty: 'The Key cannot be empty',
|
||||
|
||||
// info
|
||||
redisInfoTitle: 'Redis server information',
|
||||
version: 'Version',
|
||||
port: 'Port',
|
||||
mode: 'Mode',
|
||||
os: 'os',
|
||||
uptimeDays: 'Uptime in days',
|
||||
execPath: 'Executable',
|
||||
confFile: 'Config file',
|
||||
clusterEnable: 'Cluster enabled',
|
||||
nodeCount: 'Node count',
|
||||
clientConn: 'Client Connection',
|
||||
connectedNum: 'Connected clients',
|
||||
blockedClientNum: 'Blocked clients',
|
||||
sysCpu: 'used_cpu_sys',
|
||||
userCpu: 'used_cpu_user',
|
||||
sysChildCpu: 'used_cpu_sys_children',
|
||||
userChildCpu: 'used_cpu_user_children',
|
||||
keyCount: 'Key Count',
|
||||
countInfo: 'Count',
|
||||
totalCmdProcess: 'total_commands_processed',
|
||||
curQps: 'instantaneous_ops_per_sec',
|
||||
expiredKeys: 'expired_keys',
|
||||
netInputBytes: 'total_net_input_bytes',
|
||||
netOutputBytes: 'total_net_output_bytes',
|
||||
persistence: 'Persistence',
|
||||
aofEnable: 'aof_enabled',
|
||||
loadingPersistence: 'loading',
|
||||
availableMemory: 'Available',
|
||||
usedMemory: 'Used',
|
||||
|
||||
renameTips: 'Click to rename',
|
||||
ttlPlaceholder: 'Unit (seconds); negative values are permanent',
|
||||
ttlTips: 'Click Change the expiration time',
|
||||
settingSuccess: 'successfully set',
|
||||
permanent: 'Permanent',
|
||||
persistenceConfirm: 'Decide to persist the key?',
|
||||
|
||||
addNewLine: 'Adding new rows',
|
||||
filterPlaceholder: 'Keyword Enter search',
|
||||
deleteConfirm: 'Sure to delete?',
|
||||
},
|
||||
};
|
||||
212
frontend/src/i18n/en/system.ts
Normal file
212
frontend/src/i18n/en/system.ts
Normal file
@@ -0,0 +1,212 @@
|
||||
export default {
|
||||
system: {
|
||||
menu: {
|
||||
filterPlaceholder: 'Input keyword filter (right click operation)',
|
||||
opTips: 'Red and orange fonts indicate disabled status (right click on the resource to operate)',
|
||||
info: 'Information',
|
||||
menu: 'Menu',
|
||||
permission: 'Permission',
|
||||
icon: 'Icon',
|
||||
routerName: 'Router Name',
|
||||
componentPath: 'Component Path',
|
||||
isCache: 'Cache or not',
|
||||
isHide: 'Whether to hide',
|
||||
tagIsDelete: 'Tag cannot be deleted',
|
||||
externalLink: 'External Link',
|
||||
yes: 'Yes',
|
||||
no: 'No',
|
||||
addSubResource: 'Adding subresources',
|
||||
enable: 'Enable',
|
||||
disable: 'Disable',
|
||||
tips: 'Tips',
|
||||
addTopMenu: 'Add a top-level menu',
|
||||
addChildrenMenuTitle: 'Adds `{parentName}` subresources',
|
||||
updateMenu: 'Change `{name}`',
|
||||
success: 'Success',
|
||||
menuCodeTips: `The menu type is the access path (if the menu path does not begin with '/', the access address will automatically concatenate the parent menu path), otherwise it is the unique code of the resource`,
|
||||
menuCodePlaceholder: `A menu that does not begin with '/' will automatically concatenate the parent menu path`,
|
||||
routerNameTips: 'For component caching to work, match the vue component name, such as ResourceLis',
|
||||
componentPathTips: 'Access path components, such as: ` system/resource/ResourceList `, default in ` views ` directory',
|
||||
isCacheTips: `If yes is selected, it will be 'keepalive' cached (reentering the page without refreshing the page and requesting data again), and needs the route name to match the vue component name`,
|
||||
isHideTips:
|
||||
'Select Hide and the route will not appear in the menu bar, but it will still be accessible. Disabled will not be able to access and operate',
|
||||
externalLinkTips: 'Inline: displayed as an iframe, external link: opened in a new TAB',
|
||||
inline: 'Embedded',
|
||||
linkAddress: 'Link Address',
|
||||
linkPlaceholder: 'External/embedded links (http://xxx.com)',
|
||||
menuNameRuleMsg: 'Please enter a resource name',
|
||||
routeNameNotEmpty: 'Route names cannot be empty',
|
||||
resourceCodePatternErrMsg: 'Only 1-32 uppercase letters, numbers, and -.: characters are allowed',
|
||||
assignedRole: 'Assigned Role',
|
||||
},
|
||||
account: {
|
||||
roleAllocation: 'Role Allocation',
|
||||
resetOtp: 'Reset OTP',
|
||||
roleName: 'Role Name',
|
||||
assigner: 'Assigner',
|
||||
allocateTime: 'Allocate Time',
|
||||
name: 'Name',
|
||||
lastLoginTime: 'Last Login Time',
|
||||
usernamePlacholder: '5-16 uppercase letters, numbers, -.: characters',
|
||||
random: 'Random',
|
||||
usernamePatternErrMsg: 'Only 5-16 uppercase letters, numbers, and -.: characters are allowed',
|
||||
accountSearchPlaceholder: 'Enter account fuzzy search and select',
|
||||
accountInfo: 'Account Information',
|
||||
allocateRoleTitle: 'Allocate the `{name}` role',
|
||||
allocated: 'Allocated',
|
||||
undistributed: 'Undistributed',
|
||||
menuAndPermission: 'Menu & Permission',
|
||||
remove: 'Remove',
|
||||
allocation: 'Allocation',
|
||||
roleCode: 'Role Code',
|
||||
roleStatus: 'Role Status',
|
||||
userMenuTitle: '`{name}` menus and permissions',
|
||||
statusEnable: 'Enable',
|
||||
statusDisable: 'Disable',
|
||||
},
|
||||
role: {
|
||||
permissionDetail: 'Permission',
|
||||
permissionAllocate: 'Permission Alloctate',
|
||||
userManage: 'User',
|
||||
roleName: 'Role Name',
|
||||
roleCode: 'Role Code',
|
||||
rolePermissionTitle: '`{name}` menus and permissions',
|
||||
roleCodePlaceholder: 'COMMON begins with the role shared by all accounts',
|
||||
statusEnable: 'Enable',
|
||||
statusDisable: 'Disable',
|
||||
allocateMenuTitle: 'Allocate permissions to `{roleName}`',
|
||||
allocateAccountTitle: 'Account associated with `{roleName}`',
|
||||
addAccount: 'Adding an account',
|
||||
userStatus: 'User Status',
|
||||
assigner: 'Assigner',
|
||||
allocateTime: 'Allocate Time',
|
||||
permissionInfo: 'Permission assignment information',
|
||||
},
|
||||
sysconf: {
|
||||
confItem: 'Config Item',
|
||||
confKey: ' Config Key',
|
||||
permission: 'Permission',
|
||||
permissionPlaceholder: 'Please enter account fuzzy search and select',
|
||||
conf: 'Config',
|
||||
confItemSetting: 'Config Item Setting',
|
||||
confValue: 'Config Value',
|
||||
|
||||
fileConf: 'File Config',
|
||||
fileConfRemark: 'System file config',
|
||||
basePath: 'Base path',
|
||||
baesPathPlaceholder: 'The default is ./file in the directory corresponding to the executable file',
|
||||
|
||||
dbmsConf: 'DBMS Config',
|
||||
dbmsConfRemark: 'DBMS Config',
|
||||
recordQuerySql: 'Record Query Sql',
|
||||
recordQuerySqlPlaceholder: 'Whether to record queries sql',
|
||||
maxResultSet: 'Max Result Set',
|
||||
maxResultSetPlaceholder: 'Maximum number of result sets allowed for sql queries. Note: 0= no limit',
|
||||
sqlExecLimt: 'sql execution time limit',
|
||||
sqlExecLimtPlaceholder: 'After that time (in seconds), the execution is aborted',
|
||||
|
||||
machineConf: 'Machine Config',
|
||||
machineConfRemark: 'Machine related configuration, such as the number of days terminal operation records are kept',
|
||||
uploadMaxFileSize: 'Upload file size limit',
|
||||
uploadMaxFileSizePlaceholder: 'Maximum file size allowed to upload (1MB, 2GB, etc.)',
|
||||
termOpSaveDays: 'Terminal records the retention time',
|
||||
termOpSaveDaysPlaceholder: 'Unit day, after which the terminal operation record will be deleted',
|
||||
guacdHost: 'guacd server ip',
|
||||
guacdHostPlaceholder: 'guacd server ip, default 127.0.0.1',
|
||||
guacdPort: 'guacd server port',
|
||||
guacdPortPlaceholder: 'guacd server port, default 4822',
|
||||
guacdFilePath: 'guacd server file path',
|
||||
guacdFilePathPlaceholder: 'guacd serves the file storage location for mounting the RDP folder',
|
||||
|
||||
systemConf: 'System-wide styling',
|
||||
systemConfRemark: 'Configuration of system icon, title, watermark information, etc',
|
||||
logoIcon: 'Logo Icon',
|
||||
logoIconPlaceholder: 'System logo icon (base64 encoded, svg format recommended, no more than 10k)',
|
||||
title: 'Menu bar title',
|
||||
titlePlaceholder: 'System menu bar title display',
|
||||
viceTitle: 'Login page title',
|
||||
viceTitlePlaceholder: 'The login page title is displayed',
|
||||
useWatermark: 'Watermarking',
|
||||
useWatermarkPlaceholder: 'Whether system watermarking is enabled',
|
||||
watermarkContent: 'Watermark information',
|
||||
watermarkContentPlaceholder: 'Watermark supplementary information, such as company name, etc',
|
||||
|
||||
ldapLoginConf: 'LDAP Login Config',
|
||||
ldapLoginConfRemark: 'LDAP Login Config',
|
||||
ldapEnable: 'Enable',
|
||||
dapEnablePlaceholder: 'Whether ldap login is enabled',
|
||||
host: 'host',
|
||||
port: 'port',
|
||||
bindDN: 'bindDN',
|
||||
bindDnPlaceholder: 'admin account for the LDAP service, for example: "cn=admin,dc=example,dc=com"',
|
||||
bindPwd: 'bindPwd',
|
||||
bindPwdPlaceholder: 'The administrator password for the LDAP service',
|
||||
baseDN: 'baseDN',
|
||||
baseDnPlaceholder: 'The user\'s base DN, for example: "ou=users,dc=example,dc=com"',
|
||||
userFilter: 'userFilter',
|
||||
userFilerPlaceholder: 'How to filter users, such as "(uid=%s), (&(objectClass=organizationalPerson)(uid=%s))"',
|
||||
uidMap: 'uidMap',
|
||||
uidMapPlaceholder: 'Mapping between user id and LDAP field name, such as: cn',
|
||||
udnMap: 'udnMap',
|
||||
udnMapPlaceholder: 'mapping between user name (dispalyName) and LDAP field name, such as displayName',
|
||||
emailMap: 'emailMap',
|
||||
emailMapPlaceholder: 'Mapping between user email and LDAP field name',
|
||||
skipTlsVerfify: 'skipTlsVerfify',
|
||||
skipTlsVerfifyPlaceholder: 'Whether the client skips TLS certificate validation',
|
||||
securityProtocol: 'security protocol',
|
||||
securityProtocolPlaceholder: 'Security protocol (Null does not use security protocol), such as StartTLS, LDAPS',
|
||||
|
||||
oauth2LoginConf: 'OAuth2 Login Config',
|
||||
oauth2LoginConfRemark: 'OAuth2 Login Config',
|
||||
oauth2Enable: 'Enable',
|
||||
oauth2EnablePlaceholder: 'Whether oauth2 login is enabled or not',
|
||||
name: 'Name',
|
||||
namePlaceholder: 'oauth2 name',
|
||||
clientId: 'Client ID',
|
||||
clientIdPlaceholder: 'oauth2 Client ID',
|
||||
clientSecret: 'Client Secret',
|
||||
clientSecretPlaceholder: 'oauth2 Client Secret',
|
||||
authorizationUrl: 'Authorization URL',
|
||||
authorizationUrlPlaceholder: 'oauth2 Authorization url',
|
||||
accessTokenUrl: 'Access Token URL',
|
||||
accessTokenUrlPlaceholder: 'oauth2 gets the token url',
|
||||
redirectUrl: 'Redirect URL',
|
||||
redirectUrlPlaceholder: 'This system url',
|
||||
scope: 'Scopes',
|
||||
scopePlaceholder: 'oauth2 Scopes',
|
||||
resourceUrl: 'Resource URL',
|
||||
resourceUrlPlaceholder: 'Get the user information resource url',
|
||||
userId: 'User ID',
|
||||
userIdPlaceholder: 'User unique identification field The format is type:fieldPath(string:username)',
|
||||
autoRegister: 'Automatic registration',
|
||||
|
||||
accountLoginConf: 'Login Security Settings',
|
||||
accountLoginConfRemark: 'Account Login Security Settings',
|
||||
useCaptcha: 'Login verification code',
|
||||
useCaptchaPlaceholder: 'Whether to enable the login CAPTCHA',
|
||||
useOtp: 'OTP',
|
||||
useOtpPlaceholder: 'Whether two-factor (OTP) validation is enabled',
|
||||
otpIssuer: 'OTP Issuer',
|
||||
loginFailCount: 'Number of login failures',
|
||||
loginFailCountPlaceholder: 'Disable login after n failed login attempts',
|
||||
loginFainMin: 'Prohibited login time',
|
||||
loginFailMinPlaceholder: 'After a specified number of login failures, re-login is prohibited within m minutes',
|
||||
},
|
||||
syslog: {
|
||||
operator: 'Operator',
|
||||
operatorPlaceholder: 'Please enter and select an account number',
|
||||
operatingResult: 'Operating Result',
|
||||
description: 'Description',
|
||||
operatingTime: 'Operating Time',
|
||||
operatingInfo: 'Operating Information',
|
||||
result: 'Result',
|
||||
response: 'Response',
|
||||
resultSuccess: 'Success',
|
||||
resultFail: 'Fail',
|
||||
resultRunning: 'Running',
|
||||
},
|
||||
oauth: {
|
||||
authSuccess: 'Authorization succeeded',
|
||||
},
|
||||
},
|
||||
};
|
||||
55
frontend/src/i18n/en/tag.ts
Normal file
55
frontend/src/i18n/en/tag.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
export default {
|
||||
tag: {
|
||||
relateTag: 'Relate Tag',
|
||||
keywordFilterPlaceholder: 'keyword filter',
|
||||
nameFilterPlaceholder: 'Keyword filtering (right-click node operation)',
|
||||
tagFilterPlaceholder: 'Enter the keyword -> Search for expanded node information',
|
||||
tagTips1: '1. Used to group assets',
|
||||
tagTips2: '2. Can be allocated in team management for resource isolation',
|
||||
tagTips3: '3. Team members who own a parent tag have access to resources that manipulate their own or child tag associations',
|
||||
machine: 'Machine',
|
||||
db: 'Db',
|
||||
code: 'Code',
|
||||
createSubTag: 'Creating child tags',
|
||||
createSubTagTitle: 'Creates a child tag for {codePath}',
|
||||
rootTag: 'Root Tag',
|
||||
selectTagPlaceholder: 'Select the associated tag',
|
||||
},
|
||||
team: {
|
||||
team: 'Team',
|
||||
member: 'Member',
|
||||
addMember: 'Adding members',
|
||||
teamMember: '[{teamName}] Member information',
|
||||
selectAccountTips: 'Please select your account first',
|
||||
joinTime: 'Join Date',
|
||||
accountName: 'Account Name',
|
||||
assigner: 'Assigner',
|
||||
allocateTag: 'Assigned tags',
|
||||
validity: 'Validity Date',
|
||||
effectiveStartTime: 'Effective Start Time',
|
||||
effectiveEndTime: 'Effective End Time',
|
||||
},
|
||||
// authcert
|
||||
ac: {
|
||||
namePlaceholder: 'Please enter a credential name (globally unique)',
|
||||
privateKeyPlaceholder: 'Please copy the contents of the private key file here',
|
||||
privateKeyPwd: 'Secret key passphrase',
|
||||
resourceCode: 'Resource Code',
|
||||
credentialName: 'Credential Name',
|
||||
resourceType: 'Resource Type',
|
||||
credentialType: 'Credential Type',
|
||||
ciphertextType: 'Ciphertext Type',
|
||||
privateKey: 'Private Key',
|
||||
ac: 'Credential',
|
||||
testConn: 'Test Connection',
|
||||
usernameExist: 'The username already exists in the account list',
|
||||
publicAc: 'Public credentials',
|
||||
acTypeEnumPublic: 'Public credentials',
|
||||
acTypeEnumPrivate: 'Ordinary certificate',
|
||||
acTypeEnumPrivileged: 'Privilege credentials',
|
||||
acTypeEnumPrivateDefault: 'Default credentials',
|
||||
ciphertextTypeEnumPassword: 'Password',
|
||||
ciphertextTypeEnumPrivateKey: 'Private key',
|
||||
ciphertextTypeEnumPublic: 'Public credentials',
|
||||
},
|
||||
};
|
||||
56
frontend/src/i18n/index.ts
Normal file
56
frontend/src/i18n/index.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
// 定义语言国际化内容
|
||||
/**
|
||||
* 说明:
|
||||
* 注意国际化定义的字段,不要与原有的定义字段相同。
|
||||
* /src/i18n/(zh-cn、en...)/module.ts 下的 ts 为各模块国际化内容。
|
||||
*/
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
import pinia from '@/store';
|
||||
import { I18nEnum } from '@/common/commonEnum';
|
||||
|
||||
const modules: Record<string, any> = import.meta.glob('./**/*.ts', { eager: true });
|
||||
|
||||
// 读取 pinia 默认语言
|
||||
const { themeConfig } = storeToRefs(useThemeConfig(pinia));
|
||||
|
||||
function initI18n() {
|
||||
// 定义变量内容
|
||||
const messages: any = {};
|
||||
const itemizeMap = new Map<string, any[]>();
|
||||
|
||||
// 对自动引入的 modules 进行分类 en-us、zh-cn
|
||||
// https://vitejs.cn/vite3-cn/guide/features.html#glob-import
|
||||
for (const path in modules) {
|
||||
const parts = path.split('/');
|
||||
const i18n = parts[1];
|
||||
|
||||
const msgs = modules[path].default;
|
||||
if (itemizeMap.get(i18n)) {
|
||||
itemizeMap.get(i18n)?.push(modules[path].default);
|
||||
} else {
|
||||
itemizeMap.set(i18n, [msgs]);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理最终格式
|
||||
itemizeMap.forEach((value, key) => {
|
||||
messages[key] = Object.assign({}, ...value);
|
||||
});
|
||||
|
||||
// https://vue-i18n.intlify.dev/guide/essentials/fallback.html#explicit-fallback-with-one-locale
|
||||
return createI18n({
|
||||
legacy: false,
|
||||
silentTranslationWarn: true,
|
||||
missingWarn: false,
|
||||
silentFallbackWarn: true,
|
||||
fallbackWarn: false,
|
||||
locale: themeConfig.value.globalI18n,
|
||||
fallbackLocale: I18nEnum.ZhCn.value,
|
||||
messages,
|
||||
});
|
||||
}
|
||||
|
||||
// 导出语言国际化
|
||||
export const i18n = initI18n();
|
||||
453
frontend/src/i18n/zh-cn/common.ts
Normal file
453
frontend/src/i18n/zh-cn/common.ts
Normal file
@@ -0,0 +1,453 @@
|
||||
// 定义内容
|
||||
export default {
|
||||
common: {
|
||||
create: '创建',
|
||||
edit: '编辑',
|
||||
delete: '删除',
|
||||
detail: '详情',
|
||||
add: '添加',
|
||||
save: '保存',
|
||||
remove: '移除',
|
||||
confirm: '确定',
|
||||
cancel: '取消',
|
||||
submit: '提交',
|
||||
operation: '操作',
|
||||
name: '名称',
|
||||
code: '编号',
|
||||
remark: '备注',
|
||||
status: '状态',
|
||||
username: '用户名',
|
||||
role: '角色',
|
||||
msg: '消息',
|
||||
type: '类型',
|
||||
time: '时间',
|
||||
account: '账号',
|
||||
password: '密码',
|
||||
createTime: '创建时间',
|
||||
creator: '创建者',
|
||||
updateTime: '更新时间',
|
||||
modifier: '修改者',
|
||||
keyword: '关键字',
|
||||
path: '路径',
|
||||
tag: '标签',
|
||||
more: '更多',
|
||||
enable: '启用',
|
||||
disable: '禁用',
|
||||
hint: '提示',
|
||||
yes: '是',
|
||||
no: '否',
|
||||
refresh: '刷新',
|
||||
basic: '基本',
|
||||
other: '其他',
|
||||
reset: '重置',
|
||||
success: '成功',
|
||||
fail: '失败',
|
||||
previousStep: '上一步',
|
||||
nextStep: '下一步',
|
||||
copy: '复制',
|
||||
pleaseInput: '请输入{label}',
|
||||
pleaseSelect: '请选择{label}',
|
||||
formValidationError: '请正确填写表单信息',
|
||||
createTitle: '创建{name}',
|
||||
editTitle: '编辑{name}',
|
||||
detailTitle: '{name}详情',
|
||||
deleteConfirm: '此操作将删除【{name}】, 是否继续?',
|
||||
saveSuccess: '保存成功',
|
||||
deleteSuccess: '删除成功',
|
||||
operateSuccess: '操作成功',
|
||||
},
|
||||
layout: {
|
||||
user: {
|
||||
title0: '组件大小',
|
||||
langSwitch: '语言切换',
|
||||
menuSearch: '菜单搜索',
|
||||
layoutConf: '布局配置',
|
||||
news: '消息',
|
||||
fullScreenOn: '开全屏',
|
||||
fullScreenOff: '关全屏',
|
||||
dropdownLarge: '大型',
|
||||
dropdownDefault: '默认',
|
||||
dropdownSmall: '小型',
|
||||
index: '首页',
|
||||
personalCenter: '个人中心',
|
||||
logout: '退出登录',
|
||||
searchPlaceholder: '菜单搜索',
|
||||
newTitle: '通知',
|
||||
newBtn: '全部已读',
|
||||
newGo: '前往通知中心',
|
||||
newDesc: '暂无通知',
|
||||
logOutTitle: '提示',
|
||||
logOutMessage: '此操作将退出登录, 是否继续?',
|
||||
logOutExit: '退出中',
|
||||
logoutSuccess: '安全退出成功!',
|
||||
},
|
||||
tagsView: {
|
||||
refresh: '刷新',
|
||||
close: '关闭',
|
||||
closeOther: '关闭其它',
|
||||
closeAll: '全部关闭',
|
||||
fullscreen: '当前页全屏',
|
||||
closeFullscreen: '关闭全屏',
|
||||
},
|
||||
notFound: {
|
||||
title: '地址输入错误,请重新输入地址~',
|
||||
msg: '您可以先检查网址,然后重新输入或给我们反馈问题。',
|
||||
backHomepage: '返回首页',
|
||||
},
|
||||
noAccess: {
|
||||
title: '您未被授权,没有操作权限~',
|
||||
loginAgain: '重新登录',
|
||||
},
|
||||
config: {
|
||||
configTitle: '布局配置',
|
||||
terminalTheme: '终端主题',
|
||||
theme: '主题',
|
||||
custom: '自定义',
|
||||
fontColor: '字体颜色',
|
||||
backgroundColor: '背景颜色',
|
||||
cursorColor: '光标颜色',
|
||||
fontSize: '字体大小',
|
||||
fontWeight: '字体粗细',
|
||||
editorSetting: 'Editor 设置',
|
||||
globalSetting: '全局设置',
|
||||
pagesize: '分页size',
|
||||
globalTheme: '全局主题',
|
||||
|
||||
// 菜单设置
|
||||
menuSetting: '菜单设置',
|
||||
menuBar: '菜单背景',
|
||||
menuBarFontColor: '菜单默认字体颜色',
|
||||
menuBarActiveColor: '菜单高亮背景色',
|
||||
isMenuBarColorGradual: '菜单背景渐变',
|
||||
|
||||
// 顶栏设置
|
||||
topTitle: '顶栏设置',
|
||||
twoColumnsTitle: '分栏设置',
|
||||
twoTopBar: '顶栏背景',
|
||||
twoTopBarColor: '顶栏默认字体颜色',
|
||||
twoIsTopBarColorGradual: '顶栏背景渐变',
|
||||
|
||||
twoColumnsMenuBar: '分栏菜单背景',
|
||||
twoColumnsMenuBarColor: '分栏菜单默认字体颜色',
|
||||
twoIsColumnsMenuBarColorGradual: '分栏菜单背景渐变',
|
||||
twoIsColumnsMenuHoverPreload: '分栏菜单鼠标悬停预加载',
|
||||
|
||||
// 界面设置
|
||||
interfaceSetting: '界面设置',
|
||||
isCollapse: '菜单水平折叠',
|
||||
isUniqueOpened: '菜单手风琴',
|
||||
isFixedHeader: '固定 Header',
|
||||
isClassicSplitMenu: '经典布局分割菜单',
|
||||
isLockScreen: '开启锁屏',
|
||||
lockScreenTime: '自动锁屏(s/秒)',
|
||||
interfaceDisplay: '界面显示',
|
||||
isShowLogo: '侧边栏 Logo',
|
||||
isBreadcrumb: '开启 Breadcrumb',
|
||||
isBreadcrumbIcon: '开启 Breadcrumb 图标',
|
||||
isTagsview: '开启 Tagsview',
|
||||
isTagsviewIcon: '开启 Tagsview 图标',
|
||||
isCacheTagsView: '开启 TagsView 缓存',
|
||||
isSortableTagsView: '开启 TagsView 拖拽',
|
||||
// IsShareTagsView: '开启 TagsView 共用',
|
||||
isFooter: '开启 Footer',
|
||||
isGrayscale: '灰色模式',
|
||||
isInvert: '色弱模式',
|
||||
isDark: '深色模式',
|
||||
// IsWartermark: '开启水印',
|
||||
// WartermarkText: '水印文案',
|
||||
|
||||
// 其他设置
|
||||
otherSetting: '其它设置',
|
||||
tagsStyle: 'Tagsview 风格',
|
||||
animation: '主页面切换动画',
|
||||
columnsAsideStyle: '分栏高亮风格',
|
||||
// fiveColumnsAsideLayout: '分栏布局风格',
|
||||
|
||||
layoutSwitch: '布局切换',
|
||||
defaults: '默认',
|
||||
classic: '经典',
|
||||
transverse: '横向',
|
||||
columns: '分栏',
|
||||
// tipText: '点击下方按钮,复制布局配置去 `src/stores/themeConfig.ts` 中修改。',
|
||||
// copyText: '一键复制配置',
|
||||
// resetText: '一键恢复默认',
|
||||
// copyTextSuccess: '复制成功!',
|
||||
// copyTextError: '复制失败!',
|
||||
},
|
||||
},
|
||||
staticRoutes: {
|
||||
signIn: '登录',
|
||||
notFound: '找不到此页面',
|
||||
noPower: '没有权限',
|
||||
},
|
||||
upgrade: {
|
||||
title: '新版本升级',
|
||||
msg: '新版本来啦,马上更新尝鲜吧!不用担心,更新很快的哦!',
|
||||
desc: '提示:更新会还原默认配置',
|
||||
btnOne: '残忍拒绝',
|
||||
btnTwo: '马上更新',
|
||||
btnTwoLoading: '更新中',
|
||||
},
|
||||
menu: {
|
||||
index: '首页',
|
||||
personalCenter: '个人中心',
|
||||
|
||||
tag: '标签管理',
|
||||
tagTree: '标签树',
|
||||
tagSave: '保存标签',
|
||||
tagDelete: '删除标签',
|
||||
authorization: '授权凭证',
|
||||
authorizationBase: '基础权限',
|
||||
authorizationSave: '保存权限',
|
||||
authorizationDelete: '删除权限',
|
||||
team: '团队管理',
|
||||
teamSave: '保存团队',
|
||||
teamDelete: '删除团队',
|
||||
teamMemberAdd: '添加成员',
|
||||
teamMemberDelete: '删除成员',
|
||||
teamTagSave: '保存团队标签',
|
||||
|
||||
machine: '机器管理',
|
||||
machineOp: '机器操作',
|
||||
machineOpBase: '基本权限',
|
||||
machineList: '机器列表',
|
||||
machineBase: '基本权限',
|
||||
machineCreate: '创建机器',
|
||||
machineEdit: '编辑机器',
|
||||
machineDelete: '删除机器',
|
||||
machineTerminal: '机器终端',
|
||||
machineFileConf: '文件管理',
|
||||
machineFileConfCreate: '文件-添加配置',
|
||||
machineFileConfDelete: '文件-删除配置',
|
||||
machineFileCreate: '文件-创建',
|
||||
machineFileDelete: '文件-删除',
|
||||
machineFileWrite: '文件-写入',
|
||||
machineFileUpload: '文件-上传',
|
||||
machineScript: '脚本管理',
|
||||
machineScriptSave: '脚本-保存',
|
||||
machineScriptDelete: '脚本-删除',
|
||||
machineScriptRun: '脚本-执行',
|
||||
machineKillprocess: '终止进程',
|
||||
machineCronJob: '计划任务',
|
||||
machineCronJobSvae: '计划任务-保存',
|
||||
machineCronJobDelete: '计划任务-删除',
|
||||
machineSecurityConfig: '安全配置',
|
||||
machineSecurityCmdSvae: '命令配置-保存',
|
||||
machineSecurityCmdDelete: '命令配置-删除',
|
||||
|
||||
dbms: 'DBMS',
|
||||
dbDataOp: '数据操作',
|
||||
dbDataOpBase: '基本权限',
|
||||
dbDataOpSqlScriptRun: 'SQL脚本执行',
|
||||
dbInstance: '数据库实例',
|
||||
dbInstanceBase: '基本权限',
|
||||
dbInstanceSave: '保存实例',
|
||||
dbInstanceDelete: '删除实例',
|
||||
dbBase: '数据库基本权限',
|
||||
dbSave: '保存数据库',
|
||||
dbDelete: '删除数据库',
|
||||
dbDataSync: '数据同步',
|
||||
dbDataSyncBase: '基本权限',
|
||||
dbDataSyncSave: '保存同步',
|
||||
dbDataSyncDelete: '删除同步',
|
||||
dbDataSyncChangeStatus: '启用停用',
|
||||
dbDataSyncLog: '同步日志',
|
||||
dbTransfer: '数据库迁移',
|
||||
dbTransferBase: '基本权限',
|
||||
dbTransferSave: '保存迁移任务',
|
||||
dbTransferDelete: '删除迁移任务',
|
||||
dbTransferChangeStatus: '启用停用',
|
||||
dbTransferRun: '执行迁移任务',
|
||||
dbTransferRunLog: '迁移日志查看',
|
||||
dbTransferFileShow: '迁移文件-查看',
|
||||
dbTransferFileDelete: '迁移文件-删除',
|
||||
dbTransferFileDownload: '迁移文件-下载',
|
||||
dbTransferFileRun: '迁移文件-执行',
|
||||
|
||||
redis: 'Redis',
|
||||
redisDataOp: '数据操作',
|
||||
redisDataOpBase: '基本权限',
|
||||
redisDataOpSave: '数据保存',
|
||||
redisDataOpDelete: '数据删除',
|
||||
redisManage: 'Redis管理',
|
||||
redisManageBase: '基本权限',
|
||||
|
||||
mongo: 'Mongo',
|
||||
mongoDataOp: '数据操作',
|
||||
mongoDataOpBase: '基本权限',
|
||||
mongoDataOpSave: '数据保存',
|
||||
mongoDataOpDelete: '数据删除',
|
||||
mongoManage: 'Mongo管理',
|
||||
mongoManageBase: '基本权限',
|
||||
|
||||
flow: '工单流程',
|
||||
myTask: '我的任务',
|
||||
myFlow: '我的流程',
|
||||
flowProcDef: '流程定义',
|
||||
flowProcDefSave: '保存流程定义',
|
||||
flowProcDefDelete: '删除流程定义',
|
||||
|
||||
system: '系统管理',
|
||||
menuPermission: '菜单权限',
|
||||
menuPermissionBase: '基本权限',
|
||||
menuPermissionAdd: '添加菜单权限',
|
||||
menuPermissionEdit: '编辑菜单权限',
|
||||
menuPermissionDelete: '删除菜单权限',
|
||||
menuPermissionEnableDisable: '启用/禁用菜单权限',
|
||||
account: '账号管理',
|
||||
accountBase: '基本权限',
|
||||
accountAdd: '添加账号',
|
||||
accountEdit: '编辑账号',
|
||||
accountDelete: '删除账号',
|
||||
accountEnableDisable: '启用/禁用账号',
|
||||
accountRoleAllocation: '角色分配',
|
||||
role: '角色管理',
|
||||
roleBase: '基本权限',
|
||||
roleAdd: '添加角色',
|
||||
roleEdit: '编辑角色',
|
||||
roleDelete: '删除角色',
|
||||
roleMenuPermissionAllocation: '菜单权限分配',
|
||||
sysConf: '系统配置',
|
||||
sysConfBase: '基本权限',
|
||||
sysConfSave: '保存配置',
|
||||
opLog: '操作日志',
|
||||
opLogBase: '基本权限',
|
||||
|
||||
noPagePermission: '无页面权限',
|
||||
authcertShowciphertext: '授权凭证密文查看',
|
||||
},
|
||||
home: {
|
||||
personalInfo: '个人信息',
|
||||
welcomeMsg: '您好, {name},生活变的再糟糕,也不妨碍我变得更好!',
|
||||
lastLoginIp: '上次登录IP',
|
||||
lastLoginTime: '上次登录时间',
|
||||
msgNotify: '消息通知',
|
||||
noOpRecord: '暂无操作记录',
|
||||
msgTypeLogin: '登录',
|
||||
msgTypeNotify: '通知',
|
||||
},
|
||||
personal: {
|
||||
updateInfo: '更新信息',
|
||||
basicInfo: '基本信息',
|
||||
inputNewPasswordPlaceholder: '请输入新密码',
|
||||
updatePersonalInfo: '更新个人信息',
|
||||
accountInfo: '账号信息',
|
||||
currentStatus: '当前状态',
|
||||
boundUp: '已绑定',
|
||||
notBound: '未绑定',
|
||||
immediateBinding: '立即绑定',
|
||||
unbundle: '解绑',
|
||||
updateSuccess: '更新成功',
|
||||
bindingSuccess: '绑定成功',
|
||||
unbundleSuccess: '解绑成功',
|
||||
},
|
||||
login: {
|
||||
accountPasswordLogin: '账号密码登录',
|
||||
thirdPartyLogin: '第三方登录',
|
||||
ldapLogin: 'LDAP 登录',
|
||||
inputUsernamePlaceholder: '请输入用户名',
|
||||
inputPasswordPlaceholder: '请输入密码',
|
||||
inputCaptchaPlaceholder: '请输入验证码',
|
||||
login: '登 录',
|
||||
loginFailTip: '提示:登录失败超过{loginFailCount}次后将被限制{loginFailMin}分钟内不可再次登录',
|
||||
loginSuccessTip: '欢迎回来!',
|
||||
changePassword: '修改密码',
|
||||
oldPassword: '旧密码',
|
||||
newPassword: '新密码',
|
||||
passwordRuleTip: '须为8位以上且包含字⺟⼤⼩写+数字+特殊符号',
|
||||
passwordChangeSuccessTip: '密码修改成功, 新密码已填充至登录密码框',
|
||||
otpValidation: 'OTP校验',
|
||||
qrCode: '二维码',
|
||||
enterOtpCodeTip: '请输入令牌APP中显示的授权码',
|
||||
updateBasicInfo: '修改基本信息',
|
||||
name: '姓名',
|
||||
inputNamePlaceholder: '请输入姓名',
|
||||
},
|
||||
components: {
|
||||
df: {
|
||||
fieldModelPlaceholder: 'model关联的字段',
|
||||
fieldLabel: 'label',
|
||||
fieldPlaceholder: 'placeholder',
|
||||
optionalValues: '可选值',
|
||||
optionalValuesPlaceholder: '可选值 ,分割',
|
||||
required: '必填',
|
||||
},
|
||||
terminal: {
|
||||
connError: '连接出错',
|
||||
notConn: '未连接',
|
||||
connSuccess: '连接成功',
|
||||
connFail: '连接失败',
|
||||
connErrMsg: '提示: 连接错误...',
|
||||
connConfirm: '确认重新连接?',
|
||||
connected: '已连接',
|
||||
search: '搜索',
|
||||
reConnTips: '点击连接状态可重连',
|
||||
minimize: '最小化',
|
||||
fullScreenTitle: '全屏|退出全屏',
|
||||
close: '关闭',
|
||||
|
||||
serachPlaceholder: '请输入查找内容,回车搜索',
|
||||
regexMatch: '正则匹配',
|
||||
fullWordMatching: '单词全匹配',
|
||||
caseSensitive: '区分大小写',
|
||||
incrementalSearch: '增量查找',
|
||||
previous: '上一个',
|
||||
next: '下一个',
|
||||
noMatchMsg: '未查询到匹配项',
|
||||
},
|
||||
crontab: {
|
||||
crontabInputPlaceholder: '可点击左边按钮配置',
|
||||
crontabTitle: '生成 cron',
|
||||
second: '秒',
|
||||
minute: '分钟',
|
||||
hour: '小时',
|
||||
day: '日',
|
||||
month: '月',
|
||||
week: '周',
|
||||
year: '年',
|
||||
timeExpression: '时间表达式',
|
||||
crontabCompleteExpression: 'crontab完整表达式',
|
||||
|
||||
dayCrontype1: '允许的通配符[, - * / L M]',
|
||||
crontype2: '不指定',
|
||||
crontype3: '周期从',
|
||||
|
||||
crontypeFrom: '从',
|
||||
crontypeEvery: '每',
|
||||
appoint: '指定',
|
||||
|
||||
crontypeStartDay: '号开始',
|
||||
crontypeExecDay: '日执行一次',
|
||||
monthLastDay: '本月最后一天',
|
||||
|
||||
hourCronType1: '允许的通配符[, - * /]',
|
||||
crontypeStartHour: '小时开始',
|
||||
crontypeExecHour: '小时执行一次',
|
||||
|
||||
crontypeStartMin: '分钟开始',
|
||||
crontypeExecMin: '分钟执行一次',
|
||||
|
||||
crontypeStartSecond: '秒开始',
|
||||
crontypeExecSecond: '秒执行一次',
|
||||
|
||||
crontypeStartMonth: '月开始',
|
||||
crontypeExecMonth: '月执行一次',
|
||||
|
||||
yearly: '每年',
|
||||
crontypeStartYear: '年开始',
|
||||
crontypeExecYear: '年执行一次',
|
||||
|
||||
weekCronType1: '允许的通配符[, - * / L #]',
|
||||
monday: '周一',
|
||||
tuesday: '周二',
|
||||
wednesday: '周三',
|
||||
thursday: '周四',
|
||||
friday: '周五',
|
||||
saturday: '周六',
|
||||
sunday: '周日',
|
||||
|
||||
last5runTimes: '最近5次运行时间',
|
||||
calculationing: '计算结果中',
|
||||
},
|
||||
},
|
||||
};
|
||||
203
frontend/src/i18n/zh-cn/db.ts
Normal file
203
frontend/src/i18n/zh-cn/db.ts
Normal file
@@ -0,0 +1,203 @@
|
||||
export default {
|
||||
db: {
|
||||
// db instance
|
||||
dbManage: '库管理',
|
||||
port: '端口',
|
||||
connParam: '连接参数',
|
||||
keywordPlaceholder: 'host / 名称 / 编号',
|
||||
acName: '授权凭证',
|
||||
dbInst: '数据库实例',
|
||||
manageDbTitle: '管理【{instName}】数据库',
|
||||
sqlitePathPlaceholder: '请输入sqlite文件在服务器的绝对地址',
|
||||
connParamPlaceholder: '其他连接参数,形如: key1=value1&key2=value2',
|
||||
connSuccess: '连接成功',
|
||||
showDb: '查看库',
|
||||
db: '数据库',
|
||||
dbFilterPlaceholder: '库名: 输入可过滤',
|
||||
sqlRecord: 'SQL记录',
|
||||
dump: '导出',
|
||||
dumpContent: '导出内容',
|
||||
structure: '结构',
|
||||
data: '数据',
|
||||
extName: '扩展名',
|
||||
dbFilterPlacehoder: '按数据库名称筛选',
|
||||
allDb: '全部数据库',
|
||||
dumpDb: '导出数据库',
|
||||
getDbMode: '获库方式',
|
||||
noDumpDbMsg: '请添加要导出的数据库',
|
||||
allSelect: '全选',
|
||||
selectDbPlacehoder: '获库方式为‘指定库名’时,可选择',
|
||||
|
||||
// db
|
||||
dbInstInfo: '数据库实例信息',
|
||||
newQuery: '新建查询',
|
||||
locationTagTree: '定位至左侧树的指定位置',
|
||||
dbShowSetting: '数据库展示配置',
|
||||
showFieldComments: '显示字段备注',
|
||||
autoLocationTagTree: '自动定位树节点',
|
||||
cacheTableInfo: '缓存表信息-[不开启则实时获取表信息]',
|
||||
dbName: '库名',
|
||||
table: '表',
|
||||
createTable: '创建表',
|
||||
tableOp: '表操作',
|
||||
copyTable: '复制表',
|
||||
renameTable: '重命名',
|
||||
editTable: '编辑表',
|
||||
delTable: '删除表',
|
||||
close: '关闭',
|
||||
closeOther: '关闭其他',
|
||||
noDbInstMsg: '请选择数据库实例及对应的schema',
|
||||
query: '查询',
|
||||
nQuery: '新查询',
|
||||
renamePrompt: '重命名表【{db}.{tableName}】',
|
||||
noChange: '无更改',
|
||||
isCopyTableData: '是否复制数据?',
|
||||
execSuccess: '执行成功',
|
||||
execFail: '执行失败',
|
||||
sqlScriptRun: 'SQL脚本执行',
|
||||
saveSql: '保存SQL',
|
||||
execInfo: '执行信息',
|
||||
result: '结果',
|
||||
times: '耗时',
|
||||
resultSet: '结果集',
|
||||
tableDataEmptyTextTips: 'tips: select *开头的单表查询或点击表名默认查询的数据,可双击数据在线修改',
|
||||
noSelctRunSqlMsg: '请选中需要执行的sql',
|
||||
enterExecRemarkTips: '请输入备注',
|
||||
execRemarkPlaceholder: '输入执行该sql的备注信息',
|
||||
currentSqlTabIsRunning: '当前结果集tab正在执行, 请使用新标签执行',
|
||||
sqlCannotEmpty: 'sql内容不能为空',
|
||||
enterSqlScriptNameTips: '请输入SQL脚本名',
|
||||
scriptFileUploadRunning: `'{filename}' 正在上传执行, 请关注结果通知`,
|
||||
runSql: '执行SQL',
|
||||
newTabRunSql: '新标签执行SQL',
|
||||
formatSql: '格式化SQL',
|
||||
|
||||
execTime: '执行时间',
|
||||
oneClickCopy: '一键复制',
|
||||
asc: '升序',
|
||||
desc: '降序',
|
||||
fixed: '固定',
|
||||
cancelFiexd: '取消固定',
|
||||
formView: '表单视图',
|
||||
genJson: '生成JSON',
|
||||
exportCsv: '导出CSV',
|
||||
exportSql: '导出SQL',
|
||||
onlySelectOneData: '只能选择一行数据',
|
||||
|
||||
editField: '编辑字段',
|
||||
valueTypeNoMatch: '输入内容与类型不匹配',
|
||||
|
||||
tableFieldConf: '表格字段配置',
|
||||
columnFilterPlaceholder: '输入列名或备注过滤',
|
||||
selectAll: '选择所有',
|
||||
submitUpdate: '提交修改',
|
||||
cancelUpdate: '取消修改',
|
||||
autoCompleteColumnPlaceholder: '选择列 或 输入SQL条件表达式后回车或点击查询图标过滤结果, 输入时可根据字段名提示',
|
||||
selectColumn: '选择列',
|
||||
columnName: '列名',
|
||||
homePage: '首页',
|
||||
previousPage: '上一页',
|
||||
rowsPage: '条/页',
|
||||
rows: '条',
|
||||
conditionInputDialogTitle: '请输入 [{columnName}] 的值',
|
||||
addDataDialogTitle: '添加`{tableName}`表数据',
|
||||
|
||||
exportContent: '导出内容',
|
||||
selectExportTable: '请先选择要导出的表',
|
||||
tableNamePlaceholder: '表名: 输入可过滤',
|
||||
comment: '备注',
|
||||
commentPlaceholder: '备注: 输入可过滤',
|
||||
dataSize: '数据大小',
|
||||
indexSize: '索引大小',
|
||||
column: '列',
|
||||
index: '索引',
|
||||
nullable: '是否可为空',
|
||||
seqInIndex: '列序列号',
|
||||
|
||||
// DbSqlExecLog
|
||||
selectDbPlaceholder: '请选择数据库',
|
||||
restoreSql: '还原SQL',
|
||||
stmtType: '操作类型',
|
||||
execUser: '执行人',
|
||||
execRes: '执行结果',
|
||||
oldValue: '原值',
|
||||
|
||||
// db transfer
|
||||
pleaseSetting: '请设置',
|
||||
log: '日志',
|
||||
stop: '停止',
|
||||
run: '运行',
|
||||
file: '文件',
|
||||
taskName: '任务名',
|
||||
srcDb: '源库',
|
||||
runState: '运行状态',
|
||||
createDbTransferDialogTitle: '新增数据库迁移任务(迁移不会对源库造成修改)',
|
||||
editDbTransferDialogTitle: '修改数据库迁移任务(迁移不会对源库造成修改)',
|
||||
stopConfirm: '确定停止?',
|
||||
runConfirm: '确定运行?',
|
||||
transferFileManage: '迁移文件管理',
|
||||
dbFileType: '文件数据库类型',
|
||||
targetDb: '目标数据库',
|
||||
fileDbType: 'sql语言',
|
||||
transferFileRunDialogTitle: '指定数据库执行sql文件',
|
||||
targetDbTypeSelectError: '请选择[{dbType}]数据库',
|
||||
cronAble: '定时迁移',
|
||||
transferMode: '迁移方式',
|
||||
transfer2Db: '迁移到数据库',
|
||||
transfer2File: '迁移到文件',
|
||||
fileSaveDays: '文件保留天数',
|
||||
transferStrategy: '迁移策略',
|
||||
day: '天',
|
||||
transferFull: '全量',
|
||||
transferIncrement: '增量(暂不可用)',
|
||||
nameCase: '转换表、字段名',
|
||||
none: '无',
|
||||
lower: '小写',
|
||||
upper: '大写',
|
||||
dbObj: '数据库对象',
|
||||
allTable: '全部表',
|
||||
custom: '自定义',
|
||||
noTransferTableMsg: '请选择需要迁移的表',
|
||||
|
||||
// dbSync
|
||||
recentState: '最近任务状态',
|
||||
dbSync: '数据同步',
|
||||
realTime: '实时',
|
||||
noRealTime: '非实时',
|
||||
srcDataSql: '源数据sql',
|
||||
targetDbTable: '目标库表',
|
||||
pageSize: '分页大小',
|
||||
pageSizePlaceholder: '同步数据时查询的每页数据大小',
|
||||
updateField: '更新字段',
|
||||
updateFieldTips: '查询数据源的时候会带上这个字段当前最大值,支持带别名,如:t.create_time',
|
||||
updateFiledPlaceholder: '查询数据源的时候会带上这个字段当前最大值',
|
||||
updateFieldValue: '更新值',
|
||||
updateFieldValueTips: '记录更新字段当前值,如:当前时间,当前日期等,下次查询数据时会带上该值条件',
|
||||
updateFieldValuePlaceholder: '更新字段当前最大值',
|
||||
fieldValueSrc: '值来源',
|
||||
fieldValueSrcTips: '从查询结果中取更新值的字段名,默认同更新字段,如果查询结果指定了字段别名且与原更新字段不一致,则取这个字段值为当前更新值',
|
||||
fieldValueSrcPlaceholder: '更新值来源',
|
||||
fieldMap: '字段映射',
|
||||
srcField: '源字段',
|
||||
targetField: '目标字段',
|
||||
sqlPreview: 'sql预览',
|
||||
selectSql: '查询sql',
|
||||
insertSql: '插入sql',
|
||||
keyDuplicateStrategy: '键冲突策略',
|
||||
fieldMapError: '字段映射中存在重复的目标字段,请检查',
|
||||
noDataSqlMsg: '请输入数据sql',
|
||||
notSelectSql: 'sql语句错误,请输入select语句',
|
||||
notOneSql: 'sql语句错误,请输入单条查询语句',
|
||||
notColumnSql: '没有查询到字段,请检查sql',
|
||||
|
||||
// enums
|
||||
getDbNamesModeAuto: '实时获取',
|
||||
getDbNamesModeAssign: '指定库名',
|
||||
|
||||
ignore: '忽略',
|
||||
replate: '替换',
|
||||
|
||||
running: '运行中',
|
||||
waitRun: '待运行',
|
||||
},
|
||||
};
|
||||
90
frontend/src/i18n/zh-cn/flow.ts
Normal file
90
frontend/src/i18n/zh-cn/flow.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
export default {
|
||||
flow: {
|
||||
// procdef
|
||||
approvalNode: '审批节点',
|
||||
procdef: '流程定义',
|
||||
triggeringCondition: '触发条件',
|
||||
triggeringConditionTips: 'go template语法。若输出结果为1,则表示触发该审批流程',
|
||||
conditionPlaceholder: '触发条件, 返回值=1, 则表示触发该审批流程',
|
||||
conditionDefault: `{{/* DBMS-执行sql规则; param参数描述如下 */}}
|
||||
{{/* stmtType: select / read / insert / update / delete / ddl ; */}}
|
||||
{{ if eq .bizType "db_sql_exec_flow"}}
|
||||
{{/* 不是select和read语句时,开启流程审批 */}}
|
||||
{{ if and (ne .param.stmtType "select") (ne .param.stmtType "read") }}
|
||||
1
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* Redis-执行命令规则; param参数描述如下 */}}
|
||||
{{/* cmdType: read(读命令) / write(写命令); */}}
|
||||
{{/* cmd: get/set/hset...等 */}}
|
||||
{{ if eq .bizType "redis_run_cmd_flow"}}
|
||||
{{ if eq .param.cmdType "write" }}
|
||||
1
|
||||
{{ end }}
|
||||
{{ end }}`,
|
||||
nodeName: '节点名称',
|
||||
nodeNameTips: '点击指定节点可进行拖拽排序',
|
||||
auditor: '审核人员',
|
||||
tasksNotEmpty: '请完善审批节点任务',
|
||||
tasksNoComplete: '请完善第{index}个审批节点任务信息',
|
||||
// procdef status enum
|
||||
enable: '启用',
|
||||
disable: '禁用',
|
||||
|
||||
// procinst
|
||||
startProcess: '发起流程',
|
||||
cancelProcessConfirm: '确认取消该流程?',
|
||||
bizType: '业务类型',
|
||||
bizKey: '业务Key',
|
||||
initiator: '发起人',
|
||||
procdefName: '流程名',
|
||||
bizStatus: '业务状态',
|
||||
startingTime: '发起时间',
|
||||
endTime: '结束时间',
|
||||
duration: '持续时间',
|
||||
proc: '流程',
|
||||
bizInfo: '业务信息',
|
||||
approvalNodeNotExist: '不存在审批节点',
|
||||
resourceNotExistFlow: '该资源无需审批操作',
|
||||
procinstFormError: '请正确填写信息',
|
||||
procinstStartSuccess: '流程发起成功',
|
||||
// db run sql flow biz
|
||||
runSql: '执行SQL',
|
||||
selectDbPlaceholder: '请选择数据库',
|
||||
// redis run cmd flow biz
|
||||
runCmd: '执行Cmd',
|
||||
selectRedisPlaceholder: '请选择Redis实例与库',
|
||||
cmdPlaceholder: `如: SET 'key' 'value'; 多条命令;分割`,
|
||||
// ProcinstStatusEnum
|
||||
active: '执行中',
|
||||
completed: '完成',
|
||||
suspended: '挂起',
|
||||
terminated: '终止',
|
||||
cancelled: '取消',
|
||||
handleResult: '处理结果',
|
||||
runResult: '执行结果',
|
||||
// ProcinstBizStatus
|
||||
waitHandle: '待处理',
|
||||
handleSuccess: '处理成功',
|
||||
handleFail: '处理失败',
|
||||
noHandle: '不处理',
|
||||
// ProcinstTaskStatus
|
||||
waitProcess: '待处理',
|
||||
pass: '通过',
|
||||
reject: '拒绝',
|
||||
back: '回退',
|
||||
canceled: '取消',
|
||||
// FlowBizType
|
||||
dbSqlExec: 'DBMS-执行SQL',
|
||||
redisRunCmd: 'Redis-执行命令',
|
||||
|
||||
// task
|
||||
audit: '审核',
|
||||
procinstStatus: '流程状态',
|
||||
taskStatus: '任务状态',
|
||||
taskName: '当前节点',
|
||||
taskBeginTime: '开始时间',
|
||||
flowAudit: '流程审批',
|
||||
},
|
||||
};
|
||||
135
frontend/src/i18n/zh-cn/machine.ts
Normal file
135
frontend/src/i18n/zh-cn/machine.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
export default {
|
||||
machine: {
|
||||
keywordPlaceholder: 'ip / 名称 / 编号',
|
||||
acName: '授权凭证',
|
||||
runningStat: '运行状态',
|
||||
fs: '磁盘(挂载点=>可用/总)',
|
||||
remark: '备注',
|
||||
memberInfo: '内存(可用/总)',
|
||||
cpuInfo: 'CPU(空闲)',
|
||||
file: '文件',
|
||||
directory: '目录',
|
||||
folder: '文件夹',
|
||||
script: '脚本',
|
||||
process: '进程',
|
||||
terminalPlayback: '终端回放',
|
||||
createMachine: '添加机器',
|
||||
editMachine: '编辑机器',
|
||||
reConnTips: '确认重新连接?',
|
||||
clickReConn: '点击重连',
|
||||
port: '端口',
|
||||
sshTunnel: 'SSH隧道',
|
||||
newOpenTabTerminalTips: '按住ctrl则为新标签打开',
|
||||
newTab: '新窗口',
|
||||
openTerminal: '打开终端',
|
||||
newTabOpenTerminal: '打开终端(新窗口)',
|
||||
fileManage: '文件管理',
|
||||
scriptManage: '脚本管理',
|
||||
machineState: '机器状态',
|
||||
remoteFileDesktopManage: '远程桌面文件管理', // Remote desktop file management
|
||||
remoteDesktop: '远程桌面',
|
||||
protocol: '协议',
|
||||
ipAndPort: 'ip和port',
|
||||
connSuccess: '连接成功',
|
||||
noAcErrMsg: '请完善授权凭证账号信息',
|
||||
|
||||
// MachineRec
|
||||
playback: '回放',
|
||||
cmd: '命令',
|
||||
execCmdRecord: '执行命令记录', //Executive command record
|
||||
execTime: '执行时间', // execution time
|
||||
operator: '操作人',
|
||||
beginTime: '开始时间',
|
||||
endTime: '结束时间',
|
||||
|
||||
// MachineStats
|
||||
basicInfo: '基本信息', // basic information
|
||||
hostname: '主机名',
|
||||
runTime: '运行时间',
|
||||
totalTask: '总任务',
|
||||
runningTask: '运行中任务',
|
||||
load: '负载',
|
||||
disk: '磁盘',
|
||||
mountPoint: '挂载点',
|
||||
available: '可使用',
|
||||
used: '已使用',
|
||||
networkCard: '网卡',
|
||||
receive: '接收',
|
||||
send: '发送',
|
||||
memory: '内存',
|
||||
cpuUsageRate: 'CPU使用率',
|
||||
|
||||
// process
|
||||
processName: '进程名',
|
||||
selectSortType: '请选择排序类型',
|
||||
selectProcessNum: '请选择进程个数',
|
||||
cpuDesc: 'CUP降序',
|
||||
memDesc: '内存降序',
|
||||
virtualMemory: '虚拟内存',
|
||||
fixedMemory: '固定内存',
|
||||
procState: '进程状态',
|
||||
startTime: '启动时间',
|
||||
procCpuRunTime: '该进程实际使用CPU运作的时间',
|
||||
killProcConfirm: '确定终止该进程?',
|
||||
kill: '终止',
|
||||
|
||||
// script
|
||||
execute: '执行',
|
||||
scriptParam: '脚本参数',
|
||||
execResult: '执行结果',
|
||||
execCompleted: '执行完成', // execution is completed
|
||||
scriptParamTips1: '1. 脚本内容中可使用{{.model}}作为占位符',
|
||||
scriptParamTips2: '2. 执行脚本时可输入对应表单内容对占位符进行替换后执行',
|
||||
scriptResultEnumResult: '有结果',
|
||||
scriptResultEnumNoResult: '无结果',
|
||||
scriptResultEnumRealTime: '实时交互',
|
||||
scriptTypeEnumPrivate: '私有',
|
||||
scriptTypeEnumPublic: '公共',
|
||||
|
||||
// security
|
||||
cmdConfig: '命令配置',
|
||||
filterCmds: '过滤命令',
|
||||
relateMachine: '关联机器',
|
||||
newCmd: '新建命令',
|
||||
cmdPlaceholder: '请输入命令正则表达式',
|
||||
|
||||
// cronjob
|
||||
cronjob: '计划任务',
|
||||
machineCode: '机器编号',
|
||||
cronjobRunning: '运行中',
|
||||
cronjobNoRun: '未运行',
|
||||
cronjobRun: '执行',
|
||||
cronJobExecStatusEnumSuccess: '成功',
|
||||
cronJobExecStatusEnumFail: '失败',
|
||||
cronjobExecResult: '执行结果',
|
||||
cronjobExecTime: '执行时间',
|
||||
cronjobExecRecord: '执行记录',
|
||||
runSuccess: '执行成功',
|
||||
cronjobRunState: '运行状态',
|
||||
execResRecordType: '结果记录类型',
|
||||
cronExpression: 'cron表达式',
|
||||
|
||||
// file
|
||||
upload: '上传',
|
||||
download: '下载',
|
||||
copy: '复制',
|
||||
move: '移动',
|
||||
paste: '粘贴',
|
||||
fileNameFilterPlaceholder: '名称: 输入可过滤',
|
||||
calculate: '计算',
|
||||
modificationTime: '修改时间',
|
||||
attribute: '属性',
|
||||
user: '用户',
|
||||
group: '组',
|
||||
renameTips: 'rename: 双击文件名单元格修改后回车',
|
||||
fileDetail: '文件详情',
|
||||
createFile: '新建文件',
|
||||
pasteSuccess: '粘贴成功',
|
||||
sameDirNoPaste: '同目录下不能粘贴',
|
||||
renameSuccess: '重命名成功',
|
||||
newFileNameNotEmpty: '新名称不能为空',
|
||||
fileTooLargeTips: '文件太大, 请下载使用',
|
||||
uploadSuccess: '上传成功',
|
||||
fileExceedsSysConf: '上传的文件超过系统配置的【{uploadMaxFileSize}】',
|
||||
},
|
||||
};
|
||||
44
frontend/src/i18n/zh-cn/mongo.ts
Normal file
44
frontend/src/i18n/zh-cn/mongo.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
export default {
|
||||
mongo: {
|
||||
mongo: 'MongoDB',
|
||||
db: '数据库',
|
||||
keywordPlaceholder: 'host / 名称 / 编号',
|
||||
connUrl: '连接url',
|
||||
|
||||
dbList: '数据库列表',
|
||||
isEmpty: '是否为空',
|
||||
deleteDbConfirm: '确定删除该库?',
|
||||
coll: '集合',
|
||||
deleteCollConfirm: '确定删除该集合?',
|
||||
collState: '集合状态',
|
||||
createDbAndColl: '新建库&集合',
|
||||
dbName: '库名',
|
||||
collName: '集合名',
|
||||
createColl: '新建集合',
|
||||
collTitle: '`{dbName}` 集合',
|
||||
|
||||
template: '模板',
|
||||
cmdTemplatePlaceholder: '选择命令模板',
|
||||
moreCmdTips: '更多命令查看',
|
||||
usersInfoDesc: '获取用户信息',
|
||||
createUserDesc: '创建新用户',
|
||||
grantRolesToUserDesc: '授予对用户的额外角色',
|
||||
dropUserDesc: '删除用户',
|
||||
roleInfoDesc: '获取角色信息',
|
||||
createRoleDesc: '创建角色',
|
||||
runSuccess: '执行成功',
|
||||
|
||||
queryParam: '查询参数',
|
||||
queryParamPlaceholder: '点击输入相应查询条件',
|
||||
deleteDocConfirm: '确定删除该文档?',
|
||||
doc: '文档',
|
||||
findParamErrMsg: 'filter或sort字段json字符串值错误。注意: json key需双引号',
|
||||
docErrMsg: '文档内容错误,无法解析为json对象',
|
||||
insertSuccess: '新增成功',
|
||||
insertFail: '新增失败',
|
||||
idNotExist: '文档的_id属性不存在',
|
||||
modifyFail: '修改失败',
|
||||
deleteFail: '删除失败',
|
||||
docParse2jsonFail: '文档内容解析为json对象失败',
|
||||
},
|
||||
};
|
||||
64
frontend/src/i18n/zh-cn/redis.ts
Normal file
64
frontend/src/i18n/zh-cn/redis.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
export default {
|
||||
redis: {
|
||||
standaloneInfo: '单机信息',
|
||||
clusterInfo: '集群信息',
|
||||
node: '节点',
|
||||
clusterIpTips: 'ip:port1@port2:port1指redis服务器与客户端通信的端口,port2则是集群内部节点间通信的端口',
|
||||
masterSlaveRelationTips: `如果节点是slave,并且已知master节点,则为master节点ID;否则为符号'-'`,
|
||||
configEpochTips: '节点的epoch值(如果该节点是从节点,则为其主节点的epoch值)。每当节点发生失败切换时,都会创建一个新的,独特的,递增的epoch。',
|
||||
keywordPlaceholder: 'host / 名称 / 编号',
|
||||
hostTips: `请输入host:port;sentinel模式为: mastername=sentinelhost:port,若集群或哨兵需设多个节点可使用','分割`,
|
||||
nodePassword: '节点密码',
|
||||
sentinelHostErr: 'sentinel模式host需为: mastername=sentinelhost:sentinelport模式',
|
||||
delimiter: '分隔符',
|
||||
keyMatchTips: 'match 支持*模糊key, 回车搜索',
|
||||
loadMore: '加载更多',
|
||||
addKey: '新增key',
|
||||
newTabOpen: '新tab打开',
|
||||
redisSelectErr: '请先选择redis',
|
||||
flushDbTips: '确定清空[{db}]库的所有key?',
|
||||
keyNotEmpty: 'Key不能为空',
|
||||
|
||||
// info
|
||||
redisInfoTitle: 'Redis服务器信息',
|
||||
version: '版本',
|
||||
port: '端口',
|
||||
mode: '模式',
|
||||
os: '操作系统',
|
||||
uptimeDays: '运行天数',
|
||||
execPath: '可执行文件路径',
|
||||
confFile: '配置文件路径',
|
||||
clusterEnable: '是否启用集群模式',
|
||||
nodeCount: '节点总数',
|
||||
clientConn: '客户端连接',
|
||||
connectedNum: '已连接客户端数',
|
||||
blockedClientNum: '正在等待阻塞命令客户端数',
|
||||
sysCpu: '系统CPU',
|
||||
userCpu: '用户CPU',
|
||||
sysChildCpu: '后台系统CPU',
|
||||
userChildCpu: '后台用户CPU',
|
||||
keyCount: '键值统计',
|
||||
countInfo: '统计信息',
|
||||
totalCmdProcess: '总处理命令数',
|
||||
curQps: '当前qps',
|
||||
expiredKeys: '过期key的总数量',
|
||||
netInputBytes: '网络入口流量字节数',
|
||||
netOutputBytes: '网络出口流量字节数',
|
||||
persistence: '持久化',
|
||||
aofEnable: '是否启用aof',
|
||||
loadingPersistence: '是否正在载入持久化文件',
|
||||
availableMemory: '可用内存',
|
||||
usedMemory: '已用内存',
|
||||
|
||||
renameTips: '点击重命名',
|
||||
ttlPlaceholder: '单位(秒),负数永久',
|
||||
ttlTips: '点击修改过期时间',
|
||||
settingSuccess: '设置成功',
|
||||
permanent: '永久',
|
||||
persistenceConfirm: '确定持久化该key?',
|
||||
|
||||
addNewLine: '添加新行',
|
||||
filterPlaceholder: '关键词回车搜索',
|
||||
deleteConfirm: '确定删除?',
|
||||
},
|
||||
};
|
||||
210
frontend/src/i18n/zh-cn/system.ts
Normal file
210
frontend/src/i18n/zh-cn/system.ts
Normal file
@@ -0,0 +1,210 @@
|
||||
export default {
|
||||
system: {
|
||||
menu: {
|
||||
filterPlaceholder: '输入关键字过滤(右击操作)',
|
||||
opTips: '红色、橙色字体表示禁用状态 (右击资源进行操作)',
|
||||
info: '资源信息',
|
||||
menu: '菜单',
|
||||
permission: '权限',
|
||||
icon: '图标',
|
||||
routerName: '路由名',
|
||||
componentPath: '组件路径',
|
||||
isCache: '是否缓存',
|
||||
isHide: '是否隐藏',
|
||||
tagIsDelete: 'tag不可删除',
|
||||
externalLink: '外链',
|
||||
yes: '是',
|
||||
no: '否',
|
||||
addSubResource: '添加子资源',
|
||||
enable: '启用',
|
||||
disable: '禁用',
|
||||
tips: '提示',
|
||||
addTopMenu: '添加顶级菜单',
|
||||
addChildrenMenuTitle: '添加`{parentName}`的子资源',
|
||||
updateMenu: '修改`{name}`',
|
||||
success: '成功',
|
||||
menuCodeTips: `菜单类型则为访问路径(若菜单路径不以'/'开头则访问地址会自动拼接父菜单路径)、否则为资源唯一编码`,
|
||||
menuCodePlaceholder: `菜单不以'/'开头则自动拼接父菜单路径`,
|
||||
routerNameTips: '与vue的组件名一致才可使组件缓存生效,如ResourceLis',
|
||||
componentPathTips: '访问的组件路径,如:`system/resource/ResourceList`,默认在`views`目录下',
|
||||
isCacheTips: '选择是则会被`keep-alive`缓存(重新进入页面不会刷新页面及重新请求数据),需要路由名与vue的组件名一致',
|
||||
isHideTips: '选择隐藏则路由将不会出现在菜单栏中,但仍然可以访问。禁用则不可访问与操作',
|
||||
externalLinkTips: '内嵌: 以iframe展示、外链: 新标签打开',
|
||||
inline: '内嵌',
|
||||
linkAddress: '链接地址',
|
||||
linkPlaceholder: '外链/内嵌的链接地址(http://xxx.com)',
|
||||
menuNameRuleMsg: '请输入资源名称',
|
||||
routeNameNotEmpty: '路由名不能为空',
|
||||
resourceCodePatternErrMsg: '只允许输入1-32位大小写字母、数字、_-.:',
|
||||
assignedRole: '已分配角色',
|
||||
},
|
||||
account: {
|
||||
roleAllocation: '角色分配',
|
||||
resetOtp: '重置OTP',
|
||||
assigner: '分配者',
|
||||
allocateTime: '分配时间',
|
||||
name: '姓名',
|
||||
lastLoginTime: '最后登录时间',
|
||||
deleteAccountConfirm: '确定删除【{name}】的账号?',
|
||||
usernamePlacholder: '5-16位大小写字母、数字、_-.:',
|
||||
random: '随机',
|
||||
usernamePatternErrMsg: '只允许输入5-16位大小写字母、数字、_-.:',
|
||||
accountSearchPlaceholder: '输入账号模糊搜索并选择',
|
||||
accountInfo: '账号信息',
|
||||
allocateRoleTitle: '分配 `{name}` 的角色',
|
||||
allocated: '已分配',
|
||||
undistributed: '未分配',
|
||||
menuAndPermission: '菜单&权限',
|
||||
remove: '移除',
|
||||
allocation: '分配',
|
||||
roleStatus: '角色状态',
|
||||
userMenuTitle: '`{name}` 的菜单&权限',
|
||||
statusEnable: '启用',
|
||||
statusDisable: '禁用',
|
||||
},
|
||||
role: {
|
||||
permissionDetail: '权限详情',
|
||||
permissionAllocate: '权限分配',
|
||||
userManage: '用户管理',
|
||||
roleName: '角色名',
|
||||
roleCode: '角色编码',
|
||||
rolePermissionTitle: '`{name} 的菜单&权限`',
|
||||
roleCodePlaceholder: 'COMMON开头则为所有账号共有角色',
|
||||
statusEnable: '启用',
|
||||
statusDisable: '禁用',
|
||||
allocateMenuTitle: '分配 `{roleName}` 的菜单&权限',
|
||||
allocateAccountTitle: '`{roleName}` 关联的账号',
|
||||
addAccount: '添加账号',
|
||||
userStatus: '用户状态',
|
||||
assigner: '分配者',
|
||||
allocateTime: '分配时间',
|
||||
permissionInfo: '权限分配信息',
|
||||
},
|
||||
sysconf: {
|
||||
confItem: '配置项',
|
||||
confKey: '配置key',
|
||||
permission: '权限',
|
||||
permissionPlaceholder: '请输入账号模糊搜索并选择',
|
||||
conf: '配置',
|
||||
confItemSetting: '配置项设置',
|
||||
confValue: '配置值',
|
||||
|
||||
fileConf: '文件配置',
|
||||
fileConfRemark: '系统文件配置',
|
||||
basePath: '基础路径',
|
||||
baesPathPlaceholder: '默认为可执行文件对应目录下./file',
|
||||
|
||||
dbmsConf: 'DBMS配置',
|
||||
dbmsConfRemark: '数据库相关配置',
|
||||
recordQuerySql: '记录查询sql',
|
||||
recordQuerySqlPlaceholder: '是否记录查询类sql',
|
||||
maxResultSet: '最大结果集',
|
||||
maxResultSetPlaceholder: '允许sql查询的最大结果集数。注: 0=不限制',
|
||||
sqlExecLimt: 'sql执行时间限制',
|
||||
sqlExecLimtPlaceholder: '超过该时间(单位:秒),执行将被取消',
|
||||
|
||||
machineConf: '机器相关配置',
|
||||
machineConfRemark: '机器相关配置,如终端操作记录保存天数等',
|
||||
uploadMaxFileSize: '上传文件大小限制',
|
||||
uploadMaxFileSizePlaceholder: '允许上传的最大文件大小(1MB、2GB等)',
|
||||
termOpSaveDays: '终端记录保存时间',
|
||||
termOpSaveDaysPlaceholder: '单位天,超过该时间,将删除终端操作记录',
|
||||
guacdHost: 'guacd服务ip',
|
||||
guacdHostPlaceholder: 'guacd服务ip,默认 127.0.0.1',
|
||||
guacdPort: 'guacd服务端口',
|
||||
guacdPortPlaceholder: 'guacd服务端口,默认 4822',
|
||||
guacdFilePath: 'guacd服务文件存储位置',
|
||||
guacdFilePathPlaceholder: 'guacd服务文件存储位置,用于挂载RDP文件夹',
|
||||
|
||||
systemConf: '系统全局样式设置',
|
||||
systemConfRemark: '系统icon、标题、水印信息等配置',
|
||||
logoIcon: 'logo图标',
|
||||
logoIconPlaceholder: '系统logo图标(base64编码, 建议svg格式,不超过10k)',
|
||||
title: '菜单栏标题',
|
||||
titlePlaceholder: '系统菜单栏标题展示',
|
||||
viceTitle: '登录页标题',
|
||||
viceTitlePlaceholder: '登录页标题展示',
|
||||
useWatermark: '是否启用水印',
|
||||
useWatermarkTips: '是否启用系统水印',
|
||||
watermarkContent: '水印补充信息',
|
||||
watermarkContentPlaceholder: '水印补充信息,如公司名称等',
|
||||
|
||||
ldapLoginConf: 'LDAP登录配置',
|
||||
ldapLoginConfRemark: 'ldap登录相关配置',
|
||||
ldapEnable: '是否启用',
|
||||
dapEnablePlaceholder: '是否启用ldap登录',
|
||||
host: 'host',
|
||||
port: 'port',
|
||||
bindDN: 'bindDN',
|
||||
bindDnPlaceholder: 'LDAP服务的管理员账号,如: "cn=admin,dc=example,dc=com"',
|
||||
bindPwd: 'bindPwd',
|
||||
bindPwdPlaceholder: 'LDAP服务的管理员密码',
|
||||
baseDN: 'baseDN',
|
||||
baseDnPlaceholder: '用户所在的 base DN, 如: "ou=users,dc=example,dc=com"',
|
||||
userFilter: 'userFilter',
|
||||
userFilerPlaceholder: '过滤用户的方式, 如: "(uid=%s)、(&(objectClass=organizationalPerson)(uid=%s))"',
|
||||
uidMap: 'uidMap',
|
||||
uidMapPlaceholder: '用户id和 LDAP 字段名之间的映射关系,如: cn',
|
||||
udnMap: 'udnMap',
|
||||
udnMapPlaceholder: '用户姓名(dispalyName)和 LDAP 字段名之间的映射关系,如: displayName',
|
||||
emailMap: 'emailMap',
|
||||
emailMapPlaceholder: '用户email和 LDAP 字段名之间的映射关系',
|
||||
skipTlsVerfify: 'skipTlsVerfify',
|
||||
skipTlsVerfifyPlaceholder: '客户端是否跳过 TLS 证书验证',
|
||||
securityProtocol: '安全协议',
|
||||
securityProtocolPlaceholder: '安全协议(为Null不使用安全协议),如: StartTLS, LDAPS',
|
||||
|
||||
oauth2LoginConf: 'OAuth2登录配置',
|
||||
oauth2LoginConfRemark: 'oauth2登录相关配置信息',
|
||||
oauth2Enable: '是否启用',
|
||||
oauth2EnablePlaceholder: '是否启用oauth2登录',
|
||||
name: '名称',
|
||||
namePlaceholder: 'oauth2名称',
|
||||
clientId: 'Client ID',
|
||||
clientIdPlaceholder: 'oauth2 Client ID',
|
||||
clientSecret: 'Client Secret',
|
||||
clientSecretPlaceholder: 'oauth2 Client Secret',
|
||||
authorizationUrl: 'Authorization URL',
|
||||
authorizationUrlPlaceholder: 'oauth2 授权地址',
|
||||
accessTokenUrl: 'Access Token URL',
|
||||
accessTokenUrlPlaceholder: 'oauth2 获取token地址',
|
||||
redirectUrl: 'Redirect URL',
|
||||
redirectUrlPlaceholder: '本系统地址',
|
||||
scope: 'Scopes',
|
||||
scopePlaceholder: 'oauth2 Scopes',
|
||||
resourceUrl: 'Resource URL',
|
||||
resourceUrlPlaceholder: '获取用户信息资源地址',
|
||||
userId: 'User ID',
|
||||
userIdPlaceholder: '用户唯一标识字段;格式为type:fieldPath(string:username)',
|
||||
autoRegister: '是否自动注册',
|
||||
|
||||
accountLoginConf: '账号登录安全设置',
|
||||
accountLoginConfRemark: '系统账号登录相关安全设置',
|
||||
useCaptcha: '登录验证码',
|
||||
useCaptchaPlaceholder: '是否启用登录验证码',
|
||||
useOtp: '是否启用OTP',
|
||||
useOtpPlaceholder: '是否启用双因素(OTP)校验',
|
||||
otpIssuer: 'OTP签发人',
|
||||
loginFailCount: '允许登录失败次数',
|
||||
loginFailCountPlaceholder: '登录失败n次后禁止登录',
|
||||
loginFainMin: '登录失败禁止登录时间',
|
||||
loginFailMinPlaceholder: '登录失败指定次数后禁止m分钟内再次登录',
|
||||
},
|
||||
syslog: {
|
||||
operator: '操作人',
|
||||
operatorPlaceholder: '请输入并选择账号',
|
||||
operatingResult: '操作结果',
|
||||
description: '描述',
|
||||
operatingTime: '操作时间',
|
||||
operatingInfo: '操作信息',
|
||||
result: '结果',
|
||||
response: '响应信息',
|
||||
resultSuccess: '成功',
|
||||
resultFail: '失败',
|
||||
resultRunning: '执行中',
|
||||
},
|
||||
oauth: {
|
||||
authSuccess: '授权认证成功',
|
||||
},
|
||||
},
|
||||
};
|
||||
56
frontend/src/i18n/zh-cn/tag.ts
Normal file
56
frontend/src/i18n/zh-cn/tag.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
export default {
|
||||
tag: {
|
||||
relateTag: '关联标签',
|
||||
keywordFilterPlaceholder: '关键字过滤',
|
||||
nameFilterPlaceholder: '关键字过滤(右击节点操作)',
|
||||
tagFilterPlaceholder: '输入关键字->搜索已展开节点信息',
|
||||
tagTips1: '1. 用于将资产进行归类',
|
||||
tagTips2: '2. 可在团队管理中进行分配,用于资源隔离',
|
||||
tagTips3: '3. 拥有父标签的团队成员可访问操作其自身或子标签关联的资源',
|
||||
machine: '机器',
|
||||
db: '数据库',
|
||||
code: '编号',
|
||||
createSubTag: '创建子标签',
|
||||
createSubTagTitle: '创建【{codePath}】的子标签',
|
||||
rootTag: '根标签',
|
||||
selectTagPlaceholder: '请选择关联标签',
|
||||
},
|
||||
team: {
|
||||
team: '团队',
|
||||
member: '成员',
|
||||
addMember: '添加成员',
|
||||
teamMember: '【{teamName}】成员信息',
|
||||
selectAccountTips: '请先选择账号',
|
||||
joinTime: '加入时间',
|
||||
accountName: '姓名',
|
||||
assigner: '分配人',
|
||||
allocateTag: '分配标签',
|
||||
validity: '有效期',
|
||||
effectiveStartTime: '生效开始时间',
|
||||
effectiveEndTime: '生效结束时间',
|
||||
},
|
||||
// authcert
|
||||
ac: {
|
||||
namePlaceholder: '请输入凭证名 (全局唯一)',
|
||||
privateKeyPlaceholder: '请将私钥文件内容拷贝至此',
|
||||
privateKeyPwd: '秘钥密码',
|
||||
resourceCode: '资源编号',
|
||||
credentialName: '凭证名称',
|
||||
resourceType: '资源类型',
|
||||
credentialType: '凭证类型',
|
||||
ciphertextType: '密文类型',
|
||||
privateKey: '秘钥',
|
||||
ac: '授权凭证',
|
||||
testConn: '测试连接',
|
||||
connSuccess: '连接成功',
|
||||
usernameExist: '该用户名已存在于该账号列表中',
|
||||
publicAc: '公共凭证',
|
||||
acTypeEnumPublic: '公共凭证',
|
||||
acTypeEnumPrivate: '普通凭证',
|
||||
acTypeEnumPrivileged: '特权凭证',
|
||||
acTypeEnumPrivateDefault: '默认凭证',
|
||||
ciphertextTypeEnumPassword: '密码',
|
||||
ciphertextTypeEnumPrivateKey: '秘钥',
|
||||
ciphertextTypeEnumPublic: '公共凭证',
|
||||
},
|
||||
};
|
||||
@@ -2,29 +2,25 @@
|
||||
<div class="layout-columns-aside">
|
||||
<el-scrollbar>
|
||||
<ul>
|
||||
<li
|
||||
v-for="(v, k) in state.columnsAsideList"
|
||||
:key="k"
|
||||
@click="onColumnsAsideMenuClick(v, k)"
|
||||
:ref="
|
||||
(el) => {
|
||||
if (el) columnsAsideOffsetTopRefs[k] = el;
|
||||
}
|
||||
"
|
||||
:class="{ 'layout-columns-active': state.liIndex === k }"
|
||||
:title="v.meta.title"
|
||||
>
|
||||
<div class="layout-columns-aside-li-box" v-if="!v.meta.link || (v.meta.link && v.meta.linkType == 1)">
|
||||
<li v-for="(v, k) in state.columnsAsideList" :key="k" @click="onColumnsAsideMenuClick(v, k)" :ref="(el) => {
|
||||
if (el) columnsAsideOffsetTopRefs[k] = el;
|
||||
}
|
||||
" :class="{ 'layout-columns-active': state.liIndex === k }" :title="$t(v.meta.title)">
|
||||
<div class="layout-columns-aside-li-box"
|
||||
v-if="!v.meta.link || (v.meta.link && v.meta.linkType == 1)">
|
||||
<i :class="v.meta.icon"></i>
|
||||
<div class="layout-columns-aside-li-box-title font12">
|
||||
{{ v.meta.title && v.meta.title.length >= 4 ? v.meta.title.substr(0, 4) : v.meta.title }}
|
||||
{{ $t(v.meta.title) && $t(v.meta.title).length >= 4 ? $t(v.meta.title).substr(0, 4) :
|
||||
$t(v.meta.title) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-columns-aside-li-box" v-else>
|
||||
<a :href="v.meta.link" target="_blank">
|
||||
<i :class="v.meta.icon"></i>
|
||||
<div class="layout-columns-aside-li-box-title font12">
|
||||
{{ v.meta.title && v.meta.title.length >= 4 ? v.meta.title.substr(0, 4) : v.meta.title }}
|
||||
{{ $t(v.meta.title) && $t(v.meta.title).length >= 4 ? $t(v.meta.title).substr(0, 4) :
|
||||
$t(v.meta.title)
|
||||
}}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
<el-breadcrumb-item v-for="(v, k) in state.breadcrumbList" :key="v.meta.title">
|
||||
<span v-if="k === state.breadcrumbList.length - 1" class="layout-navbars-breadcrumb-span">
|
||||
<SvgIcon :name="v.meta.icon" class="layout-navbars-breadcrumb-iconfont" v-if="themeConfig.isBreadcrumbIcon" />
|
||||
{{ v.meta.title }}
|
||||
{{ $t(v.meta.title) }}
|
||||
</span>
|
||||
<a v-else @click.prevent="onBreadcrumbClick(v)">
|
||||
<SvgIcon :name="v.meta.icon" class="layout-navbars-breadcrumb-iconfont" v-if="themeConfig.isBreadcrumbIcon" />
|
||||
{{ v.meta.title }}
|
||||
{{ $t(v.meta.title) }}
|
||||
</a>
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<el-autocomplete
|
||||
v-model="state.menuQuery"
|
||||
:fetch-suggestions="menuSearch"
|
||||
placeholder="菜单搜索"
|
||||
:placeholder="$t('layout.user.searchPlaceholder')"
|
||||
prefix-icon="el-icon-search"
|
||||
ref="layoutMenuAutocompleteRef"
|
||||
@select="onHandleSelect"
|
||||
@@ -16,7 +16,7 @@
|
||||
</el-icon>
|
||||
</template>
|
||||
<template #default="{ item }">
|
||||
<div><SvgIcon :name="item.meta.icon" class="mr5" />{{ item.meta.title }}</div>
|
||||
<div><SvgIcon :name="item.meta.icon" class="mr5" />{{ $t(item.meta.title) }}</div>
|
||||
</template>
|
||||
</el-autocomplete>
|
||||
</el-dialog>
|
||||
@@ -27,6 +27,9 @@
|
||||
import { reactive, ref, nextTick } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useRoutesList } from '@/store/routesList';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const layoutMenuAutocompleteRef: any = ref(null);
|
||||
const router = useRouter();
|
||||
@@ -50,16 +53,18 @@ const openSearch = () => {
|
||||
const closeSearch = () => {
|
||||
state.isShowSearch = false;
|
||||
};
|
||||
|
||||
// 菜单搜索数据过滤
|
||||
const menuSearch = (queryString: any, cb: any) => {
|
||||
let results = queryString ? state.tagsViewList.filter(createFilter(queryString)) : state.tagsViewList;
|
||||
let results = queryString ? state.tagsViewList.filter(createFilter(t(queryString))) : state.tagsViewList;
|
||||
cb(results);
|
||||
};
|
||||
// 菜单搜索过滤
|
||||
const createFilter = (queryString: any) => {
|
||||
return (restaurant: any) => {
|
||||
return (
|
||||
restaurant.path.toLowerCase().indexOf(queryString.toLowerCase()) > -1 || restaurant.meta.title.toLowerCase().indexOf(queryString.toLowerCase()) > -1
|
||||
t(restaurant.path).toLowerCase().indexOf(queryString.toLowerCase()) > -1 ||
|
||||
t(restaurant.meta.title).toLowerCase().indexOf(queryString.toLowerCase()) > -1
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
<template>
|
||||
<div class="layout-breadcrumb-seting">
|
||||
<el-drawer title="布局设置" v-model="themeConfig.isDrawer" direction="rtl" destroy-on-close size="240px" @close="onDrawerClose">
|
||||
<el-drawer :title="$t('layout.config.configTitle')" v-model="themeConfig.isDrawer" direction="rtl" destroy-on-close size="240px" @close="onDrawerClose">
|
||||
<el-scrollbar class="layout-breadcrumb-seting-bar">
|
||||
<!-- ssh终端主题 -->
|
||||
<el-divider content-position="left">终端主题</el-divider>
|
||||
<el-divider content-position="left">{{ $t('layout.config.terminalTheme') }}</el-divider>
|
||||
<div class="layout-breadcrumb-seting-bar-flex">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">主题</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.theme') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-select @change="setLocalThemeConfig" v-model="themeConfig.terminalTheme" size="small" style="width: 140px">
|
||||
<el-select v-model="themeConfig.terminalTheme" size="small" style="width: 140px">
|
||||
<el-option v-for="(_, k) in themes" :key="k" :label="k" :value="k"> </el-option>
|
||||
<el-option label="自定义" value="custom"> </el-option>
|
||||
<el-option :label="$t('layout.config.custom')" value="custom"> </el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="themeConfig.terminalTheme == 'custom'">
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt10">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">字体颜色</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.fontColor') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-color-picker v-model="themeConfig.terminalForeground" size="small" @change="onColorPickerChange('terminalForeground')">
|
||||
</el-color-picker>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">背景颜色</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.backgroundColor') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-color-picker v-model="themeConfig.terminalBackground" size="small" @change="onColorPickerChange('terminalBackground')">
|
||||
</el-color-picker>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">cursor颜色</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.cursorColor') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-color-picker v-model="themeConfig.terminalCursor" size="small" @change="onColorPickerChange('terminalCursor')">
|
||||
</el-color-picker>
|
||||
@@ -38,35 +38,27 @@
|
||||
</template>
|
||||
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt10">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">字体大小</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.fontSize') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-input-number
|
||||
v-model="themeConfig.terminalFontSize"
|
||||
controls-position="right"
|
||||
:min="12"
|
||||
:max="24"
|
||||
@change="setLocalThemeConfig"
|
||||
size="small"
|
||||
style="width: 90px"
|
||||
>
|
||||
<el-input-number v-model="themeConfig.terminalFontSize" controls-position="right" :min="12" :max="24" size="small" style="width: 90px">
|
||||
</el-input-number>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt10">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">字体粗细</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.fontWeight') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-select @change="setLocalThemeConfig" v-model="themeConfig.terminalFontWeight" size="small" style="width: 90px">
|
||||
<el-select v-model="themeConfig.terminalFontWeight" size="small" style="width: 90px">
|
||||
<el-option label="normal" value="normal"> </el-option>
|
||||
<el-option label="bold" value="bold"> </el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-divider content-position="left">editor 设置</el-divider>
|
||||
<el-divider content-position="left">{{ $t('layout.config.editorSetting') }}</el-divider>
|
||||
<div class="layout-breadcrumb-seting-bar-flex">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">主题</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.theme') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-select @change="setLocalThemeConfig" v-model="themeConfig.editorTheme" size="small" style="width: 130px">
|
||||
<el-select v-model="themeConfig.editorTheme" size="small" style="width: 130px">
|
||||
<el-option label="vs" value="vs"> </el-option>
|
||||
<el-option label="vs-dark" value="vs-dark"> </el-option>
|
||||
<el-option label="SolarizedLight" value="SolarizedLight"> </el-option>
|
||||
@@ -75,16 +67,15 @@
|
||||
</div>
|
||||
|
||||
<!-- 全局设置 -->
|
||||
<el-divider content-position="left">全局设置</el-divider>
|
||||
<el-divider content-position="left">{{ $t('layout.config.globalSetting') }}</el-divider>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">分页size</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.pagesize') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-input-number
|
||||
v-model="themeConfig.defaultListPageSize"
|
||||
controls-position="right"
|
||||
:min="10"
|
||||
:max="50"
|
||||
@change="setLocalThemeConfig"
|
||||
size="small"
|
||||
style="width: 90px"
|
||||
>
|
||||
@@ -93,7 +84,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 全局主题 -->
|
||||
<el-divider content-position="left">全局主题</el-divider>
|
||||
<el-divider content-position="left">{{ $t('layout.config.globalTheme') }}</el-divider>
|
||||
<div class="layout-breadcrumb-seting-bar-flex">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">primary</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
@@ -125,129 +116,156 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 菜单 / 顶栏 -->
|
||||
<el-divider content-position="left">菜单 / 顶栏</el-divider>
|
||||
<!-- 菜单 -->
|
||||
<el-divider content-position="left">{{ $t('layout.config.menuSetting') }}</el-divider>
|
||||
<div class="layout-breadcrumb-seting-bar-flex">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">顶栏背景</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-color-picker v-model="themeConfig.topBar" size="small" @change="onBgColorPickerChange('topBar')"> </el-color-picker>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">菜单背景</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.menuBar') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-color-picker v-model="themeConfig.menuBar" size="small" @change="onBgColorPickerChange('menuBar')"> </el-color-picker>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layout-breadcrumb-seting-bar-flex">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">
|
||||
{{ $t('layout.config.menuBarFontColor') }}
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-color-picker v-model="themeConfig.menuBarColor" size="small" @change="onBgColorPickerChange('menuBarColor')"> </el-color-picker>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt14">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">
|
||||
{{ $t('layout.config.menuBarActiveColor') }}
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isMenuBarColorHighlight" @change="onMenuBarHighlightChange"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt14">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">
|
||||
{{ $t('layout.config.isMenuBarColorGradual') }}
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isMenuBarColorGradual" @change="onMenuBarGradualChange"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="layout-breadcrumb-seting-bar-flex">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">顶栏背景</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-color-picker v-model="themeConfig.topBar" size="small"
|
||||
@change="onBgColorPickerChange('topBar')">
|
||||
</el-color-picker>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layout-breadcrumb-seting-bar-flex">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">分栏菜单背景</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-color-picker v-model="themeConfig.columnsMenuBar" size="small" @change="onBgColorPickerChange('columnsMenuBar')"> </el-color-picker>
|
||||
<el-color-picker v-model="themeConfig.columnsMenuBar" size="small"
|
||||
@change="onBgColorPickerChange('columnsMenuBar')"> </el-color-picker>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">顶栏默认字体颜色</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-color-picker v-model="themeConfig.topBarColor" size="small" @change="onBgColorPickerChange('topBarColor')"> </el-color-picker>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">菜单默认字体颜色</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-color-picker v-model="themeConfig.menuBarColor" size="small" @change="onBgColorPickerChange('menuBarColor')"> </el-color-picker>
|
||||
<el-color-picker v-model="themeConfig.topBarColor" size="small"
|
||||
@change="onBgColorPickerChange('topBarColor')">
|
||||
</el-color-picker>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layout-breadcrumb-seting-bar-flex">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">分栏菜单默认字体颜色</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-color-picker v-model="themeConfig.columnsMenuBarColor" size="small" @change="onBgColorPickerChange('columnsMenuBarColor')">
|
||||
<el-color-picker v-model="themeConfig.columnsMenuBarColor" size="small"
|
||||
@change="onBgColorPickerChange('columnsMenuBarColor')">
|
||||
</el-color-picker>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt10">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">顶栏背景渐变</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isTopBarColorGradual" @change="onTopBarGradualChange"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt14">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">菜单背景渐变</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isMenuBarColorGradual" @change="onMenuBarGradualChange"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt14">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">分栏菜单背景渐变</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isColumnsMenuBarColorGradual" @change="onColumnsMenuBarGradualChange"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt14">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">菜单字体背景高亮</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isMenuBarColorHighlight" @change="onMenuBarHighlightChange"></el-switch>
|
||||
<el-switch v-model="themeConfig.isTopBarColorGradual"
|
||||
@change="onTopBarGradualChange"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt14">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">分栏菜单背景渐变</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isColumnsMenuBarColorGradual"
|
||||
@change="onColumnsMenuBarGradualChange"></el-switch>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- 界面设置 -->
|
||||
<el-divider content-position="left">界面设置</el-divider>
|
||||
<el-divider content-position="left">{{ $t('layout.config.interfaceSetting') }}</el-divider>
|
||||
<div class="layout-breadcrumb-seting-bar-flex">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">菜单水平折叠</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">
|
||||
{{ $t('layout.config.isCollapse') }}
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isCollapse" @change="onThemeConfigChange"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">菜单手风琴</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">
|
||||
{{ $t('layout.config.isUniqueOpened') }}
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isUniqueOpened" @change="setLocalThemeConfig"></el-switch>
|
||||
<el-switch v-model="themeConfig.isUniqueOpened"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">固定 Header</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">
|
||||
{{ $t('layout.config.isFixedHeader') }}
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isFixedHeader" @change="onIsFixedHeaderChange"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15" :style="{ opacity: themeConfig.layout !== 'classic' ? 0.5 : 1 }">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">经典布局分割菜单</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">
|
||||
{{ $t('layout.config.isClassicSplitMenu') }}
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isClassicSplitMenu" :disabled="themeConfig.layout !== 'classic'" @change="onClassicSplitMenuChange">
|
||||
</el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">开启锁屏</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">
|
||||
{{ $t('layout.config.isLockScreen') }}
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isLockScreen" @change="setLocalThemeConfig"></el-switch>
|
||||
<el-switch v-model="themeConfig.isLockScreen"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt11">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">自动锁屏(s/秒)</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">
|
||||
{{ $t('layout.config.lockScreenTime') }}
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-input-number
|
||||
v-model="themeConfig.lockScreenTime"
|
||||
controls-position="right"
|
||||
:min="0"
|
||||
:max="9999"
|
||||
@change="setLocalThemeConfig"
|
||||
size="small"
|
||||
style="width: 90px"
|
||||
>
|
||||
<el-input-number v-model="themeConfig.lockScreenTime" controls-position="right" :min="0" :max="9999" size="small" style="width: 90px">
|
||||
</el-input-number>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 界面显示 -->
|
||||
<el-divider content-position="left">界面显示</el-divider>
|
||||
<el-divider content-position="left">{{ $t('layout.config.interfaceDisplay') }}</el-divider>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">侧边栏 Logo</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.isShowLogo') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isShowLogo" @change="onIsShowLogoChange"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15" :style="{ opacity: themeConfig.layout === 'transverse' ? 0.5 : 1 }">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">开启Breadcrumb</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">
|
||||
{{ $t('layout.config.isBreadcrumb') }}
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch
|
||||
v-model="themeConfig.isBreadcrumb"
|
||||
@@ -257,60 +275,68 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">开启Breadcrumb图标</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">
|
||||
{{ $t('layout.config.isBreadcrumbIcon') }}
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isBreadcrumbIcon" @change="setLocalThemeConfig"></el-switch>
|
||||
<el-switch v-model="themeConfig.isBreadcrumbIcon"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">开启 Tagsview</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.isTagsview') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isTagsview" @change="setLocalThemeConfig"></el-switch>
|
||||
<el-switch v-model="themeConfig.isTagsview"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">开启 Tagsview图标</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">
|
||||
{{ $t('layout.config.isTagsviewIcon') }}
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isTagsviewIcon" @change="setLocalThemeConfig"></el-switch>
|
||||
<el-switch v-model="themeConfig.isTagsviewIcon"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">开启 TagsView缓存</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">
|
||||
{{ $t('layout.config.isCacheTagsView') }}
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isCacheTagsView" @change="setLocalThemeConfig"></el-switch>
|
||||
<el-switch v-model="themeConfig.isCacheTagsView"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">开启 TagsView拖拽</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">
|
||||
{{ $t('layout.config.isSortableTagsView') }}
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isSortableTagsView" @change="onSortableTagsViewChange"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">开启 Footer</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.isFooter') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isFooter" @change="setLocalThemeConfig"></el-switch>
|
||||
<el-switch v-model="themeConfig.isFooter"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">灰色模式</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.isGrayscale') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isGrayscale" @change="onAddFilterChange('grayscale')"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">色弱模式</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.isInvert') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-switch v-model="themeConfig.isInvert" @change="onAddFilterChange('invert')"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 其它设置 -->
|
||||
<el-divider content-position="left">其他设置</el-divider>
|
||||
<el-divider content-position="left">{{ $t('layout.config.otherSetting') }}</el-divider>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">Tagsview 风格</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.tagsStyle') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-select v-model="themeConfig.tagsStyle" placeholder="请选择" size="small" style="width: 90px" @change="setLocalThemeConfig">
|
||||
<el-select v-model="themeConfig.tagsStyle" placeholder="请选择" size="small" style="width: 90px">
|
||||
<el-option label="风格1" value="tags-style-one"></el-option>
|
||||
<el-option label="风格2" value="tags-style-two"></el-option>
|
||||
<el-option label="风格3" value="tags-style-three"></el-option>
|
||||
@@ -318,9 +344,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">主页面切换动画</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('layout.config.animation') }}</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-select v-model="themeConfig.animation" placeholder="请选择" size="small" style="width: 90px" @change="setLocalThemeConfig">
|
||||
<el-select v-model="themeConfig.animation" size="small" style="width: 90px">
|
||||
<el-option label="slide-right" value="slide-right"></el-option>
|
||||
<el-option label="slide-left" value="slide-left"></el-option>
|
||||
<el-option label="opacitys" value="opacitys"></el-option>
|
||||
@@ -328,9 +354,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex mt15 mb28">
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">分栏高亮风格</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-label">
|
||||
{{ $t('layout.config.columnsAsideStyle') }}
|
||||
</div>
|
||||
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||
<el-select v-model="themeConfig.columnsAsideStyle" placeholder="请选择" size="small" style="width: 90px" @change="setLocalThemeConfig">
|
||||
<el-select v-model="themeConfig.columnsAsideStyle" placeholder="请选择" size="small" style="width: 90px">
|
||||
<el-option label="圆角" value="columns-round"></el-option>
|
||||
<el-option label="卡片" value="columns-card"></el-option>
|
||||
</el-select>
|
||||
@@ -338,7 +366,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 布局切换 -->
|
||||
<el-divider content-position="left">布局切换</el-divider>
|
||||
<el-divider content-position="left">{{ $t('layout.config.layoutSwitch') }}</el-divider>
|
||||
<div class="layout-drawer-content-flex">
|
||||
<!-- defaults 布局 -->
|
||||
<div class="layout-drawer-content-item" @click="onSetLayout('defaults')">
|
||||
@@ -351,7 +379,7 @@
|
||||
</section>
|
||||
<div class="layout-tips-warp" :class="{ 'layout-tips-warp-active': themeConfig.layout === 'defaults' }">
|
||||
<div class="layout-tips-box">
|
||||
<p class="layout-tips-txt">默认</p>
|
||||
<p class="layout-tips-txt">{{ $t('layout.config.defaults') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -368,7 +396,7 @@
|
||||
</section>
|
||||
<div class="layout-tips-warp" :class="{ 'layout-tips-warp-active': themeConfig.layout === 'classic' }">
|
||||
<div class="layout-tips-box">
|
||||
<p class="layout-tips-txt">经典</p>
|
||||
<p class="layout-tips-txt">{{ $t('layout.config.classic') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -384,7 +412,7 @@
|
||||
</section>
|
||||
<div class="layout-tips-warp" :class="{ 'layout-tips-warp-active': themeConfig.layout === 'transverse' }">
|
||||
<div class="layout-tips-box">
|
||||
<p class="layout-tips-txt">横向</p>
|
||||
<p class="layout-tips-txt">{{ $t('layout.config.transverse') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -400,7 +428,7 @@
|
||||
</section>
|
||||
<div class="layout-tips-warp" :class="{ 'layout-tips-warp-active': themeConfig.layout === 'columns' }">
|
||||
<div class="layout-tips-box">
|
||||
<p class="layout-tips-txt">分栏</p>
|
||||
<p class="layout-tips-txt">{{ $t('layout.config.columns') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -429,12 +457,12 @@ import ClipboardJS from 'clipboard';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
import { getLightColor } from '@/common/utils/theme';
|
||||
import { setLocal, getLocal, removeLocal } from '@/common/utils/storage';
|
||||
import { setLocal, getLocal } from '@/common/utils/storage';
|
||||
import mittBus from '@/common/utils/mitt';
|
||||
import themes from '@/components/terminal/themes';
|
||||
|
||||
const copyConfigBtnRef = ref();
|
||||
const { themeConfig } = storeToRefs(useThemeConfig());
|
||||
const { themeConfig } = storeToRefs(useThemeConfig()) as any;
|
||||
|
||||
// 1、全局主题
|
||||
const onColorPickerChange = (color: string) => {
|
||||
@@ -475,7 +503,7 @@ const setGraduaFun = (el: string, bool: boolean, color: string) => {
|
||||
if (!els) return false;
|
||||
if (bool) els.setAttribute('style', `background-image:linear-gradient(to bottom left , ${color}, ${getLightColor(color, 0.6)})`);
|
||||
else els.setAttribute('style', `background-image:${color}`);
|
||||
setLocalThemeConfig();
|
||||
|
||||
const elNavbars: any = document.querySelector('.layout-navbars-breadcrumb-index');
|
||||
const elAside: any = document.querySelector('.layout-container .el-aside');
|
||||
const elColumns: any = document.querySelector('.layout-container .layout-columns-aside');
|
||||
@@ -498,7 +526,6 @@ const onMenuBarHighlightChange = () => {
|
||||
} else {
|
||||
elActive.setAttribute('id', ``);
|
||||
}
|
||||
setLocalThemeConfig();
|
||||
}, 0);
|
||||
});
|
||||
};
|
||||
@@ -510,30 +537,26 @@ const onThemeConfigChange = () => {
|
||||
// 3、界面设置 --> 固定 Header
|
||||
const onIsFixedHeaderChange = () => {
|
||||
themeConfig.value.isFixedHeaderChange = themeConfig.value.isFixedHeader ? false : true;
|
||||
setLocalThemeConfig();
|
||||
};
|
||||
// 3、界面设置 --> 经典布局分割菜单
|
||||
const onClassicSplitMenuChange = () => {
|
||||
themeConfig.value.isBreadcrumb = false;
|
||||
setLocalThemeConfig();
|
||||
|
||||
mittBus.emit('getBreadcrumbIndexSetFilterRoutes');
|
||||
};
|
||||
// 4、界面显示 --> 侧边栏 Logo
|
||||
const onIsShowLogoChange = () => {
|
||||
themeConfig.value.isShowLogoChange = themeConfig.value.isShowLogo ? false : true;
|
||||
setLocalThemeConfig();
|
||||
};
|
||||
// 4、界面显示 --> 面包屑 Breadcrumb
|
||||
const onIsBreadcrumbChange = () => {
|
||||
if (themeConfig.value.layout === 'classic') {
|
||||
themeConfig.value.isClassicSplitMenu = false;
|
||||
}
|
||||
setLocalThemeConfig();
|
||||
};
|
||||
// 4、界面显示 --> 开启 TagsView 拖拽
|
||||
const onSortableTagsViewChange = () => {
|
||||
mittBus.emit('openOrCloseSortable');
|
||||
setLocalThemeConfig();
|
||||
};
|
||||
// 4、界面显示 --> 暗模式/灰色模式/色弱模式
|
||||
const onAddFilterChange = (attr: string) => {
|
||||
@@ -545,7 +568,7 @@ const onAddFilterChange = (attr: string) => {
|
||||
const cssAttr = attr === 'grayscale' ? `grayscale(${themeConfig.value.isGrayscale ? 1 : 0})` : `invert(${themeConfig.value.isInvert ? '80%' : '0%'})`;
|
||||
const appEle: any = document.querySelector('#app');
|
||||
appEle.setAttribute('style', `filter: ${cssAttr}`);
|
||||
setLocalThemeConfig();
|
||||
|
||||
setLocal('appFilterStyle', appEle.style.cssText);
|
||||
};
|
||||
// 5、布局切换
|
||||
@@ -603,7 +626,6 @@ const onDrawerClose = () => {
|
||||
themeConfig.value.isFixedHeaderChange = false;
|
||||
themeConfig.value.isShowLogoChange = false;
|
||||
themeConfig.value.isDrawer = false;
|
||||
setLocalThemeConfig();
|
||||
};
|
||||
// 布局配置弹窗打开
|
||||
const openDrawer = () => {
|
||||
@@ -613,16 +635,12 @@ const openDrawer = () => {
|
||||
onCopyConfigClick(copyConfigBtnRef.value?.$el);
|
||||
});
|
||||
};
|
||||
|
||||
// 触发 store 布局配置更新
|
||||
const setDispatchThemeConfig = () => {
|
||||
setLocalThemeConfig();
|
||||
setLocalThemeConfigStyle();
|
||||
};
|
||||
// 存储布局配置
|
||||
const setLocalThemeConfig = () => {
|
||||
removeLocal('themeConfig');
|
||||
setLocal('themeConfig', themeConfig.value);
|
||||
};
|
||||
|
||||
// 存储布局配置全局主题样式(html根标签)
|
||||
const setLocalThemeConfigStyle = () => {
|
||||
setLocal('themeConfigStyle', document.documentElement.style.cssText);
|
||||
|
||||
@@ -23,24 +23,32 @@
|
||||
<el-dropdown-item command="small" :disabled="state.disabledSize === 'small'">小型</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown> -->
|
||||
</el-dropdown> -->
|
||||
|
||||
<el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onLanguageChange">
|
||||
<div class="layout-navbars-breadcrumb-user-icon">
|
||||
<SvgIcon :size="16" :name="EnumValue.getEnumByValue(I18nEnum, themeConfig.globalI18n)?.extra.icon" :title="$t('layout.user.langSwitch')" />
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-for="item in I18nEnum" :key="item.value" :command="item.value" :disabled="themeConfig.globalI18n === item.value">
|
||||
{{ item.label }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
|
||||
<div class="layout-navbars-breadcrumb-user-icon" @click="onSearchClick">
|
||||
<el-icon title="菜单搜索">
|
||||
<search />
|
||||
</el-icon>
|
||||
<SvgIcon name="search" :title="$t('layout.user.menuSearch')" />
|
||||
</div>
|
||||
<div class="layout-navbars-breadcrumb-user-icon" @click="onLayoutSetingClick">
|
||||
<el-icon title="布局设置">
|
||||
<setting />
|
||||
</el-icon>
|
||||
<SvgIcon name="setting" :title="$t('layout.user.layoutConf')" />
|
||||
</div>
|
||||
<div class="layout-navbars-breadcrumb-user-icon">
|
||||
<el-popover placement="bottom" trigger="click" :visible="state.isShowUserNewsPopover" :width="300" popper-class="el-popover-pupop-user-news">
|
||||
<template #reference>
|
||||
<el-badge :is-dot="false" @click="state.isShowUserNewsPopover = !state.isShowUserNewsPopover">
|
||||
<el-icon title="消息">
|
||||
<bell />
|
||||
</el-icon>
|
||||
<SvgIcon name="bell" :title="$t('layout.user.news')" />
|
||||
</el-badge>
|
||||
</template>
|
||||
<transition name="el-zoom-in-top">
|
||||
@@ -49,12 +57,8 @@
|
||||
</el-popover>
|
||||
</div>
|
||||
<div class="layout-navbars-breadcrumb-user-icon mr10" @click="onScreenfullClick">
|
||||
<el-icon v-if="!state.isScreenfull" title="关全屏">
|
||||
<full-screen />
|
||||
</el-icon>
|
||||
<el-icon v-else title="开全屏">
|
||||
<crop />
|
||||
</el-icon>
|
||||
<SvgIcon v-if="!state.isScreenfull" name="full-screen" :title="$t('layout.user.fullScreenOff')" />
|
||||
<SvgIcon v-else name="crop" />
|
||||
</div>
|
||||
<el-dropdown trigger="click" :show-timeout="70" :hide-timeout="50" @command="onHandleCommandClick">
|
||||
<span class="layout-navbars-breadcrumb-user-link" style="cursor: pointer">
|
||||
@@ -64,9 +68,9 @@
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="/home">首页</el-dropdown-item>
|
||||
<el-dropdown-item command="/personal">个人中心</el-dropdown-item>
|
||||
<el-dropdown-item divided command="logOut">退出登录</el-dropdown-item>
|
||||
<el-dropdown-item command="/home">{{ $t('layout.user.index') }}</el-dropdown-item>
|
||||
<el-dropdown-item command="/personal">{{ $t('layout.user.personalCenter') }}</el-dropdown-item>
|
||||
<el-dropdown-item divided command="logOut">{{ $t('layout.user.logout') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
@@ -88,20 +92,23 @@ import UserNews from '@/layout/navBars/breadcrumb/userNews.vue';
|
||||
import SearchMenu from '@/layout/navBars/breadcrumb/search.vue';
|
||||
import mittBus from '@/common/utils/mitt';
|
||||
import openApi from '@/common/openApi';
|
||||
import { saveThemeConfig, getThemeConfig } from '@/common/utils/storage';
|
||||
import { getThemeConfig } from '@/common/utils/storage';
|
||||
import { useDark, usePreferredDark } from '@vueuse/core';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { I18nEnum } from '@/common/commonEnum';
|
||||
import EnumValue from '@/common/Enum';
|
||||
|
||||
const router = useRouter();
|
||||
const searchRef = ref();
|
||||
const state = reactive({
|
||||
isScreenfull: false,
|
||||
isShowUserNewsPopover: false,
|
||||
disabledI18n: 'zh-cn',
|
||||
disabledSize: '',
|
||||
});
|
||||
const { userInfo } = storeToRefs(useUserInfo());
|
||||
const themeConfigStore = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(themeConfigStore);
|
||||
const { t } = useI18n();
|
||||
|
||||
// 设置分割样式
|
||||
const layoutUserFlexNum = computed(() => {
|
||||
@@ -111,6 +118,16 @@ const layoutUserFlexNum = computed(() => {
|
||||
else num = '';
|
||||
return num;
|
||||
});
|
||||
|
||||
// 页面加载时
|
||||
onMounted(() => {
|
||||
const themeConfig = getThemeConfig();
|
||||
if (themeConfig) {
|
||||
initComponentSize();
|
||||
isDark.value = themeConfig.isDark;
|
||||
}
|
||||
});
|
||||
|
||||
// 全屏点击时
|
||||
const onScreenfullClick = () => {
|
||||
if (!screenfull.isEnabled) {
|
||||
@@ -130,16 +147,16 @@ const onHandleCommandClick = (path: string) => {
|
||||
ElMessageBox({
|
||||
closeOnClickModal: false,
|
||||
closeOnPressEscape: false,
|
||||
title: '提示',
|
||||
message: '此操作将退出登录, 是否继续?',
|
||||
title: t('layout.user.logOutTitle'),
|
||||
message: t('layout.user.logOutMessage'),
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
confirmButtonText: t('common.confirm'),
|
||||
cancelButtonText: t('common.cancel'),
|
||||
beforeClose: async (action, instance, done) => {
|
||||
if (action === 'confirm') {
|
||||
await openApi.logout();
|
||||
instance.confirmButtonLoading = true;
|
||||
instance.confirmButtonText = '退出中';
|
||||
instance.confirmButtonText = t('layout.user.logOutExit');
|
||||
setTimeout(() => {
|
||||
done();
|
||||
setTimeout(() => {
|
||||
@@ -156,7 +173,7 @@ const onHandleCommandClick = (path: string) => {
|
||||
resetRoute(); // 删除/重置路由
|
||||
router.push('/login');
|
||||
setTimeout(() => {
|
||||
ElMessage.success('安全退出成功!');
|
||||
ElMessage.success(t('layout.user.logoutSuccess'));
|
||||
}, 300);
|
||||
})
|
||||
.catch(() => {});
|
||||
@@ -175,7 +192,6 @@ watch(preDark, (newValue) => {
|
||||
|
||||
const switchDark = () => {
|
||||
themeConfigStore.switchDark(isDark.value);
|
||||
saveThemeConfig(themeConfig.value);
|
||||
};
|
||||
|
||||
// // 菜单搜索点击
|
||||
@@ -211,14 +227,10 @@ const initComponentSize = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 页面加载时
|
||||
onMounted(() => {
|
||||
const themeConfig = getThemeConfig();
|
||||
if (themeConfig) {
|
||||
initComponentSize();
|
||||
isDark.value = themeConfig.isDark;
|
||||
}
|
||||
});
|
||||
// 语言切换
|
||||
const onLanguageChange = (lang: string) => {
|
||||
themeConfig.value.globalI18n = lang;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="layout-navbars-breadcrumb-user-news">
|
||||
<div class="head-box">
|
||||
<div class="head-box-title">通知</div>
|
||||
<div class="head-box-btn" v-if="newsList.length > 0" @click="onAllReadClick">全部已读</div>
|
||||
<div class="head-box-title">{{ $t('layout.user.newTitle') }}</div>
|
||||
<div class="head-box-btn" v-if="newsList.length > 0" @click="onAllReadClick">{{ $t('layout.user.newBtn') }}</div>
|
||||
</div>
|
||||
<div class="content-box">
|
||||
<template v-if="newsList.length > 0">
|
||||
@@ -14,9 +14,9 @@
|
||||
<div class="content-box-time">{{ v.time }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-empty description="暂无通知" v-else></el-empty>
|
||||
<el-empty :description="$t('layout.user.newDesc')" v-else></el-empty>
|
||||
</div>
|
||||
<div class="foot-box" @click="toMsgCenter" v-if="newsList.length > 0">前往通知中心</div>
|
||||
<div class="foot-box" @click="toMsgCenter" v-if="newsList.length > 0">{{ $t('layout.user.newGo') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -59,33 +59,41 @@ export default {
|
||||
justify-content: space-between;
|
||||
height: 35px;
|
||||
align-items: center;
|
||||
|
||||
.head-box-btn {
|
||||
color: var(--el-color-primary);
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
opacity: 0.8;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-box {
|
||||
font-size: 13px;
|
||||
|
||||
.content-box-item {
|
||||
padding-top: 12px;
|
||||
|
||||
&:last-of-type {
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.content-box-msg {
|
||||
color: #999999;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.content-box-time {
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.foot-box {
|
||||
height: 35px;
|
||||
color: var(--el-color-primary);
|
||||
@@ -96,10 +104,12 @@ export default {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-top: 1px solid #ebeef5;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(.el-empty__description p) {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
>
|
||||
<SvgIcon name="iconfont icon-tag-view-active" class="layout-navbars-tagsview-ul-li-iconfont font14" v-if="isActive(v)" />
|
||||
<SvgIcon :name="v.icon" class="layout-navbars-tagsview-ul-li-iconfont" v-if="!isActive(v) && themeConfig.isTagsviewIcon" />
|
||||
<span>{{ v.title }}</span>
|
||||
<span>{{ $t(v.title) }}</span>
|
||||
<template v-if="isActive(v)">
|
||||
<SvgIcon
|
||||
name="RefreshRight"
|
||||
@@ -74,7 +74,7 @@ const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const contextmenuItems = [
|
||||
new ContextmenuItem(0, '刷新').withIcon('RefreshRight').withOnClick((data: any) => {
|
||||
new ContextmenuItem(0, 'layout.tagsView.refresh').withIcon('RefreshRight').withOnClick((data: any) => {
|
||||
// path为fullPath
|
||||
let { path } = data;
|
||||
let currentTag = tagsViews.value.find((v: any) => v.path === path);
|
||||
@@ -82,18 +82,18 @@ const contextmenuItems = [
|
||||
router.push({ path, query: currentTag?.query });
|
||||
}),
|
||||
|
||||
new ContextmenuItem(1, '关闭').withIcon('Close').withOnClick((data: any) => closeCurrentTagsView(data.path)),
|
||||
new ContextmenuItem(1, 'layout.tagsView.close').withIcon('Close').withOnClick((data: any) => closeCurrentTagsView(data.path)),
|
||||
|
||||
new ContextmenuItem(2, '关闭其他').withIcon('CircleClose').withOnClick((data: any) => {
|
||||
new ContextmenuItem(2, 'layout.tagsView.closeOther').withIcon('CircleClose').withOnClick((data: any) => {
|
||||
let { path } = data;
|
||||
let currentTag = tagsViews.value.find((v: any) => v.path === path);
|
||||
router.push({ path, query: currentTag?.query });
|
||||
closeOtherTagsView(path);
|
||||
}),
|
||||
|
||||
new ContextmenuItem(3, '关闭所有').withIcon('FolderDelete').withOnClick((data: any) => closeAllTagsView(data.path)),
|
||||
new ContextmenuItem(3, 'layout.tagsView.closeAll').withIcon('FolderDelete').withOnClick((data: any) => closeAllTagsView(data.path)),
|
||||
|
||||
new ContextmenuItem(4, '当前页全屏').withIcon('full-screen').withOnClick((data: any) => openCurrenFullscreen(data.path)),
|
||||
new ContextmenuItem(4, 'layout.tagsView.fullscreen').withIcon('full-screen').withOnClick((data: any) => openCurrenFullscreen(data.path)),
|
||||
];
|
||||
|
||||
const state = reactive({
|
||||
|
||||
@@ -6,19 +6,19 @@
|
||||
<el-sub-menu :index="val.path" v-if="val.children && val.children.length > 0" :key="val.path">
|
||||
<template #title>
|
||||
<SvgIcon :name="val.meta.icon" />
|
||||
<span>{{ val.meta.title }}</span>
|
||||
<span>{{ $t(val.meta.title) }}</span>
|
||||
</template>
|
||||
<SubItem :chil="val.children" />
|
||||
</el-sub-menu>
|
||||
<el-menu-item :index="val.path" :key="val?.path" v-else>
|
||||
<template #title v-if="!val.meta.link || (val.meta.link && val.meta.linkType == 1)">
|
||||
<SvgIcon :name="val.meta.icon" />
|
||||
{{ val.meta.title }}
|
||||
{{ $t(val.meta.title) }}
|
||||
</template>
|
||||
<template #title v-else>
|
||||
<a :href="val.meta.link" target="_blank">
|
||||
<SvgIcon :name="val.meta.icon" />
|
||||
{{ val.meta.title }}
|
||||
{{ $t(val.meta.title) }}
|
||||
</a>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
@@ -57,8 +57,7 @@ const menuLists = computed(() => {
|
||||
// 设置横向滚动条可以鼠标滚轮滚动
|
||||
const onElMenuHorizontalScroll = (e: any) => {
|
||||
const eventDelta = e.wheelDelta || -e.deltaY * 40;
|
||||
proxy.$refs.elMenuHorizontalScrollRef.$refs.wrapRef.scrollLeft =
|
||||
proxy.$refs.elMenuHorizontalScrollRef.$refs.wrapRef.scrollLeft + eventDelta / 4;
|
||||
proxy.$refs.elMenuHorizontalScrollRef.$refs.wrapRef.scrollLeft = proxy.$refs.elMenuHorizontalScrollRef.$refs.wrapRef.scrollLeft + eventDelta / 4;
|
||||
};
|
||||
// 初始化数据,页面刷新时,滚动条滚动到对应位置
|
||||
const initElMenuOffsetLeft = () => {
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
<el-sub-menu :index="val.path" :key="val.path" v-if="val.children && val.children.length > 0">
|
||||
<template #title>
|
||||
<SvgIcon :name="val.meta.icon" />
|
||||
<span>{{ val.meta.title }}</span>
|
||||
<span>{{ $t(val.meta.title) }}</span>
|
||||
</template>
|
||||
<sub-item :chil="val.children" />
|
||||
</el-sub-menu>
|
||||
<el-menu-item :index="val.path" :key="val?.path" v-else>
|
||||
<template v-if="!val.meta.link || (val.meta.link && val.meta.linkType == 1)">
|
||||
<SvgIcon :name="val.meta.icon" />
|
||||
<span>{{ val.meta.title }}</span>
|
||||
<span>{{ $t(val.meta.title) }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a :href="val.meta.link" target="_blank">
|
||||
<SvgIcon :name="val.meta.icon" />
|
||||
{{ val.meta.title }}
|
||||
{{ $t(val.meta.title) }}
|
||||
</a>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
@@ -11,17 +11,17 @@
|
||||
<el-sub-menu :index="val.path" v-if="val.children && val.children.length > 0" :key="val.path">
|
||||
<template #title>
|
||||
<SvgIcon :name="val.meta.icon" />
|
||||
<span>{{ val.meta.title }}</span>
|
||||
<span>{{ $t(val.meta.title) }}</span>
|
||||
</template>
|
||||
<SubItem :chil="val.children" />
|
||||
</el-sub-menu>
|
||||
<el-menu-item :index="val.path" :key="val?.path" v-else>
|
||||
<SvgIcon :name="val.meta.icon" />
|
||||
<template #title v-if="!val.meta.link || (val.meta.link && val.meta.linkType == 1)">
|
||||
<span>{{ val.meta.title }}</span>
|
||||
<span>{{ $t(val.meta.title) }}</span>
|
||||
</template>
|
||||
<template #title v-else>
|
||||
<a :href="val.meta.link" target="_blank">{{ val.meta.title }}</a></template
|
||||
<a :href="val.meta.link" target="_blank">{{ $t(val.meta.title) }}</a></template
|
||||
>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="layout-view-bg-white flex layout-view-link">
|
||||
<a :href="currentRouteMeta.link" target="_blank" class="flex-margin">{{ currentRouteMeta.title }}:{{ currentRouteMeta.link }}</a>
|
||||
<a :href="currentRouteMeta.link" target="_blank" class="flex-margin"> {{ $t(currentRouteMeta.title) }}:{{ currentRouteMeta.link }} </a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -4,27 +4,27 @@ import App from '@/App.vue';
|
||||
import router from './router';
|
||||
import pinia from '@/store/index';
|
||||
import { directive } from '@/directive/index';
|
||||
import { globalComponentSize } from '@/common/utils/componentSize';
|
||||
import { registElSvgIcon } from '@/common/utils/svgIcons';
|
||||
|
||||
import ElementPlus from 'element-plus';
|
||||
import 'element-plus/dist/index.css';
|
||||
import 'element-plus/theme-chalk/dark/css-vars.css';
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { i18n } from '@/i18n/index';
|
||||
|
||||
import 'splitpanes/dist/splitpanes.css';
|
||||
|
||||
import '@/theme/index.scss';
|
||||
import '@/assets/font/font.css';
|
||||
import '@/assets/iconfont/iconfont.js';
|
||||
import { getThemeConfig } from './common/utils/storage';
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
registElSvgIcon(app);
|
||||
directive(app);
|
||||
|
||||
app.use(pinia).use(router).use(ElementPlus, { size: globalComponentSize, locale: zhCn }).mount('#app');
|
||||
app.use(pinia).use(router).use(i18n).use(ElementPlus, { size: getThemeConfig()?.globalComponentSize }).mount('#app');
|
||||
|
||||
// 屏蔽警告信息
|
||||
app.config.warnHandler = () => null;
|
||||
|
||||
@@ -25,7 +25,7 @@ export const staticRoutes: Array<RouteRecordRaw> = [
|
||||
name: 'login',
|
||||
component: () => import('@/views/login/index.vue'),
|
||||
meta: {
|
||||
title: '登录',
|
||||
title: 'staticRoutes.signIn',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -40,7 +40,7 @@ export const staticRoutes: Array<RouteRecordRaw> = [
|
||||
name: 'oauth2Callback',
|
||||
component: () => import('@/views/oauth/Oauth2Callback.vue'),
|
||||
meta: {
|
||||
title: 'oauth2回调',
|
||||
title: 'oauth2 callback',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -49,7 +49,7 @@ export const staticRoutes: Array<RouteRecordRaw> = [
|
||||
component: () => import('@/views/ops/machine/SshTerminalPage.vue'),
|
||||
meta: {
|
||||
// 将路径 'xxx?name=名字' 里的name字段值替换到title里
|
||||
title: '终端 | {name}',
|
||||
title: 'terminal | {name}',
|
||||
// 是否根据query对标题名进行参数替换,即最终显示为‘终端_机器名’
|
||||
titleRename: true,
|
||||
},
|
||||
@@ -60,7 +60,7 @@ export const staticRoutes: Array<RouteRecordRaw> = [
|
||||
component: () => import('@/views/ops/machine/RdpTerminalPage.vue'),
|
||||
meta: {
|
||||
// 将路径 'xxx?name=名字' 里的name字段值替换到title里
|
||||
title: '终端 | {name}',
|
||||
title: 'terminal | {name}',
|
||||
// 是否根据query对标题名进行参数替换,即最终显示为‘终端_机器名’
|
||||
titleRename: true,
|
||||
},
|
||||
@@ -74,7 +74,7 @@ export const errorRoutes: Array<RouteRecordRaw> = [
|
||||
name: 'notFound',
|
||||
component: () => import('@/views/error/404.vue'),
|
||||
meta: {
|
||||
title: '找不到此页面',
|
||||
title: 'staticRoutes.notFound',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -82,7 +82,7 @@ export const errorRoutes: Array<RouteRecordRaw> = [
|
||||
name: 'noPower',
|
||||
component: () => import('@/views/error/401.vue'),
|
||||
meta: {
|
||||
title: '没有权限',
|
||||
title: 'staticRoutes.noPower',
|
||||
},
|
||||
},
|
||||
// Resolve refresh page, route warnings
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { formatDate } from '@/common/utils/format';
|
||||
import { useUserInfo } from '@/store/userInfo';
|
||||
import { getSysStyleConfig } from '@/common/sysconfig';
|
||||
import { getServerConf, getSysStyleConfig } from '@/common/sysconfig';
|
||||
import { getLocal, getThemeConfig } from '@/common/utils/storage';
|
||||
|
||||
// 系统默认logo图标,对应于@/assets/image/logo.svg
|
||||
@@ -154,9 +154,14 @@ export const useThemeConfig = defineStore('themeConfig', {
|
||||
initThemeConfig() {
|
||||
// 获取缓存中的布局配置
|
||||
const tc = getThemeConfig();
|
||||
|
||||
if (tc) {
|
||||
this.themeConfig = tc;
|
||||
document.documentElement.style.cssText = getLocal('themeConfigStyle');
|
||||
} else {
|
||||
getServerConf().then((res) => {
|
||||
this.themeConfig.globalI18n = res.i18n;
|
||||
})
|
||||
}
|
||||
|
||||
// 根据后台系统配置初始化
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
<div class="left">
|
||||
<div class="left-item">
|
||||
<div class="left-item-animation left-item-num">401</div>
|
||||
<div class="left-item-animation left-item-title">您未被授权或登录超时,没有操作权限</div>
|
||||
<div class="left-item-animation left-item-title">{{ $t('layout.noAccess.title') }}</div>
|
||||
<div class="left-item-animation left-item-msg"></div>
|
||||
<div class="left-item-animation left-item-btn">
|
||||
<el-button type="primary" round @click="onSetAuth">重新登录</el-button>
|
||||
<el-button type="primary" round @click="onSetAuth">
|
||||
{{ $t('layout.noAccess.loginAgain') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -46,16 +48,19 @@ export default {
|
||||
height: 100%;
|
||||
background-color: var(--bg-main-color);
|
||||
display: flex;
|
||||
|
||||
.error-flex {
|
||||
margin: auto;
|
||||
display: flex;
|
||||
height: 350px;
|
||||
width: 900px;
|
||||
|
||||
.left {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
||||
.left-item {
|
||||
.left-item-animation {
|
||||
opacity: 0;
|
||||
@@ -63,33 +68,39 @@ export default {
|
||||
animation-duration: 0.5s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
.left-item-num {
|
||||
color: #d6e0f6;
|
||||
font-size: 55px;
|
||||
}
|
||||
|
||||
.left-item-title {
|
||||
font-size: 20px;
|
||||
// color: #333333;
|
||||
margin: 15px 0 5px 0;
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
|
||||
.left-item-msg {
|
||||
color: #c0bebe;
|
||||
font-size: 12px;
|
||||
margin-bottom: 30px;
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.left-item-btn {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
flex: 1;
|
||||
opacity: 0;
|
||||
animation-name: error-img;
|
||||
animation-duration: 2s;
|
||||
animation-fill-mode: forwards;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
<div class="left">
|
||||
<div class="left-item">
|
||||
<div class="left-item-animation left-item-num">404</div>
|
||||
<div class="left-item-animation left-item-title">地址输入有误,请重新输入地址~</div>
|
||||
<div class="left-item-animation left-item-msg">您可以先检查网址,然后重新输入</div>
|
||||
<div class="left-item-animation left-item-title">{{ $t('layout.notFound.title') }}</div>
|
||||
<div class="left-item-animation left-item-msg">{{ $t('layout.notFound.msg') }}</div>
|
||||
<div class="left-item-animation left-item-btn">
|
||||
<el-button type="primary" round @click="onGoHome">返回首页</el-button>
|
||||
<el-button type="primary" round @click="onGoHome">
|
||||
{{ $t('layout.notFound.backHomepage') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -39,16 +41,19 @@ export default {
|
||||
height: 100%;
|
||||
background-color: var(--bg-main-color);
|
||||
display: flex;
|
||||
|
||||
.error-flex {
|
||||
margin: auto;
|
||||
display: flex;
|
||||
height: 350px;
|
||||
width: 900px;
|
||||
|
||||
.left {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
||||
.left-item {
|
||||
.left-item-animation {
|
||||
opacity: 0;
|
||||
@@ -56,33 +61,39 @@ export default {
|
||||
animation-duration: 0.5s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
.left-item-num {
|
||||
color: #d6e0f6;
|
||||
font-size: 55px;
|
||||
}
|
||||
|
||||
.left-item-title {
|
||||
font-size: 20px;
|
||||
// color: #333333;
|
||||
margin: 15px 0 5px 0;
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
|
||||
.left-item-msg {
|
||||
color: #c0bebe;
|
||||
font-size: 12px;
|
||||
margin-bottom: 30px;
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.left-item-btn {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
flex: 1;
|
||||
opacity: 0;
|
||||
animation-name: error-img;
|
||||
animation-duration: 2s;
|
||||
animation-fill-mode: forwards;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
</template>
|
||||
|
||||
<el-form :model="form" ref="formRef" :rules="rules" label-width="auto">
|
||||
<el-form-item prop="bizType" label="业务类型">
|
||||
<EnumSelect v-model="form.bizType" :enums="FlowBizType" placeholder="请选择业务类型" />
|
||||
<el-form-item prop="bizType" :label="$t('flow.bizType')">
|
||||
<EnumSelect v-model="form.bizType" :enums="FlowBizType" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="remark" label="备注">
|
||||
<el-input v-model.trim="form.remark" type="textarea" placeholder="备注" auto-complete="off" clearable></el-input>
|
||||
<el-form-item prop="remark" :label="$t('common.remark')">
|
||||
<el-input v-model.trim="form.remark" type="textarea" auto-complete="off" clearable></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider content-position="left">业务信息</el-divider>
|
||||
<el-divider content-position="left">{{ $t('flow.bizInfo') }}</el-divider>
|
||||
<component
|
||||
ref="bizFormRef"
|
||||
v-if="form.bizType"
|
||||
@@ -26,17 +26,18 @@
|
||||
</el-form>
|
||||
|
||||
<span v-if="flowProcdef || !state.form.procdefId">
|
||||
<el-divider content-position="left">审批节点</el-divider>
|
||||
<el-divider content-position="left">{{ $t('flow.approvalNode') }}</el-divider>
|
||||
|
||||
<ProcdefTasks v-if="flowProcdef" :procdef="flowProcdef" />
|
||||
|
||||
<el-result v-if="!state.form.procdefId" icon="error" title="不存在审批节点" sub-title="该资源无需审批操作"> </el-result>
|
||||
<el-result v-if="!state.form.procdefId" icon="error" :title="$t('flow.approvalNodeNotExist')" :sub-title="$t('flow.resourceNotExistFlow')">
|
||||
</el-result>
|
||||
</span>
|
||||
|
||||
<template #footer>
|
||||
<div>
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk" :disabled="!state.form.procdefId">确 定</el-button>
|
||||
<el-button @click="cancel()">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk" :disabled="!state.form.procdefId">{{ $t('common.confirm') }}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
@@ -52,9 +53,13 @@ import { FlowBizType } from './enums';
|
||||
import EnumSelect from '@/components/enumselect/EnumSelect.vue';
|
||||
import ProcdefTasks from './components/ProcdefTasks.vue';
|
||||
import RedisRunCmdFlowBizForm from './flowbiz/redis/RedisRunCmdFlowBizForm.vue';
|
||||
import { useI18nPleaseInput, useI18nPleaseSelect } from '@/hooks/useI18n';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const DbSqlExecFlowBizForm = defineAsyncComponent(() => import('./flowbiz/dbms/DbSqlExecFlowBizForm.vue'));
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
@@ -79,14 +84,14 @@ const rules = {
|
||||
bizType: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择流程业务类型',
|
||||
message: useI18nPleaseSelect('flow.bizType'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
remark: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入申请备注',
|
||||
message: useI18nPleaseInput('common.remark'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
@@ -125,12 +130,12 @@ const btnOk = async () => {
|
||||
await formRef.value.validate();
|
||||
await bizFormRef.value.validateBizForm();
|
||||
} catch (e: any) {
|
||||
ElMessage.error('请正确填写信息');
|
||||
ElMessage.error(t('flow.procinstFormError'));
|
||||
return false;
|
||||
}
|
||||
|
||||
await procinstStart();
|
||||
ElMessage.success('流程发起成功');
|
||||
ElMessage.success(t('flow.procinstStartSuccess'));
|
||||
emit('val-change', state.form);
|
||||
//重置表单域
|
||||
cancel();
|
||||
|
||||
@@ -6,24 +6,20 @@
|
||||
</template>
|
||||
|
||||
<el-form :model="form" ref="formRef" :rules="rules" label-width="auto">
|
||||
<el-form-item prop="name" label="名称">
|
||||
<el-input v-model.trim="form.name" placeholder="请输入流程名称" auto-complete="off" clearable></el-input>
|
||||
<el-form-item prop="name" :label="$t('common.name')">
|
||||
<el-input v-model.trim="form.name" auto-complete="off" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="defKey" label="key">
|
||||
<el-input :disabled="form.id" v-model.trim="form.defKey" placeholder="请输入流程key" auto-complete="off" clearable></el-input>
|
||||
<el-form-item prop="defKey" label="Key">
|
||||
<el-input :disabled="form.id" v-model.trim="form.defKey" auto-complete="off" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="status" label="状态">
|
||||
<el-select v-model="form.status" placeholder="请选择状态">
|
||||
<el-option v-for="item in ProcdefStatus" :key="item.value" :label="item.label" :value="item.value"> </el-option>
|
||||
</el-select>
|
||||
<el-form-item prop="status" :label="$t('common.status')">
|
||||
<EnumSelect :enums="ProcdefStatus" v-model="form.status" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="condition" label="触发条件">
|
||||
<el-form-item prop="condition" :label="$t('flow.triggeringCondition')">
|
||||
<template #label>
|
||||
触发条件
|
||||
<el-tooltip content="go template语法。若输出结果为1,则表示触发该审批流程" placement="top">
|
||||
<el-icon>
|
||||
<question-filled />
|
||||
</el-icon>
|
||||
{{ $t('flow.triggeringCondition') }}
|
||||
<el-tooltip :content="$t('flow.triggeringConditionTips')" placement="top">
|
||||
<SvgIcon name="question-filled" />
|
||||
</el-tooltip>
|
||||
</template>
|
||||
|
||||
@@ -31,42 +27,46 @@
|
||||
v-model="form.condition"
|
||||
:rows="10"
|
||||
type="textarea"
|
||||
placeholder="触发条件, 返回值=1, 则表示触发该审批流程"
|
||||
:placeholder="$t('flow.conditionPlaceholder')"
|
||||
auto-complete="off"
|
||||
clearable
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="remark" label="备注">
|
||||
<el-input v-model.trim="form.remark" placeholder="备注" auto-complete="off" clearable></el-input>
|
||||
<el-form-item prop="remark" :label="$t('common.remark')">
|
||||
<el-input v-model.trim="form.remark" auto-complete="off" clearable></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item ref="tagSelectRef" prop="codePaths" label="关联资源">
|
||||
<el-form-item ref="tagSelectRef" prop="codePaths" :label="$t('tag.relateTag')">
|
||||
<tag-tree-check height="300px" v-model="form.codePaths" :tag-type="[TagResourceTypeEnum.DbName.value, TagResourceTypeEnum.Redis.value]" />
|
||||
</el-form-item>
|
||||
|
||||
<el-divider content-position="left">审批节点</el-divider>
|
||||
<el-divider content-position="left">{{ $t('flow.approvalNode') }}</el-divider>
|
||||
|
||||
<el-table ref="taskTableRef" :data="tasks" row-key="taskKey" stripe style="width: 100%">
|
||||
<el-table-column prop="name" label="名称" min-width="100px">
|
||||
<el-table-column prop="name" min-width="100px">
|
||||
<template #header>
|
||||
<el-button class="ml0" type="primary" circle size="small" icon="Plus" @click="addTask()"> </el-button>
|
||||
<span class="ml10">节点名称</span>
|
||||
<el-tooltip content="点击指定节点可进行拖拽排序" placement="top">
|
||||
<el-icon class="ml5">
|
||||
<question-filled />
|
||||
</el-icon>
|
||||
<span class="ml10">{{ $t('flow.nodeName') }}<span class="ml5" style="color: red">*</span></span>
|
||||
<el-tooltip :content="$t('flow.nodeNameTips')" placement="top">
|
||||
<SvgIcon class="ml5" name="question-filled" />
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.name"> </el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="userId" label="审核人员" min-width="150px" show-overflow-tooltip>
|
||||
|
||||
<el-table-column prop="userId" min-width="150px" show-overflow-tooltip>
|
||||
<template #header>
|
||||
<span class="ml10">{{ $t('flow.auditor') }}<span class="ml5" style="color: red">*</span></span>
|
||||
</template>
|
||||
|
||||
<template #default="scope">
|
||||
<AccountSelectFormItem v-model="scope.row.userId" label="" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="60px">
|
||||
|
||||
<el-table-column :label="$t('common.operation')" width="110px">
|
||||
<template #default="scope">
|
||||
<el-link @click="deleteTask(scope.$index)" class="ml5" type="danger" icon="delete" plain></el-link>
|
||||
</template>
|
||||
@@ -76,8 +76,8 @@
|
||||
|
||||
<template #footer>
|
||||
<div>
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">确 定</el-button>
|
||||
<el-button @click="cancel()">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">{{ $t('common.confirm') }}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
@@ -95,6 +95,11 @@ import { randomUuid } from '../../common/utils/string';
|
||||
import { ProcdefStatus } from './enums';
|
||||
import TagTreeCheck from '../ops/component/TagTreeCheck.vue';
|
||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
||||
import EnumSelect from '@/components/enumselect/EnumSelect.vue';
|
||||
import { useI18nFormValidate, useI18nPleaseInput, useI18nSaveSuccessMsg } from '@/hooks/useI18n';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
@@ -117,14 +122,14 @@ const rules = {
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入流程名称',
|
||||
message: useI18nPleaseInput('common.name'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
defKey: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入流程key',
|
||||
message: useI18nPleaseInput('Key'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
@@ -161,23 +166,7 @@ watch(props, (newValue: any) => {
|
||||
state.tasks = tasks;
|
||||
} else {
|
||||
state.form = { status: ProcdefStatus.Enable.value } as any;
|
||||
state.form.condition = `{{/* DBMS-执行sql规则; param参数描述如下 */}}
|
||||
{{/* stmtType: select / read / insert / update / delete / ddl ; */}}
|
||||
{{ if eq .bizType "db_sql_exec_flow"}}
|
||||
{{/* 不是select和read语句时,开启流程审批 */}}
|
||||
{{ if and (ne .param.stmtType "select") (ne .param.stmtType "read") }}
|
||||
1
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* Redis-执行命令规则; param参数描述如下 */}}
|
||||
{{/* cmdType: read(读命令) / write(写命令); */}}
|
||||
{{/* cmd: get/set/hset...等 */}}
|
||||
{{ if eq .bizType "redis_run_cmd_flow"}}
|
||||
{{ if eq .param.cmdType "write" }}
|
||||
1
|
||||
{{ end }}
|
||||
{{ end }}`;
|
||||
state.form.condition = t('flow.conditionDefault');
|
||||
state.tasks = [];
|
||||
}
|
||||
});
|
||||
@@ -205,13 +194,7 @@ const deleteTask = (idx: any) => {
|
||||
};
|
||||
|
||||
const btnOk = async () => {
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
} catch (e: any) {
|
||||
ElMessage.error('请正确填写信息');
|
||||
return false;
|
||||
}
|
||||
|
||||
await useI18nFormValidate(formRef);
|
||||
const checkRes = checkTasks();
|
||||
if (checkRes.err) {
|
||||
ElMessage.error(checkRes.err);
|
||||
@@ -220,7 +203,7 @@ const btnOk = async () => {
|
||||
|
||||
state.form.tasks = JSON.stringify(checkRes.tasks);
|
||||
await saveFlowDefExec();
|
||||
ElMessage.success('操作成功');
|
||||
useI18nSaveSuccessMsg();
|
||||
emit('val-change', state.form);
|
||||
//重置表单域
|
||||
formRef.value.resetFields();
|
||||
@@ -229,14 +212,14 @@ const btnOk = async () => {
|
||||
|
||||
const checkTasks = () => {
|
||||
if (state.tasks?.length == 0) {
|
||||
return { err: '请完善审批节点任务' };
|
||||
return { err: t('flow.tasksNotEmpty') };
|
||||
}
|
||||
|
||||
const tasks = [];
|
||||
for (let i = 0; i < state.tasks.length; i++) {
|
||||
const task = { ...state.tasks[i] };
|
||||
if (!task.name || !task.userId) {
|
||||
return { err: `请完善第${i + 1}个审批节点任务信息` };
|
||||
return { err: t('flow.tasksNoComplete', { index: i + 1 }) };
|
||||
}
|
||||
// 转为字符串(方便后续万一需要调整啥的)
|
||||
task.userId = `${task.userId}`;
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
:columns="columns"
|
||||
>
|
||||
<template #tableHeader>
|
||||
<el-button v-auth="perms.save" type="primary" icon="plus" @click="editFlowDef(false)">添加</el-button>
|
||||
<el-button v-auth="perms.del" :disabled="state.selectionData.length < 1" @click="deleteProcdef()" type="danger" icon="delete">删除</el-button>
|
||||
<el-button v-auth="perms.save" type="primary" icon="plus" @click="editFlowDef(false)">{{ $t('common.create') }}</el-button>
|
||||
<el-button v-auth="perms.del" :disabled="state.selectionData.length < 1" @click="deleteProcdef()" type="danger" icon="delete">
|
||||
{{ $t('common.delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<template #tasks="{ data }">
|
||||
@@ -23,7 +25,7 @@
|
||||
</template>
|
||||
|
||||
<template #action="{ data }">
|
||||
<el-button link v-if="actionBtns[perms.save]" @click="editFlowDef(data)" type="primary">编辑</el-button>
|
||||
<el-button link v-if="actionBtns[perms.save]" @click="editFlowDef(data)" type="primary">{{ $t('common.edit') }}</el-button>
|
||||
</template>
|
||||
</page-table>
|
||||
|
||||
@@ -38,7 +40,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, onMounted, Ref } from 'vue';
|
||||
import { procdefApi } from './api';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||
import { TableColumn } from '@/components/pagetable';
|
||||
import { hasPerms } from '@/components/auth/auth';
|
||||
@@ -47,27 +48,31 @@ import ProcdefEdit from './ProcdefEdit.vue';
|
||||
import ProcdefTasks from './components/ProcdefTasks.vue';
|
||||
import { ProcdefStatus } from './enums';
|
||||
import TagCodePath from '../ops/component/TagCodePath.vue';
|
||||
import { useI18nCreateTitle, useI18nDeleteConfirm, useI18nDeleteSuccessMsg, useI18nEditTitle } from '@/hooks/useI18n';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const perms = {
|
||||
save: 'flow:procdef:save',
|
||||
del: 'flow:procdef:del',
|
||||
};
|
||||
|
||||
const searchItems = [SearchItem.input('name', '名称'), SearchItem.input('defKey', 'key')];
|
||||
const searchItems = [SearchItem.input('name', 'common.name'), SearchItem.input('defKey', 'key')];
|
||||
const columns = [
|
||||
TableColumn.new('name', '名称'),
|
||||
TableColumn.new('defKey', 'key'),
|
||||
TableColumn.new('status', '状态').typeTag(ProcdefStatus),
|
||||
TableColumn.new('remark', '备注'),
|
||||
TableColumn.new('tasks', '审批节点').isSlot().alignCenter().setMinWidth(60),
|
||||
TableColumn.new('codePaths', '关联资源').isSlot().setMinWidth('250px'),
|
||||
TableColumn.new('creator', '创建账号'),
|
||||
TableColumn.new('createTime', '创建时间').isTime(),
|
||||
TableColumn.new('name', 'common.name'),
|
||||
TableColumn.new('defKey', 'Key'),
|
||||
TableColumn.new('status', 'common.status').typeTag(ProcdefStatus),
|
||||
TableColumn.new('remark', 'common.remark'),
|
||||
TableColumn.new('tasks', 'flow.approvalNode').isSlot().alignCenter().setMinWidth(60),
|
||||
TableColumn.new('codePaths', 'tag.relateTag').isSlot().setMinWidth('250px'),
|
||||
TableColumn.new('creator', 'common.creator'),
|
||||
TableColumn.new('createTime', 'common.createTime').isTime(),
|
||||
];
|
||||
|
||||
// 该用户拥有的的操作列按钮权限
|
||||
const actionBtns: any = hasPerms([perms.save, perms.del]);
|
||||
const actionColumn = TableColumn.new('action', '操作').isSlot().fixedRight().setMinWidth(160).noShowOverflowTooltip().alignCenter();
|
||||
const actionColumn = TableColumn.new('action', 'common.operation').isSlot().fixedRight().setMinWidth(160).noShowOverflowTooltip().alignCenter();
|
||||
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
const state = reactive({
|
||||
@@ -84,7 +89,7 @@ const state = reactive({
|
||||
pageSize: 0,
|
||||
},
|
||||
flowDefEditor: {
|
||||
title: '新建流程定义',
|
||||
title: '',
|
||||
visible: false,
|
||||
data: null as any,
|
||||
},
|
||||
@@ -109,17 +114,17 @@ const search = async () => {
|
||||
|
||||
const showProcdefTasks = (procdef: any) => {
|
||||
state.flowTasksDialog.tasks = procdef.tasks;
|
||||
state.flowTasksDialog.title = procdef.name + '-审批节点';
|
||||
state.flowTasksDialog.title = procdef.name + ' - ' + t('flow.approvalNode');
|
||||
state.flowTasksDialog.visible = true;
|
||||
};
|
||||
|
||||
const editFlowDef = (data: any) => {
|
||||
if (!data) {
|
||||
state.flowDefEditor.data = null;
|
||||
state.flowDefEditor.title = '新建流程定义';
|
||||
state.flowDefEditor.title = useI18nCreateTitle('flow.procdef');
|
||||
} else {
|
||||
state.flowDefEditor.data = data;
|
||||
state.flowDefEditor.title = '编辑流程定义';
|
||||
state.flowDefEditor.title = useI18nEditTitle('flow.procdef');
|
||||
}
|
||||
state.flowDefEditor.visible = true;
|
||||
};
|
||||
@@ -131,13 +136,9 @@ const valChange = () => {
|
||||
|
||||
const deleteProcdef = async () => {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定删除【${state.selectionData.map((x: any) => x.name).join(', ')}】的流程定义?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
await useI18nDeleteConfirm(state.selectionData.map((x: any) => x.name).join(', '));
|
||||
await procdefApi.del.request({ id: state.selectionData.map((x: any) => x.id).join(',') });
|
||||
ElMessage.success('删除成功');
|
||||
useI18nDeleteSuccessMsg();
|
||||
search();
|
||||
} catch (err) {
|
||||
//
|
||||
|
||||
@@ -8,29 +8,28 @@
|
||||
<div>
|
||||
<el-divider content-position="left">流程信息</el-divider>
|
||||
<el-descriptions :column="3" border>
|
||||
<el-descriptions-item label="流程名">{{ procinst.procdefName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="业务">
|
||||
<el-descriptions-item :span="1" label="流程名">{{ procinst.procdefName }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="1" label="业务">
|
||||
<enum-tag :enums="FlowBizType" :value="procinst.bizType"></enum-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="发起人">
|
||||
<el-descriptions-item :span="1" label="发起人">
|
||||
<AccountInfo :account-id="procinst.creatorId" :username="procinst.creator" />
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="流程状态">
|
||||
<el-descriptions-item :span="1" label="流程状态">
|
||||
<enum-tag :enums="ProcinstStatus" :value="procinst.status"></enum-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="业务状态">
|
||||
<el-descriptions-item :span="1" label="业务状态">
|
||||
<enum-tag :enums="ProcinstBizStatus" :value="procinst.bizStatus"></enum-tag>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="发起时间">{{ formatDate(procinst.createTime) }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="1" label="发起时间">{{ formatDate(procinst.createTime) }}</el-descriptions-item>
|
||||
|
||||
<div v-if="procinst.duration">
|
||||
<el-descriptions-item label="结束时间">{{ formatDate(procinst.endTime) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="持续时间">{{ formatTime(procinst.duration) }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="1.5" label="结束时间">{{ formatDate(procinst.endTime) }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="1.5" label="持续时间">{{ formatTime(procinst.duration) }}</el-descriptions-item>
|
||||
</div>
|
||||
|
||||
<el-descriptions-item label="备注">
|
||||
<el-descriptions-item :span="3" label="备注">
|
||||
{{ procinst.remark }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
@@ -9,20 +9,20 @@
|
||||
:columns="columns"
|
||||
>
|
||||
<template #tableHeader>
|
||||
<el-button type="primary" icon="plus" @click="startProcInst()">发起流程</el-button>
|
||||
<el-button type="primary" icon="plus" @click="startProcInst()">{{ $t('flow.startProcess') }}</el-button>
|
||||
</template>
|
||||
|
||||
<template #action="{ data }">
|
||||
<el-button link @click="showProcinst(data)" type="primary">查看</el-button>
|
||||
<el-button link @click="showProcinst(data)" type="primary">{{ $t('common.detail') }}</el-button>
|
||||
|
||||
<el-popconfirm
|
||||
v-if="data.status == ProcinstStatus.Active.value || data.status == ProcinstStatus.Suspended.value"
|
||||
title="确认取消该流程?"
|
||||
:title="$t('flow.cancelProcessConfirm')"
|
||||
width="160"
|
||||
@confirm="procinstCancel(data)"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button link type="warning">取消</el-button>
|
||||
<el-button link type="warning">{{ $t('common.cancel') }}</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
@@ -49,35 +49,37 @@ import { TableColumn } from '@/components/pagetable';
|
||||
import { SearchItem } from '@/components/SearchForm';
|
||||
import ProcinstDetail from './ProcinstDetail.vue';
|
||||
import { FlowBizType, ProcinstBizStatus, ProcinstStatus } from './enums';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { formatTime } from '@/common/utils/format';
|
||||
import ProcInstEdit from './ProcInstEdit.vue';
|
||||
import { useI18nDetailTitle, useI18nOperateSuccessMsg } from '@/hooks/useI18n';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const searchItems = [
|
||||
SearchItem.select('status', '流程状态').withEnum(ProcinstStatus),
|
||||
SearchItem.select('bizType', '业务类型').withEnum(FlowBizType),
|
||||
SearchItem.input('bizKey', '业务key'),
|
||||
SearchItem.select('status', 'common.status').withEnum(ProcinstStatus),
|
||||
SearchItem.select('bizType', 'flow.bizType').withEnum(FlowBizType),
|
||||
SearchItem.input('bizKey', 'flow.bizKey'),
|
||||
];
|
||||
|
||||
const columns = [
|
||||
TableColumn.new('bizType', '业务').typeTag(FlowBizType),
|
||||
TableColumn.new('remark', '备注'),
|
||||
TableColumn.new('creator', '发起人'),
|
||||
TableColumn.new('bizKey', '业务key'),
|
||||
TableColumn.new('procdefName', '流程名'),
|
||||
TableColumn.new('status', '流程状态').typeTag(ProcinstStatus),
|
||||
TableColumn.new('bizStatus', '业务状态').typeTag(ProcinstBizStatus),
|
||||
TableColumn.new('createTime', '发起时间').isTime(),
|
||||
TableColumn.new('endTime', '结束时间').isTime(),
|
||||
TableColumn.new('duration', '持续时间').setFormatFunc((data: any, prop: string) => {
|
||||
TableColumn.new('bizType', 'flow.bizType').typeTag(FlowBizType),
|
||||
TableColumn.new('remark', 'common.remark'),
|
||||
TableColumn.new('creator', 'flow.initiator'),
|
||||
TableColumn.new('bizKey', 'flow.bizKey'),
|
||||
TableColumn.new('procdefName', 'flow.procdefName'),
|
||||
TableColumn.new('status', 'common.status').setAddWidth(8).typeTag(ProcinstStatus),
|
||||
TableColumn.new('bizStatus', 'flow.bizStatus').typeTag(ProcinstBizStatus),
|
||||
TableColumn.new('createTime', 'flow.startingTime').isTime(),
|
||||
TableColumn.new('endTime', 'flow.endTime').isTime(),
|
||||
TableColumn.new('duration', 'flow.duration').setFormatFunc((data: any, prop: string) => {
|
||||
const duration = data[prop];
|
||||
if (!duration) {
|
||||
return '';
|
||||
}
|
||||
return formatTime(duration);
|
||||
}),
|
||||
// TableColumn.new('bizHandleRes', '业务处理结果'),
|
||||
TableColumn.new('action', '操作').isSlot().fixedRight().setMinWidth(160).noShowOverflowTooltip().alignCenter(),
|
||||
TableColumn.new('action', 'common.operation').isSlot().fixedRight().setMinWidth(160).noShowOverflowTooltip().alignCenter(),
|
||||
];
|
||||
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
@@ -96,13 +98,13 @@ const state = reactive({
|
||||
pageSize: 0,
|
||||
},
|
||||
procinstDetail: {
|
||||
title: '查看流程',
|
||||
title: '',
|
||||
visible: false,
|
||||
procinstId: 0,
|
||||
instTaskId: 0,
|
||||
},
|
||||
procinstEdit: {
|
||||
title: '发起流程',
|
||||
title: '',
|
||||
visible: false,
|
||||
},
|
||||
});
|
||||
@@ -115,17 +117,18 @@ const search = async () => {
|
||||
|
||||
const procinstCancel = async (data: any) => {
|
||||
await procinstApi.cancel.request({ id: data.id });
|
||||
ElMessage.success('操作成功');
|
||||
useI18nOperateSuccessMsg();
|
||||
search();
|
||||
};
|
||||
|
||||
const showProcinst = (data: any) => {
|
||||
state.procinstDetail.procinstId = data.id;
|
||||
state.procinstDetail.title = '流程查看';
|
||||
state.procinstDetail.title = useI18nDetailTitle('flow.proc');
|
||||
state.procinstDetail.visible = true;
|
||||
};
|
||||
|
||||
const startProcInst = () => {
|
||||
state.procinstEdit.title = t('flow.startProcess');
|
||||
state.procinstEdit.visible = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
</template>
|
||||
|
||||
<template #action="{ data }">
|
||||
<el-button link @click="showProcinst(data, false)" type="primary">查看</el-button>
|
||||
<el-button v-if="data.status == ProcinstTaskStatus.Process.value" link @click="showProcinst(data, true)" type="primary">审核</el-button>
|
||||
<el-button link @click="showProcinst(data, false)" type="primary">{{ $t('common.detail') }}</el-button>
|
||||
<el-button v-if="data.status == ProcinstTaskStatus.Process.value" link @click="showProcinst(data, true)" type="primary">
|
||||
{{ $t('flow.audit') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</page-table>
|
||||
|
||||
@@ -38,28 +40,35 @@ import { SearchItem } from '@/components/SearchForm';
|
||||
import ProcinstDetail from './ProcinstDetail.vue';
|
||||
import { FlowBizType, ProcinstStatus, ProcinstTaskStatus } from './enums';
|
||||
import { formatTime } from '@/common/utils/format';
|
||||
import { useI18nDetailTitle } from '@/hooks/useI18n';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const searchItems = [SearchItem.select('status', '任务状态').withEnum(ProcinstTaskStatus), SearchItem.select('bizType', '业务类型').withEnum(FlowBizType)];
|
||||
const { t } = useI18n();
|
||||
|
||||
const searchItems = [
|
||||
SearchItem.select('status', 'common.status').withEnum(ProcinstTaskStatus),
|
||||
SearchItem.select('bizType', 'flow.bizType').withEnum(FlowBizType),
|
||||
];
|
||||
const columns = [
|
||||
TableColumn.new('procinst.bizType', '业务').typeTag(FlowBizType),
|
||||
TableColumn.new('procinst.remark', '备注'),
|
||||
TableColumn.new('procinst.creator', '发起人'),
|
||||
TableColumn.new('procinst.status', '流程状态').typeTag(ProcinstStatus),
|
||||
TableColumn.new('status', '任务状态').typeTag(ProcinstTaskStatus),
|
||||
TableColumn.new('procinst.bizKey', '业务key'),
|
||||
TableColumn.new('procinst.procdefName', '流程名'),
|
||||
TableColumn.new('taskName', '当前节点'),
|
||||
TableColumn.new('procinst.createTime', '发起时间').isTime(),
|
||||
TableColumn.new('createTime', '开始时间').isTime(),
|
||||
TableColumn.new('endTime', '结束时间').isTime(),
|
||||
TableColumn.new('duration', '持续时间').setFormatFunc((data: any, prop: string) => {
|
||||
TableColumn.new('procinst.bizType', 'flow.bizType').typeTag(FlowBizType),
|
||||
TableColumn.new('procinst.remark', 'common.remark'),
|
||||
TableColumn.new('procinst.creator', 'flow.initiator'),
|
||||
TableColumn.new('procinst.status', 'flow.procinstStatus').typeTag(ProcinstStatus),
|
||||
TableColumn.new('status', 'flow.taskStatus').typeTag(ProcinstTaskStatus),
|
||||
TableColumn.new('procinst.bizKey', 'flow.bizKey'),
|
||||
TableColumn.new('procinst.procdefName', 'flow.procdefName'),
|
||||
TableColumn.new('taskName', 'flow.taskName'),
|
||||
TableColumn.new('procinst.createTime', 'flow.startingTime').isTime(),
|
||||
TableColumn.new('createTime', 'flow.taskBeginTime').isTime(),
|
||||
TableColumn.new('endTime', 'flow.endTime').isTime(),
|
||||
TableColumn.new('duration', 'flow.duration').setFormatFunc((data: any, prop: string) => {
|
||||
const duration = data[prop];
|
||||
if (!duration) {
|
||||
return '';
|
||||
}
|
||||
return formatTime(duration);
|
||||
}),
|
||||
TableColumn.new('action', '操作').isSlot().fixedRight().setMinWidth(160).noShowOverflowTooltip().alignCenter(),
|
||||
TableColumn.new('action', 'common.operation').isSlot().fixedRight().setMinWidth(160).noShowOverflowTooltip().alignCenter(),
|
||||
];
|
||||
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
@@ -78,7 +87,7 @@ const state = reactive({
|
||||
pageSize: 0,
|
||||
},
|
||||
procinstDetail: {
|
||||
title: '查看流程',
|
||||
title: '',
|
||||
visible: false,
|
||||
procinstId: 0,
|
||||
instTaskId: 0,
|
||||
@@ -95,10 +104,10 @@ const showProcinst = (data: any, audit: boolean) => {
|
||||
state.procinstDetail.procinstId = data.procinstId;
|
||||
if (!audit) {
|
||||
state.procinstDetail.instTaskId = 0;
|
||||
state.procinstDetail.title = '流程查看';
|
||||
state.procinstDetail.title = useI18nDetailTitle('flow.proc');
|
||||
} else {
|
||||
state.procinstDetail.instTaskId = data.id;
|
||||
state.procinstDetail.title = '流程审批';
|
||||
state.procinstDetail.title = t('flow.flowAudit');
|
||||
}
|
||||
state.procinstDetail.visible = true;
|
||||
};
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import { EnumValue } from '@/common/Enum';
|
||||
|
||||
export const ProcdefStatus = {
|
||||
Enable: EnumValue.of(1, '启用').setTagType('success'),
|
||||
Disable: EnumValue.of(-1, '禁用').setTagType('warning'),
|
||||
Enable: EnumValue.of(1, 'flow.enable').setTagType('success'),
|
||||
Disable: EnumValue.of(-1, 'flow.disable').setTagType('warning'),
|
||||
};
|
||||
|
||||
export const ProcinstStatus = {
|
||||
Active: EnumValue.of(1, '执行中').setTagType('primary'),
|
||||
Completed: EnumValue.of(2, '完成').setTagType('success'),
|
||||
Suspended: EnumValue.of(-1, '挂起').setTagType('warning'),
|
||||
Terminated: EnumValue.of(-2, '终止').setTagType('danger'),
|
||||
Cancelled: EnumValue.of(-3, '取消').setTagType('warning'),
|
||||
Active: EnumValue.of(1, 'flow.active').setTagType('primary'),
|
||||
Completed: EnumValue.of(2, 'flow.completed').setTagType('success'),
|
||||
Suspended: EnumValue.of(-1, 'flow.suspended').setTagType('warning'),
|
||||
Terminated: EnumValue.of(-2, 'flow.terminated').setTagType('danger'),
|
||||
Cancelled: EnumValue.of(-3, 'flow.cancelled').setTagType('warning'),
|
||||
};
|
||||
|
||||
export const ProcinstBizStatus = {
|
||||
Wait: EnumValue.of(1, '待处理').setTagType('primary'),
|
||||
Success: EnumValue.of(2, '处理成功').setTagType('success'),
|
||||
Fail: EnumValue.of(-2, '处理失败').setTagType('danger'),
|
||||
No: EnumValue.of(-1, '不处理').setTagType('warning'),
|
||||
Wait: EnumValue.of(1, 'flow.waitHandle').setTagType('primary'),
|
||||
Success: EnumValue.of(2, 'flow.handleSuccess').setTagType('success'),
|
||||
Fail: EnumValue.of(-2, 'flow.handleFail').setTagType('danger'),
|
||||
No: EnumValue.of(-1, 'flow.noHandle').setTagType('warning'),
|
||||
};
|
||||
|
||||
export const ProcinstTaskStatus = {
|
||||
Process: EnumValue.of(1, '待处理').setTagType('primary'),
|
||||
Pass: EnumValue.of(2, '通过').setTagType('success'),
|
||||
Reject: EnumValue.of(-1, '拒绝').setTagType('danger'),
|
||||
Back: EnumValue.of(-2, '驳回').setTagType('warning'),
|
||||
Canceled: EnumValue.of(-3, '取消').setTagType('warning'),
|
||||
Process: EnumValue.of(1, 'flow.waitProcess').setTagType('primary'),
|
||||
Pass: EnumValue.of(2, 'flow.pass').setTagType('success'),
|
||||
Reject: EnumValue.of(-1, 'flow.reject').setTagType('danger'),
|
||||
Back: EnumValue.of(-2, 'flow.back').setTagType('warning'),
|
||||
Canceled: EnumValue.of(-3, 'flow.canceled').setTagType('warning'),
|
||||
};
|
||||
|
||||
export const FlowBizType = {
|
||||
DbSqlExec: EnumValue.of('db_sql_exec_flow', 'DBMS-执行SQL').setTagType('warning'),
|
||||
RedisRunWriteCmd: EnumValue.of('redis_run_cmd_flow', 'Redis-执行命令').setTagType('danger'),
|
||||
DbSqlExec: EnumValue.of('db_sql_exec_flow', 'flow.dbSqlExec').setTagType('warning'),
|
||||
RedisRunWriteCmd: EnumValue.of('redis_run_cmd_flow', 'flow.redisRunCmd').setTagType('danger'),
|
||||
};
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-descriptions :column="3" border>
|
||||
<el-descriptions-item :span="3" label="标签"><TagCodePath :path="db.codePaths" /></el-descriptions-item>
|
||||
<el-descriptions-item :span="3" :label="$t('common.tag')"><TagCodePath :path="db.codePaths" /></el-descriptions-item>
|
||||
|
||||
<el-descriptions-item :span="1" label="名称">{{ db?.name }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="1" label="主机">
|
||||
<el-descriptions-item :span="1" :label="$t('common.name')">{{ db?.name }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="1" label="Host">
|
||||
<SvgIcon :name="getDbDialect(db?.type).getInfo().icon" :size="20" />
|
||||
{{ `${db?.host}:${db?.port}` }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item :span="1" label="数据库">{{ dbName }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="1" :label="$t('tag.db')">{{ dbName }}</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="执行SQL">
|
||||
<el-descriptions-item :label="$t('flow.runSql')">
|
||||
<monaco-editor height="300px" language="sql" v-model="sql" :options="{ readOnly: true }" />
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<div v-if="runRes && runRes.length > 0">
|
||||
<el-divider content-position="left">处理结果</el-divider>
|
||||
<el-divider content-position="left">{{ $t('flow.handleResult') }}</el-divider>
|
||||
<el-table :data="runRes" :max-height="400">
|
||||
<el-table-column prop="sql" label="SQL" show-overflow-tooltip />
|
||||
|
||||
<el-table-column prop="res" label="执行结果" :min-width="30" show-overflow-tooltip>
|
||||
<el-table-column prop="res" :label="$t('flow.runResult')" :min-width="30" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-popover placement="top" :width="400" trigger="hover">
|
||||
<template #reference>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<el-form :model="bizForm" ref="formRef" :rules="rules" label-width="auto">
|
||||
<el-form-item prop="dbId" label="数据库" required>
|
||||
<el-form-item prop="dbId" :label="$t('tag.db')" required>
|
||||
<db-select-tree
|
||||
placeholder="请选择数据库"
|
||||
:placeholder="$t('flow.selectDbPlaceholder')"
|
||||
v-model:db-id="bizForm.dbId"
|
||||
v-model:db-name="bizForm.dbName"
|
||||
v-model:db-type="dbType"
|
||||
@@ -24,19 +24,23 @@ import DbSelectTree from '@/views/ops/db/component/DbSelectTree.vue';
|
||||
import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
|
||||
import { registerDbCompletionItemProvider } from '@/views/ops/db/db';
|
||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useI18nPleaseInput } from '@/hooks/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const rules = {
|
||||
dbId: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择数据库',
|
||||
message: t('flow.selectDbPlaceholder'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
sql: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入执行SQL',
|
||||
message: useI18nPleaseInput('flow.runSql'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-descriptions :column="3" border>
|
||||
<el-descriptions-item :span="3" label="标签"><TagCodePath :path="redis.codePaths" /></el-descriptions-item>
|
||||
<el-descriptions-item :span="3" :label="$t('common.tag')"><TagCodePath :path="redis.codePaths" /></el-descriptions-item>
|
||||
|
||||
<el-descriptions-item :span="2" label="编号">{{ redis?.code }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="1" label="名称">{{ redis?.name }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="2" :label="$t('common.code')">{{ redis?.code }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="1" :label="$t('common.name')">{{ redis?.name }}</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item :span="1" label="主机">{{ `${redis?.host}` }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="1" label="库">{{ state.db }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="1" label="Host">{{ `${redis?.host}` }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="1" label="DB">{{ state.db }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="1" label="mode">
|
||||
{{ redis.mode }}
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item :span="3" label="执行Cmd">
|
||||
<el-descriptions-item :span="3" :label="$t('flow.runCmd')">
|
||||
<el-input type="textarea" disabled v-model="cmd" rows="5" />
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<div v-if="runRes && runRes.length > 0">
|
||||
<el-divider content-position="left">处理结果</el-divider>
|
||||
<el-divider content-position="left">{{ $t('flow.handleResult') }}</el-divider>
|
||||
<el-table :data="runRes" :max-height="400">
|
||||
<el-table-column prop="cmd" label="命令" show-overflow-tooltip />
|
||||
<el-table-column prop="res" label="执行结果" :min-width="50" show-overflow-tooltip> </el-table-column>
|
||||
<el-table-column prop="cmd" label="Cmd" show-overflow-tooltip />
|
||||
<el-table-column prop="res" :label="$t('flow.runResult')" :min-width="50" show-overflow-tooltip> </el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<template>
|
||||
<el-form :model="bizForm" ref="formRef" :rules="rules" label-width="auto">
|
||||
<el-form-item prop="id" label="库" required>
|
||||
<el-form-item prop="id" label="DB" required>
|
||||
<TagTreeResourceSelect
|
||||
v-bind="$attrs"
|
||||
v-model="selectRedis"
|
||||
@change="changeRedis"
|
||||
:resource-type="TagResourceTypeEnum.Redis.value"
|
||||
:tag-path-node-type="NodeTypeTagPath"
|
||||
placeholder="请选择Redis实例与库"
|
||||
:placeholder="$t('flow.selectRedisPlaceholder')"
|
||||
>
|
||||
</TagTreeResourceSelect>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="cmd" label="CMD" required>
|
||||
<el-input type="textarea" v-model="bizForm.cmd" placeholder="如: SET 'key' 'value'; 多条命令;分割" :rows="5" />
|
||||
<el-input type="textarea" v-model="bizForm.cmd" :placeholder="$t('flow.cmdPlaceholder')" :rows="5" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
@@ -25,19 +25,23 @@ import TagTreeResourceSelect from '@/views/ops/component/TagTreeResourceSelect.v
|
||||
import { NodeType, TagTreeNode } from '@/views/ops/component/tag';
|
||||
import { redisApi } from '@/views/ops/redis/api';
|
||||
import { sleep } from '@/common/utils/loading';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useI18nPleaseInput } from '@/hooks/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const rules = {
|
||||
id: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择Redis实例',
|
||||
message: t('flow.selectRedisPlaceholder'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
cmd: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入执行CMD',
|
||||
message: useI18nPleaseInput('flow.runCmd'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<el-row :gutter="15">
|
||||
<!-- 个人信息 -->
|
||||
<el-col :xs="24" :sm="16">
|
||||
<el-card shadow="hover" header="个人信息">
|
||||
<el-card shadow="hover" :header="$t('home.personalInfo')">
|
||||
<div class="personal-user">
|
||||
<div class="personal-user-left">
|
||||
<el-upload
|
||||
@@ -20,17 +20,17 @@
|
||||
</div>
|
||||
<div class="personal-user-right">
|
||||
<el-row>
|
||||
<el-col :span="24" class="personal-title mb18"
|
||||
>{{ currentTime }},{{ userInfo.name }},生活变的再糟糕,也不妨碍我变得更好!
|
||||
<el-col :span="24" class="personal-title mb18">
|
||||
{{ $t('home.welcomeMsg', { name: userInfo.name }) }}
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-row>
|
||||
<el-col :xs="24" :sm="12" class="personal-item mb6">
|
||||
<div class="personal-item-label">用户名:</div>
|
||||
<div class="personal-item-label">{{ $t('common.username') }}:</div>
|
||||
<div class="personal-item-value">{{ userInfo.username }}</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" class="personal-item mb6">
|
||||
<div class="personal-item-label">角色:</div>
|
||||
<div class="personal-item-label">{{ $t('common.role') }}:</div>
|
||||
<div class="personal-item-value">{{ roleInfo }}</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -38,11 +38,11 @@
|
||||
<el-col :span="24">
|
||||
<el-row>
|
||||
<el-col :xs="24" :sm="12" class="personal-item mb6">
|
||||
<div class="personal-item-label">上次登录IP:</div>
|
||||
<div class="personal-item-label">{{ $t('home.lastLoginIp') }}:</div>
|
||||
<div class="personal-item-value">{{ userInfo.lastLoginIp }}</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" class="personal-item mb6">
|
||||
<div class="personal-item-label">上次登录时间:</div>
|
||||
<div class="personal-item-label">{{ $t('home.lastLoginTime') }}:</div>
|
||||
<div class="personal-item-value">{{ formatDate(userInfo.lastLoginTime) }}</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -57,13 +57,13 @@
|
||||
<el-col :xs="24" :sm="8" class="pl15 personal-info">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<span>消息通知</span>
|
||||
<span @click="showMsgs" class="personal-info-more">更多</span>
|
||||
<span>{{ $t('home.msgNotify') }}</span>
|
||||
<span @click="showMsgs" class="personal-info-more">{{ $t('common.more') }}</span>
|
||||
</template>
|
||||
<div class="personal-info-box">
|
||||
<ul class="personal-info-ul">
|
||||
<li v-for="(v, k) in state.msgs as any" :key="k" class="personal-info-li">
|
||||
<a class="personal-info-li-title">{{ `[${getMsgTypeDesc(v.type)}] ${v.msg}` }}</a>
|
||||
<a class="personal-info-li-title">{{ `[${$t(EnumValue.getLabelByValue(MsgTypeEnum, v.type))}] ${v.msg}` }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -89,7 +89,13 @@
|
||||
</template>
|
||||
<el-row>
|
||||
<el-col :sm="24">
|
||||
<el-table :data="state.machine.opLogs" :height="state.resourceOpTableHeight" stripe size="small" empty-text="暂无操作记录">
|
||||
<el-table
|
||||
:data="state.machine.opLogs"
|
||||
:height="state.resourceOpTableHeight"
|
||||
stripe
|
||||
size="small"
|
||||
:empty-text="$t('home.noOpRecord')"
|
||||
>
|
||||
<el-table-column prop="createTime" show-overflow-tooltip width="135">
|
||||
<template #default="scope">
|
||||
{{ formatDate(scope.row.createTime) }}
|
||||
@@ -123,7 +129,7 @@
|
||||
</template>
|
||||
<el-row>
|
||||
<el-col :sm="24">
|
||||
<el-table :data="state.db.opLogs" :height="state.resourceOpTableHeight" stripe size="small" empty-text="暂无操作记录">
|
||||
<el-table :data="state.db.opLogs" :height="state.resourceOpTableHeight" stripe size="small" :empty-text="$t('home.noOpRecord')">
|
||||
<el-table-column prop="createTime" show-overflow-tooltip min-width="135">
|
||||
<template #default="scope">
|
||||
{{ formatDate(scope.row.createTime) }}
|
||||
@@ -164,7 +170,7 @@
|
||||
</template>
|
||||
<el-row>
|
||||
<el-col :sm="24">
|
||||
<el-table :data="state.redis.opLogs" :height="state.resourceOpTableHeight" stripe size="small" empty-text="暂无操作记录">
|
||||
<el-table :data="state.redis.opLogs" :height="state.resourceOpTableHeight" stripe size="small" :empty-text="$t('home.noOpRecord')">
|
||||
<el-table-column prop="createTime" show-overflow-tooltip min-width="135">
|
||||
<template #default="scope">
|
||||
{{ formatDate(scope.row.createTime) }}
|
||||
@@ -203,7 +209,7 @@
|
||||
</template>
|
||||
<el-row>
|
||||
<el-col :sm="24">
|
||||
<el-table :data="state.mongo.opLogs" :height="state.resourceOpTableHeight" stripe size="small" empty-text="暂无操作记录">
|
||||
<el-table :data="state.mongo.opLogs" :height="state.resourceOpTableHeight" stripe size="small" :empty-text="$t('home.noOpRecord')">
|
||||
<el-table-column prop="createTime" show-overflow-tooltip min-width="135">
|
||||
<template #default="scope">
|
||||
{{ formatDate(scope.row.createTime) }}
|
||||
@@ -226,15 +232,15 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-dialog width="900px" title="消息" v-model="msgDialog.visible">
|
||||
<el-dialog width="900px" :title="$t('common.msg')" v-model="msgDialog.visible">
|
||||
<el-table border :data="msgDialog.msgs.list" size="small">
|
||||
<el-table-column property="type" label="类型" width="60">
|
||||
<el-table-column property="type" :label="$t('common.type')" width="60">
|
||||
<template #default="scope">
|
||||
{{ getMsgTypeDesc(scope.row.type) }}
|
||||
{{ $t(EnumValue.getLabelByValue(MsgTypeEnum, scope.row.type)) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column property="msg" label="消息"></el-table-column>
|
||||
<el-table-column property="createTime" label="时间" width="150">
|
||||
<el-table-column property="msg" :label="$t('common.msg')"></el-table-column>
|
||||
<el-table-column property="createTime" :label="$t('common.time')" width="150">
|
||||
<template #default="scope">
|
||||
{{ formatDate(scope.row.createTime) }}
|
||||
</template>
|
||||
@@ -274,6 +280,8 @@ import { getAllTagInfoByCodePaths } from '../ops/component/tag';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { getFileUrl, getUploadFileUrl } from '@/common/request';
|
||||
import { saveUser } from '@/common/utils/storage';
|
||||
import EnumValue from '../../common/Enum';
|
||||
import { MsgTypeEnum } from './enums';
|
||||
|
||||
const router = useRouter();
|
||||
const { userInfo } = storeToRefs(useUserInfo());
|
||||
@@ -352,15 +360,6 @@ const searchMsg = async () => {
|
||||
state.msgDialog.msgs = await getMsgs();
|
||||
};
|
||||
|
||||
const getMsgTypeDesc = (type: number) => {
|
||||
if (type == 1) {
|
||||
return '登录';
|
||||
}
|
||||
if (type == 2) {
|
||||
return '通知';
|
||||
}
|
||||
};
|
||||
|
||||
const getAccountInfo = async () => {
|
||||
state.accountInfo = await personApi.accountInfo.request();
|
||||
};
|
||||
|
||||
6
frontend/src/views/home/enums.ts
Normal file
6
frontend/src/views/home/enums.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { EnumValue } from '@/common/Enum';
|
||||
|
||||
export const MsgTypeEnum = {
|
||||
Login: EnumValue.of(1, 'home.msgTypeLogin'),
|
||||
Notify: EnumValue.of(2, 'home.msgTypeNotify'),
|
||||
};
|
||||
@@ -2,12 +2,20 @@
|
||||
<div>
|
||||
<el-form ref="loginFormRef" :model="loginForm" :rules="rules" class="login-content-form" size="large">
|
||||
<el-form-item prop="username">
|
||||
<el-input type="text" placeholder="请输入用户名" prefix-icon="user" v-model="loginForm.username" clearable autocomplete="off"> </el-input>
|
||||
<el-input
|
||||
type="text"
|
||||
:placeholder="$t('login.inputUsernamePlaceholder')"
|
||||
prefix-icon="user"
|
||||
v-model="loginForm.username"
|
||||
clearable
|
||||
autocomplete="off"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
type="password"
|
||||
placeholder="请输入密码"
|
||||
:placeholder="$t('login.inputPasswordPlaceholder')"
|
||||
prefix-icon="lock"
|
||||
v-model="loginForm.password"
|
||||
autocomplete="off"
|
||||
@@ -22,7 +30,7 @@
|
||||
<el-input
|
||||
type="text"
|
||||
maxlength="6"
|
||||
placeholder="请输入验证码"
|
||||
:placeholder="$t('login.inputCaptchaPlaceholder')"
|
||||
prefix-icon="position"
|
||||
v-model="loginForm.captcha"
|
||||
clearable
|
||||
@@ -38,30 +46,35 @@
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="ldapEnabled" prop="ldapLogin">
|
||||
<el-checkbox v-model="loginForm.ldapLogin" label="LDAP 登录" size="small" />
|
||||
<el-checkbox v-model="loginForm.ldapLogin" :label="$t('login.ldapLogin')" size="small" />
|
||||
</el-form-item>
|
||||
<span v-if="showLoginFailTips" style="color: #f56c6c; font-size: 12px">
|
||||
提示:登录失败超过{{ accountLoginSecurity.loginFailCount }}次后将被限制{{ accountLoginSecurity.loginFailMin }}分钟内不可再次登录
|
||||
{{
|
||||
$t('login.loginFailTip', {
|
||||
loginFailCount: accountLoginSecurity.loginFailCount,
|
||||
loginFailMin: accountLoginSecurity.loginFailMin,
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
<el-form-item>
|
||||
<el-button type="primary" class="login-content-submit" round @click="login" :loading="loading.signIn">
|
||||
<span>登 录</span>
|
||||
<span>{{ $t('login.login') }}</span>
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-dialog title="修改密码" v-model="changePwdDialog.visible" :close-on-click-modal="false" width="450px" :destroy-on-close="true">
|
||||
<el-dialog :title="$t('login.changePassword')" v-model="changePwdDialog.visible" :close-on-click-modal="false" width="450px" :destroy-on-close="true">
|
||||
<el-form :model="changePwdDialog.form" :rules="changePwdDialog.rules" ref="changePwdFormRef" label-width="auto">
|
||||
<el-form-item prop="username" label="用户名" required>
|
||||
<el-form-item prop="username" :label="$t('common.username')" required>
|
||||
<el-input v-model.trim="changePwdDialog.form.username" disabled></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="oldPassword" label="旧密码" required>
|
||||
<el-form-item prop="oldPassword" :label="$t('login.oldPassword')" required>
|
||||
<el-input v-model.trim="changePwdDialog.form.oldPassword" autocomplete="new-password" type="password"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="newPassword" label="新密码" required>
|
||||
<el-form-item prop="newPassword" :label="$t('login.newPassword')" required>
|
||||
<el-input
|
||||
v-model.trim="changePwdDialog.form.newPassword"
|
||||
placeholder="须为8位以上且包含字⺟⼤⼩写+数字+特殊符号"
|
||||
:placeholder="$t('login.passwordRuleTip')"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
></el-input>
|
||||
@@ -70,14 +83,16 @@
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancelChangePwd">取 消</el-button>
|
||||
<el-button @click="changePwd" type="primary" :loading="loading.changePwd">确 定</el-button>
|
||||
<el-button @click="cancelChangePwd">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button @click="changePwd" type="primary" :loading="loading.changePwd">
|
||||
{{ $t('common.confirm') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
title="OTP校验"
|
||||
:title="$t('login.otpValidation')"
|
||||
v-model="otpDialog.visible"
|
||||
@close="loading.signIn = false"
|
||||
:close-on-click-modal="false"
|
||||
@@ -85,7 +100,7 @@
|
||||
:destroy-on-close="true"
|
||||
>
|
||||
<el-form ref="otpFormRef" :model="otpDialog.form" :rules="otpDialog.rules" @submit.native.prevent label-width="auto">
|
||||
<el-form-item v-if="otpDialog.otpUrl" label="二维码">
|
||||
<el-form-item v-if="otpDialog.otpUrl" :label="$t('login.qrCode')">
|
||||
<qrcode-vue :value="otpDialog.otpUrl" :size="200" level="H" />
|
||||
</el-form-item>
|
||||
|
||||
@@ -96,31 +111,35 @@
|
||||
v-model.trim="otpDialog.form.code"
|
||||
clearable
|
||||
@keyup.enter="otpVerify"
|
||||
placeholder="请输入令牌APP中显示的授权码"
|
||||
:placeholder="$t('login.enterOtpCodeTip')"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="otpVerify" type="primary" :loading="loading.otpConfirm">确 定</el-button>
|
||||
<el-button @click="otpVerify" type="primary" :loading="loading.otpConfirm">
|
||||
{{ $t('common.confirm') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="修改基本信息" v-model="baseInfoDialog.visible" :close-on-click-modal="false" width="450px" :destroy-on-close="true">
|
||||
<el-dialog :title="$t('updateBasicInfo')" v-model="baseInfoDialog.visible" :close-on-click-modal="false" width="450px" :destroy-on-close="true">
|
||||
<el-form :model="baseInfoDialog.form" :rules="baseInfoDialog.rules" ref="baseInfoFormRef" label-width="auto">
|
||||
<el-form-item prop="username" label="用户名" required>
|
||||
<el-form-item prop="username" :label="$t('common.username')" required>
|
||||
<el-input v-model.trim="baseInfoDialog.form.username"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="name" label="姓名" required>
|
||||
<el-form-item prop="name" :label="$t('login.name')" required>
|
||||
<el-input v-model.trim="baseInfoDialog.form.name"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="updateUserInfo()" type="primary" :loading="loading.updateUserConfirm">确 定</el-button>
|
||||
<el-button @click="updateUserInfo()" type="primary" :loading="loading.updateUserConfirm">
|
||||
{{ $t('common.confirm') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -145,11 +164,14 @@ import { AccountUsernamePattern } from '@/common/pattern';
|
||||
import { getToken } from '@/common/utils/storage';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
import { getFileUrl } from '@/common/request';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const rules = {
|
||||
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
||||
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
||||
captcha: [{ required: true, message: '请输入验证码', trigger: 'blur' }],
|
||||
username: [{ required: true, message: t('login.inputUsernamePlaceholder'), trigger: 'blur' }],
|
||||
password: [{ required: true, message: t('login.inputPasswordPlaceholder'), trigger: 'blur' }],
|
||||
captcha: [{ required: true, message: t('login.inputCaptchaPlaceholder'), trigger: 'blur' }],
|
||||
};
|
||||
|
||||
// 定义变量内容
|
||||
@@ -189,10 +211,10 @@ const state = reactive({
|
||||
},
|
||||
rules: {
|
||||
newPassword: [
|
||||
{ required: true, message: '请输入新密码', trigger: 'blur' },
|
||||
{ required: true, message: t('login.inputNewPasswordPlaceholder'), trigger: 'blur' },
|
||||
{
|
||||
pattern: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[`~!@#$%^&*()_+<>?:"{},.\/\\;'[\]])[A-Za-z\d`~!@#$%^&*()_+<>?:"{},.\/\\;'[\]]{8,}$/,
|
||||
message: '须为8位以上且包含字⺟⼤⼩写+数字+特殊符号',
|
||||
message: t('login.passwordRuleTip'),
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
@@ -206,7 +228,7 @@ const state = reactive({
|
||||
otpToken: '',
|
||||
},
|
||||
rules: {
|
||||
code: [{ required: true, message: '请输入OTP授权码', trigger: 'blur' }],
|
||||
code: [{ required: true, message: t('login.inputOtpCodePlaceholder'), trigger: 'blur' }],
|
||||
},
|
||||
},
|
||||
baseInfoDialog: {
|
||||
@@ -217,14 +239,14 @@ const state = reactive({
|
||||
},
|
||||
rules: {
|
||||
username: [
|
||||
{ required: true, message: '请输入用户名', trigger: 'blur' },
|
||||
{ required: true, message: t('login.inputUsernamePlaceholder'), trigger: 'blur' },
|
||||
{
|
||||
pattern: AccountUsernamePattern.pattern,
|
||||
message: AccountUsernamePattern.message,
|
||||
trigger: ['blur'],
|
||||
},
|
||||
],
|
||||
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
|
||||
name: [{ required: true, message: t('login.inputNamePlaceholder'), trigger: 'blur' }],
|
||||
},
|
||||
},
|
||||
loading: {
|
||||
@@ -424,7 +446,7 @@ const toIndex = async () => {
|
||||
setTimeout(async () => {
|
||||
// 关闭 loading
|
||||
state.loading.signIn = true;
|
||||
ElMessage.success(`${currentTimeInfo},欢迎回来!`);
|
||||
ElMessage.success(t('login.loginSuccessTip'));
|
||||
// 水印设置用户信息
|
||||
storesThemeConfig.setWatermarkUser();
|
||||
}, 300);
|
||||
@@ -444,7 +466,7 @@ const changePwd = async () => {
|
||||
changePwdReq.oldPassword = await RsaEncrypt(form.oldPassword);
|
||||
changePwdReq.newPassword = await RsaEncrypt(form.newPassword);
|
||||
await openApi.changePwd(changePwdReq);
|
||||
ElMessage.success('密码修改成功, 新密码已填充至登录密码框');
|
||||
ElMessage.success(t('login.passwordChangeSuccessTip'));
|
||||
state.loginForm.password = state.changePwdDialog.form.newPassword;
|
||||
state.changePwdDialog.visible = false;
|
||||
getCaptcha();
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
<div class="login-right-warp-main-form">
|
||||
<div v-if="!state.isScan">
|
||||
<el-tabs v-model="state.tabsActiveName">
|
||||
<el-tab-pane label="账号密码登录" name="account">
|
||||
<el-tab-pane :label="$t('login.accountPasswordLogin')" name="account">
|
||||
<Account ref="loginForm" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<div class="mt20" v-show="state.oauth2LoginConfig.enable">
|
||||
<el-button link size="small">第三方登录: </el-button>
|
||||
<el-button link size="small">{{ $t('login.thirdPartyLogin') }}: </el-button>
|
||||
<el-tooltip :content="state.oauth2LoginConfig.name" placement="top-start">
|
||||
<el-button link size="small" type="primary" @click="oauth2Login">
|
||||
<el-icon :size="18">
|
||||
@@ -52,6 +52,7 @@ import loginBgSplitImg from '@/assets/image/login-bg-split.svg';
|
||||
import openApi from '@/common/openApi';
|
||||
import config from '@/common/config';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
// 引入组件
|
||||
const Account = defineAsyncComponent(() => import('./component/AccountLogin.vue'));
|
||||
@@ -61,18 +62,20 @@ const loginForm = ref<{ loginResDeal: (data: any) => void } | null>(null);
|
||||
// 定义变量内容
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
const { locale } = useI18n();
|
||||
|
||||
const state = reactive({
|
||||
tabsActiveName: 'account',
|
||||
isScan: false,
|
||||
oauth2LoginConfig: {
|
||||
name: 'OAuth2登录',
|
||||
name: 'OAuth2 Login',
|
||||
enable: false,
|
||||
},
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
storesThemeConfig.setWatermarkUser(true);
|
||||
locale.value = themeConfig.value.globalI18n;
|
||||
state.oauth2LoginConfig = await openApi.oauth2LoginConfig();
|
||||
});
|
||||
|
||||
@@ -104,11 +107,13 @@ const oauth2Login = () => {
|
||||
.login-container {
|
||||
height: 100%;
|
||||
background: var(--bg-main-color);
|
||||
|
||||
.login-left {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
background-color: rgba(211, 239, 255, 1);
|
||||
margin-right: 100px;
|
||||
|
||||
.login-left-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -117,24 +122,29 @@ const oauth2Login = () => {
|
||||
left: 80px;
|
||||
z-index: 1;
|
||||
animation: logoAnimation 0.3s ease;
|
||||
|
||||
img {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
}
|
||||
|
||||
.login-left-logo-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
span {
|
||||
margin-left: 10px;
|
||||
font-size: 28px;
|
||||
color: #26a59a;
|
||||
}
|
||||
|
||||
.login-left-logo-text-msg {
|
||||
font-size: 12px;
|
||||
color: #32a99e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login-left-img {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
@@ -142,20 +152,24 @@ const oauth2Login = () => {
|
||||
transform: translate(-50%, -50%);
|
||||
width: 100%;
|
||||
height: 52%;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
animation: error-num 0.6s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.login-left-waves {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: -100px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-right {
|
||||
width: 700px;
|
||||
|
||||
.login-right-warp {
|
||||
border: 1px solid var(--el-color-primary-light-3);
|
||||
border-radius: 3px;
|
||||
@@ -164,12 +178,14 @@ const oauth2Login = () => {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background-color: var(--bg-main-color);
|
||||
|
||||
.login-right-warp-one,
|
||||
.login-right-warp-two {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
@@ -177,6 +193,7 @@ const oauth2Login = () => {
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.login-right-warp-one {
|
||||
&::before {
|
||||
filter: hue-rotate(0deg);
|
||||
@@ -187,6 +204,7 @@ const oauth2Login = () => {
|
||||
background: linear-gradient(90deg, transparent, var(--el-color-primary));
|
||||
animation: loginLeft 3s linear infinite;
|
||||
}
|
||||
|
||||
&::after {
|
||||
filter: hue-rotate(60deg);
|
||||
top: -100%;
|
||||
@@ -198,6 +216,7 @@ const oauth2Login = () => {
|
||||
animation-delay: 0.7s;
|
||||
}
|
||||
}
|
||||
|
||||
.login-right-warp-two {
|
||||
&::before {
|
||||
filter: hue-rotate(120deg);
|
||||
@@ -209,6 +228,7 @@ const oauth2Login = () => {
|
||||
animation: loginRight 3s linear infinite;
|
||||
animation-delay: 1.4s;
|
||||
}
|
||||
|
||||
&::after {
|
||||
filter: hue-rotate(300deg);
|
||||
bottom: -100%;
|
||||
@@ -220,10 +240,12 @@ const oauth2Login = () => {
|
||||
animation-delay: 2.1s;
|
||||
}
|
||||
}
|
||||
|
||||
.login-right-warp-mian {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
.login-right-warp-main-title {
|
||||
height: 110px;
|
||||
line-height: 110px;
|
||||
@@ -234,9 +256,11 @@ const oauth2Login = () => {
|
||||
animation-delay: 0.3s;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.login-right-warp-main-form {
|
||||
flex: 1;
|
||||
padding: 0 50px 50px;
|
||||
|
||||
.login-content-main-sacn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -247,6 +271,7 @@ const oauth2Login = () => {
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
color: var(--el-color-primary);
|
||||
|
||||
&-delta {
|
||||
position: absolute;
|
||||
width: 35px;
|
||||
@@ -257,11 +282,13 @@ const oauth2Login = () => {
|
||||
background: var(--el-color-white);
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
transition: all ease 0.3s;
|
||||
color: var(--el-color-primary) !important;
|
||||
}
|
||||
|
||||
i {
|
||||
width: 47px;
|
||||
height: 50px;
|
||||
|
||||
@@ -7,9 +7,12 @@ import { onMounted } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import openApi from '@/common/openApi';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const queryParam = route.query;
|
||||
@@ -26,7 +29,7 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
const res: any = await openApi.oauth2Callback(queryParam);
|
||||
ElMessage.success('授权认证成功');
|
||||
ElMessage.success(t('system.oauth.authSuccess'));
|
||||
top?.opener.postMessage(res);
|
||||
window.close();
|
||||
} catch (e: any) {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="auth-cert-edit">
|
||||
<el-dialog :title="props.title" v-model="dialogVisible" :show-close="false" width="500px" :destroy-on-close="true" :close-on-click-modal="false">
|
||||
<el-dialog :title="props.title" v-model="dialogVisible" :show-close="false" width="600px" :destroy-on-close="true" :close-on-click-modal="false">
|
||||
<el-form ref="acForm" :model="state.form" label-width="auto" :rules="rules">
|
||||
<el-form-item prop="type" label="凭证类型" required>
|
||||
<el-select @change="changeType" v-model="form.type" placeholder="请选择凭证类型">
|
||||
<el-form-item prop="type" :label="$t('ac.credentialType')" required>
|
||||
<el-select @change="changeType" v-model="form.type">
|
||||
<el-option
|
||||
v-for="item in AuthCertTypeEnum"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:label="$t(item.label)"
|
||||
:value="item.value"
|
||||
v-show="!props.disableType?.includes(item.value)"
|
||||
>
|
||||
@@ -15,12 +15,12 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="ciphertextType" label="密文类型" required>
|
||||
<el-select v-model="form.ciphertextType" placeholder="请选择密文类型" @change="changeCiphertextType">
|
||||
<el-form-item prop="ciphertextType" :label="$t('ac.ciphertextType')" required>
|
||||
<el-select v-model="form.ciphertextType" @change="changeCiphertextType">
|
||||
<el-option
|
||||
v-for="item in AuthCertCiphertextTypeEnum"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:label="$t(item.label)"
|
||||
:value="item.value"
|
||||
v-show="!props.disableCiphertextType?.includes(item.value)"
|
||||
:disabled="item.value == AuthCertCiphertextTypeEnum.Public.value && form.type == AuthCertTypeEnum.Public.value"
|
||||
@@ -30,45 +30,45 @@
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="showResourceEdit">
|
||||
<el-form-item prop="type" label="资源类型" required>
|
||||
<el-select :disabled="form.id" v-model="form.resourceType" placeholder="请选择资源类型">
|
||||
<el-form-item prop="type" :label="$t('ac.resourceType')" required>
|
||||
<el-select :disabled="form.id" v-model="form.resourceType">
|
||||
<el-option
|
||||
:key="TagResourceTypeEnum.Machine.value"
|
||||
:label="TagResourceTypeEnum.Machine.label"
|
||||
:label="$t(TagResourceTypeEnum.Machine.label)"
|
||||
:value="TagResourceTypeEnum.Machine.value"
|
||||
/>
|
||||
|
||||
<el-option :key="TagResourceTypeEnum.Db.value" :label="TagResourceTypeEnum.Db.label" :value="TagResourceTypeEnum.Db.value" />
|
||||
<el-option
|
||||
:key="TagResourceTypeEnum.Redis.value"
|
||||
:label="TagResourceTypeEnum.Redis.label"
|
||||
:label="$t(TagResourceTypeEnum.Redis.label)"
|
||||
:value="TagResourceTypeEnum.Redis.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item prop="resourceCode" label="资源编号" required>
|
||||
<el-input :disabled="form.id" v-model="form.resourceCode" placeholder="请输入资源编号"></el-input>
|
||||
<el-form-item prop="resourceCode" :label="$t('ac.resourceCode')" required>
|
||||
<el-input :disabled="form.id" v-model="form.resourceCode"></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<el-form-item v-if="form.type == AuthCertTypeEnum.Public.value" prop="name" label="名称" required>
|
||||
<el-input :disabled="form.id" v-model="form.name" placeholder="请输入凭证名 (全局唯一)"></el-input>
|
||||
<el-form-item v-if="form.type == AuthCertTypeEnum.Public.value" prop="name" :label="$t('common.name')" required>
|
||||
<el-input :disabled="form.id" v-model="form.name" :placeholder="$t('ac.namePlaceholder')"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="form.ciphertextType != AuthCertCiphertextTypeEnum.Public.value">
|
||||
<el-form-item prop="username" label="用户名">
|
||||
<el-form-item prop="username" :label="$t('common.username')">
|
||||
<el-input v-model="form.username"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.ciphertextType == AuthCertCiphertextTypeEnum.Password.value" prop="ciphertext" label="密码">
|
||||
<el-input type="password" show-password clearable v-model.trim="form.ciphertext" placeholder="请输入密码" autocomplete="new-password">
|
||||
<el-form-item v-if="form.ciphertextType == AuthCertCiphertextTypeEnum.Password.value" prop="ciphertext" :label="$t('common.password')">
|
||||
<el-input type="password" show-password clearable v-model.trim="form.ciphertext" autocomplete="new-password">
|
||||
<template #suffix>
|
||||
<SvgIcon v-if="form.id" v-auth="'authcert:showciphertext'" @click="getCiphertext" name="search" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.ciphertextType == AuthCertCiphertextTypeEnum.PrivateKey.value" prop="ciphertext" label="秘钥">
|
||||
<el-form-item v-if="form.ciphertextType == AuthCertCiphertextTypeEnum.PrivateKey.value" prop="ciphertext" :label="$t('ac.privateKey')">
|
||||
<div class="w100" style="position: relative">
|
||||
<SvgIcon
|
||||
v-if="form.id"
|
||||
@@ -77,17 +77,17 @@
|
||||
name="search"
|
||||
style="position: absolute; top: 5px; right: 5px; cursor: pointer; z-index: 1"
|
||||
/>
|
||||
<el-input type="textarea" :rows="5" v-model="form.ciphertext" placeholder="请将私钥文件内容拷贝至此"> </el-input>
|
||||
<el-input type="textarea" :rows="5" v-model="form.ciphertext" :placeholder="$t('ac.privateKeyPlaceholder')"> </el-input>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.ciphertextType == AuthCertCiphertextTypeEnum.PrivateKey.value" prop="passphrase" label="秘钥密码">
|
||||
<el-form-item v-if="form.ciphertextType == AuthCertCiphertextTypeEnum.PrivateKey.value" prop="passphrase" :label="$t('ac.privateKeyPwd')">
|
||||
<el-input type="password" show-password v-model="form.extra.passphrase"> </el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<el-form-item label="公共凭证">
|
||||
<el-form-item :label="$t('ac.publicAc')">
|
||||
<el-select default-first-option filterable v-model="form.ciphertext" @change="changePublicAuthCert">
|
||||
<el-option v-for="item in state.publicAuthCerts" :key="item.name" :label="item.name" :value="item.name">
|
||||
{{ item.name }}
|
||||
@@ -102,14 +102,14 @@
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<el-form-item label="备注">
|
||||
<el-form-item :label="$t('common.remark')">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="2"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancelEdit">取 消</el-button>
|
||||
<el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
|
||||
<el-button @click="cancelEdit">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" :loading="btnLoading" @click="btnOk">{{ $t('common.confirm') }}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -123,11 +123,14 @@ import EnumTag from '@/components/enumtag/EnumTag.vue';
|
||||
import { resourceAuthCertApi } from '../tag/api';
|
||||
import { ResourceCodePattern } from '@/common/pattern';
|
||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: '凭证保存',
|
||||
default: '',
|
||||
},
|
||||
authCert: {
|
||||
type: Object,
|
||||
@@ -162,7 +165,7 @@ const rules = {
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入凭证名',
|
||||
message: t('common.pleaseInput', { label: t('common.name') }),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
{
|
||||
@@ -174,7 +177,7 @@ const rules = {
|
||||
resourceCode: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入资源编号',
|
||||
message: t('common.pleaseInput', { label: t('ac.resourceCode') }),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="auth-cert-manage">
|
||||
<el-table :data="authCerts" max-height="180" stripe size="small">
|
||||
<el-table :data="authCerts" :max-height="180" stripe size="small">
|
||||
<el-table-column min-wdith="120px">
|
||||
<template #header>
|
||||
<el-button v-auth="'authcert:save'" class="ml0" type="primary" circle size="small" icon="Plus" @click="edit(null)"> </el-button>
|
||||
@@ -10,7 +10,7 @@
|
||||
<el-button class="ml1" v-auth="'authcert:del'" type="danger" @click="deleteRow(scope.$index)" icon="delete" link></el-button>
|
||||
|
||||
<el-button
|
||||
title="测试连接"
|
||||
:title="$t('ac.testConn')"
|
||||
:loading="props.testConnBtnLoading && scope.$index == state.idx"
|
||||
:disabled="props.testConnBtnLoading"
|
||||
class="ml1"
|
||||
@@ -22,19 +22,18 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- <el-table-column prop="name" label="名称" show-overflow-tooltip min-width="100px"> </el-table-column> -->
|
||||
<el-table-column prop="username" label="用户名" min-width="120px" show-overflow-tooltip> </el-table-column>
|
||||
<el-table-column prop="ciphertextType" label="密文类型" width="100px">
|
||||
<el-table-column prop="username" :label="$t('common.username')" min-width="120px" show-overflow-tooltip> </el-table-column>
|
||||
<el-table-column prop="ciphertextType" :label="$t('ac.ciphertextType')" width="100px">
|
||||
<template #default="scope">
|
||||
<EnumTag :value="scope.row.ciphertextType" :enums="AuthCertCiphertextTypeEnum" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="type" label="凭证类型" width="100px">
|
||||
<el-table-column prop="type" :label="$t('ac.credentialType')" width="100px">
|
||||
<template #default="scope">
|
||||
<EnumTag :value="scope.row.type" :enums="AuthCertTypeEnum" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" show-overflow-tooltip width="120px"> </el-table-column>
|
||||
<el-table-column prop="remark" :label="$t('common.remark')" show-overflow-tooltip width="120px"> </el-table-column>
|
||||
</el-table>
|
||||
|
||||
<ResourceAuthCertEdit
|
||||
@@ -55,6 +54,9 @@ import { resourceAuthCertApi } from '../tag/api';
|
||||
import EnumTag from '@/components/enumtag/EnumTag.vue';
|
||||
import ResourceAuthCertEdit from './ResourceAuthCertEdit.vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
resourceType: { type: Number },
|
||||
@@ -117,17 +119,6 @@ const cancelEdit = () => {
|
||||
|
||||
const btnOk = async (authCert: any) => {
|
||||
const isEdit = authCert.id;
|
||||
// if (!isEdit) {
|
||||
// const res = await resourceAuthCertApi.listByQuery.request({
|
||||
// name: authCert.name,
|
||||
// pageNum: 1,
|
||||
// pageSize: 100,
|
||||
// });
|
||||
// if (res.total) {
|
||||
// ElMessage.error('该授权凭证名称已存在');
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
if (isEdit || state.idx >= 0) {
|
||||
authCerts.value[state.idx] = authCert;
|
||||
@@ -136,7 +127,7 @@ const btnOk = async (authCert: any) => {
|
||||
}
|
||||
|
||||
if (authCerts.value?.filter((x: any) => x.username == authCert.username).length > 0) {
|
||||
ElMessage.error('该用户名已存在于该账号列表中');
|
||||
ElMessage.error(t('ac.usernameExist'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
style="width: 100%"
|
||||
v-model="sshTunnelMachineId"
|
||||
@clear="clear"
|
||||
placeholder="请选择SSH隧道机器"
|
||||
placeholder="SSH tunnel machine"
|
||||
clearable
|
||||
>
|
||||
<el-option v-for="item in sshTunnelMachineList" :key="item.id" :label="`${item.ip}:${item.port} [${item.name}]`" :value="item.id"> </el-option>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div style="display: inline-flex; justify-content: center; align-items: center; cursor: pointer; vertical-align: middle">
|
||||
<el-popover :show-after="500" @show="showTagInfo" placement="top-start" title="标签信息" :width="300" trigger="hover">
|
||||
<el-popover :show-after="500" @show="showTagInfo" placement="top-start" :title="$t('common.tag')" :width="300" trigger="hover">
|
||||
<template #reference>
|
||||
<el-icon>
|
||||
<InfoFilled />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="card pd5">
|
||||
<el-input v-model="filterText" placeholder="输入关键字->搜索已展开节点信息" clearable size="small" class="mb5 w100" />
|
||||
<el-input v-model="filterText" :placeholder="$t('tag.tagFilterPlaceholder')" clearable size="small" class="mb5 w100" />
|
||||
<el-scrollbar class="tag-tree">
|
||||
<el-tree
|
||||
ref="treeRef"
|
||||
@@ -26,11 +26,11 @@
|
||||
<slot v-else :node="node" :data="data" name="prefix"></slot>
|
||||
|
||||
<span class="ml3" :title="data.labelRemark">
|
||||
<slot name="label" :data="data" v-if="!data.disabled"> {{ data.label }}</slot>
|
||||
<slot name="label" :data="data" v-if="!data.disabled"> {{ $t(data.label) }}</slot>
|
||||
<!-- 禁用状态 -->
|
||||
<slot name="disabledLabel" :data="data" v-else>
|
||||
<el-link type="danger" disabled :underline="false">
|
||||
{{ `${data.label}` }}
|
||||
{{ `${$t(data.label)}` }}
|
||||
</el-link>
|
||||
</slot>
|
||||
</span>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="w100 tag-tree-check">
|
||||
<el-input v-model="filterTag" @input="onFilterValChanged" clearable placeholder="输入关键字过滤" size="small" />
|
||||
<el-input v-model="filterTag" @input="onFilterValChanged" clearable :placeholder="$t('tag.keywordFilterPlaceholder')" size="small" />
|
||||
<div class="mt3" style="border: 1px solid var(--el-border-color)">
|
||||
<el-scrollbar :style="{ height: props.height }">
|
||||
<el-tree
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
v-model="state.selectTags"
|
||||
@change="changeTag"
|
||||
:data="tags"
|
||||
placeholder="请选择关联标签"
|
||||
:placeholder="$t('tag.selectTagPlaceholder')"
|
||||
:default-expanded-keys="defaultExpandedKeys"
|
||||
show-checkbox
|
||||
node-key="codePath"
|
||||
|
||||
@@ -161,7 +161,7 @@ export class NodeType {
|
||||
* @returns
|
||||
*/
|
||||
export function getTagPathSearchItem(resourceType: number) {
|
||||
return SearchItem.select('tagPath', '标签').withOptionsApi(
|
||||
return SearchItem.select('tagPath', 'common.tag').withOptionsApi(
|
||||
OptionsApi.new(tagApi.getResourceTagPaths, {resourceType}).withConvertFn((res: any) => {
|
||||
return res.map((x: any) => {
|
||||
return {
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
width="38%"
|
||||
>
|
||||
<el-form :model="form" ref="dbForm" :rules="rules" label-width="auto">
|
||||
<el-form-item prop="name" label="名称" required>
|
||||
<el-input v-model.trim="form.name" placeholder="请输入数据库别名" auto-complete="off"></el-input>
|
||||
<el-form-item prop="name" :label="$t('common.name')" required>
|
||||
<el-input v-model.trim="form.name" auto-complete="off"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="authCertName" label="授权凭证" required>
|
||||
<el-select v-model="form.authCertName" placeholder="请选择授权凭证" filterable>
|
||||
<el-form-item prop="authCertName" :label="$t('db.acName')" required>
|
||||
<el-select v-model="form.authCertName" filterable>
|
||||
<el-option v-for="item in state.authCerts" :key="item.id" :label="`${item.name}`" :value="item.name">
|
||||
{{ item.name }}
|
||||
|
||||
@@ -31,13 +31,11 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="getDatabaseMode" label="获库方式" required>
|
||||
<el-select v-model="form.getDatabaseMode" @change="onChangeGetDatabaseMode" placeholder="请选择库名获取方式">
|
||||
<el-option v-for="item in DbGetDbNamesMode" :key="item.value" :label="item.label" :value="item.value"> </el-option>
|
||||
</el-select>
|
||||
<el-form-item prop="getDatabaseMode" :label="$t('db.getDbMode')" required>
|
||||
<EnumSelect :enums="DbGetDbNamesMode" v-model="form.getDatabaseMode" @change="onChangeGetDatabaseMode" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="database" label="数据库名">
|
||||
<el-form-item prop="database" label="DB">
|
||||
<el-select
|
||||
:disabled="form.getDatabaseMode == DbGetDbNamesMode.Auto.value || !form.authCertName"
|
||||
v-model="dbNamesSelected"
|
||||
@@ -48,26 +46,28 @@
|
||||
filterable
|
||||
:filter-method="filterDbNames"
|
||||
allow-create
|
||||
placeholder="获库方式为‘指定库名’时,可选择"
|
||||
:placeholder="$t('db.selectDbPlacehoder')"
|
||||
@focus="getAllDatabase(form.authCertName)"
|
||||
:loading="state.loadingDbNames"
|
||||
>
|
||||
<template #header>
|
||||
<el-checkbox v-model="checkAllDbNames" :indeterminate="indeterminateDbNames" @change="handleCheckAll"> 全选 </el-checkbox>
|
||||
<el-checkbox v-model="checkAllDbNames" :indeterminate="indeterminateDbNames" @change="handleCheckAll">
|
||||
{{ $t('db.allSelect') }}
|
||||
</el-checkbox>
|
||||
</template>
|
||||
<el-option v-for="db in state.dbNamesFiltered" :key="db" :label="db" :value="db" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="remark" label="备注">
|
||||
<el-form-item prop="remark" :label="$t('common.remark')">
|
||||
<el-input v-model.trim="form.remark" auto-complete="off" type="textarea"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button type="primary" @click="btnOk">确 定</el-button>
|
||||
<el-button @click="cancel()">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="btnOk">{{ $t('common.confirm') }}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -77,7 +77,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { toRefs, reactive, watch, ref } from 'vue';
|
||||
import { dbApi } from './api';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import type { CheckboxValueType } from 'element-plus';
|
||||
import { DbType } from '@/views/ops/db/dialect';
|
||||
|
||||
@@ -86,6 +85,8 @@ import { AuthCertCiphertextTypeEnum } from '../tag/enums';
|
||||
import { resourceAuthCertApi } from '../tag/api';
|
||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
||||
import { DbGetDbNamesMode } from './enums';
|
||||
import EnumSelect from '@/components/enumselect/EnumSelect.vue';
|
||||
import { useI18nFormValidate, useI18nPleaseInput, useI18nPleaseSelect } from '@/hooks/useI18n';
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@@ -106,39 +107,31 @@ const props = defineProps({
|
||||
const emit = defineEmits(['update:visible', 'cancel', 'val-change', 'confirm']);
|
||||
|
||||
const rules = {
|
||||
tagId: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择标签',
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
|
||||
instanceId: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择数据库实例',
|
||||
message: useI18nPleaseSelect('db.dbInst'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入别名',
|
||||
message: useI18nPleaseInput('common.name'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
authCertName: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择授权凭证',
|
||||
message: useI18nPleaseSelect('db.acName'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
getDatabaseMode: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择库名获取方式',
|
||||
message: useI18nPleaseSelect('db.getDbMode'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
@@ -237,13 +230,7 @@ const open = async () => {
|
||||
};
|
||||
|
||||
const btnOk = async () => {
|
||||
try {
|
||||
await dbForm.value.validate();
|
||||
} catch (e: any) {
|
||||
ElMessage.error('请正确填写信息');
|
||||
return false;
|
||||
}
|
||||
|
||||
await useI18nFormValidate(dbForm);
|
||||
emit('confirm', state.form);
|
||||
};
|
||||
|
||||
|
||||
@@ -46,12 +46,12 @@
|
||||
<template #database="{ data }">
|
||||
<el-popover placement="bottom" :width="200" trigger="click">
|
||||
<template #reference>
|
||||
<el-button @click="getDbNames(data)" type="primary" link>查看库</el-button>
|
||||
<el-button @click="getDbNames(data)" type="primary" link>{{ $t('db.showDb') }}</el-button>
|
||||
</template>
|
||||
<el-table :data="filterDbs" v-loading="state.loadingDbNames" size="small">
|
||||
<el-table-column prop="dbName" label="数据库">
|
||||
<el-table-column prop="dbName" :label="$t('db.db')">
|
||||
<template #header>
|
||||
<el-input v-model="state.dbNameSearch" size="small" placeholder="库名: 输入可过滤" clearable />
|
||||
<el-input v-model="state.dbNameSearch" size="small" :placeholder="$t('db.dbFilterPlaceholder')" clearable />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -63,24 +63,24 @@
|
||||
</template>
|
||||
|
||||
<template #action="{ data }">
|
||||
<el-button v-auth="perms.saveDb" @click="editDb(data)" type="primary" link>编辑</el-button>
|
||||
<el-button v-auth="perms.saveDb" @click="editDb(data)" type="primary" link>{{ $t('common.edit') }}</el-button>
|
||||
|
||||
<el-divider direction="vertical" border-style="dashed" />
|
||||
|
||||
<el-button type="primary" @click="onShowSqlExec(data)" link>SQL记录</el-button>
|
||||
<el-button type="primary" @click="onShowSqlExec(data)" link>{{ $t('db.sqlRecord') }}</el-button>
|
||||
|
||||
<el-divider direction="vertical" border-style="dashed" />
|
||||
|
||||
<el-dropdown @command="handleMoreActionCommand">
|
||||
<span class="el-dropdown-link-more">
|
||||
更多
|
||||
{{ $t('common.more') }}
|
||||
<el-icon class="el-icon--right">
|
||||
<arrow-down />
|
||||
</el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item :command="{ type: 'dumpDb', data }"> 导出 </el-dropdown-item>
|
||||
<el-dropdown-item :command="{ type: 'dumpDb', data }"> {{ $t('db.dump') }} </el-dropdown-item>
|
||||
<!-- <el-dropdown-item
|
||||
:command="{ type: 'backupDb', data }"
|
||||
v-if="actionBtns[perms.backupDb] && supportAction('backupDb', data.type)"
|
||||
@@ -106,18 +106,18 @@
|
||||
</page-table>
|
||||
</el-drawer>
|
||||
|
||||
<el-dialog width="750px" :title="`${exportDialog.db} 数据库导出`" v-model="exportDialog.visible">
|
||||
<el-dialog width="750px" :title="`${exportDialog.db} DB Dump`" v-model="exportDialog.visible">
|
||||
<el-row justify="space-between">
|
||||
<el-col :span="9">
|
||||
<el-form-item label="导出内容: ">
|
||||
<el-form-item :label="$t('db.dumpContent')">
|
||||
<el-checkbox-group v-model="exportDialog.contents" :min="1">
|
||||
<el-checkbox label="结构" value="结构" />
|
||||
<el-checkbox label="数据" value="数据" />
|
||||
<el-checkbox :label="$t('db.structure')" value="结构" />
|
||||
<el-checkbox :label="$t('db.data')" value="数据" />
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="9">
|
||||
<el-form-item label="扩展名: ">
|
||||
<el-form-item :label="$t('db.extName')">
|
||||
<el-radio-group v-model="exportDialog.extName">
|
||||
<el-radio label="sql" value="sql" />
|
||||
<el-radio label="gzip" value="gzip" />
|
||||
@@ -130,8 +130,8 @@
|
||||
<el-transfer
|
||||
v-model="exportDialog.value"
|
||||
filterable
|
||||
filter-placeholder="按数据库名称筛选"
|
||||
:titles="['全部数据库', '导出数据库']"
|
||||
:filter-placeholder="$t('db.dbFilterPlacehoder')"
|
||||
:titles="[$t('db.allDb'), $t('db.dumpDb')]"
|
||||
:data="exportDialog.data"
|
||||
max-height="300"
|
||||
size="small"
|
||||
@@ -140,15 +140,15 @@
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="exportDialog.visible = false">取消</el-button>
|
||||
<el-button @click="dumpDbs()" type="primary">确定</el-button>
|
||||
<el-button @click="exportDialog.visible = false">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button @click="dumpDbs()" type="primary">{{ $t('common.confirm') }}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
width="90%"
|
||||
:title="`${sqlExecLogDialog.title} - SQL执行记录`"
|
||||
:title="`${sqlExecLogDialog.title} - SQL`"
|
||||
:before-close="onBeforeCloseSqlExecDialog"
|
||||
:close-on-click-modal="false"
|
||||
v-model="sqlExecLogDialog.visible"
|
||||
@@ -157,7 +157,7 @@
|
||||
<db-sql-exec-log :db-id="sqlExecLogDialog.dbId" :dbs="sqlExecLogDialog.dbs" />
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
<!-- <el-dialog
|
||||
width="80%"
|
||||
:title="`${dbBackupDialog.title} - 数据库备份`"
|
||||
:close-on-click-modal="false"
|
||||
@@ -185,7 +185,7 @@
|
||||
v-model="dbRestoreDialog.visible"
|
||||
>
|
||||
<db-restore-list :dbId="dbRestoreDialog.dbId" :dbNames="dbRestoreDialog.dbs" />
|
||||
</el-dialog>
|
||||
</el-dialog> -->
|
||||
|
||||
<db-edit
|
||||
@confirm="confirmEditDb"
|
||||
@@ -210,18 +210,19 @@ import { hasPerms } from '@/components/auth/auth';
|
||||
import DbSqlExecLog from './DbSqlExecLog.vue';
|
||||
import { DbType } from './dialect';
|
||||
import { getDbDialect } from './dialect/index';
|
||||
import DbBackupList from './DbBackupList.vue';
|
||||
import DbBackupHistoryList from './DbBackupHistoryList.vue';
|
||||
import DbRestoreList from './DbRestoreList.vue';
|
||||
import ResourceTags from '../component/ResourceTags.vue';
|
||||
import { sleep } from '@/common/utils/loading';
|
||||
import { DbGetDbNamesMode } from './enums';
|
||||
import { DbInst } from './db';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import DrawerHeader from '@/components/drawer-header/DrawerHeader.vue';
|
||||
import { useI18nCreateTitle, useI18nDeleteConfirm, useI18nDeleteSuccessMsg, useI18nEditTitle, useI18nSaveSuccessMsg } from '@/hooks/useI18n';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const DbEdit = defineAsyncComponent(() => import('./DbEdit.vue'));
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
instance: {
|
||||
type: [Object],
|
||||
@@ -237,13 +238,13 @@ const dialogVisible = defineModel<boolean>('visible');
|
||||
const emit = defineEmits(['cancel']);
|
||||
|
||||
const columns = ref([
|
||||
TableColumn.new('name', '名称'),
|
||||
TableColumn.new('authCertName', '授权凭证'),
|
||||
TableColumn.new('getDatabaseMode', '获库方式').typeTag(DbGetDbNamesMode),
|
||||
TableColumn.new('database', '库').isSlot().setMinWidth(80),
|
||||
TableColumn.new('remark', '备注'),
|
||||
TableColumn.new('code', '编号'),
|
||||
TableColumn.new('action', '操作').isSlot().setMinWidth(210).fixedRight().alignCenter(),
|
||||
TableColumn.new('name', 'common.name'),
|
||||
TableColumn.new('authCertName', 'db.acName'),
|
||||
TableColumn.new('getDatabaseMode', 'db.getDbMode').typeTag(DbGetDbNamesMode),
|
||||
TableColumn.new('database', 'DB').isSlot().setMinWidth(80),
|
||||
TableColumn.new('remark', 'common.remark'),
|
||||
TableColumn.new('code', 'common.code'),
|
||||
TableColumn.new('action', 'common.operation').isSlot().setMinWidth(210).fixedRight().alignCenter(),
|
||||
]);
|
||||
|
||||
const perms = {
|
||||
@@ -319,7 +320,7 @@ const state = reactive({
|
||||
dbEditDialog: {
|
||||
visible: false,
|
||||
data: null as any,
|
||||
title: '新增数据库',
|
||||
title: '',
|
||||
},
|
||||
filterDb: {
|
||||
param: '',
|
||||
@@ -367,14 +368,14 @@ const editDb = (data: any) => {
|
||||
instanceId: props.instance.id,
|
||||
};
|
||||
}
|
||||
state.dbEditDialog.title = data ? '编辑数据库' : '新增数据库';
|
||||
state.dbEditDialog.title = data ? useI18nEditTitle('db.db') : useI18nCreateTitle('db.db');
|
||||
state.dbEditDialog.visible = true;
|
||||
};
|
||||
|
||||
const confirmEditDb = async (db: any) => {
|
||||
db.instanceId = props.instance.id;
|
||||
await dbApi.saveDb.request(db);
|
||||
ElMessage.success('保存成功');
|
||||
useI18nSaveSuccessMsg();
|
||||
search();
|
||||
cancelEditDb();
|
||||
};
|
||||
@@ -386,15 +387,11 @@ const cancelEditDb = () => {
|
||||
|
||||
const deleteDb = async () => {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定删除【${state.selectionData.map((x: any) => x.name).join(', ')}】库?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
});
|
||||
await useI18nDeleteConfirm(state.selectionData.map((x: any) => x.name).join('、'));
|
||||
for (let db of state.selectionData) {
|
||||
await dbApi.deleteDb.request({ id: db.id });
|
||||
}
|
||||
ElMessage.success('删除成功');
|
||||
useI18nDeleteSuccessMsg();
|
||||
} catch (err) {
|
||||
//
|
||||
} finally {
|
||||
@@ -480,7 +477,7 @@ const onDumpDbs = async (row: any) => {
|
||||
state.exportDialog.value = [];
|
||||
state.exportDialog.data = data;
|
||||
state.exportDialog.dbId = row.id;
|
||||
state.exportDialog.contents = ['结构', '数据'];
|
||||
state.exportDialog.contents = [t('db.structure'), t('db.data')];
|
||||
state.exportDialog.extName = 'sql';
|
||||
state.exportDialog.visible = true;
|
||||
};
|
||||
@@ -489,7 +486,7 @@ const onDumpDbs = async (row: any) => {
|
||||
* 数据库信息导出
|
||||
*/
|
||||
const dumpDbs = async () => {
|
||||
isTrue(state.exportDialog.value.length > 0, '请添加要导出的数据库');
|
||||
isTrue(state.exportDialog.value.length > 0, t('db.noDumpDbMsg'));
|
||||
let type = 0;
|
||||
for (let c of state.exportDialog.contents) {
|
||||
if (c == '结构') {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
:columns="columns"
|
||||
>
|
||||
<template #dbSelect>
|
||||
<el-select v-model="query.db" placeholder="请选择数据库" filterable clearable>
|
||||
<el-select v-model="query.db" :placeholder="$t('db.selectDbPlaceholder')" filterable clearable>
|
||||
<el-option v-for="item in dbs" :key="item" :label="`${item}`" :value="item"> </el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
@@ -18,6 +18,7 @@
|
||||
<template #action="{ data }">
|
||||
<el-link
|
||||
v-if="
|
||||
data.oldValue != '' &&
|
||||
data.status == DbSqlExecStatusEnum.Success.value &&
|
||||
(data.type == DbSqlExecTypeEnum.Update.value || data.type == DbSqlExecTypeEnum.Delete.value)
|
||||
"
|
||||
@@ -27,12 +28,12 @@
|
||||
:underline="false"
|
||||
@click="onShowRollbackSql(data)"
|
||||
>
|
||||
还原SQL</el-link
|
||||
{{ $t('db.restoreSql') }}</el-link
|
||||
>
|
||||
</template>
|
||||
</page-table>
|
||||
|
||||
<el-dialog width="55%" :title="`还原SQL`" v-model="rollbackSqlDialog.visible">
|
||||
<el-dialog width="55%" :title="$t('db.restoreSql')" v-model="rollbackSqlDialog.visible">
|
||||
<el-input type="textarea" :autosize="{ minRows: 15, maxRows: 30 }" v-model="rollbackSqlDialog.sql" size="small"> </el-input>
|
||||
</el-dialog>
|
||||
</div>
|
||||
@@ -58,23 +59,23 @@ const props = defineProps({
|
||||
});
|
||||
|
||||
const searchItems = [
|
||||
SearchItem.slot('db', '数据库', 'dbSelect'),
|
||||
SearchItem.input('table', '表名'),
|
||||
SearchItem.select('type', '操作类型').withEnum(DbSqlExecTypeEnum),
|
||||
SearchItem.slot('db', 'db.db', 'dbSelect'),
|
||||
SearchItem.input('table', 'db.table'),
|
||||
SearchItem.select('type', 'db.stmtType').withEnum(DbSqlExecTypeEnum),
|
||||
];
|
||||
|
||||
const columns = ref([
|
||||
TableColumn.new('db', '数据库'),
|
||||
TableColumn.new('table', '表'),
|
||||
TableColumn.new('type', '类型').typeTag(DbSqlExecTypeEnum).setAddWidth(10),
|
||||
TableColumn.new('creator', '执行人'),
|
||||
TableColumn.new('db', 'db.db'),
|
||||
TableColumn.new('table', 'db.type'),
|
||||
TableColumn.new('type', 'db.stmtType').typeTag(DbSqlExecTypeEnum).setAddWidth(10),
|
||||
TableColumn.new('creator', 'db.execUser'),
|
||||
TableColumn.new('sql', 'SQL').canBeautify(),
|
||||
TableColumn.new('remark', '备注'),
|
||||
TableColumn.new('status', '执行状态').typeTag(DbSqlExecStatusEnum),
|
||||
TableColumn.new('res', '执行结果'),
|
||||
TableColumn.new('createTime', '执行时间').isTime(),
|
||||
TableColumn.new('oldValue', '原值').canBeautify(),
|
||||
TableColumn.new('action', '操作').isSlot().setMinWidth(90).fixedRight().alignCenter(),
|
||||
TableColumn.new('remark', 'common.remark'),
|
||||
TableColumn.new('status', 'common.status').typeTag(DbSqlExecStatusEnum),
|
||||
TableColumn.new('res', 'db.execRes'),
|
||||
TableColumn.new('createTime', 'db.execTime').isTime(),
|
||||
TableColumn.new('oldValue', 'db.oldValue').canBeautify(),
|
||||
TableColumn.new('action', 'common.operation').isSlot().setMinWidth(90).fixedRight().alignCenter(),
|
||||
]);
|
||||
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
|
||||
@@ -1,30 +1,37 @@
|
||||
<template>
|
||||
<div class="db-transfer-edit">
|
||||
<el-drawer :title="title" v-model="dialogVisible" :before-close="cancel" :destroy-on-close="true" :close-on-click-modal="false" size="40%">
|
||||
<el-drawer :title="title" v-model="dialogVisible" :before-close="cancel" :destroy-on-close="true" :close-on-click-modal="false" size="45%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="title" :back="cancel" />
|
||||
</template>
|
||||
|
||||
<el-form :model="form" ref="dbForm" :rules="rules" label-width="auto">
|
||||
<el-divider content-position="left">基本信息</el-divider>
|
||||
<el-divider content-position="left">{{ $t('common.basic') }}</el-divider>
|
||||
|
||||
<el-form-item prop="taskName" label="任务名" required>
|
||||
<el-input v-model.trim="form.taskName" placeholder="请输入任务名" auto-complete="off" />
|
||||
<el-form-item prop="taskName" :label="$t('db.taskName')" required>
|
||||
<el-input v-model.trim="form.taskName" auto-complete="off" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-row class="w100">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="status" label="启用状态">
|
||||
<el-switch v-model="form.status" inline-prompt active-text="启用" inactive-text="禁用" :active-value="1" :inactive-value="-1" />
|
||||
<el-form-item prop="status" :label="$t('common.status')">
|
||||
<el-switch
|
||||
v-model="form.status"
|
||||
inline-prompt
|
||||
:active-text="$t('common.enable')"
|
||||
:inactive-text="$t('common.disable')"
|
||||
:active-value="1"
|
||||
:inactive-value="-1"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="cronAble" label="定时迁移" required>
|
||||
<el-form-item prop="cronAble" :label="$t('db.cronAble')" required>
|
||||
<el-radio-group v-model="form.cronAble">
|
||||
<el-radio label="是" :value="1" />
|
||||
<el-radio label="否" :value="-1" />
|
||||
<el-radio :label="$t('common.yes')" :value="1" />
|
||||
<el-radio :label="$t('common.no')" :value="-1" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -35,9 +42,8 @@
|
||||
<CrontabInput v-model="form.cron" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="srcDbId" label="源数据库" class="w100" required>
|
||||
<el-form-item prop="srcDbId" :label="$t('db.srcDb')" class="w100" required>
|
||||
<db-select-tree
|
||||
placeholder="请选择源数据库"
|
||||
v-model:db-id="form.srcDbId"
|
||||
v-model:inst-name="form.srcInstName"
|
||||
v-model:db-name="form.srcDbName"
|
||||
@@ -47,18 +53,18 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="mode" label="迁移方式" required>
|
||||
<el-form-item prop="mode" :label="$t('db.transferMode')" required>
|
||||
<el-radio-group v-model="form.mode">
|
||||
<el-radio label="迁移到数据库" :value="1" />
|
||||
<el-radio label="迁移到文件(自动命名)" :value="2" />
|
||||
<el-radio :label="$t('db.transfer2Db')" :value="1" />
|
||||
<el-radio :label="$t('db.transfer2File')" :value="2" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.mode === 2">
|
||||
<el-row class="w100">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="targetFileDbType" label="文件数据库类型" :required="form.mode === 2">
|
||||
<el-select v-model="form.targetFileDbType" placeholder="数据库类型" clearable filterable>
|
||||
<el-form-item prop="targetFileDbType" :label="$t('db.dbFileType')" :required="form.mode === 2">
|
||||
<el-select v-model="form.targetFileDbType" clearable filterable>
|
||||
<el-option
|
||||
v-for="(dbTypeAndDialect, key) in getDbDialectMap()"
|
||||
:key="key"
|
||||
@@ -76,10 +82,10 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="文件保留天数">
|
||||
<el-form-item :label="$t('db.fileSaveDays')">
|
||||
<el-input-number v-model="form.fileSaveDays" :min="-1" :max="1000">
|
||||
<template #suffix>
|
||||
<span>天</span>
|
||||
<span>{{ $t('db.day') }}</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
@@ -87,16 +93,15 @@
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="strategy" label="迁移策略" required>
|
||||
<el-form-item prop="strategy" :label="$t('db.transferStrategy')" required>
|
||||
<el-radio-group v-model="form.strategy">
|
||||
<el-radio label="全量" :value="1" />
|
||||
<el-radio label="增量(暂不可用)" :value="2" disabled />
|
||||
<el-radio :label="$t('db.transferFull')" :value="1" />
|
||||
<el-radio :label="$t('db.transferIncrement')" :value="2" disabled />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.mode == 1" prop="targetDbId" label="目标数据库" class="w100" :required="form.mode === 1">
|
||||
<el-form-item v-if="form.mode == 1" prop="targetDbId" :label="$t('db.targetDb')" class="w100" :required="form.mode === 1">
|
||||
<db-select-tree
|
||||
placeholder="请选择目标数据库"
|
||||
v-model:db-id="form.targetDbId"
|
||||
v-model:inst-name="form.targetInstName"
|
||||
v-model:db-name="form.targetDbName"
|
||||
@@ -106,17 +111,17 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="nameCase" label="转换表、字段名" required>
|
||||
<el-form-item prop="nameCase" :label="$t('db.nameCase')" required>
|
||||
<el-radio-group v-model="form.nameCase">
|
||||
<el-radio label="无" :value="1" />
|
||||
<el-radio label="大写" :value="2" />
|
||||
<el-radio label="小写" :value="3" />
|
||||
<el-radio :label="$t('db.none')" :value="1" />
|
||||
<el-radio :label="$t('db.upper')" :value="2" />
|
||||
<el-radio :label="$t('db.lower')" :value="3" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider content-position="left">数据库对象</el-divider>
|
||||
<el-divider content-position="left">{{ $t('db.dbObj') }}</el-divider>
|
||||
<el-form-item>
|
||||
<el-input v-model="state.filterSrcTableText" placeholder="过滤表" size="small" />
|
||||
<el-input v-model="state.filterSrcTableText" placeholder="filter table" size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item class="w100">
|
||||
<el-tree
|
||||
@@ -136,8 +141,8 @@
|
||||
|
||||
<template #footer>
|
||||
<div>
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">确 定</el-button>
|
||||
<el-button @click="cancel()">{{ $t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">{{ $t('common.confirm') }}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
@@ -154,6 +159,10 @@ import { getDbDialect, getDbDialectMap } from '@/views/ops/db/dialect';
|
||||
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||
import _ from 'lodash';
|
||||
import DrawerHeader from '@/components/drawer-header/DrawerHeader.vue';
|
||||
import { useI18nFormValidate, useI18nPleaseInput, useI18nPleaseSelect, useI18nSaveSuccessMsg } from '@/hooks/useI18n';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
@@ -173,35 +182,35 @@ const rules = {
|
||||
taskName: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入任务名',
|
||||
message: useI18nPleaseInput('db.taskName'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
srcDbId: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择源库',
|
||||
message: useI18nPleaseSelect('db.srcDb'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
targetDbId: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择目标库',
|
||||
message: useI18nPleaseSelect('db.targetDb'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
targetFileDbType: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择目标文件语言类型',
|
||||
message: useI18nPleaseSelect('db.dbFileType'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
cron: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择cron表达式',
|
||||
message: useI18nPleaseSelect('cron'),
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
@@ -262,12 +271,12 @@ const state = reactive({
|
||||
srcTableTree: [
|
||||
{
|
||||
id: 'tab-check',
|
||||
label: '表',
|
||||
label: t('db.table'),
|
||||
children: [
|
||||
{ id: 'all', label: '全部表(*)' },
|
||||
{ id: 'all', label: `${t('db.allTable')}(*)` },
|
||||
{
|
||||
id: 'table-list',
|
||||
label: '自定义',
|
||||
label: t('db.custom'),
|
||||
disabled: srcTableListDisabled,
|
||||
children: [] as any[],
|
||||
},
|
||||
@@ -394,29 +403,23 @@ const getCheckedKeys = () => {
|
||||
};
|
||||
|
||||
const btnOk = async () => {
|
||||
dbForm.value.validate(async (valid: boolean) => {
|
||||
if (!valid) {
|
||||
ElMessage.error('请正确填写信息');
|
||||
return false;
|
||||
}
|
||||
await useI18nFormValidate(dbForm);
|
||||
state.submitForm = await getReqForm();
|
||||
|
||||
state.submitForm = await getReqForm();
|
||||
let checkedKeys = getCheckedKeys();
|
||||
if (checkedKeys.length > 0) {
|
||||
state.submitForm.checkedKeys = checkedKeys.join(',');
|
||||
}
|
||||
|
||||
let checkedKeys = getCheckedKeys();
|
||||
if (checkedKeys.length > 0) {
|
||||
state.submitForm.checkedKeys = checkedKeys.join(',');
|
||||
}
|
||||
if (!state.submitForm.checkedKeys) {
|
||||
ElMessage.error(t('db.noTransferTableMsg'));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!state.submitForm.checkedKeys) {
|
||||
ElMessage.error('请选择需要迁移的表');
|
||||
return false;
|
||||
}
|
||||
|
||||
await saveExec();
|
||||
ElMessage.success('保存成功');
|
||||
emit('val-change', state.form);
|
||||
cancel();
|
||||
});
|
||||
await saveExec();
|
||||
useI18nSaveSuccessMsg();
|
||||
emit('val-change', state.form);
|
||||
cancel();
|
||||
};
|
||||
|
||||
const cancel = () => {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user