首页🐱🐱
This commit is contained in:
parent
b588915cb2
commit
e4b562ed86
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="config-editor">
|
<div class="config-editor">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
@ -6,6 +5,41 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="editor-container">
|
<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="input-section">
|
||||||
<div class="button-group">
|
<div class="button-group">
|
||||||
<button @click="addEntry" class="gradient-btn">添加</button>
|
<button @click="addEntry" class="gradient-btn">添加</button>
|
||||||
@ -14,6 +48,8 @@
|
|||||||
<button @click="insertTemplate('LogicCommand')" class="gradient-btn">预设 LogicCommand</button>
|
<button @click="insertTemplate('LogicCommand')" class="gradient-btn">预设 LogicCommand</button>
|
||||||
<button @click="insertTemplate('LogicCommandSet')" class="gradient-btn">预设 LogicCommandSet</button>
|
<button @click="insertTemplate('LogicCommandSet')" class="gradient-btn">预设 LogicCommandSet</button>
|
||||||
<button @click="clearAll" class="gradient-btn">清空所有</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>
|
||||||
|
|
||||||
<div class="message-section">
|
<div class="message-section">
|
||||||
@ -28,6 +64,8 @@
|
|||||||
v-model="newEntry"
|
v-model="newEntry"
|
||||||
placeholder="输入 LogicCommand 或 LogicCommandSet 标签"
|
placeholder="输入 LogicCommand 或 LogicCommandSet 标签"
|
||||||
class="entry-textarea"
|
class="entry-textarea"
|
||||||
|
@dragover.prevent
|
||||||
|
@drop="dropTag"
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -51,7 +89,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import '../../assets/styles/common.css'
|
import '../../assets/styles/common.css'
|
||||||
|
|
||||||
// 响应式数据
|
// 响应式数据
|
||||||
@ -63,6 +101,168 @@ const xmlContent = ref('')
|
|||||||
const errorMsg = ref('')
|
const errorMsg = ref('')
|
||||||
const warningMsg = ref('')
|
const warningMsg = ref('')
|
||||||
const lastModified = ref('')
|
const lastModified = ref('')
|
||||||
|
const draggedTag = ref(null)
|
||||||
|
const searchQuery = ref('')
|
||||||
|
const filteredTags = ref([])
|
||||||
|
// 修改计算属性:从entries和uploadedTags中提取标签列表
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取LogicCommand和LogicCommandSet节点
|
||||||
|
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 = () => {
|
const addEntry = () => {
|
||||||
@ -105,7 +305,6 @@ const addEntry = () => {
|
|||||||
updateContent()
|
updateContent()
|
||||||
newEntry.value = ''
|
newEntry.value = ''
|
||||||
errorMsg.value = ''
|
errorMsg.value = ''
|
||||||
warningMsg.value = ''
|
|
||||||
warningMsg.value = '条目添加成功!'
|
warningMsg.value = '条目添加成功!'
|
||||||
formatXml()
|
formatXml()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -310,13 +509,53 @@ const getFileSize = () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<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 {
|
.config-editor {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
max-width: 1200px;
|
max-width: 1400px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-container {
|
.editor-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||||
@ -324,7 +563,76 @@ const getFileSize = () => {
|
|||||||
padding: 24px;
|
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 {
|
.input-section {
|
||||||
|
flex: 1;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,6 +702,10 @@ const getFileSize = () => {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.editor-section {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.editor-section h3 {
|
.editor-section h3 {
|
||||||
color: #1a237e;
|
color: #1a237e;
|
||||||
margin-bottom: 12px;
|
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) {
|
@media (max-width: 768px) {
|
||||||
.config-editor {
|
.config-editor {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
@ -464,5 +787,13 @@ const getFileSize = () => {
|
|||||||
.xml-textarea {
|
.xml-textarea {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.xml-stats {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xml-stats span {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
Loading…
x
Reference in New Issue
Block a user