首页🐱🐱

This commit is contained in:
Kunagisa 2025-07-24 21:19:23 +08:00
parent b588915cb2
commit e4b562ed86

View File

@ -1,4 +1,3 @@
<template>
<div class="config-editor">
<div class="page-header">
@ -6,6 +5,41 @@
</div>
<div class="editor-container">
<!-- 新增的侧边栏 -->
<div class="sidebar" v-if="tagList.length > 0">
<h3>标签列表</h3>
<!-- 添加搜索框 -->
<div class="search-box">
<input
type="text"
v-model="searchQuery"
placeholder="输入ID搜索..."
@input="searchTags"
/>
<button @click="clearSearch" class="clear-btn">×</button>
</div>
<div class="tag-list">
<div
v-for="tag in filteredTags"
:key="tag.id"
class="tag-item"
draggable="true"
@dragstart="dragStart(tag)"
@click="insertTag(tag)"
>
<span class="tag-type">{{ tag.type }}</span>
<span class="tag-id">{{ tag.id }}</span>
<!-- 添加缓存值预览 -->
<span class="tag-preview" v-if="tag.content.length > 50">
{{ tag.content.substring(0, 50) }}...
</span>
<span class="tag-preview" v-else>
{{ tag.content }}
</span>
</div>
</div>
</div>
<div class="input-section">
<div class="button-group">
<button @click="addEntry" class="gradient-btn">添加</button>
@ -14,6 +48,8 @@
<button @click="insertTemplate('LogicCommand')" class="gradient-btn">预设 LogicCommand</button>
<button @click="insertTemplate('LogicCommandSet')" class="gradient-btn">预设 LogicCommandSet</button>
<button @click="clearAll" class="gradient-btn">清空所有</button>
<input type="file" id="fileInput" accept=".xml" @change="handleFileUpload" style="display: none">
<button @click="triggerFileInput" class="gradient-btn">上传 XML</button>
</div>
<div class="message-section">
@ -28,6 +64,8 @@
v-model="newEntry"
placeholder="输入 LogicCommand 或 LogicCommandSet 标签"
class="entry-textarea"
@dragover.prevent
@drop="dropTag"
></textarea>
</div>
</div>
@ -51,7 +89,7 @@
</template>
<script setup>
import { ref } from 'vue'
import { ref, computed } from 'vue'
import '../../assets/styles/common.css'
//
@ -63,6 +101,168 @@ const xmlContent = ref('')
const errorMsg = ref('')
const warningMsg = ref('')
const lastModified = ref('')
const draggedTag = ref(null)
const searchQuery = ref('')
const filteredTags = ref([])
// entriesuploadedTags
const tagList = computed(() => {
const tags = []
//
entries.value.forEach(entry => {
const parser = new DOMParser()
const doc = parser.parseFromString(entry, 'application/xml')
const element = doc.documentElement
const id = element.getAttribute('id')
if (id) {
tags.push({
id: id,
type: element.tagName,
content: entry,
source: 'editor'
})
}
})
//
uploadedTags.value.forEach(tag => {
tags.push({
id: tag.id,
type: tag.type,
content: tag.content,
source: 'upload'
})
})
//
filteredTags.value = [...tags]
return tags
})
//
const dragStart = (tag) => {
draggedTag.value = tag
}
//
const searchTags = () => {
if (!searchQuery.value.trim()) {
filteredTags.value = [...tagList.value]
return
}
const query = searchQuery.value.toLowerCase()
filteredTags.value = tagList.value.filter(tag =>
tag.id.toLowerCase().includes(query) ||
tag.content.toLowerCase().includes(query)
)
}
//
const clearSearch = () => {
searchQuery.value = ''
filteredTags.value = [...tagList.value]
}
//
const dropTag = (e) => {
if (draggedTag.value) {
insertTag(draggedTag.value)
draggedTag.value = null
}
}
//
const insertTag = (tag) => {
// 使
newEntry.value = tag.content
}
//
const triggerFileInput = () => {
document.getElementById('fileInput').click()
}
//
const handleFileUpload = (event) => {
const file = event.target.files[0]
if (!file) return
const reader = new FileReader()
reader.onload = (e) => {
try {
const content = e.target.result
parseAndImportXml(content)
} catch (error) {
errorMsg.value = '文件解析失败: ' + error.message
}
}
reader.readAsText(file)
}
//
const uploadedTags = ref([])
// XML
const parseAndImportXml = (xmlString) => {
try {
const parser = new DOMParser()
const xmlDoc = parser.parseFromString(xmlString, 'application/xml')
//
const parserError = xmlDoc.querySelector('parsererror')
if (parserError) {
throw new Error('XML格式错误: ' + parserError.textContent)
}
// LogicCommandLogicCommandSet
const commands = xmlDoc.getElementsByTagName('LogicCommand')
const commandSets = xmlDoc.getElementsByTagName('LogicCommandSet')
//
uploadedTags.value = []
//
for (let i = 0; i < commands.length; i++) {
const command = commands[i]
const id = command.getAttribute('id')
if (id) {
// XMLSerializer
const rawContent = command.outerHTML
.replace(/ xmlns="[^"]*"/g, '') // xmlns
.replace(/\s+/g, ' ') //
.trim()
uploadedTags.value.push({
id: id,
type: 'LogicCommand',
content: rawContent
})
}
}
for (let i = 0; i < commandSets.length; i++) {
const commandSet = commandSets[i]
const id = commandSet.getAttribute('id')
if (id) {
// XMLSerializer
const rawContent = commandSet.outerHTML
.replace(/ xmlns="[^"]*"/g, '') // xmlns
.replace(/\s+/g, ' ') //
.trim()
uploadedTags.value.push({
id: id,
type: 'LogicCommandSet',
content: rawContent
})
}
}
warningMsg.value = `成功解析 ${commands.length + commandSets.length} 个标签,可在标签列表中选择添加到编辑区`
errorMsg.value = ''
} catch (error) {
errorMsg.value = 'XML解析错误: ' + error.message
warningMsg.value = ''
}
}
//
const addEntry = () => {
@ -105,7 +305,6 @@ const addEntry = () => {
updateContent()
newEntry.value = ''
errorMsg.value = ''
warningMsg.value = ''
warningMsg.value = '条目添加成功!'
formatXml()
} catch (e) {
@ -310,13 +509,53 @@ const getFileSize = () => {
</script>
<style scoped>
/* 新增的搜索框样式 */
.search-box {
position: relative;
margin-bottom: 12px;
}
.search-box input {
width: 100%;
padding: 8px 30px 8px 12px;
border: 1px solid #e0e0e0;
border-radius: 6px;
font-size: 14px;
}
.search-box input:focus {
outline: none;
border-color: #1a237e;
}
.clear-btn {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
color: #999;
font-size: 16px;
padding: 0 4px;
}
.clear-btn:hover {
color: #666;
}
.config-editor {
padding: 20px;
max-width: 1200px;
max-width: 1400px;
margin: 0 auto;
display: flex;
flex-direction: column;
}
.editor-container {
display: flex;
gap: 20px;
background: white;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
@ -324,7 +563,76 @@ const getFileSize = () => {
padding: 24px;
}
/* 新增的侧边栏样式 */
.sidebar {
width: 250px;
min-width: 250px;
background: #f8f9fa;
border-radius: 8px;
padding: 16px;
border: 1px solid #e0e0e0;
overflow-y: auto;
max-height: 800px;
}
.sidebar h3 {
color: #1a237e;
margin-bottom: 12px;
font-size: 16px;
padding-bottom: 8px;
border-bottom: 1px solid #e0e0e0;
}
.tag-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.tag-item {
padding: 10px;
background: white;
border-radius: 6px;
border: 1px solid #e0e0e0;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
flex-direction: column;
gap: 4px;
}
.tag-preview {
font-size: 12px;
color: #888;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-family: 'Courier New', monospace;
}
.tag-item:hover {
border-color: #1a237e;
background: #f0f2ff;
}
.tag-item:active {
transform: scale(0.98);
}
.tag-type {
font-size: 12px;
color: #666;
margin-bottom: 4px;
}
.tag-id {
font-family: 'Courier New', monospace;
font-size: 13px;
word-break: break-all;
}
.input-section {
flex: 1;
margin-bottom: 24px;
}
@ -394,6 +702,10 @@ const getFileSize = () => {
font-size: 14px;
}
.editor-section {
flex: 1;
}
.editor-section h3 {
color: #1a237e;
margin-bottom: 12px;
@ -443,6 +755,17 @@ const getFileSize = () => {
}
/* 响应式设计 */
@media (max-width: 1024px) {
.editor-container {
flex-direction: column;
}
.sidebar {
width: 100%;
max-height: 200px;
}
}
@media (max-width: 768px) {
.config-editor {
padding: 16px;
@ -464,5 +787,13 @@ const getFileSize = () => {
.xml-textarea {
font-size: 13px;
}
.xml-stats {
flex-wrap: wrap;
}
.xml-stats span {
margin-bottom: 4px;
}
}
</style>