🎨 Refactor save service

This commit is contained in:
2025-04-30 01:52:30 +08:00
parent d7a848e7ad
commit 198ba44ceb
17 changed files with 846 additions and 925 deletions

View File

@@ -5,6 +5,7 @@ import {useLogStore} from '@/stores/logStore';
import { useI18n } from 'vue-i18n';
import { ref } from 'vue';
import {SUPPORTED_LOCALES, setLocale, SupportedLocaleType} from '@/i18n';
import { EncodingType } from '@/../bindings/voidraft/internal/models/models';
const editorStore = useEditorStore();
const configStore = useConfigStore();
@@ -13,6 +14,20 @@ const { t, locale } = useI18n();
// 语言下拉菜单
const showLanguageMenu = ref(false);
// 编码下拉菜单
const showEncodingMenu = ref(false);
// 支持的编码格式
const SUPPORTED_ENCODINGS = [
{ code: EncodingType.EncodingUTF8, name: 'UTF-8' },
{ code: EncodingType.EncodingUTF8BOM, name: 'UTF-8 with BOM' },
{ code: EncodingType.EncodingUTF16LE, name: 'UTF-16 LE' },
{ code: EncodingType.EncodingUTF16BE, name: 'UTF-16 BE' },
{ code: EncodingType.EncodingISO88591, name: 'ISO-8859-1' },
{ code: EncodingType.EncodingGB18030, name: 'GB18030' },
{ code: EncodingType.EncodingGBK, name: 'GBK' },
{ code: EncodingType.EncodingBig5, name: 'Big5' }
];
// 切换语言
const changeLanguage = (localeCode: SupportedLocaleType) => {
@@ -23,6 +38,29 @@ const changeLanguage = (localeCode: SupportedLocaleType) => {
// 切换语言菜单显示
const toggleLanguageMenu = () => {
showLanguageMenu.value = !showLanguageMenu.value;
if (showLanguageMenu.value) {
showEncodingMenu.value = false;
}
};
// 切换编码
const changeEncoding = (encoding: EncodingType) => {
configStore.setEncoding(encoding);
showEncodingMenu.value = false;
};
// 切换编码菜单显示
const toggleEncodingMenu = () => {
showEncodingMenu.value = !showEncodingMenu.value;
if (showEncodingMenu.value) {
showLanguageMenu.value = false;
}
};
// 获取编码名称
const getEncodingDisplayName = (encoding: EncodingType) => {
const encodingItem = SUPPORTED_ENCODINGS.find(item => item.code === encoding);
return encodingItem ? encodingItem.name : encoding;
};
</script>
@@ -61,19 +99,37 @@ const toggleLanguageMenu = () => {
<button class="tab-btn" @click="configStore.increaseTabSize" :disabled="configStore.config.tabSize >= configStore.MAX_TAB_SIZE">+</button>
</span>
</span>
<span class="encoding">{{ t('toolbar.encoding') }}</span>
<!-- 编码选择按钮 -->
<div class="selector-dropdown">
<button class="selector-btn" @click="toggleEncodingMenu">
{{ getEncodingDisplayName(configStore.config.encoding) }}
<span class="arrow"></span>
</button>
<div class="selector-menu" v-if="showEncodingMenu">
<div
v-for="encoding in SUPPORTED_ENCODINGS"
:key="encoding.code"
class="selector-option"
:class="{ active: configStore.config.encoding === encoding.code }"
@click="changeEncoding(encoding.code)"
>
{{ encoding.name }}
</div>
</div>
</div>
<!-- 语言切换按钮 -->
<div class="language-selector">
<button class="language-btn" @click="toggleLanguageMenu">
<div class="selector-dropdown">
<button class="selector-btn" @click="toggleLanguageMenu">
{{ locale }}
<span class="arrow-up"></span>
<span class="arrow"></span>
</button>
<div class="language-menu" v-if="showLanguageMenu">
<div class="selector-menu" v-if="showLanguageMenu">
<div
v-for="lang in SUPPORTED_LOCALES"
:key="lang.code"
class="language-option"
class="selector-option"
:class="{ active: locale === lang.code }"
@click="changeLanguage(lang.code)"
>
@@ -200,17 +256,12 @@ const toggleLanguageMenu = () => {
}
}
}
.encoding {
color: var(--text-muted);
font-size: 11px;
}
/* 语言切换样式 */
.language-selector {
/* 通用下拉选择器样式 */
.selector-dropdown {
position: relative;
.language-btn {
.selector-btn {
background: none;
border: none;
color: var(--text-muted);
@@ -226,13 +277,13 @@ const toggleLanguageMenu = () => {
background-color: rgba(255, 255, 255, 0.05);
}
.arrow-up {
.arrow {
font-size: 8px;
margin-left: 2px;
}
}
.language-menu {
.selector-menu {
position: absolute;
bottom: 100%;
right: 0;
@@ -240,11 +291,13 @@ const toggleLanguageMenu = () => {
border: 1px solid var(--border-color);
border-radius: 3px;
margin-bottom: 4px;
min-width: 100px;
min-width: 120px;
max-height: 200px;
overflow-y: auto;
z-index: 1000;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
.language-option {
.selector-option {
padding: 4px 8px;
cursor: pointer;
font-size: 11px;

View File

@@ -43,14 +43,12 @@ const i18n = createI18n({
GetLanguage().then(lang => {
if (lang) {
i18n.global.locale = lang as any;
document.documentElement.setAttribute('lang', lang);
}
}).catch(error => {
console.error('Failed to get language from backend:', error);
// 如果获取失败,使用浏览器语言作为后备
const browserLang = getBrowserLanguage();
i18n.global.locale = browserLang as any;
document.documentElement.setAttribute('lang', browserLang);
});
// 切换语言的方法

View File

@@ -1,21 +1,11 @@
import {createApp} from 'vue';
import App from './App.vue';
import '@/assets/styles/index.css';
import PrimeVue from 'primevue/config';
import Aura from '@primeuix/themes/aura';
import {createPinia} from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
import i18n from './i18n';
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
const app = createApp(App);
app.use(pinia)
app.use(PrimeVue, {
theme: {
preset: Aura
}
});
app.use(i18n);
app.mount('#app');

View File

@@ -3,10 +3,10 @@ import {ref, watch} from 'vue';
import {useDebounceFn} from '@vueuse/core';
import {
GetEditorConfig,
ResetToDefault,
ResetConfig,
UpdateEditorConfig
} from '@/../bindings/voidraft/internal/services/configservice';
import {EditorConfig, TabType} from '@/../bindings/voidraft/internal/models/models';
import {EditorConfig, TabType, EncodingType} from '@/../bindings/voidraft/internal/models/models';
import {useLogStore} from './logStore';
import { useI18n } from 'vue-i18n';
@@ -20,6 +20,26 @@ const DEFAULT_TAB_SIZE = 4;
const MIN_TAB_SIZE = 2;
const MAX_TAB_SIZE = 8;
// 支持的编码
const SUPPORTED_ENCODINGS = [
EncodingType.EncodingUTF8,
EncodingType.EncodingUTF8BOM,
EncodingType.EncodingUTF16LE,
EncodingType.EncodingUTF16BE,
EncodingType.EncodingISO88591,
EncodingType.EncodingGB18030,
EncodingType.EncodingGBK,
EncodingType.EncodingBig5
];
// 配置项限制定义
const CONFIG_LIMITS = {
fontSize: { min: MIN_FONT_SIZE, max: MAX_FONT_SIZE, default: DEFAULT_FONT_SIZE },
tabSize: { min: MIN_TAB_SIZE, max: MAX_TAB_SIZE, default: DEFAULT_TAB_SIZE },
tabType: { values: [TabType.TabTypeSpaces, TabType.TabTypeTab], default: TabType.TabTypeSpaces },
encoding: { values: SUPPORTED_ENCODINGS, default: EncodingType.EncodingUTF8 }
};
export const useConfigStore = defineStore('config', () => {
// 获取日志store
const logStore = useLogStore();
@@ -28,7 +48,7 @@ export const useConfigStore = defineStore('config', () => {
// 配置状态
const config = ref<EditorConfig>(new EditorConfig({
fontSize: DEFAULT_FONT_SIZE,
encoding: 'UTF-8',
encoding: EncodingType.EncodingUTF8,
enableTabIndent: true,
tabSize: DEFAULT_TAB_SIZE,
tabType: TabType.TabTypeSpaces
@@ -58,42 +78,44 @@ export const useConfigStore = defineStore('config', () => {
let hasChanges = false;
// 验证字体大小
if (config.value.fontSize < MIN_FONT_SIZE || config.value.fontSize > MAX_FONT_SIZE) {
if (config.value.fontSize < CONFIG_LIMITS.fontSize.min || config.value.fontSize > CONFIG_LIMITS.fontSize.max) {
const oldValue = config.value.fontSize;
config.value.fontSize = oldValue < MIN_FONT_SIZE ? MIN_FONT_SIZE :
oldValue > MAX_FONT_SIZE ? MAX_FONT_SIZE :
DEFAULT_FONT_SIZE;
config.value.fontSize = oldValue < CONFIG_LIMITS.fontSize.min ? CONFIG_LIMITS.fontSize.min :
oldValue > CONFIG_LIMITS.fontSize.max ? CONFIG_LIMITS.fontSize.max :
CONFIG_LIMITS.fontSize.default;
logStore.warning(t('config.fontSizeFixed', {
value: oldValue,
fixed: config.value.fontSize
}));
logStore.warning(t('config.fontSizeFixed'));
hasChanges = true;
}
// 验证Tab大小
if (config.value.tabSize < MIN_TAB_SIZE || config.value.tabSize > MAX_TAB_SIZE) {
if (config.value.tabSize < CONFIG_LIMITS.tabSize.min || config.value.tabSize > CONFIG_LIMITS.tabSize.max) {
const oldValue = config.value.tabSize;
config.value.tabSize = oldValue < MIN_TAB_SIZE ? MIN_TAB_SIZE :
oldValue > MAX_TAB_SIZE ? MAX_TAB_SIZE :
DEFAULT_TAB_SIZE;
config.value.tabSize = oldValue < CONFIG_LIMITS.tabSize.min ? CONFIG_LIMITS.tabSize.min :
oldValue > CONFIG_LIMITS.tabSize.max ? CONFIG_LIMITS.tabSize.max :
CONFIG_LIMITS.tabSize.default;
logStore.warning(t('config.tabSizeFixed', {
value: oldValue,
fixed: config.value.tabSize
}));
logStore.warning(t('config.tabSizeFixed'));
hasChanges = true;
}
// 验证TabType是否合法
const validTabTypes = [TabType.TabTypeSpaces, TabType.TabTypeTab];
if (!validTabTypes.includes(config.value.tabType)) {
if (!CONFIG_LIMITS.tabType.values.includes(config.value.tabType)) {
const oldValue = config.value.tabType;
config.value.tabType = TabType.TabTypeSpaces;
config.value.tabType = CONFIG_LIMITS.tabType.default;
logStore.warning(t('config.tabTypeFixed', { value: oldValue }));
logStore.warning(t('config.tabTypeFixed'));
hasChanges = true;
}
// 验证编码类型是否合法
if (!CONFIG_LIMITS.encoding.values.includes(config.value.encoding)) {
const oldValue = config.value.encoding;
config.value.encoding = CONFIG_LIMITS.encoding.default;
logStore.warning(t('config.encodingFixed'));
hasChanges = true;
}
@@ -121,67 +143,69 @@ export const useConfigStore = defineStore('config', () => {
}
}, {deep: true});
// 字体缩放
function increaseFontSize() {
if (config.value.fontSize < MAX_FONT_SIZE) {
config.value.fontSize += 1;
// 更新特定配置项的类型安全方法
function updateConfig<K extends keyof EditorConfig>(
key: K,
value: EditorConfig[K] | ((currentValue: EditorConfig[K]) => EditorConfig[K])
) {
if (typeof value === 'function') {
const currentValue = config.value[key];
const fn = value as (val: EditorConfig[K]) => EditorConfig[K];
config.value[key] = fn(currentValue);
} else {
config.value[key] = value;
}
}
// 字体缩小
function decreaseFontSize() {
if (config.value.fontSize > MIN_FONT_SIZE) {
config.value.fontSize -= 1;
}
// 用于数字类型配置的增减方法
function adjustFontSize(amount: number) {
let newValue = config.value.fontSize + amount;
if (newValue < MIN_FONT_SIZE) newValue = MIN_FONT_SIZE;
if (newValue > MAX_FONT_SIZE) newValue = MAX_FONT_SIZE;
config.value.fontSize = newValue;
}
// 重置字体大小
function resetFontSize() {
config.value.fontSize = DEFAULT_FONT_SIZE;
function adjustTabSize(amount: number) {
let newValue = config.value.tabSize + amount;
if (newValue < MIN_TAB_SIZE) newValue = MIN_TAB_SIZE;
if (newValue > MAX_TAB_SIZE) newValue = MAX_TAB_SIZE;
config.value.tabSize = newValue;
}
// 设置编码
function setEncoding(newEncoding: string) {
config.value.encoding = newEncoding;
}
// Tab相关方法
function toggleTabIndent() {
config.value.enableTabIndent = !config.value.enableTabIndent;
}
// 增加Tab大小
function increaseTabSize() {
if (config.value.tabSize < MAX_TAB_SIZE) {
config.value.tabSize += 1;
}
}
// 减少Tab大小
function decreaseTabSize() {
if (config.value.tabSize > MIN_TAB_SIZE) {
config.value.tabSize -= 1;
}
}
// 切换Tab类型空格或制表符
// Tab相关类型安全的配置切换
function toggleTabType() {
config.value.tabType = config.value.tabType === TabType.TabTypeSpaces
? TabType.TabTypeTab
config.value.tabType = config.value.tabType === TabType.TabTypeSpaces
? TabType.TabTypeTab
: TabType.TabTypeSpaces;
}
// 设置编码类型
function setEncoding(encoding: string) {
// 验证编码是否有效的EncodingType
const encodingType = encoding as EncodingType;
if (SUPPORTED_ENCODINGS.includes(encodingType)) {
config.value.encoding = encodingType;
} else {
logStore.warning(t('config.invalidEncoding'));
}
}
// 重置为默认配置
async function resetToDefaults() {
try {
await ResetToDefault();
await loadConfigFromBackend();
await ResetConfig();
await loadConfigFromBackend();
logStore.info(t('config.resetSuccess'));
} catch (error) {
console.error('Failed to reset configuration:', error);
logStore.error(t('config.resetFailed'));
}
}
return {
// 状态
config,
@@ -193,18 +217,26 @@ export const useConfigStore = defineStore('config', () => {
DEFAULT_FONT_SIZE,
MIN_TAB_SIZE,
MAX_TAB_SIZE,
SUPPORTED_ENCODINGS,
// 方法
// 核心方法
loadConfigFromBackend,
saveConfigToBackend,
updateConfig,
resetToDefaults,
// 字体大小方法
increaseFontSize: () => adjustFontSize(1),
decreaseFontSize: () => adjustFontSize(-1),
resetFontSize: () => updateConfig('fontSize', DEFAULT_FONT_SIZE),
// 编码操作
setEncoding,
increaseFontSize,
decreaseFontSize,
resetFontSize,
toggleTabIndent,
increaseTabSize,
decreaseTabSize,
toggleTabType,
resetToDefaults
// Tab操作
toggleTabIndent: () => updateConfig('enableTabIndent', val => !val),
increaseTabSize: () => adjustTabSize(1),
decreaseTabSize: () => adjustTabSize(-1),
toggleTabType
};
});

View File

@@ -43,9 +43,6 @@ export const useEditorStore = defineStore('editor', () => {
documentStats,
editorView,
// 配置引用
config: configStore.config,
// 方法
setEditorView,
updateDocumentStats,