From b3bb43dcdfce7706e5b1202d35575e570a756071 Mon Sep 17 00:00:00 2001 From: AoXuan Date: Fri, 19 Sep 2025 01:26:43 +0800 Subject: [PATCH 1/3] =?UTF-8?q?refactor(TabFunction):=20=E6=95=B4=E7=90=86?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=A1=B9=EF=BC=8C=E6=95=B4=E5=90=88=E4=B8=80?= =?UTF-8?q?=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/views/setting/TabFunction.vue | 195 ++++++++++++++++++++- frontend/src/views/setting/TabStart.vue | 58 ------ frontend/src/views/setting/TabUpdate.vue | 108 ------------ frontend/src/views/setting/TabVoice.vue | 58 ------ frontend/src/views/setting/index.vue | 20 +-- 5 files changed, 197 insertions(+), 242 deletions(-) delete mode 100644 frontend/src/views/setting/TabStart.vue delete mode 100644 frontend/src/views/setting/TabUpdate.vue delete mode 100644 frontend/src/views/setting/TabVoice.vue diff --git a/frontend/src/views/setting/TabFunction.vue b/frontend/src/views/setting/TabFunction.vue index e6dd1cf..8ff5bfb 100644 --- a/frontend/src/views/setting/TabFunction.vue +++ b/frontend/src/views/setting/TabFunction.vue @@ -2,14 +2,65 @@ import { QuestionCircleOutlined } from '@ant-design/icons-vue' import type { SettingsData } from '@/types/settings' -const { settings, historyRetentionOptions, handleSettingChange } = defineProps<{ +const { settings, historyRetentionOptions, updateSourceOptions, voiceTypeOptions, handleSettingChange, checkUpdate } = defineProps<{ settings: SettingsData historyRetentionOptions: { label: string; value: number }[] + updateSourceOptions: { label: string; value: string }[] + voiceTypeOptions: { label: string; value: string }[] handleSettingChange: (category: keyof SettingsData, key: string, value: any) => Promise + checkUpdate: () => Promise }>() diff --git a/frontend/src/views/setting/TabStart.vue b/frontend/src/views/setting/TabStart.vue deleted file mode 100644 index 2f995f8..0000000 --- a/frontend/src/views/setting/TabStart.vue +++ /dev/null @@ -1,58 +0,0 @@ - - diff --git a/frontend/src/views/setting/TabUpdate.vue b/frontend/src/views/setting/TabUpdate.vue deleted file mode 100644 index debdcf0..0000000 --- a/frontend/src/views/setting/TabUpdate.vue +++ /dev/null @@ -1,108 +0,0 @@ - - diff --git a/frontend/src/views/setting/TabVoice.vue b/frontend/src/views/setting/TabVoice.vue deleted file mode 100644 index 70f2372..0000000 --- a/frontend/src/views/setting/TabVoice.vue +++ /dev/null @@ -1,58 +0,0 @@ - - diff --git a/frontend/src/views/setting/index.vue b/frontend/src/views/setting/index.vue index 8cde780..4f178a3 100644 --- a/frontend/src/views/setting/index.vue +++ b/frontend/src/views/setting/index.vue @@ -16,9 +16,6 @@ import { mirrorManager } from '@/utils/mirrorManager' import TabBasic from './TabBasic.vue' import TabFunction from './TabFunction.vue' import TabNotify from './TabNotify.vue' -import TabUpdate from './TabUpdate.vue' -import TabStart from './TabStart.vue' -import TabVoice from './TabVoice.vue' import TabAdvanced from './TabAdvanced.vue' import TabOthers from './TabOthers.vue' @@ -278,7 +275,10 @@ onMounted(() => { @@ -290,20 +290,6 @@ onMounted(() => { :testing-notify="testingNotify" /> - - - - - - - - - Date: Fri, 19 Sep 2025 01:29:49 +0800 Subject: [PATCH 2/3] =?UTF-8?q?refactor(index.vue):=20=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E5=8C=96=E4=B8=80=E4=B8=8Bcss?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/views/setting/index.vue | 293 +++++++++++++++++++++++---- 1 file changed, 248 insertions(+), 45 deletions(-) diff --git a/frontend/src/views/setting/index.vue b/frontend/src/views/setting/index.vue index 4f178a3..d08e9e5 100644 --- a/frontend/src/views/setting/index.vue +++ b/frontend/src/views/setting/index.vue @@ -190,7 +190,10 @@ const openDevTools = () => (window as any).electronAPI?.openDevTools?.() // 更新检查 const checkUpdate = async () => { try { - const response = await Service.checkUpdateApiUpdateCheckPost({ current_version: version, if_force: true }) + const response = await Service.checkUpdateApiUpdateCheckPost({ + current_version: version, + if_force: true, + }) if (response.code === 200) { if (response.if_need_update) { updateData.value = response.update_info @@ -229,7 +232,9 @@ const refreshMirrorConfig = async () => { } catch (e) { console.error('刷新镜像配置失败', e) message.error('刷新镜像配置失败') - } finally { refreshingConfig.value = false } + } finally { + refreshingConfig.value = false + } } const goToMirrorTest = () => router.push('/mirror-test') @@ -244,7 +249,9 @@ const testNotify = async () => { } catch (e) { console.error('测试通知发送失败', e) message.error('测试通知发送失败') - } finally { testingNotify.value = false } + } finally { + testingNotify.value = false + } } onMounted(() => { @@ -291,8 +298,8 @@ onMounted(() => { /> - { :go-to-mirror-test="goToMirrorTest" /> - + - + From e56993028760444308d493981f0791ac33527b13 Mon Sep 17 00:00:00 2001 From: AoXuan Date: Fri, 19 Sep 2025 01:45:40 +0800 Subject: [PATCH 3/3] =?UTF-8?q?feat(QueueItemManager,=20TimeSetManager):?= =?UTF-8?q?=20=E5=A2=9E=E5=8A=A0=E5=AE=9A=E6=97=B6=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E5=92=8C=E4=BB=BB=E5=8A=A1=E5=88=97=E8=A1=A8=E7=9A=84=E6=8B=96?= =?UTF-8?q?=E6=8B=BD=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/queue/QueueItemManager.vue | 289 ++++++++++++--- .../src/components/queue/TimeSetManager.vue | 337 +++++++++++++++--- 2 files changed, 525 insertions(+), 101 deletions(-) diff --git a/frontend/src/components/queue/QueueItemManager.vue b/frontend/src/components/queue/QueueItemManager.vue index 8a2ff04..c0c0c18 100644 --- a/frontend/src/components/queue/QueueItemManager.vue +++ b/frontend/src/components/queue/QueueItemManager.vue @@ -11,49 +11,67 @@ - - - - + + @@ -61,6 +79,7 @@ import { onMounted, ref, watch } from 'vue' import { message } from 'ant-design-vue' import { DeleteOutlined, PlusOutlined } from '@ant-design/icons-vue' +import draggable from 'vuedraggable' import { Service } from '@/api' // Props @@ -141,7 +160,7 @@ const loadOptions = async () => { const updateQueueItemScript = async (record: any) => { try { loading.value = true - + const response = await Service.updateItemApiQueueItemUpdatePost({ queueId: props.queueId, queueItemId: record.id, @@ -170,7 +189,7 @@ const updateQueueItemScript = async (record: any) => { const addQueueItem = async () => { try { loading.value = true - + // 直接创建队列项,默认ScriptId为null(未选择) const createResponse = await Service.addItemApiQueueItemAddPost({ queueId: props.queueId, @@ -211,6 +230,44 @@ const deleteQueueItem = async (itemId: string) => { } } +// 拖拽结束处理函数 +const onDragEnd = async (evt: any) => { + // 如果位置没有变化,直接返回 + if (evt.oldIndex === evt.newIndex) { + return + } + + try { + loading.value = true + + // 构造排序后的ID列表 + const sortedIds = queueItems.value.map(item => item.id) + + // 调用排序API + const response = await Service.reorderItemApiQueueItemOrderPost({ + queueId: props.queueId, + indexList: sortedIds, + }) + + if (response.code === 200) { + message.success('任务顺序已更新') + // 刷新数据以确保与服务器同步 + emit('refresh') + } else { + message.error('更新任务顺序失败: ' + (response.message || '未知错误')) + // 如果失败,刷新数据恢复原状态 + emit('refresh') + } + } catch (error: any) { + console.error('拖拽排序失败:', error) + message.error('更新任务顺序失败: ' + (error?.message || '网络错误')) + // 如果失败,刷新数据恢复原状态 + emit('refresh') + } finally { + loading.value = false + } +} + // 初始化 onMounted(() => { loadOptions() @@ -474,6 +531,124 @@ onMounted(() => { padding: 40px 0; } +/* 拖拽表格样式 */ +.draggable-table-container { + width: 100%; + border: 1px solid var(--ant-color-border); + border-radius: 6px; + overflow: hidden; +} + +.draggable-table-header { + display: flex; + background-color: var(--ant-color-fill-quaternary); + border-bottom: 1px solid var(--ant-color-border); +} + +.header-cell { + padding: 12px 16px; + font-weight: 600; + color: var(--ant-color-text); + text-align: center; + border-right: 1px solid var(--ant-color-border); +} + +.header-cell:last-child { + border-right: none; +} + +.index-cell { + width: 80px; + min-width: 80px; + max-width: 80px; +} + +.script-cell { + flex: 1; + min-width: 200px; +} + +.actions-cell { + width: 180px; + min-width: 180px; + max-width: 180px; +} + +.draggable-container { + min-height: 60px; +} + +.draggable-row { + display: flex; + align-items: center; + background: var(--ant-color-bg-container); + border-bottom: 1px solid var(--ant-color-border); + transition: all 0.2s ease; + cursor: move; +} + +.draggable-row:last-child { + border-bottom: none; +} + +.draggable-row:hover { + background-color: var(--ant-color-fill-quaternary); +} + +.draggable-row.row-dragging { + cursor: not-allowed; +} + +.row-cell { + padding: 12px 16px; + text-align: center; + border-right: 1px solid var(--ant-color-border); + display: flex; + align-items: center; + justify-content: center; +} + +.row-cell:last-child { + border-right: none; +} + +.row-cell.index-cell { + width: 80px; + min-width: 80px; + max-width: 80px; + font-weight: 500; + color: var(--ant-color-text-secondary); +} + +.row-cell.script-cell { + flex: 1; + min-width: 200px; +} + +.row-cell.actions-cell { + width: 180px; + min-width: 180px; + max-width: 180px; +} + +/* 拖拽状态样式 */ +.ghost { + opacity: 0.5; + background: var(--ant-color-primary-bg); + border: 2px dashed var(--ant-color-primary); +} + +.chosen { + background: var(--ant-color-primary-bg-hover); + transform: scale(1.02); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.drag { + transform: rotate(5deg); + opacity: 0.8; +} + /* 响应式设计 */ @media (max-width: 1200px) { .queue-items-grid { @@ -489,6 +664,30 @@ onMounted(() => { .queue-item-card-item { padding: 12px; } + + .draggable-row { + flex-direction: column; + align-items: stretch; + } + + .row-cell, + .header-cell { + border-right: none; + border-bottom: 1px solid var(--ant-color-border); + } + + .row-cell:last-child, + .header-cell:last-child { + border-bottom: none; + } + + .index-cell, + .script-cell, + .actions-cell { + width: 100% !important; + min-width: auto !important; + max-width: none !important; + } } /* 标签样式 */ @@ -589,4 +788,4 @@ onMounted(() => { .script-select :deep(.ant-select-item-option-content) { font-size: 13px !important; } - \ No newline at end of file + diff --git a/frontend/src/components/queue/TimeSetManager.vue b/frontend/src/components/queue/TimeSetManager.vue index 469ff48..085b48f 100644 --- a/frontend/src/components/queue/TimeSetManager.vue +++ b/frontend/src/components/queue/TimeSetManager.vue @@ -16,60 +16,78 @@ - - - - - - + + @@ -77,6 +95,7 @@ import { ref, watch } from 'vue' import { message } from 'ant-design-vue' import { DeleteOutlined, PlusOutlined } from '@ant-design/icons-vue' +import draggable from 'vuedraggable' import { Service } from '@/api' import dayjs from 'dayjs' @@ -159,7 +178,7 @@ const timeSets = ref([...props.timeSets]) const processTimeSets = (rawTimeSets: any[]) => { return rawTimeSets.map(item => ({ ...item, - timeValue: parseTimeString(item.time) + timeValue: parseTimeString(item.time), })) } @@ -221,7 +240,7 @@ const addTimeSet = async () => { const updateTimeSetTime = async (timeSet: any) => { try { const timeString = formatTimeValue(timeSet.timeValue) - + const response = await Service.updateTimeSetApiQueueTimeUpdatePost({ queueId: props.queueId, timeSetId: timeSet.id, @@ -297,6 +316,44 @@ const deleteTimeSet = async (timeSetId: string) => { message.error('删除定时项失败: ' + (error?.message || '网络错误')) } } + +// 拖拽结束处理函数 +const onDragEnd = async (evt: any) => { + // 如果位置没有变化,直接返回 + if (evt.oldIndex === evt.newIndex) { + return + } + + try { + loading.value = true + + // 构造排序后的ID列表 + const sortedIds = timeSets.value.map(item => item.id) + + // 调用排序API + const response = await Service.reorderTimeSetApiQueueTimeOrderPost({ + queueId: props.queueId, + indexList: sortedIds, + }) + + if (response.code === 200) { + message.success('定时顺序已更新') + // 刷新数据以确保与服务器同步 + emit('refresh') + } else { + message.error('更新定时顺序失败: ' + (response.message || '未知错误')) + // 如果失败,刷新数据恢复原状态 + emit('refresh') + } + } catch (error: any) { + console.error('拖拽排序失败:', error) + message.error('更新定时顺序失败: ' + (error?.message || '网络错误')) + // 如果失败,刷新数据恢复原状态 + emit('refresh') + } finally { + loading.value = false + } +} @@ -831,7 +1054,9 @@ const deleteTimeSet = async (timeSetId: string) => { transition: background 0.2s ease; } -[data-theme='dark'] .ant-picker-dropdown .ant-picker-time-panel-column::-webkit-scrollbar-thumb:hover { +[data-theme='dark'] + .ant-picker-dropdown + .ant-picker-time-panel-column::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.45); }