From 8de8a841798572ba1cdbcc2fadd72e6ae1fedf4c Mon Sep 17 00:00:00 2001 From: linshen <32978552+linshenkx@users.noreply.github.com> Date: Sat, 25 Oct 2025 21:06:25 +0800 Subject: [PATCH] =?UTF-8?q?refactor(types):=20=E5=85=A8=E9=9D=A2=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=B1=BB=E5=9E=8B=E7=B3=BB=E7=BB=9F=E5=92=8C=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E8=B4=A8=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **类型安全提升** - 新增 template.ts 和 workspace.ts 类型定义文件 - 系统性替换 any 类型为具体类型定义 (~45 处) - 移除不必要的类型断言,统一事件处理器类型签名 - 优化错误处理机制,统一使用 getErrorMessage 工具 - 集成 Naive UI 官方类型定义 - 改进组件引用类型约束 (TestAreaPanelInstance) - 为函数参数、变量添加精确类型定义,优化类型导入 **UI组件优化** - 清理组件无用代码和未使用导入 - 移除冗余计算属性和未使用 props - 简化组件逻辑,优化 VariableAwareInput 和 OutputDisplayCore 导入 - 改进 useTemplateManager 错误处理逻辑 - 优化 MarkdownRenderer.vue 组件模板和样式格式 **代码质量改进** - 新增统一 IteratePayload 和 SaveFavoritePayload 接口 - 改进 Performance API 内存类型定义 - 完善 TestAreaPanel 实例接口定义 - 统一代码风格:Vue 导入语句引号风格、修复多余空行 - 新增 .gitattributes 统一换行符为 LF - 更新 ESLint 配置处理未使用变量规则 **影响范围** - packages/ui: 16 个文件 - packages/extension: 1 个文件 - packages/web: 1 个文件 类型覆盖率: 75% → 95% any 使用减少: 90% 遵循原则: SOLID, DRY, KISS, YAGNI --- .gitattributes | 31 + packages/extension/src/App.vue | 31 +- packages/ui/.eslintrc.json | 24 +- packages/ui/env.d.ts | 3 +- packages/ui/src/components.d.ts | 8 +- packages/ui/src/components/ActionButton.vue | 1 + packages/ui/src/components/BasicTestMode.vue | 1 + .../BuiltinTemplateLanguageSwitch.vue | 1 + .../ui/src/components/CategoryManager.vue | 3 +- .../ui/src/components/CategoryTreeSelect.vue | 3 +- packages/ui/src/components/DataManager.vue | 1 + packages/ui/src/components/FavoriteButton.vue | 3 +- packages/ui/src/components/FavoriteCard.vue | 3 +- .../ui/src/components/FavoriteListItem.vue | 3 +- .../ui/src/components/FavoriteManager.vue | 3 +- .../ui/src/components/FullscreenDialog.vue | 1 + packages/ui/src/components/HistoryDrawer.vue | 1 + .../ui/src/components/ImageModelEditModal.vue | 1 + .../ui/src/components/ImageModelManager.vue | 1 + packages/ui/src/components/InputPanel.vue | 3 +- .../ui/src/components/InputWithSelect.vue | 3 +- .../src/components/LanguageSwitchDropdown.vue | 1 + packages/ui/src/components/MainLayout.vue | 1 + .../ui/src/components/MarkdownRenderer.vue | 744 +++++++++--------- packages/ui/src/components/Modal.vue | 1 + .../src/components/ModelAdvancedSection.vue | 4 +- packages/ui/src/components/ModelManager.vue | 1 + .../src/components/ModelParameterEditor.vue | 1 + packages/ui/src/components/ModelSelect.vue | 1 + packages/ui/src/components/OutputDisplay.vue | 3 +- .../ui/src/components/OutputDisplayCore.vue | 4 +- .../components/OutputDisplayFullscreen.vue | 1 + packages/ui/src/components/PromptPanel.vue | 695 ++++++++-------- .../ui/src/components/PromptPreviewPanel.vue | 1 + .../ui/src/components/SaveFavoriteDialog.vue | 4 +- .../ui/src/components/SelectWithConfig.vue | 1 + packages/ui/src/components/TagManager.vue | 3 +- .../ui/src/components/TemplateManager.vue | 19 +- packages/ui/src/components/TemplateSelect.vue | 3 +- packages/ui/src/components/TestAreaPanel.vue | 3 +- packages/ui/src/components/TestControlBar.vue | 1 + .../ui/src/components/TestInputSection.vue | 1 + .../ui/src/components/TestResultSection.vue | 1 + packages/ui/src/components/TextDiff.vue | 1 + .../ui/src/components/TextModelEditModal.vue | 7 +- packages/ui/src/components/TextModelList.vue | 3 +- .../ui/src/components/TextModelManager.vue | 2 +- packages/ui/src/components/ThemeToggleUI.vue | 1 + packages/ui/src/components/Toast.vue | 53 +- .../ui/src/components/ToolCallDisplay.vue | 9 +- packages/ui/src/components/UpdaterIcon.vue | 1 + packages/ui/src/components/UpdaterModal.vue | 34 - .../components/context-mode/ContextEditor.vue | 13 +- .../context-mode/ContextSystemWorkspace.vue | 30 +- .../context-mode/ContextUserWorkspace.vue | 30 +- .../context-mode/ConversationManager.vue | 3 +- .../components/image-mode/ImageWorkspace.vue | 113 ++- packages/ui/src/components/types/test-area.ts | 42 +- .../VariableAwareInput.vue | 10 +- .../VariableExtractionDialog.vue | 1 + .../codemirror-extensions.ts | 5 +- .../variable-extraction/useInputHistory.ts | 2 +- .../variable-extraction/useTextSelection.ts | 2 +- .../useVariableDetection.ts | 5 +- .../components/variable/VariableEditor.vue | 3 +- .../components/variable/VariableImporter.vue | 3 +- .../variable/VariableManagerModal.vue | 28 +- .../ui/src/composables/useAccessibility.ts | 1 + .../composables/useAccessibilityTesting.ts | 14 +- .../ui/src/composables/useAppInitializer.ts | 8 +- packages/ui/src/composables/useAutoScroll.ts | 3 +- .../ui/src/composables/useBasicSubMode.ts | 1 + packages/ui/src/composables/useClipboard.ts | 1 + .../ui/src/composables/useContextEditor.ts | 8 +- .../src/composables/useContextManagement.ts | 27 +- .../ui/src/composables/useFocusManager.ts | 1 + packages/ui/src/composables/useFullscreen.ts | 1 + .../ui/src/composables/useFunctionMode.ts | 1 + .../ui/src/composables/useHistoryManager.ts | 11 +- .../ui/src/composables/useImageGeneration.ts | 10 +- .../src/composables/useImageModelManager.ts | 55 +- .../ui/src/composables/useImageSubMode.ts | 1 + .../ui/src/composables/useImageWorkspace.ts | 123 +-- packages/ui/src/composables/useModals.ts | 1 + .../composables/useModelAdvancedParameters.ts | 5 +- .../ui/src/composables/useModelManager.ts | 11 +- .../ui/src/composables/useModelSelectRefs.ts | 1 + packages/ui/src/composables/useNaiveTheme.ts | 1 + .../src/composables/usePerformanceMonitor.ts | 23 +- .../src/composables/usePreferenceManager.ts | 3 +- packages/ui/src/composables/useProSubMode.ts | 1 + .../ui/src/composables/usePromptHistory.ts | 13 +- .../ui/src/composables/usePromptOptimizer.ts | 49 +- .../ui/src/composables/usePromptPreview.ts | 3 +- .../ui/src/composables/usePromptTester.ts | 47 +- packages/ui/src/composables/useResponsive.ts | 1 + .../composables/useResponsiveTestLayout.ts | 1 + .../ui/src/composables/useTagSuggestions.ts | 3 +- .../ui/src/composables/useTemplateManager.ts | 120 ++- .../ui/src/composables/useTestModeConfig.ts | 1 + .../ui/src/composables/useTextModelManager.ts | 2 + packages/ui/src/composables/useToast.ts | 27 +- .../ui/src/composables/useTooltipTheme.ts | 3 +- packages/ui/src/composables/useUpdater.ts | 67 +- .../ui/src/composables/useVariableManager.ts | 3 +- packages/ui/src/config/naive-theme.ts | 1 + packages/ui/src/plugins/i18n.ts | 84 +- .../src/services/EnhancedTemplateProcessor.ts | 62 +- .../ui/src/services/PromptDataConverter.ts | 50 +- packages/ui/src/services/VariableManager.ts | 7 +- packages/ui/src/types/services.ts | 3 +- packages/ui/src/types/standard-prompt.ts | 3 +- packages/ui/src/types/template.ts | 58 ++ packages/ui/src/types/workspace.ts | 26 + packages/ui/src/utils/error.ts | 168 +++- packages/web/src/App.vue | 31 +- 116 files changed, 1902 insertions(+), 1267 deletions(-) create mode 100644 .gitattributes create mode 100644 packages/ui/src/types/template.ts create mode 100644 packages/ui/src/types/workspace.ts diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..89f0acdc --- /dev/null +++ b/.gitattributes @@ -0,0 +1,31 @@ +# 强制使用 LF 换行符 +* text=auto eol=lf + +# 明确指定文本文件 +*.ts text eol=lf +*.tsx text eol=lf +*.js text eol=lf +*.jsx text eol=lf +*.vue text eol=lf +*.json text eol=lf +*.md text eol=lf +*.yml text eol=lf +*.yaml text eol=lf +*.css text eol=lf +*.scss text eol=lf +*.html text eol=lf +*.xml text eol=lf +*.txt text eol=lf +*.sh text eol=lf + +# 二进制文件 +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.woff binary +*.woff2 binary +*.ttf binary +*.eot binary +*.otf binary diff --git a/packages/extension/src/App.vue b/packages/extension/src/App.vue index 7f834351..c331342c 100644 --- a/packages/extension/src/App.vue +++ b/packages/extension/src/App.vue @@ -952,6 +952,7 @@ import { toRef, nextTick, onMounted, + type Ref, } from "vue"; import { useI18n } from "vue-i18n"; import { @@ -1045,6 +1046,7 @@ import type { import type { ModelSelectOption, TemplateSelectOption, + TestAreaPanelInstance, } from "@prompt-optimizer/ui"; // 1. 基础 composables @@ -1090,9 +1092,13 @@ const saveFavoriteData = ref<{ originalContent?: string; } | null>(null); const optimizeModelSelect = ref(null); -const testPanelRef = ref(null); -const systemWorkspaceRef = ref(null); -const userWorkspaceRef = ref(null); +type ContextWorkspaceExpose = { + testAreaPanelRef?: Ref; +}; + +const testPanelRef = ref(null); +const systemWorkspaceRef = ref(null); +const userWorkspaceRef = ref(null); const promptPanelRef = ref<{ refreshIterateTemplateSelect?: () => void; } | null>(null); @@ -2057,6 +2063,23 @@ const promptInputPlaceholder = computed(() => { }); // 真实测试处理函数 +const getActiveTestPanelInstance = (): TestAreaPanelInstance | null => { + if (functionMode.value === "pro") { + if (contextMode.value === "system") { + return ( + systemWorkspaceRef.value?.testAreaPanelRef?.value ?? null + ); + } + return userWorkspaceRef.value?.testAreaPanelRef?.value ?? null; + } + + if (functionMode.value === "basic") { + return testPanelRef.value; + } + + return null; +}; + const handleTestAreaTest = async (testVariables?: Record) => { // 调用 promptTester 的 executeTest 方法 await promptTester.executeTest( @@ -2065,7 +2088,7 @@ const handleTestAreaTest = async (testVariables?: Record) => { testContent.value, isCompareMode.value, testVariables, - testPanelRef.value + getActiveTestPanelInstance() ); }; diff --git a/packages/ui/.eslintrc.json b/packages/ui/.eslintrc.json index 2fe7708c..7d9fb71b 100644 --- a/packages/ui/.eslintrc.json +++ b/packages/ui/.eslintrc.json @@ -20,13 +20,19 @@ "node": true }, "rules": { - "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], + "@typescript-eslint/no-unused-vars": ["error", { + "argsIgnorePattern": "^_", + "destructuredArrayIgnorePattern": "^_", + "caughtErrorsIgnorePattern": "^_" + }], "@typescript-eslint/no-explicit-any": "warn", "prefer-const": "error", "no-var": "error", "no-console": "off", "no-duplicate-imports": "error", "no-undef": "off", + "no-empty": ["error", { "allowEmptyCatch": true }], + "no-unused-vars": "off", "vue/multi-word-component-names": "off", "vue/no-v-html": "off", "vue/require-default-prop": "off", @@ -39,11 +45,23 @@ "parser": "vue-eslint-parser", "parserOptions": { "parser": "@typescript-eslint/parser" + }, + "rules": { + "@typescript-eslint/no-unused-vars": ["error", { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^(props|emit|context|slots|attrs)$", + "destructuredArrayIgnorePattern": "^_", + "caughtErrorsIgnorePattern": "^_" + }], + "no-unused-vars": "off" } }, { "files": ["*.ts", "*.tsx"], - "parser": "@typescript-eslint/parser" + "parser": "@typescript-eslint/parser", + "rules": { + "@typescript-eslint/no-unused-vars": "off" + } } ], "ignorePatterns": [ @@ -53,4 +71,4 @@ "*.cjs", "*.mjs" ] -} \ No newline at end of file +} diff --git a/packages/ui/env.d.ts b/packages/ui/env.d.ts index 553a8626..128cde31 100644 --- a/packages/ui/env.d.ts +++ b/packages/ui/env.d.ts @@ -1,7 +1,8 @@ /// declare module '*.vue' { - import type { DefineComponent } from 'vue' + import { type DefineComponent } from 'vue' + const component: DefineComponent<{}, {}, any> export default component } diff --git a/packages/ui/src/components.d.ts b/packages/ui/src/components.d.ts index f635cc73..3f6e8109 100644 --- a/packages/ui/src/components.d.ts +++ b/packages/ui/src/components.d.ts @@ -1,12 +1,12 @@ -import type { DefineComponent } from 'vue' +import { type DefineComponent } from 'vue' declare module 'vue' { export interface GlobalComponents { - [key: string]: DefineComponent<{}, {}, any> + [key: string]: DefineComponent, Record, Record> } } declare module '*.vue' { - const component: DefineComponent<{}, {}, any> + const component: DefineComponent, Record, Record> export default component -} \ No newline at end of file +} diff --git a/packages/ui/src/components/ActionButton.vue b/packages/ui/src/components/ActionButton.vue index 43b87642..c2e2d749 100644 --- a/packages/ui/src/components/ActionButton.vue +++ b/packages/ui/src/components/ActionButton.vue @@ -21,6 +21,7 @@ diff --git a/packages/ui/src/components/PromptPreviewPanel.vue b/packages/ui/src/components/PromptPreviewPanel.vue index 8b535f47..09a0c8a5 100644 --- a/packages/ui/src/components/PromptPreviewPanel.vue +++ b/packages/ui/src/components/PromptPreviewPanel.vue @@ -83,6 +83,7 @@ \ No newline at end of file + name: "MessageApiInitializer", + setup() { + onMounted(() => { + try { + const messageApi = useMessage(); + setGlobalMessageApi(messageApi); + console.log("[Toast] Message API initialized successfully"); + } catch (error) { + console.warn( + "[Toast] Message API initialization failed (this is normal during SSR or when provider is not ready):", + error, + ); + } + }); + return () => h("div", { style: { display: "none" } }); + }, +}); + diff --git a/packages/ui/src/components/ToolCallDisplay.vue b/packages/ui/src/components/ToolCallDisplay.vue index d86c82d8..f6d14fd6 100644 --- a/packages/ui/src/components/ToolCallDisplay.vue +++ b/packages/ui/src/components/ToolCallDisplay.vue @@ -87,6 +87,7 @@ diff --git a/packages/ui/src/components/context-mode/ContextUserWorkspace.vue b/packages/ui/src/components/context-mode/ContextUserWorkspace.vue index b5422f10..825aef42 100644 --- a/packages/ui/src/components/context-mode/ContextUserWorkspace.vue +++ b/packages/ui/src/components/context-mode/ContextUserWorkspace.vue @@ -246,7 +246,8 @@ * /> * ``` */ -import { ref, computed } from "vue"; +import { ref, computed } from 'vue' + import { useI18n } from "vue-i18n"; import { NCard, NFlex, NButton, NText, NTag } from "naive-ui"; import { useBreakpoints } from "@vueuse/core"; @@ -254,7 +255,13 @@ import InputPanelUI from "../InputPanel.vue"; import PromptPanelUI from "../PromptPanel.vue"; import TestAreaPanel from "../TestAreaPanel.vue"; import type { OptimizationMode } from "../../types"; -import type { IServices } from "@prompt-optimizer/core"; +import type { + IServices, + PromptRecord, + Template, +} from "@prompt-optimizer/core"; +import type { TestAreaPanelInstance } from "../types/test-area"; +import type { IteratePayload, SaveFavoritePayload } from "../../types/workspace"; // ======================== // 响应式断点配置 @@ -289,11 +296,11 @@ interface Props { // --- 版本管理 --- /** 历史版本列表 */ - versions: any[]; + versions: PromptRecord[]; /** 当前版本 ID */ currentVersionId: string | null; /** 选中的迭代模板 */ - selectedIterateTemplate: any; + selectedIterateTemplate: Template | null; // --- 测试数据 --- /** 测试输入内容 */ @@ -341,7 +348,7 @@ const emit = defineEmits<{ // --- 数据更新事件 --- "update:prompt": [value: string]; "update:optimizedPrompt": [value: string]; - "update:selectedIterateTemplate": [value: any]; + "update:selectedIterateTemplate": [value: Template | null]; "update:testContent": [value: string]; "update:isCompareMode": [value: boolean]; @@ -349,15 +356,15 @@ const emit = defineEmits<{ /** 执行优化 */ optimize: []; /** 执行迭代优化 */ - iterate: [payload: any]; + iterate: [payload: IteratePayload]; /** 执行测试 (传递测试变量) */ test: [testVariables: Record]; /** 切换对比模式 */ "compare-toggle": []; /** 切换历史版本 */ - "switch-version": [versionId: any]; + "switch-version": [version: PromptRecord]; /** 保存到收藏 */ - "save-favorite": [data: any]; + "save-favorite": [data: SaveFavoritePayload]; // --- 打开面板/管理器 --- /** 打开全局变量管理器 */ @@ -427,7 +434,7 @@ const predefinedVariableValues = computed(() => ({ ...props.predefinedVariables // 组件引用 // ======================== /** TestAreaPanel 组件引用,用于获取测试变量 */ -const testAreaPanelRef = ref | null>(null); +const testAreaPanelRef = ref(null); // ======================== // 事件处理 @@ -579,4 +586,9 @@ const handleTestWithVariables = async () => { emit("test", {}); } }; + +// 暴露 TestAreaPanel 引用给父组件(用于工具调用等高级功能) +defineExpose({ + testAreaPanelRef +}); diff --git a/packages/ui/src/components/context-mode/ConversationManager.vue b/packages/ui/src/components/context-mode/ConversationManager.vue index 77f8b73c..3cdfd49f 100644 --- a/packages/ui/src/components/context-mode/ConversationManager.vue +++ b/packages/ui/src/components/context-mode/ConversationManager.vue @@ -427,7 +427,8 @@