refactor(queue): 优化队列管理页面的布局和交互,增加开关配置功能

This commit is contained in:
2025-08-30 20:59:51 +08:00
parent c15c74895b
commit f28b4cbad0
3 changed files with 441 additions and 316 deletions

View File

@@ -18,6 +18,9 @@
size="middle" size="middle"
:scroll="{ x: 600 }" :scroll="{ x: 600 }"
> >
<template #emptyText>
<span>暂无队列项</span>
</template>
<template #bodyCell="{ column, record, index }"> <template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'index'"> {{ index + 1 }}个脚本 </template> <template v-if="column.key === 'index'"> {{ index + 1 }}个脚本 </template>
<template v-else-if="column.key === 'script'"> <template v-else-if="column.key === 'script'">
@@ -45,9 +48,6 @@
</template> </template>
</a-table> </a-table>
<div v-if="!queueItems.length && !loading" class="empty-state">
<a-empty description="暂无队列项数据" />
</div>
<!-- 队列项编辑弹窗 --> <!-- 队列项编辑弹窗 -->
<a-modal <a-modal

View File

@@ -23,6 +23,9 @@
size="middle" size="middle"
:scroll="{ x: 800 }" :scroll="{ x: 800 }"
> >
<template #emptyText>
<span>暂无定时项</span>
</template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.key === 'enabled'"> <template v-if="column.key === 'enabled'">
<a-switch <a-switch
@@ -58,10 +61,6 @@
</template> </template>
</a-table> </a-table>
<div v-if="!timeSets.length && !loading" class="empty-state">
<a-empty :description="!props.queueId ? '请先选择一个队列' : '暂无定时项数据'" />
</div>
<!-- 定时项编辑弹窗 --> <!-- 定时项编辑弹窗 -->
<a-modal <a-modal
v-model:open="modalVisible" v-model:open="modalVisible"
@@ -373,10 +372,6 @@ const deleteTimeSet = async (timeSetId: string) => {
font-weight: 600; font-weight: 600;
} }
.empty-state {
text-align: center;
padding: 40px 0;
}
/* 表格样式优化 */ /* 表格样式优化 */
:deep(.ant-table-tbody > tr > td) { :deep(.ant-table-tbody > tr > td) {

View File

@@ -1,131 +1,196 @@
<template> <template>
<div v-if="loading" class="loading-box"> <!-- 加载状态 -->
<a-spin tip="加载中,请稍候..." size="large" /> <div v-if="loading" class="loading-container">
<a-spin size="large" tip="加载中,请稍候..." />
</div> </div>
<div v-else class="queue-content"> <!-- 主要内容 -->
<!-- 队列头部 --> <div v-else class="queue-main">
<!-- 页面头部 -->
<div class="queue-header"> <div class="queue-header">
<div class="header-title"> <div class="header-left">
<h1>调度队列</h1> <h1 class="page-title">调度队列</h1>
<p class="page-description">管理您的自动化调度队列和任务配置</p>
</div> </div>
<a-space size="middle"> <div class="header-actions">
<a-space size="middle">
<a-button
type="primary"
size="large"
@click="handleAddQueue"
v-if="queueList.length > 0 || currentQueueData"
>
<template #icon>
<PlusOutlined />
</template>
新建队列
</a-button>
<a-popconfirm
v-if="queueList.length > 0"
title="确定要删除这个队列吗?"
ok-text="确定"
cancel-text="取消"
@confirm="handleRemoveQueue(activeQueueId)"
>
<a-button danger size="large" :disabled="!activeQueueId">
<template #icon>
<DeleteOutlined />
</template>
删除当前队列
</a-button>
</a-popconfirm>
<a-button size="large" @click="handleRefresh">
<template #icon>
<ReloadOutlined />
</template>
刷新
</a-button>
</a-space>
</div>
</div>
<!-- 空状态 -->
<div v-if="!queueList.length || !currentQueueData" class="empty-state">
<a-empty
image="https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg"
:image-style="{ height: '120px' }"
description="当前没有队列"
>
<template #description>
<span class="empty-description">
您还没有创建任何调度队列点击下方按钮来创建您的第一个队列
</span>
</template>
<a-button type="primary" size="large" @click="handleAddQueue"> <a-button type="primary" size="large" @click="handleAddQueue">
<template #icon> <template #icon>
<PlusOutlined /> <PlusOutlined />
</template> </template>
新建队列 新建队列
</a-button> </a-button>
<a-button size="large" @click="handleRefresh"> </a-empty>
<template #icon>
<ReloadOutlined />
</template>
刷新
</a-button>
</a-space>
</div> </div>
<!-- 如果没有计划显示占位符 -->
<!-- 如果没有队列显示占位符 -->
<div v-if="!queueList.length || !currentQueueData" class="placeholder-container">
<div class="placeholder-content">
<h2>当前没有队列</h2>
<p>您还没有创建任何调度队列点击下方按钮来创建您的第一个队列</p>
<a-button type="primary" size="large" @click="handleAddQueue">
<template #icon>
<PlusOutlined />
</template>
新建队列
</a-button>
</div>
</div>
<!-- 队列内容 --> <!-- 队列内容 -->
<div class="queue-main-content" v-else-if="currentQueueData"> <div v-else class="queue-content">
<!-- 队列选择 --> <!-- 队列选择卡片 -->
<div class="queue-selector"> <a-card class="queue-selector-card" :bordered="false">
<a-tabs <template #title>
v-model:activeKey="activeQueueId" <div class="card-title">
type="editable-card" <span>队列选择</span>
@edit="onTabEdit" <a-tag :color="queueList.length > 0 ? 'success' : 'default'">
@change="onQueueChange" {{ queueList.length }} 个队列
class="queue-tabs" </a-tag>
> </div>
<a-tab-pane </template>
v-for="queue in queueList"
:key="queue.id"
:tab="queue.name"
:closable="queueList.length > 1"
/>
</a-tabs>
</div>
<!-- 队列配置区域 --> <div class="queue-selection-container">
<div class="queue-config-section"> <!-- 队列按钮组 -->
<div class="section-header"> <div class="queue-buttons-container">
<div class="section-title"> <a-space wrap size="middle">
<div class="queue-name-editor"> <a-button
v-for="queue in queueList"
:key="queue.id"
:type="activeQueueId === queue.id ? 'primary' : 'default'"
size="large"
@click="onQueueChange(queue.id)"
class="queue-button"
>
{{ queue.name }}
</a-button>
</a-space>
</div>
</div>
</a-card>
<!-- 队列配置卡片 -->
<a-card class="queue-config-card" :bordered="false">
<template #title>
<div class="queue-title-container">
<div v-if="!isEditingQueueName" class="queue-title-display">
<span class="queue-title-text">{{ currentQueueName || '队列配置' }}</span>
<a-button type="text" size="small" @click="startEditQueueName" class="queue-edit-btn">
<template #icon>
<EditOutlined />
</template>
</a-button>
</div>
<div v-else class="queue-title-edit">
<a-input <a-input
v-model:value="currentQueueName" v-model:value="currentQueueName"
placeholder="请输入队列名称" placeholder="请输入队列名称"
size="large" size="small"
class="queue-name-input" class="queue-title-input"
@blur="onQueueNameBlur" @blur="finishEditQueueName"
@pressEnter="onQueueNameBlur" @pressEnter="finishEditQueueName"
:maxlength="50"
ref="queueNameInputRef"
/>
</div>
</div>
</template>
<!-- 队列开关配置 -->
<div class="config-section">
<div class="queue-switches">
<div class="switch-item">
<div class="switch-label">
<span class="switch-title">启动时运行</span>
<span class="switch-description">程序启动时自动运行此队列</span>
</div>
<a-switch
v-model:checked="currentStartUpEnabled"
@change="onQueueSwitchChange"
size="default"
/>
</div>
<div class="switch-item">
<div class="switch-label">
<span class="switch-title">定时运行</span>
<span class="switch-description">按照设定的时间自动运行此队列</span>
</div>
<a-switch
v-model:checked="currentTimeEnabled"
@change="onQueueSwitchChange"
size="default"
/> />
</div> </div>
</div> </div>
<!-- <div class="section-controls">-->
<!-- <a-space>-->
<!-- <span class="status-label">状态</span>-->
<!-- <a-switch -->
<!-- v-model:checked="currentQueueEnabled" -->
<!-- @change="onQueueStatusChange"-->
<!-- checked-children="启用"-->
<!-- un-checked-children="禁用"-->
<!-- />-->
<!-- </a-space>-->
<!-- </div>-->
</div> </div>
<!-- 定时项组件 --> <a-divider />
<TimeSetManager
v-if="activeQueueId && currentQueueData"
:queue-id="activeQueueId"
:time-sets="currentTimeSets"
@refresh="refreshTimeSets"
/>
<!-- 队列项组件 --> <!-- 定时项管理 -->
<QueueItemManager <div class="config-section">
v-if="activeQueueId && currentQueueData" <TimeSetManager
:queue-id="activeQueueId" v-if="activeQueueId && currentQueueData"
:queue-items="currentQueueItems" :queue-id="activeQueueId"
@refresh="refreshQueueItems" :time-sets="currentTimeSets"
/> @refresh="refreshTimeSets"
</div> />
</div>
<a-divider />
<!-- 队列项管理 -->
<div class="config-section">
<QueueItemManager
v-if="activeQueueId && currentQueueData"
:queue-id="activeQueueId"
:queue-items="currentQueueItems"
@refresh="refreshQueueItems"
/>
</div>
</a-card>
</div> </div>
</div> </div>
<!-- 悬浮保存按钮 -->
<a-float-button
type="primary"
@click="handleSave"
class="float-button"
:style="{ right: '24px' }"
>
<template #icon>
<SaveOutlined />
</template>
</a-float-button>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted, ref, nextTick } from 'vue' import { computed, onMounted, ref, nextTick, watch } from 'vue'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import { PlusOutlined, ReloadOutlined, SaveOutlined } from '@ant-design/icons-vue' import { PlusOutlined, ReloadOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons-vue'
import { Service } from '@/api' import { Service } from '@/api'
import TimeSetManager from '@/components/queue/TimeSetManager.vue' import TimeSetManager from '@/components/queue/TimeSetManager.vue'
import QueueItemManager from '@/components/queue/QueueItemManager.vue' import QueueItemManager from '@/components/queue/QueueItemManager.vue'
@@ -138,6 +203,11 @@ const currentQueueData = ref<Record<string, any> | null>(null)
// 当前队列的名称和状态 // 当前队列的名称和状态
const currentQueueName = ref<string>('') const currentQueueName = ref<string>('')
const currentQueueEnabled = ref<boolean>(true) const currentQueueEnabled = ref<boolean>(true)
// 新增:启动时运行和定时运行的开关状态
const currentStartUpEnabled = ref<boolean>(false)
const currentTimeEnabled = ref<boolean>(false)
// 队列名称编辑状态
const isEditingQueueName = ref<boolean>(false)
// 当前队列的定时项和队列项 // 当前队列的定时项和队列项
const currentTimeSets = ref<any[]>([]) const currentTimeSets = ref<any[]>([])
@@ -159,7 +229,7 @@ const fetchQueues = async () => {
try { try {
// API响应格式: {"uid": "xxx", "type": "QueueConfig"} // API响应格式: {"uid": "xxx", "type": "QueueConfig"}
const queueId = item.uid const queueId = item.uid
const queueName = response.data[queueId]?.Info?.Name || `队列 ${index + 1}` const queueName = response.data[queueId]?.Info?.Name || `新调度队列`
console.log('Queue ID:', queueId, 'Name:', queueName, 'Type:', typeof queueId) // 调试日志 console.log('Queue ID:', queueId, 'Name:', queueName, 'Type:', typeof queueId) // 调试日志
return { return {
id: queueId, id: queueId,
@@ -169,7 +239,7 @@ const fetchQueues = async () => {
console.warn('解析队列项失败:', itemError, item) console.warn('解析队列项失败:', itemError, item)
return { return {
id: `queue_${index}`, id: `queue_${index}`,
name: `队列 ${index + 1}`, name: `新调度队列`,
} }
} }
}) })
@@ -225,6 +295,10 @@ const loadQueueData = async (queueId: string) => {
// 使用nextTick确保DOM更新后再加载数据 // 使用nextTick确保DOM更新后再加载数据
await nextTick() await nextTick()
// 更新开关状态 - 从API响应中获取
currentStartUpEnabled.value = queueData.Info?.StartUpEnabled ?? false
currentTimeEnabled.value = queueData.Info?.TimeEnabled ?? false
await new Promise(resolve => setTimeout(resolve, 50)) await new Promise(resolve => setTimeout(resolve, 50))
// 加载定时项和队列项数据 - 添加错误处理 // 加载定时项和队列项数据 - 添加错误处理
@@ -363,6 +437,7 @@ const refreshQueueItems = async () => {
// 队列名称编辑失焦处理 // 队列名称编辑失焦处理
const onQueueNameBlur = () => { const onQueueNameBlur = () => {
// 当用户编辑完队列名称后,更新按钮显示的名称
if (activeQueueId.value) { if (activeQueueId.value) {
const currentQueue = queueList.value.find(queue => queue.id === activeQueueId.value) const currentQueue = queueList.value.find(queue => queue.id === activeQueueId.value)
if (currentQueue) { if (currentQueue) {
@@ -372,22 +447,35 @@ const onQueueNameBlur = () => {
} }
} }
// 队列状态切换处理 // 开始编辑队列名称
const onQueueStatusChange = () => { const startEditQueueName = () => {
// 状态切换时只更新本地状态,不自动保存 isEditingQueueName.value = true
// 使用 nextTick 确保 DOM 更新后再获取焦点
setTimeout(() => {
const input = document.querySelector('.queue-title-input input') as HTMLInputElement
if (input) {
input.focus()
input.select()
}
}, 100)
} }
// 标签页编辑处理 // 完成编辑队列名称
const onTabEdit = async (targetKey: string | MouseEvent, action: 'add' | 'remove') => { const finishEditQueueName = () => {
try { isEditingQueueName.value = false
if (action === 'add') { onQueueNameBlur()
await handleAddQueue() }
} else if (action === 'remove' && typeof targetKey === 'string') {
await handleRemoveQueue(targetKey) // 队列开关切换处理
} const onQueueSwitchChange = () => {
} catch (error) { // 开关切换时自动保存
console.error('标签页操作失败:', error) autoSave()
} }
// 队列状态切换处理
const onQueueStatusChange = () => {
// 状态切换时自动保存
autoSave()
} }
// 添加队列 // 添加队列
@@ -396,7 +484,7 @@ const handleAddQueue = async () => {
const response = await Service.addQueueApiQueueAddPost() const response = await Service.addQueueApiQueueAddPost()
if (response.code === 200 && response.queueId) { if (response.code === 200 && response.queueId) {
const defaultName = `队列 ${queueList.value.length + 1}` const defaultName = '新调度队列'
const newQueue = { const newQueue = {
id: response.queueId, id: response.queueId,
name: defaultName, name: defaultName,
@@ -409,7 +497,9 @@ const handleAddQueue = async () => {
currentQueueEnabled.value = true currentQueueEnabled.value = true
await loadQueueData(newQueue.id) await loadQueueData(newQueue.id)
message.success('队列创建成功')
// 显示名称修改提示
message.info('已创建新的调度队列,建议您修改为更有意义的名称', 3)
} else { } else {
message.error('队列创建失败: ' + (response.message || '未知错误')) message.error('队列创建失败: ' + (response.message || '未知错误'))
} }
@@ -452,6 +542,8 @@ const onQueueChange = async (queueId: string) => {
if (!queueId) return if (!queueId) return
try { try {
// 立即更新activeQueueId以确保按钮高亮切换
activeQueueId.value = queueId
// 清空当前数据,避免渲染问题 // 清空当前数据,避免渲染问题
currentTimeSets.value = [] currentTimeSets.value = []
currentQueueItems.value = [] currentQueueItems.value = []
@@ -462,17 +554,13 @@ const onQueueChange = async (queueId: string) => {
} }
} }
// 动保存处理 // 动保存处理
const handleSave = async () => { const autoSave = async () => {
if (!activeQueueId.value) { if (!activeQueueId.value) return
message.warning('请先选择一个队列')
return
}
try { try {
await saveQueueData() await saveQueueData()
message.success('保存成功')
} catch (error) { } catch (error) {
message.error('保存失败') console.error('自动保存失败:', error)
} }
} }
@@ -481,11 +569,14 @@ const saveQueueData = async () => {
if (!activeQueueId.value) return if (!activeQueueId.value) return
try { try {
// 构建符合API要求的数据结构 // 构建符合API要求的数据结构,包含开关状态
const queueData: Record<string, any> = { const queueData: Record<string, any> = {
name: currentQueueName.value, "Info": {
enabled: currentQueueEnabled.value, "Name": currentQueueName.value,
// 这里可以添加其他需要保存的队列配置 "StartUpEnabled": currentStartUpEnabled.value,
"TimeEnabled": currentTimeEnabled.value,
"AfterAccomplish": "NoAction" // 保持默认值
}
} }
const response = await Service.updateQueueApiQueueUpdatePost({ const response = await Service.updateQueueApiQueueUpdatePost({
@@ -509,6 +600,16 @@ const handleRefresh = async () => {
loading.value = false loading.value = false
} }
// 自动保存功能
watch(
() => [currentQueueName.value, currentQueueEnabled.value, currentStartUpEnabled.value, currentTimeEnabled.value],
async () => {
await nextTick()
autoSave()
},
{ deep: true }
)
// 初始化 // 初始化
onMounted(async () => { onMounted(async () => {
try { try {
@@ -521,67 +622,39 @@ onMounted(async () => {
</script> </script>
<style scoped> <style scoped>
/* 空状态样式 */ .queue-container {
.empty-state { min-height: 100vh;
flex: 1; background: var(--ant-color-bg-layout);
padding: 24px;
}
.loading-container {
display: flex; display: flex;
align-items: center;
justify-content: center; justify-content: center;
align-items: center;
min-height: 400px;
} }
.empty-content { .queue-main {
text-align: center; max-width: 1400px;
padding: 48px; margin: 0 auto;
background: var(--ant-color-bg-container);
border-radius: 16px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
border: 1px solid var(--ant-color-border-secondary);
} }
.empty-icon { /* 页面头部 */
font-size: 64px;
color: var(--ant-color-text-tertiary);
margin-bottom: 24px;
}
.empty-content h3 {
font-size: 20px;
font-weight: 600;
color: var(--ant-color-text);
margin: 0 0 8px 0;
}
.empty-content p {
font-size: 14px;
color: var(--ant-color-text-secondary);
margin: 0 0 32px 0;
}
/* 队列内容区域 */
.queue-content {
flex: 1;
display: flex;
flex-direction: column;
background: var(--ant-color-bg-container);
border-radius: 16px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
border: 1px solid var(--ant-color-border-secondary);
overflow: hidden;
}
/* 队列头部样式 */
.queue-header { .queue-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: flex-end;
padding: 24px 32px; margin-bottom: 24px;
background: var(--ant-color-bg-container); padding: 0 4px;
border-bottom: 1px solid var(--ant-color-border-secondary);
margin-bottom: 5px;
} }
.header-title h1 { .header-left {
margin: 0; flex: 1;
}
.page-title {
margin: 0 0 8px 0;
font-size: 32px; font-size: 32px;
font-weight: 700; font-weight: 700;
color: var(--ant-color-text); color: var(--ant-color-text);
@@ -591,48 +664,81 @@ onMounted(async () => {
background-clip: text; background-clip: text;
} }
/* 队列选择器 */ .page-description {
.queue-selector { margin: 0;
padding: 0 32px; font-size: 16px;
background: var(--ant-color-bg-container); color: var(--ant-color-text-secondary);
border-bottom: 1px solid var(--ant-color-border-secondary); line-height: 1.5;
} }
/* 队列主内容 */ .header-actions {
.queue-main-content { flex-shrink: 0;
flex: 1; }
/* 空状态 */
.empty-state {
display: flex;
justify-content: center;
align-items: center;
min-height: 400px;
background: var(--ant-color-bg-container);
border-radius: 12px;
border: 1px solid var(--ant-color-border-secondary);
}
.empty-description {
color: var(--ant-color-text-secondary);
font-size: 16px;
margin-bottom: 16px;
display: block;
}
/* 队列内容 */
.queue-content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 24px;
} }
/* 队列配置区域 */ /* 队列选择卡片 */
.queue-config-section { .queue-selector-card {
flex: 1; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
padding: 24px 32px; border-radius: 12px;
overflow: auto;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 24px;
border: 1px solid var(--ant-color-border-secondary); border: 1px solid var(--ant-color-border-secondary);
border-radius: 8px;
margin-bottom: 24px;
background: var(--ant-color-bg-container);
} }
.section-title h3 { .card-title {
margin: 0; display: flex;
color: var(--ant-color-text); align-items: center;
gap: 12px;
font-size: 18px; font-size: 18px;
font-weight: 600; font-weight: 600;
} }
.section-controls { .queue-selection-container {
padding: 16px;
}
/* 队列按钮组 */
.queue-buttons-container {
display: flex; display: flex;
align-items: center; flex-wrap: wrap;
gap: 12px;
margin-bottom: 16px;
}
.queue-button {
flex: 1 1 120px;
border-radius: 8px;
transition: all 0.2s ease;
}
/* 队列配置卡片 */
.queue-config-card {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
border-radius: 12px;
border: 1px solid var(--ant-color-border-secondary);
min-height: 600px;
} }
.status-label { .status-label {
@@ -641,124 +747,148 @@ onMounted(async () => {
font-weight: 500; font-weight: 500;
} }
/* 队列名称编辑器样式 */ /* 队列名称编辑 */
.queue-name-editor { .queue-title-container {
display: flex; display: flex;
align-items: center; align-items: center;
} justify-content: space-between;
.queue-name-input {
max-width: 300px;
font-size: 18px;
font-weight: 600;
}
.queue-name-input :deep(.ant-input) {
border: 1px solid transparent;
background: transparent;
color: var(--ant-color-text);
font-size: 18px;
font-weight: 600;
padding: 4px 8px;
border-radius: 6px;
transition: all 0.3s ease;
}
.queue-name-input :deep(.ant-input:hover) {
border-color: var(--ant-color-border);
}
.queue-name-input :deep(.ant-input:focus) {
border-color: var(--ant-color-primary);
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}
.loading-box {
min-height: 400px;
display: flex;
justify-content: center;
align-items: center;
}
.placeholder-container {
display: flex;
justify-content: center;
align-items: center;
height: 400px;
}
.placeholder-content {
text-align: center;
max-width: 500px;
}
.placeholder-content h2 {
font-size: 24px;
font-weight: 600;
color: var(--ant-color-text);
margin-bottom: 16px; margin-bottom: 16px;
} }
.placeholder-content p { .queue-title-display {
font-size: 16px;
color: var(--ant-color-text-secondary);
margin-bottom: 24px;
line-height: 1.5;
}
.float-button {
width: 60px;
height: 60px;
}
.empty-content-fancy {
transition:
box-shadow 0.3s,
transform 0.2s;
border: none;
border-radius: 24px;
}
.empty-icon {
font-size: 80px;
margin-bottom: 32px;
border-radius: 50%;
width: 100px;
height: 100px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; gap: 8px;
margin-left: auto;
margin-right: auto;
} }
.empty-content-fancy h2 { .queue-title-text {
font-size: 26px; font-size: 18px;
font-weight: 700; font-weight: 600;
margin: 0 0 12px 0;
letter-spacing: 1px;
color: var(--ant-color-text); color: var(--ant-color-text);
} }
.empty-content-fancy h1 { .queue-edit-btn {
font-size: 16px; color: var(--ant-color-primary);
padding: 0;
}
/* 队列名称输入框 */
.queue-title-input {
flex: 1;
max-width: 400px;
border-radius: 8px; border-radius: 8px;
padding: 8px 16px; transition: all 0.2s ease;
margin: 0 0 12px 0; }
display: inline-block;
/* 配置区域 */
.config-section {
margin-bottom: 24px;
}
/* 开关配置 */
.queue-switches {
display: flex;
flex-direction: column;
gap: 16px;
}
.switch-item {
display: flex;
justify-content: space-between;
align-items: center;
}
.switch-label {
display: flex;
flex-direction: column;
gap: 4px;
}
.switch-title {
font-size: 16px;
font-weight: 500;
color: var(--ant-color-text);
}
.switch-description {
font-size: 14px;
color: var(--ant-color-text-secondary); color: var(--ant-color-text-secondary);
} }
/* 响应式设计 */
@media (max-width: 1200px) {
.queue-container {
padding: 16px;
}
.queue-header {
flex-direction: column;
align-items: flex-start;
gap: 16px;
}
.page-title {
font-size: 28px;
}
}
@media (max-width: 768px) {
.queue-container {
padding: 12px;
}
.page-title {
font-size: 24px;
}
.page-description {
font-size: 14px;
}
.queue-title-input {
max-width: 100%;
}
.header-actions {
width: 100%;
display: flex;
justify-content: center;
}
}
/* 深度样式使用全局CSS变量 */
.queue-selector-card :deep(.ant-card-head) {
border-bottom: 1px solid var(--ant-color-border-secondary);
padding: 16px 24px;
}
.queue-config-card :deep(.ant-card-head) {
border-bottom: 1px solid var(--ant-color-border-secondary);
padding: 16px 24px;
}
.queue-config-card :deep(.ant-card-head-title) {
font-size: 18px;
font-weight: 600;
}
.queue-title-input :deep(.ant-input) {
font-size: 16px;
font-weight: 500;
}
.queue-title-input :deep(.ant-input:focus) {
box-shadow: 0 0 0 2px var(--ant-color-primary-bg);
}
/* 深色模式适配 */ /* 深色模式适配 */
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
.queue-config-section { .queue-selector-card {
border-color: var(--ant-color-border-secondary); background: var(--ant-color-bg-container);
border-radius: 16px;
} }
.section-header { .queue-config-card {
border-color: var(--ant-color-border-secondary); background: var(--ant-color-bg-container);
border-radius: 16px;
} }
} }
</style> </style>