feat: Enhance message content handling and improve UI components

- Updated `getShowContentParts` function to handle message content more robustly, ensuring proper display of content parts.
- Refactored `GamepadViewer.vue` to use async component loading for `GamepadDisplay`, added a toggle for real-time preview.
- Implemented debounced search functionality in `PointGoodsView.vue` for improved performance during keyword searches.
- Enhanced `PointOrderView.vue` with order filtering capabilities and added statistics display for better user insights.
- Improved `PointUserHistoryView.vue` by adding export functionality for history data and enhanced filtering options.
- Updated `PointUserLayout.vue` to improve card styling and tab navigation experience.
- Refined `PointUserSettings.vue` layout for better user interaction and added responsive design adjustments.
- Adjusted `vite.config.mts` for better dependency management and build optimization.
This commit is contained in:
Megghy
2025-10-05 15:13:47 +08:00
parent 55e937bf2f
commit 45338ffe7d
26 changed files with 1597 additions and 487 deletions

View File

@@ -1,66 +1,121 @@
<script setup lang="ts">
import { editor } from 'monaco-editor' // 全部导入
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { onMounted, onBeforeUnmount, ref, watch } from 'vue'
import * as monaco from 'monaco-editor'
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
const { language, height = 400 } = defineProps<{
const { language, height = 400, theme = 'vs-dark', options, path } = defineProps<{
language: string
height?: number
theme?: string
options?: Record<string, any>
path?: string
}>()
const value = defineModel<string>('value')
const editorContainer = ref<HTMLElement>()
let editorInstance: editor.IStandaloneCodeEditor | null = null
// 在创建编辑器前确保容器存在
const ready = ref(false)
const initError = ref<string | null>(null)
const containerRef = ref<HTMLElement | null>(null)
let editor: monaco.editor.IStandaloneCodeEditor | null = null
let model: monaco.editor.ITextModel | null = null
let createdModel = false
onMounted(() => {
if (!editorContainer.value) return
editorInstance = editor.create(editorContainer.value, {
value: value.value,
language,
minimap: {
enabled: true,
},
colorDecorators: true,
automaticLayout: true,
})
editorInstance.onDidChangeModelContent(() => {
if (editorInstance) {
const currentValue = editorInstance.getValue()
if (currentValue !== value.value) {
value.value = currentValue
}
// 配置 Monaco Environment
;(self as any).MonacoEnvironment = {
getWorker(_: string, label: string) {
if (label === 'json') {
return new jsonWorker()
}
})
if (label === 'css' || label === 'scss' || label === 'less') {
return new cssWorker()
}
if (label === 'html' || label === 'handlebars' || label === 'razor') {
return new htmlWorker()
}
if (label === 'typescript' || label === 'javascript') {
return new tsWorker()
}
return new editorWorker()
},
}
onMounted(async () => {
try {
const uri = monaco.Uri.parse(
path ?? `inmemory://model/${crypto?.randomUUID?.() ?? Math.random().toString(36).slice(2)}.${language ?? 'txt'}`,
)
model = monaco.editor.getModel(uri)
if (!model) {
model = monaco.editor.createModel(value?.value ?? '', language, uri)
createdModel = true
}
editor = monaco.editor.create(containerRef.value!, {
model,
theme,
automaticLayout: true,
...(options ?? {}),
})
// 同步 model -> v-model
editor.onDidChangeModelContent(() => {
const current = model!.getValue()
if (current !== value.value) value.value = current
})
ready.value = true
} catch (err) {
console.error('Monaco 初始化失败:', err)
initError.value = (err as Error)?.message ?? String(err)
}
})
// v-model 变更 -> model
watch(value, (nv) => {
if (model && typeof nv === 'string' && nv !== model.getValue()) {
model.setValue(nv)
}
})
// 语言切换
watch(() => language, (lang) => {
if (model && lang) {
monaco.editor.setModelLanguage(model, lang)
}
})
// 主题切换
watch(() => theme, (t) => {
if (editor && t) {
editor.updateOptions({ theme: t })
}
})
onBeforeUnmount(() => {
if (editorInstance) {
editorInstance.dispose()
editorInstance = null
}
})
watch(value, (newValue) => {
if (editorInstance && newValue !== editorInstance.getValue()) {
editorInstance.setValue(newValue ?? '')
}
})
watch(() => language, (newLang) => {
if (editorInstance) {
const model = editorInstance.getModel()
if (model) {
editor.setModelLanguage(model, newLang)
try {
editor?.dispose()
// 仅销毁我们创建的临时 model避免复用路径时把共享 model 误删
if (createdModel && model) {
model.dispose()
}
}
} catch {}
})
</script>
<template>
<div
ref="editorContainer"
:style="`height: ${height}px;`"
/>
<div :style="`height: ${height}px; width: 100%; position: relative;`">
<div v-if="!ready" :style="`position:absolute; inset:0; display:flex; align-items:center; justify-content:center; color: var(--text-color, #888); text-align:center; padding:8px;`">
<div>
<div>正在加载编辑器</div>
<div v-if="initError" style="margin-top:6px; color:#d9534f; font-size:12px;">{{ initError }}</div>
</div>
</div>
<div ref="containerRef" :style="`height: ${height}px; width: 100%;`"></div>
</div>
</template>