Русифицировать README и интерфейс HY2XS admin

This commit is contained in:
2026-04-25 23:51:21 +05:00
parent 84a4e94567
commit 2b4a45ad23
167 changed files with 632 additions and 699 deletions
@@ -43,3 +43,5 @@ const tagsViewStore = useTagsViewStore();
}
}
</style>
+18 -16
View File
@@ -12,27 +12,27 @@ const accountStore = useAccountStore();
const route = useRoute();
const router = useRouter();
const { device } = storeToRefs(appStore); // 设备类型:desktop-宽屏设备 || mobile-窄屏设备
const { device } = storeToRefs(appStore); // Тип устройства: desktop — широкий экран, mobile — узкий экран
/**
* 左侧菜单栏显示/隐藏
* Показать или скрыть левое меню.
*/
function toggleSideBar() {
appStore.toggleSidebar(true);
}
/**
* vueUse 全屏
* Полноэкранный режим через VueUse.
*/
const { isFullscreen, toggle } = useFullscreen();
/**
* 注销
* Выход из системы.
*/
function logout() {
ElMessageBox.confirm("确定注销并退出系统吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
ElMessageBox.confirm("Выйти из системы?", "Подтверждение", {
confirmButtonText: "Выйти",
cancelButtonText: "Отмена",
type: "warning",
}).then(() => {
accountStore
@@ -48,9 +48,9 @@ function logout() {
</script>
<template>
<!-- 顶部导航栏 -->
<!-- Верхняя навигационная панель -->
<div class="navbar">
<!-- 左侧面包屑 -->
<!-- Хлебные крошки слева -->
<div class="flex">
<hamburger
:is-active="appStore.sidebar.opened"
@@ -59,25 +59,25 @@ function logout() {
<breadcrumb />
</div>
<!-- 右侧导航设置 -->
<!-- Настройки навигации справа -->
<div class="flex">
<!-- 导航栏设置(窄屏隐藏)-->
<!-- Настройки навигации, скрытые на узком экране -->
<div class="setting-container" v-if="device !== 'mobile'">
<!--全屏 -->
<!-- Полноэкранный режим -->
<div class="setting-item" @click="toggle">
<svg-icon
:icon-class="isFullscreen ? 'exit-fullscreen' : 'fullscreen'"
/>
</div>
<!-- 布局大小 -->
<el-tooltip content="布局大小" effect="dark" placement="bottom">
<!-- Размер интерфейса -->
<el-tooltip content="Размер интерфейса" effect="dark" placement="bottom">
<size-select class="setting-item" />
</el-tooltip>
<!--语言选择-->
<!-- Выбор языка -->
<lang-select class="setting-item" />
</div>
<!-- 用户头像 -->
<!-- Аватар пользователя -->
<el-dropdown trigger="click">
<div class="avatar-container">
<img src="/src/assets/logo.png" />
@@ -138,3 +138,5 @@ function logout() {
}
}
</style>
@@ -5,21 +5,21 @@ import IconEpSunny from "~icons/ep/sunny";
import IconEpMoon from "~icons/ep/moon";
/**
* 暗黑模式
* Тёмная тема.
*/
const settingsStore = useSettingsStore();
const isDark = useDark();
const toggleDark = () => useToggle(isDark);
/**
* 切换布局
* Переключение layout.
*/
function changeLayout(layout: string) {
settingsStore.changeSetting({ key: "layout", value: layout });
window.document.body.setAttribute("layout", settingsStore.layout);
}
// 主题颜色
// Цвета темы
const themeColors = ref<string[]>([
"#409EFF",
"#304156",
@@ -30,7 +30,7 @@ const themeColors = ref<string[]>([
]);
/**
* 切换主题颜色
* Переключение цвета темы.
*/
function changeThemeColor(color: string) {
settingsStore.changeSetting({ key: "themeColor", value: color });
@@ -51,8 +51,8 @@ onMounted(() => {
<template>
<div class="settings-container">
<h3 class="text-base font-bold">项目配置</h3>
<el-divider>主题</el-divider>
<h3 class="text-base font-bold">Настройки проекта</h3>
<el-divider>Тема</el-divider>
<div class="flex justify-center" @click.stop>
<el-switch
@@ -66,23 +66,23 @@ onMounted(() => {
/>
</div>
<el-divider>界面设置</el-divider>
<el-divider>Настройки интерфейса</el-divider>
<div class="py-[8px] flex justify-between">
<span class="text-xs">开启 Tags-View</span>
<span class="text-xs">Включить вкладки</span>
<el-switch v-model="settingsStore.tagsView" />
</div>
<div class="py-[8px] flex justify-between">
<span class="text-xs">固定 Header</span>
<span class="text-xs">Зафиксировать header</span>
<el-switch v-model="settingsStore.fixedHeader" />
</div>
<div class="py-[8px] flex justify-between">
<span class="text-xs">侧边栏 Logo</span>
<span class="text-xs">Логотип в боковом меню</span>
<el-switch v-model="settingsStore.sidebarLogo" />
</div>
<el-divider>主题颜色</el-divider>
<el-divider>Цвет темы</el-divider>
<ul class="w-full space-x-2 flex justify-center py-2">
<li
@@ -163,3 +163,5 @@ onMounted(() => {
}
}
</style>
@@ -35,3 +35,5 @@ function push() {
<slot />
</div>
</template>
@@ -51,3 +51,5 @@ const logo = ref(new URL(`../../../assets/logo.png`, import.meta.url).href);
opacity: 0;
}
</style>
@@ -8,7 +8,7 @@ import SvgIcon from "@/components/SvgIcon/index.vue";
const props = defineProps({
/**
* 路由(eg:level_3_1)
* Route, например level_3_1
*/
item: {
type: Object,
@@ -16,7 +16,7 @@ const props = defineProps({
},
/**
* 父层级完整路由路径(eg:/level/level_3/level_3_1)
* Полный path родительского уровня, например /level/level_3/level_3_1
*/
basePath: {
type: String,
@@ -24,34 +24,34 @@ const props = defineProps({
},
});
const onlyOneChild = ref(); // 临时变量,唯一子路由
const onlyOneChild = ref(); // Временная переменная для единственного дочернего route
/**
* 判断当前路由是否只有一个子路由
* Проверяет, есть ли у текущего route только один дочерний route
*
* 1:如果只有一个子路由: 返回 true
* 2:如果无子路由 :返回 true
* 1: если дочерний route один, возвращает true
* 2: если дочерних routes нет, возвращает true
*
* @param children 子路由数组
* @param parent 当前路由
* @param children Массив дочерних routes
* @param parent Текущий route
*/
function hasOneShowingChild(children = [], parent: any) {
// 需要显示的子路由数组
// Массив дочерних routes для отображения
const showingChildren = children.filter((item: any) => {
if (item.meta?.hidden) {
return false; // 过滤不显示的子路由
return false; // Фильтрация скрытого дочернего route
} else {
onlyOneChild.value = item; // 唯一子路由赋值(多个子路由情况 onlyOneChild 变量是用不上的)
onlyOneChild.value = item; // Запись единственного дочернего route, при нескольких routes переменная onlyOneChild не используется
return true;
}
});
// 1:如果只有一个子路由, 返回 true
// 1: если дочерний route один, возвращает true
if (showingChildren.length === 1) {
return true;
}
// 2:如果无子路由, 复制当前路由信息作为其子路由,满足只拥有一个子路由的条件,所以返回 true
// 2: если дочерних routes нет, копирует текущий route как дочерний и возвращает true
if (showingChildren.length === 0) {
onlyOneChild.value = { ...parent, path: "", noShowingChildren: true };
return true;
@@ -60,9 +60,9 @@ function hasOneShowingChild(children = [], parent: any) {
}
/**
* 解析路径
* Разбор path
*
* @param routePath 路由路径
* @param routePath Route path
*/
function resolvePath(routePath: string) {
if (isExternal(routePath)) {
@@ -71,14 +71,14 @@ function resolvePath(routePath: string) {
if (isExternal(props.basePath)) {
return props.basePath;
}
// 完整路径 = 父级路径(/level/level_3) + 路由路径
const fullPath = path.resolve(props.basePath, routePath); // 相对路径 → 绝对路径
// Полный path = parent path (/level/level_3) + route path
const fullPath = path.resolve(props.basePath, routePath); // Relative path → absolute path
return fullPath;
}
</script>
<template>
<div v-if="!item.meta || !item.meta.hidden">
<!-- 只包含一个子路由节点的路由显示其唯一子路由 -->
<!-- Route с одним дочерним route показывает этот единственный дочерний route -->
<template
v-if="
hasOneShowingChild(item.children, item) &&
@@ -98,7 +98,7 @@ function resolvePath(routePath: string) {
</app-link>
</template>
<!-- 包含多个子路由 -->
<!-- Содержит несколько дочерних routes -->
<el-sub-menu v-else :index="resolvePath(item.path)" teleported>
<template #title>
<svg-icon
@@ -119,3 +119,5 @@ function resolvePath(routePath: string) {
</el-sub-menu>
</div>
</template>
@@ -43,3 +43,5 @@ const route = useRoute();
</el-scrollbar>
</div>
</template>
@@ -119,3 +119,5 @@ defineExpose({
}
}
</style>
@@ -41,12 +41,12 @@ watch(
moveToCurrentTag();
},
{
//初始化立即执行
// Выполнить сразу при инициализации
immediate: true,
}
);
const tagMenuVisible = ref(false); // 标签操作菜单显示状态
const tagMenuVisible = ref(false); // Состояние отображения меню действий с вкладкой
watch(tagMenuVisible, (value) => {
if (value) {
document.body.addEventListener("click", closeTagMenu);
@@ -264,7 +264,7 @@ onMounted(() => {
</router-link>
</scroll-pane>
<!-- tag标签操作菜单 -->
<!-- Меню действий с вкладкой -->
<ul
v-show="tagMenuVisible"
class="tag-menu"
@@ -272,27 +272,27 @@ onMounted(() => {
>
<li @click="refreshSelectedTag(selectedTag)">
<svg-icon icon-class="refresh" />
刷新
Обновить
</li>
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">
<svg-icon icon-class="close" />
关闭
Закрыть
</li>
<li @click="closeOtherTags">
<svg-icon icon-class="close_other" />
关闭其它
Закрыть остальные
</li>
<li v-if="!isFirstView()" @click="closeLeftTags">
<svg-icon icon-class="close_left" />
关闭左侧
Закрыть слева
</li>
<li v-if="!isLastView()" @click="closeRightTags">
<svg-icon icon-class="close_right" />
关闭右侧
Закрыть справа
</li>
<li @click="closeAllTags(selectedTag)">
<svg-icon icon-class="close_all" />
关闭所有
Закрыть все
</li>
</ul>
</div>
@@ -371,3 +371,5 @@ onMounted(() => {
}
}
</style>
@@ -2,3 +2,5 @@ export { default as Navbar } from "./Navbar.vue";
export { default as AppMain } from "./AppMain.vue";
export { default as Settings } from "./Settings/index.vue";
export { default as TagsView } from "./TagsView/index.vue";
+10 -8
View File
@@ -11,11 +11,11 @@ import { useSettingsStore } from "@/store/modules/settings";
const { width } = useWindowSize();
/**
* 响应式布局容器固定宽度
* Фиксированная ширина контейнера адаптивного layout
*
* 大屏>=1200px
* 中屏>=992px
* 小屏>=768px
* Большой экран>=1200px
* Средний экран>=992px
* Малый экран>=768px
*/
const WIDTH = 992;
@@ -41,7 +41,7 @@ watchEffect(() => {
appStore.toggleDevice("desktop");
if (width.value >= 1200) {
//大屏
//Большой экран
appStore.openSideBar(true);
} else {
appStore.closeSideBar(true);
@@ -56,7 +56,7 @@ function handleOutsideClick() {
<template>
<div :class="classObj" class="app-wrapper">
<!-- 手机设备侧边栏打开遮罩层 -->
<!-- Overlay открытого бокового меню на мобильных устройствах -->
<div
v-if="classObj.mobile && classObj.openSidebar"
class="drawer-bg"
@@ -71,10 +71,10 @@ function handleOutsideClick() {
<tags-view v-if="showTagsView" />
</div>
<!--主页面-->
<!--Основная страница-->
<app-main />
<!-- 设置面板 -->
<!-- Панель настроек -->
<RightPanel v-if="showSettings">
<settings />
</RightPanel>
@@ -127,3 +127,5 @@ function handleOutsideClick() {
opacity: 0.3;
}
</style>