|
|
@@ -8,16 +8,11 @@
|
|
|
<p class="page-desc">配置系统参数,逐项编辑保存</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
-
|
|
|
+
|
|
|
<!-- 搜索框 -->
|
|
|
<div class="search-section">
|
|
|
- <el-input
|
|
|
- v-model="searchKeyword"
|
|
|
- placeholder="搜索配置参数..."
|
|
|
- clearable
|
|
|
- prefix-icon="el-icon-search"
|
|
|
- class="search-input"
|
|
|
- />
|
|
|
+ <el-input v-model="searchKeyword" placeholder="搜索配置参数..." clearable prefix-icon="el-icon-search"
|
|
|
+ class="search-input" />
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
@@ -25,19 +20,17 @@
|
|
|
<div class="page-content">
|
|
|
<!-- 分组标签页容器(粘顶) -->
|
|
|
<div class="group-tabs-wrap">
|
|
|
- <el-tabs
|
|
|
- v-model="activeGroup"
|
|
|
- type="card"
|
|
|
- class="group-tabs"
|
|
|
- @tab-click="(pane) => handleGroupChange(pane.name)"
|
|
|
- >
|
|
|
- <el-tab-pane
|
|
|
- v-for="g in groups"
|
|
|
- :key="g.key"
|
|
|
- :name="g.key"
|
|
|
+ <el-tabs v-model="activeGroup" type="card" class="group-tabs"
|
|
|
+ @tab-click="(pane) => handleGroupChange(pane.name, pane.label)">
|
|
|
+ <!-- <el-tab-pane
|
|
|
+ v-for="g in groups"
|
|
|
+ :key="g.key"
|
|
|
+ :name="g.key"
|
|
|
:label="g.name"
|
|
|
:title="g.name"
|
|
|
- />
|
|
|
+ /> -->
|
|
|
+
|
|
|
+ <el-tab-pane v-for="g in groups" :key="g.id" :name="g.id" :label="g.name.zh" :title="g.name.zh" />
|
|
|
</el-tabs>
|
|
|
</div>
|
|
|
|
|
|
@@ -50,17 +43,10 @@
|
|
|
</div>
|
|
|
<div class="card-content">
|
|
|
<div class="param-list">
|
|
|
- <XtParamItem
|
|
|
- v-for="item in visibleParams"
|
|
|
- :key="item.key"
|
|
|
- :label="item.label || item.key"
|
|
|
- :value="item.value"
|
|
|
- :type="item.type || 'text'"
|
|
|
- :placeholder="item.desc || ('请输入 ' + (item.label || item.key))"
|
|
|
- :search-keyword="searchKeyword"
|
|
|
- @save="(value) => handleParamSave(item.key, value)"
|
|
|
- @cancel="handleParamCancel"
|
|
|
- />
|
|
|
+ <XtParamItem v-for="item in visibleParams" :key="item.id" :label="item.name.zh || item.key"
|
|
|
+ :value="item.value === false ? 'false' : item.value" :type="'text'" :placeholder="item.desc || ('请输入 ' + (item.name.zh || item.id))"
|
|
|
+ :search-keyword="searchKeyword" @save="(value) => handleParamSave(item.id, value)"
|
|
|
+ @cancel="handleParamCancel" />
|
|
|
</div>
|
|
|
|
|
|
<div v-if="!loading && visibleParams.length === 0" class="empty-state">
|
|
|
@@ -76,7 +62,7 @@
|
|
|
|
|
|
<script>
|
|
|
import XtParamItem from '@/components/XtParamItem'
|
|
|
-
|
|
|
+import axios from 'axios';
|
|
|
// 尝试导入真实 API,失败则使用 Mock
|
|
|
let api
|
|
|
try {
|
|
|
@@ -89,7 +75,7 @@ try {
|
|
|
|
|
|
export default {
|
|
|
name: 'ConnectionConfigSimple',
|
|
|
-
|
|
|
+
|
|
|
components: {
|
|
|
XtParamItem
|
|
|
},
|
|
|
@@ -101,6 +87,9 @@ export default {
|
|
|
activeGroup: null,
|
|
|
paramsByGroup: {},
|
|
|
originalByGroup: {},
|
|
|
+ currentGroupName: null,
|
|
|
+ group: null,
|
|
|
+ visibleParams: {},
|
|
|
|
|
|
// 搜索关键字
|
|
|
searchKeyword: '',
|
|
|
@@ -114,42 +103,49 @@ export default {
|
|
|
},
|
|
|
|
|
|
computed: {
|
|
|
+
|
|
|
// 是否为大屏
|
|
|
isLargeScreen() {
|
|
|
return this.windowWidth >= 1440
|
|
|
},
|
|
|
|
|
|
// 当前分组名称
|
|
|
- currentGroupName() {
|
|
|
+ /* currentGroupName() {
|
|
|
+ console.log("当前分组名称")
|
|
|
const group = this.groups.find(g => g.key === this.activeGroup)
|
|
|
+ console.log(group ? group.name : '')
|
|
|
return group ? group.name : ''
|
|
|
- },
|
|
|
+ }, */
|
|
|
|
|
|
// 当前可见的参数
|
|
|
- visibleParams() {
|
|
|
+ /* visibleParams() {
|
|
|
+ console.log("当前可见的参数")
|
|
|
if (!this.activeGroup || !this.paramsByGroup[this.activeGroup]) {
|
|
|
+ console.log("当前可见的参数返回空值")
|
|
|
return []
|
|
|
}
|
|
|
+ console.log(this.paramsByGroup[this.activeGroup].filter(item => this.isItemVisible(item)))
|
|
|
return this.paramsByGroup[this.activeGroup].filter(item => this.isItemVisible(item))
|
|
|
- }
|
|
|
+ } */
|
|
|
},
|
|
|
|
|
|
async mounted() {
|
|
|
// 监听窗口大小变化
|
|
|
window.addEventListener('resize', this.handleResize)
|
|
|
-
|
|
|
+
|
|
|
// 加载分组数据
|
|
|
await this.loadGroups()
|
|
|
-
|
|
|
+
|
|
|
// 如果有活跃分组,加载参数
|
|
|
- if (this.activeGroup) {
|
|
|
+ /* if (this.activeGroup) {
|
|
|
await this.loadParams(this.activeGroup)
|
|
|
- }
|
|
|
-
|
|
|
+ } */
|
|
|
+
|
|
|
// 初始化滚动遮罩
|
|
|
this.$nextTick(() => {
|
|
|
this.setupScrollMask()
|
|
|
})
|
|
|
+
|
|
|
},
|
|
|
|
|
|
beforeDestroy() {
|
|
|
@@ -170,14 +166,28 @@ export default {
|
|
|
async loadGroups() {
|
|
|
this.loading = true
|
|
|
try {
|
|
|
- const response = await api.getGroups()
|
|
|
- if (response.code === 200) {
|
|
|
+ /* const response = await api.getGroups() */
|
|
|
+
|
|
|
+
|
|
|
+ axios.get('http://8.148.78.124:10004/api/param/group/list')
|
|
|
+ .then(response => {
|
|
|
+ if (response.data.success) {
|
|
|
+ this.groups = response.data.groups
|
|
|
+ this.currentGroupName = response.data.groups[0].name.zh
|
|
|
+ this.loadParams(response.data.groups[0].id)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+ /* if (response.code === 200) {
|
|
|
this.groups = response.data
|
|
|
+ console.log(response.data)
|
|
|
// 设置默认活跃分组
|
|
|
if (this.groups.length > 0) {
|
|
|
this.activeGroup = this.$route.query.group || this.groups[0].key
|
|
|
+
|
|
|
}
|
|
|
- }
|
|
|
+ } */
|
|
|
} catch (error) {
|
|
|
this.$message.error('加载分组失败: ' + error.message)
|
|
|
} finally {
|
|
|
@@ -187,23 +197,29 @@ export default {
|
|
|
|
|
|
// 加载指定分组的参数
|
|
|
async loadParams(group) {
|
|
|
- // 如果已有缓存则跳过
|
|
|
- if (this.paramsByGroup[group]) {
|
|
|
- return
|
|
|
- }
|
|
|
+
|
|
|
|
|
|
this.loading = true
|
|
|
try {
|
|
|
- const response = await api.getGroupParams({ group })
|
|
|
- if (response.code === 200) {
|
|
|
+ /* const response = await api.getGroupParams({ group }) */
|
|
|
+ axios.get('http://8.148.78.124:10004/api/param/group/params?group=' + group)
|
|
|
+ .then(response => {
|
|
|
+ if (response.data.success) {
|
|
|
+ // 深拷贝数据
|
|
|
+ this.visibleParams = response.data.params
|
|
|
+ this.group = group
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ /* if (response.code === 200) {
|
|
|
// 深拷贝数据
|
|
|
this.paramsByGroup[group] = JSON.parse(JSON.stringify(response.data))
|
|
|
this.originalByGroup[group] = JSON.parse(JSON.stringify(response.data))
|
|
|
-
|
|
|
+
|
|
|
// 触发响应式更新
|
|
|
this.$set(this.paramsByGroup, group, this.paramsByGroup[group])
|
|
|
this.$set(this.originalByGroup, group, this.originalByGroup[group])
|
|
|
- }
|
|
|
+ } */
|
|
|
} catch (error) {
|
|
|
this.$message.error('加载参数失败: ' + error.message)
|
|
|
} finally {
|
|
|
@@ -212,26 +228,68 @@ export default {
|
|
|
},
|
|
|
|
|
|
// 处理分组切换
|
|
|
- async handleGroupChange(key) {
|
|
|
- this.activeGroup = key
|
|
|
-
|
|
|
+ async handleGroupChange(key, label) {
|
|
|
+ /* this.activeGroup = key
|
|
|
+
|
|
|
// 优先使用本地缓存,未命中再请求
|
|
|
if (this.paramsByGroup[key]) {
|
|
|
// 缓存命中,直接使用,保持体验稳定
|
|
|
return
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 缓存未命中,异步加载
|
|
|
- await this.loadParams(key)
|
|
|
+ await this.loadParams(key) */
|
|
|
+
|
|
|
+ this.currentGroupName = label
|
|
|
+ axios.get('http://8.148.78.124:10004/api/param/group/params?group=' + key)
|
|
|
+ .then(response => {
|
|
|
+ if (response.data.success) {
|
|
|
+ // 深拷贝数据
|
|
|
+ this.visibleParams = response.data.params
|
|
|
+ this.group = key
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
},
|
|
|
|
|
|
// 保存单个参数(适配 XtParamItem)
|
|
|
async handleParamSave(key, value) {
|
|
|
+
|
|
|
+
|
|
|
+ for (let i = 0; i < this.visibleParams.length; i++) {
|
|
|
+ // 检查当前对象的 id 是否与传入的 key 相同
|
|
|
+ if (this.visibleParams[i].id === key) {
|
|
|
+ // 如果相同,将传入的 value 赋值给该对象的 value 属性
|
|
|
+ this.visibleParams[i].value = value;
|
|
|
+ break; // 找到匹配项后退出循环
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
try {
|
|
|
- const response = await api.updateParam({
|
|
|
- group: this.activeGroup,
|
|
|
- key: key,
|
|
|
- value: value
|
|
|
+
|
|
|
+ axios.post('http://8.148.78.124:10004/api/param/value', {
|
|
|
+ group: this.group,
|
|
|
+ id: key,
|
|
|
+ value: value
|
|
|
+ })
|
|
|
+ .then(response => {
|
|
|
+ if (response.data.success) {
|
|
|
+ for (let i = 0; i < this.visibleParams.length; i++) {
|
|
|
+ // 检查当前对象的 id 是否与传入的 key 相同
|
|
|
+ if (this.visibleParams[i].id === key) {
|
|
|
+ // 如果相同,将传入的 value 赋值给该对象的 value 属性
|
|
|
+ this.visibleParams[i].value = value;
|
|
|
+ break; // 找到匹配项后退出循环
|
|
|
+ } else {
|
|
|
+ throw new Error(response.message || '保存失败')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ /* const response = await api.updateParam({
|
|
|
+ group: this.activeGroup,
|
|
|
+ key: key,
|
|
|
+ value: value
|
|
|
})
|
|
|
if (response.code === 200) {
|
|
|
// 同步当前数据
|
|
|
@@ -239,17 +297,17 @@ export default {
|
|
|
if (currentItem) {
|
|
|
currentItem.value = value
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 同步 originalByGroup 中的值
|
|
|
const originalItem = this.originalByGroup[this.activeGroup].find(p => p.key === key)
|
|
|
if (originalItem) {
|
|
|
originalItem.value = value
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 不显示消息,由XtParamItem内部处理
|
|
|
} else {
|
|
|
throw new Error(response.message || '保存失败')
|
|
|
- }
|
|
|
+ } */
|
|
|
} catch (error) {
|
|
|
// 重新抛出错误,让XtParamItem处理错误显示
|
|
|
throw error
|
|
|
@@ -259,7 +317,7 @@ export default {
|
|
|
// 取消参数编辑(适配 XtParamItem)
|
|
|
handleParamCancel() {
|
|
|
// XtParamItem内部处理取消逻辑,这里可以添加全局取消逻辑
|
|
|
- console.log('参数编辑已取消')
|
|
|
+
|
|
|
},
|
|
|
|
|
|
|
|
|
@@ -278,31 +336,31 @@ export default {
|
|
|
setupScrollMask() {
|
|
|
const navWrap = this.$el.querySelector('.el-tabs__nav-wrap')
|
|
|
const tabsWrap = this.$el.querySelector('.group-tabs-wrap')
|
|
|
-
|
|
|
+
|
|
|
if (!navWrap || !tabsWrap) return
|
|
|
-
|
|
|
+
|
|
|
const checkScroll = () => {
|
|
|
const { scrollWidth, clientWidth, scrollLeft } = navWrap
|
|
|
const hasScroll = scrollWidth > clientWidth
|
|
|
-
|
|
|
+
|
|
|
if (hasScroll) {
|
|
|
tabsWrap.classList.add('has-scroll')
|
|
|
} else {
|
|
|
tabsWrap.classList.remove('has-scroll')
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 初始检查
|
|
|
checkScroll()
|
|
|
-
|
|
|
+
|
|
|
// 监听滚动和窗口大小变化
|
|
|
navWrap.addEventListener('scroll', checkScroll)
|
|
|
window.addEventListener('resize', checkScroll)
|
|
|
-
|
|
|
+
|
|
|
// 监听tabs变化
|
|
|
const observer = new MutationObserver(checkScroll)
|
|
|
observer.observe(navWrap, { childList: true, subtree: true })
|
|
|
-
|
|
|
+
|
|
|
// 保存清理函数
|
|
|
this._scrollCleanup = () => {
|
|
|
navWrap.removeEventListener('scroll', checkScroll)
|
|
|
@@ -396,7 +454,7 @@ export default {
|
|
|
backdrop-filter: blur(12px);
|
|
|
transition: all 0.2s cubic-bezier(0.4, 0.0, 0.2, 1);
|
|
|
position: relative;
|
|
|
-
|
|
|
+
|
|
|
// 左右渐隐遮罩
|
|
|
&::before,
|
|
|
&::after {
|
|
|
@@ -409,23 +467,24 @@ export default {
|
|
|
z-index: 1;
|
|
|
transition: opacity 0.3s ease;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 左侧遮罩
|
|
|
&::before {
|
|
|
left: 24px;
|
|
|
background: linear-gradient(to right, var(--color-bg-card), transparent);
|
|
|
opacity: 0;
|
|
|
}
|
|
|
-
|
|
|
- // 右侧遮罩
|
|
|
+
|
|
|
+ // 右侧遮罩
|
|
|
&::after {
|
|
|
right: 24px;
|
|
|
background: linear-gradient(to left, var(--color-bg-card), transparent);
|
|
|
opacity: 0;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 当可滚动时显示遮罩
|
|
|
&.has-scroll {
|
|
|
+
|
|
|
&::before,
|
|
|
&::after {
|
|
|
opacity: 1;
|
|
|
@@ -436,7 +495,7 @@ export default {
|
|
|
// 胶囊型Tab样式 - 完全重做(去掉顶部灰线)
|
|
|
.group-tabs {
|
|
|
position: relative;
|
|
|
-
|
|
|
+
|
|
|
:deep(.el-tabs__header) {
|
|
|
margin: 0;
|
|
|
border: 0; // 去掉header边框
|
|
|
@@ -449,33 +508,34 @@ export default {
|
|
|
:deep(.el-tabs--card > .el-tabs__header) {
|
|
|
border-bottom: 0;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
:deep(.el-tabs--card > .el-tabs__header .el-tabs__nav) {
|
|
|
border: 0;
|
|
|
}
|
|
|
|
|
|
:deep(.el-tabs__nav-wrap) {
|
|
|
+
|
|
|
// 去掉Element默认分隔线
|
|
|
&::after {
|
|
|
display: none;
|
|
|
height: 0;
|
|
|
border: 0;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 去掉可滚动tabs的分隔线
|
|
|
&.is-scrollable::after {
|
|
|
display: none;
|
|
|
height: 0;
|
|
|
border: 0;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 横向滚动 - 隐藏滚动条但保持功能
|
|
|
overflow-x: auto;
|
|
|
overflow-y: hidden;
|
|
|
scroll-behavior: smooth;
|
|
|
scrollbar-width: none; // Firefox
|
|
|
-ms-overflow-style: none; // IE
|
|
|
-
|
|
|
+
|
|
|
&::-webkit-scrollbar {
|
|
|
display: none; // Chrome/Safari
|
|
|
}
|
|
|
@@ -492,7 +552,7 @@ export default {
|
|
|
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
|
min-width: max-content;
|
|
|
position: relative;
|
|
|
-
|
|
|
+
|
|
|
// 内描边增强立体感
|
|
|
&::before {
|
|
|
content: '';
|
|
|
@@ -516,7 +576,7 @@ export default {
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
min-width: fit-content;
|
|
|
-
|
|
|
+
|
|
|
// 胶囊型外观
|
|
|
background: transparent;
|
|
|
color: var(--color-text-secondary);
|
|
|
@@ -530,15 +590,15 @@ export default {
|
|
|
padding: 0 14px;
|
|
|
cursor: pointer;
|
|
|
user-select: none;
|
|
|
-
|
|
|
+
|
|
|
// 统一过渡动画
|
|
|
transition: all 0.15s cubic-bezier(0.4, 0.0, 0.2, 1);
|
|
|
-
|
|
|
+
|
|
|
// 添加title属性显示完整文本
|
|
|
&[title] {
|
|
|
cursor: help;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 悬浮状态
|
|
|
&:hover:not(.is-active) {
|
|
|
color: var(--color-text-primary);
|
|
|
@@ -546,20 +606,19 @@ export default {
|
|
|
transform: translateY(-0.5px);
|
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 选中状态 - 更精致的设计
|
|
|
&.is-active {
|
|
|
color: var(--color-primary);
|
|
|
- background: linear-gradient(135deg,
|
|
|
- var(--color-primary-light-9, rgba(64, 158, 255, 0.12)),
|
|
|
- var(--color-primary-light-8, rgba(64, 158, 255, 0.08))
|
|
|
- );
|
|
|
+ background: linear-gradient(135deg,
|
|
|
+ var(--color-primary-light-9, rgba(64, 158, 255, 0.12)),
|
|
|
+ var(--color-primary-light-8, rgba(64, 158, 255, 0.08)));
|
|
|
font-weight: 600;
|
|
|
transform: none;
|
|
|
- box-shadow:
|
|
|
+ box-shadow:
|
|
|
0 1px 3px rgba(64, 158, 255, 0.3),
|
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.2);
|
|
|
-
|
|
|
+
|
|
|
// 底部激活指示线
|
|
|
&::after {
|
|
|
content: '';
|
|
|
@@ -575,20 +634,20 @@ export default {
|
|
|
animation: activeSlide 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 禁用状态
|
|
|
&.is-disabled {
|
|
|
color: var(--color-text-quaternary);
|
|
|
cursor: not-allowed;
|
|
|
opacity: 0.5;
|
|
|
-
|
|
|
+
|
|
|
&:hover {
|
|
|
background: transparent;
|
|
|
transform: none;
|
|
|
box-shadow: none;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 键盘焦点
|
|
|
&:focus-visible {
|
|
|
outline: 2px solid var(--color-primary);
|
|
|
@@ -604,18 +663,23 @@ export default {
|
|
|
|
|
|
.config-cards {
|
|
|
display: grid;
|
|
|
- gap: 0; /* 紧贴Tab栏 */
|
|
|
- grid-template-columns: 1fr !important; /* 仅一张卡 */
|
|
|
+ gap: 0;
|
|
|
+ /* 紧贴Tab栏 */
|
|
|
+ grid-template-columns: 1fr !important;
|
|
|
+ /* 仅一张卡 */
|
|
|
|
|
|
.config-card {
|
|
|
background: var(--color-bg-card);
|
|
|
- border-radius: 8px; /* 恢复轻微圆角,更现代 */
|
|
|
- border: 1px solid var(--color-border-tertiary); /* 使用更浅的边框 */
|
|
|
+ border-radius: 8px;
|
|
|
+ /* 恢复轻微圆角,更现代 */
|
|
|
+ border: 1px solid var(--color-border-tertiary);
|
|
|
+ /* 使用更浅的边框 */
|
|
|
box-shadow: 0 4px 12px rgba(2, 6, 23, 0.05);
|
|
|
overflow: hidden;
|
|
|
transition: all var(--duration-200) var(--ease-out);
|
|
|
animation: slideInUp 0.3s ease-out;
|
|
|
- margin-top: 16px; /* 与Tab栏保持间距 */
|
|
|
+ margin-top: 16px;
|
|
|
+ /* 与Tab栏保持间距 */
|
|
|
|
|
|
&:hover {
|
|
|
box-shadow: 0 8px 24px rgba(2, 6, 23, 0.08);
|
|
|
@@ -696,17 +760,18 @@ html.dark {
|
|
|
}
|
|
|
|
|
|
.page-content {
|
|
|
+
|
|
|
// 暗色主题适配 - 精致设计(去掉顶部灰线)
|
|
|
.group-tabs-wrap {
|
|
|
background: var(--color-bg-tertiary);
|
|
|
border-bottom-color: var(--color-border-tertiary);
|
|
|
// 去掉顶部阴影,保持干净
|
|
|
-
|
|
|
+
|
|
|
// 遮罩渐变适配暗色
|
|
|
&::before {
|
|
|
background: linear-gradient(to right, var(--color-bg-tertiary), transparent);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
&::after {
|
|
|
background: linear-gradient(to left, var(--color-bg-tertiary), transparent);
|
|
|
}
|
|
|
@@ -717,7 +782,7 @@ html.dark {
|
|
|
background: var(--color-bg-quaternary);
|
|
|
border-color: var(--color-border-tertiary);
|
|
|
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15);
|
|
|
-
|
|
|
+
|
|
|
&::before {
|
|
|
border-color: var(--color-border-quaternary);
|
|
|
}
|
|
|
@@ -734,15 +799,14 @@ html.dark {
|
|
|
|
|
|
&.is-active {
|
|
|
color: var(--color-primary);
|
|
|
- background: linear-gradient(135deg,
|
|
|
- var(--color-primary-light-9, rgba(64, 158, 255, 0.18)),
|
|
|
- var(--color-primary-light-8, rgba(64, 158, 255, 0.12))
|
|
|
- );
|
|
|
- box-shadow:
|
|
|
+ background: linear-gradient(135deg,
|
|
|
+ var(--color-primary-light-9, rgba(64, 158, 255, 0.18)),
|
|
|
+ var(--color-primary-light-8, rgba(64, 158, 255, 0.12)));
|
|
|
+ box-shadow:
|
|
|
0 1px 3px rgba(64, 158, 255, 0.4),
|
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
&.is-disabled {
|
|
|
color: var(--color-text-quaternary);
|
|
|
}
|
|
|
@@ -752,7 +816,8 @@ html.dark {
|
|
|
.config-cards {
|
|
|
.config-card {
|
|
|
background: var(--color-bg-tertiary);
|
|
|
- border-color: var(--color-border-quaternary); /* 暗色主题下更浅的边框 */
|
|
|
+ border-color: var(--color-border-quaternary);
|
|
|
+ /* 暗色主题下更浅的边框 */
|
|
|
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.15);
|
|
|
|
|
|
&:hover {
|
|
|
@@ -813,33 +878,33 @@ html.dark {
|
|
|
|
|
|
.page-content {
|
|
|
padding: 0 var(--spacing-4);
|
|
|
-
|
|
|
+
|
|
|
// 移动端Tab适配 - 胶囊风格
|
|
|
.group-tabs-wrap {
|
|
|
padding: 14px 16px;
|
|
|
margin-bottom: 12px;
|
|
|
-
|
|
|
+
|
|
|
&::before,
|
|
|
&::after {
|
|
|
top: 14px;
|
|
|
bottom: 14px;
|
|
|
width: 8px;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
&::before {
|
|
|
left: 16px;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
&::after {
|
|
|
right: 16px;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
.group-tabs {
|
|
|
:deep(.el-tabs__nav) {
|
|
|
padding: 4px;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
:deep(.el-tabs__item) {
|
|
|
height: 32px; // 降低2px
|
|
|
font-size: 13px; // 字号降一级
|
|
|
@@ -863,19 +928,19 @@ html.dark {
|
|
|
.empty-state {
|
|
|
height: 100px;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 移动端参数行适配
|
|
|
.param-item {
|
|
|
grid-template-columns: 1fr;
|
|
|
gap: 8px;
|
|
|
-
|
|
|
+
|
|
|
.param-label {
|
|
|
font-weight: 500;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
.param-actions {
|
|
|
justify-self: start;
|
|
|
-
|
|
|
+
|
|
|
.el-button {
|
|
|
padding: 4px 12px;
|
|
|
font-size: 12px;
|
|
|
@@ -895,6 +960,7 @@ html.dark {
|
|
|
opacity: 0;
|
|
|
transform: translateY(20px);
|
|
|
}
|
|
|
+
|
|
|
to {
|
|
|
opacity: 1;
|
|
|
transform: translateY(0);
|
|
|
@@ -906,10 +972,12 @@ html.dark {
|
|
|
transform: translateX(-50%) scaleX(0);
|
|
|
opacity: 0;
|
|
|
}
|
|
|
+
|
|
|
50% {
|
|
|
transform: translateX(-50%) scaleX(1.2);
|
|
|
opacity: 0.8;
|
|
|
}
|
|
|
+
|
|
|
100% {
|
|
|
transform: translateX(-50%) scaleX(1);
|
|
|
opacity: 1;
|
|
|
@@ -920,8 +988,9 @@ html.dark {
|
|
|
0% {
|
|
|
transform: rotate(0deg);
|
|
|
}
|
|
|
+
|
|
|
100% {
|
|
|
transform: rotate(360deg);
|
|
|
}
|
|
|
}
|
|
|
-</style>
|
|
|
+</style>
|