diff --git a/debug.bat b/debug.bat new file mode 100644 index 0000000..61f6d75 --- /dev/null +++ b/debug.bat @@ -0,0 +1,58 @@ +@echo off +setlocal +title CapacityReport Debug + +cd /d "%~dp0" + +set PYTHON_EXE=.venv\Scripts\python.exe +if not exist "%PYTHON_EXE%" ( + echo [ERROR] Python virtual environment not found: %PYTHON_EXE% + echo [HINT] Run this command in the project root first: uv venv + pause + exit /b 1 +) + +"%PYTHON_EXE%" -c "import fastapi, uvicorn, pandas, openpyxl, pymysql, chardet" >nul 2>&1 +if errorlevel 1 ( + echo [INFO] Installing or repairing Python dependencies... + uv pip install -r requirements.txt + if errorlevel 1 ( + echo [ERROR] Failed to install Python dependencies. + pause + exit /b 1 + ) +) + +where npm >nul 2>&1 +if errorlevel 1 ( + echo [ERROR] npm not found. Install Node.js first. + pause + exit /b 1 +) + +pushd frontend +if not exist "node_modules" ( + echo [INFO] Installing frontend dependencies... + call npm ci + if errorlevel 1 ( + echo [ERROR] Failed to install frontend dependencies. + popd + pause + exit /b 1 + ) +) +popd + +echo ======================================== +echo CapacityReport - debug mode +echo ======================================== +echo [INFO] Backend: http://127.0.0.1:9081 +echo [INFO] Frontend: http://127.0.0.1:5173 +echo [INFO] Close both debug windows to stop. +echo. + +start "CapacityReport Backend" cmd /k ""%PYTHON_EXE%" -m app.main --host 127.0.0.1 --port 9081" +start "CapacityReport Frontend" cmd /k "pushd "%~dp0frontend" && npm run dev -- --host 127.0.0.1 --port 5173" + +echo [OK] Debug services are starting. +pause diff --git a/docs/project_context.md b/docs/project_context.md index ebde477..55a02e6 100644 --- a/docs/project_context.md +++ b/docs/project_context.md @@ -619,3 +619,10 @@ - Database-related settings now stay together with `数据库配置` and `处理历史保留`; remote automation settings now own the FTP/SFTP fields, auto-delete toggle, scheduler configuration, and scheduler status panel. - `frontend/src/styles.css` now uses dedicated layout classes for the database and remote settings panes, with independent scrolling and responsive single-column stacking on narrower screens. - Verification performed: `cd frontend && npm run build` passed. Browser inspection on `http://127.0.0.1:9081/settings` confirmed the two new tabs render correctly, the remote panel shows its own configuration and scheduler cards, and horizontal overflow remained at `0`. + +## 2026-06-01: Settings remote scheduler refinement + +- `frontend/src/components/SettingsPanel.vue` keeps `远程数据源` focused on FTP/SFTP connection fields. Protocol, host, port, timeout, and FTP passive mode render on one row when width allows; remote automation and delete-source toggles now sit below `远程目录`. +- `自动调度` is now a separate settings tab. Scheduler controls are disabled unless `启用远程自动化` is on, and turning off remote automation automatically turns off scheduler enablement in the current form state and saved payload. +- `debug.bat` starts the Python backend on `127.0.0.1:9081` and the Vite frontend on `127.0.0.1:5173` for source-level debugging without requiring `frontend/dist`. +- Verification performed: `cmd /c debug.bat` started the debug backend/frontend, `cd frontend && npm run build` passed, and browser inspection confirmed the remote connection fields align in one row with no horizontal overflow. Debug processes and `frontend/dist/` were removed after verification. diff --git a/frontend/src/components/SettingsPanel.vue b/frontend/src/components/SettingsPanel.vue index c377f9c..876b8fc 100644 --- a/frontend/src/components/SettingsPanel.vue +++ b/frontend/src/components/SettingsPanel.vue @@ -82,57 +82,30 @@ -
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+ + + + + + + + + + + + + + + +
@@ -148,6 +121,17 @@ +
+ + + + + + +

自动化执行会递归下载该目录下的全部文件和文件夹到本地缓存,再按现有处理流程入库和执行脚本;自动删除源文件只会在处理成功后删除远程文件,保留目录结构。

@@ -158,122 +142,124 @@
+
+ -
- - - - - - - - - - - - - - - - - - - - -
- - - - 添加 - - -
- - {{ directory }} - - - 按实际 ZIP 目录检测 - -
-
-
-

自动调度会按文件名日期检查目标自然周 7 天;开启后会强制启用远程自动化和处理成功后删除源文件。

-
- -
-
- 调度状态 - - {{ schedulerStatusLabel }} - -
-
-
- 目标周 - {{ schedulerTargetWeekText }} -
-
- 下次检查 - {{ schedulerStatus?.next_check_at || '-' }} -
-
- 就绪标识 - {{ schedulerStatus?.ready_flag?.exists ? '已存在' : '无' }} -
-
-

{{ schedulerStatus?.last_message || '自动调度状态尚未加载' }}

-
-
- {{ row.displayName }} - - {{ row.skipped ? '已停推' : row.ready ? '就绪' : `缺 ${row.missing_days.length} 天` }} + +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + 添加 + + +
+ + {{ directory }} + + + 按实际 ZIP 目录检测
- - - 刷新状态 - - - 立即检查 - - -
+ +

自动调度依赖远程自动化;关闭远程自动化时会自动关闭调度。启用调度后会按文件名日期检查目标自然周 7 天,并强制开启处理成功后删除源文件。

+ - - -
+
+
+ 调度状态 + + {{ schedulerStatusLabel }} + +
+
+
+ 目标周 + {{ schedulerTargetWeekText }} +
+
+ 下次检查 + {{ schedulerStatus?.next_check_at || '-' }} +
+
+ 就绪标识 + {{ schedulerStatus?.ready_flag?.exists ? '已存在' : '无' }} +
+
+

{{ schedulerStatus?.last_message || '自动调度状态尚未加载' }}

+
+
+ {{ row.displayName }} + + {{ row.skipped ? '已停推' : row.ready ? '就绪' : `缺 ${row.missing_days.length} 天` }} + +
+
+ + + 刷新状态 + + + 立即检查 + + +
+ + +
@@ -579,12 +565,21 @@ const schedulerDirectoryRows = computed(() => { ...status })); }); +const schedulerControlsDisabled = computed(() => !remoteForm.enabled || !remoteForm.auto_scheduler.enabled); + +watch( + () => remoteForm.enabled, + enabled => { + if (!enabled && remoteForm.auto_scheduler.enabled) { + remoteForm.auto_scheduler.enabled = false; + } + } +); watch( () => remoteForm.auto_scheduler.enabled, enabled => { if (enabled) { - remoteForm.enabled = true; remoteForm.auto_delete_source = true; } } @@ -959,8 +954,11 @@ function normalizeAutoSchedulerConfig(config: RemoteAutoSchedulerConfig | undefi } function enforceRemoteSchedulerRules() { + if (!remoteForm.enabled) { + remoteForm.auto_scheduler.enabled = false; + return; + } if (!remoteForm.auto_scheduler.enabled) return; - remoteForm.enabled = true; remoteForm.auto_delete_source = true; remoteForm.auto_scheduler.check_interval_hours = Math.max(Number(remoteForm.auto_scheduler.check_interval_hours) || 1, 1); remoteForm.auto_scheduler.expected_directories = uniqueStrings(remoteForm.auto_scheduler.expected_directories) diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 7135562..14e9f30 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -1383,14 +1383,17 @@ select { } .settings-database-panel, -.settings-remote-grid, +.settings-remote-panel, +.settings-scheduler-panel, .settings-rules-grid { display: grid; align-items: start; gap: 18px; } -.settings-database-panel { +.settings-database-panel, +.settings-remote-panel, +.settings-scheduler-panel { grid-template-columns: minmax(420px, 680px); height: 100%; min-height: 0; @@ -1401,39 +1404,30 @@ select { scrollbar-width: thin; } -.settings-database-stack, -.settings-remote-stack { +.settings-database-stack { display: flex; min-width: 0; flex-direction: column; gap: 18px; } -.settings-remote-grid { - grid-template-columns: minmax(380px, 0.9fr) minmax(360px, 1.1fr); - height: 100%; - min-height: 0; - padding-right: 6px; - overflow-x: hidden; - overflow-y: auto; - scrollbar-color: var(--td-scrollbar-color) transparent; - scrollbar-width: thin; -} - .settings-database-panel::-webkit-scrollbar, -.settings-remote-grid::-webkit-scrollbar { +.settings-remote-panel::-webkit-scrollbar, +.settings-scheduler-panel::-webkit-scrollbar { width: 8px; height: 8px; } .settings-database-panel::-webkit-scrollbar-thumb, -.settings-remote-grid::-webkit-scrollbar-thumb { +.settings-remote-panel::-webkit-scrollbar-thumb, +.settings-scheduler-panel::-webkit-scrollbar-thumb { background: var(--td-scrollbar-color); border-radius: 8px; } .settings-database-panel::-webkit-scrollbar-track, -.settings-remote-grid::-webkit-scrollbar-track { +.settings-remote-panel::-webkit-scrollbar-track, +.settings-scheduler-panel::-webkit-scrollbar-track { background: transparent; } @@ -1442,6 +1436,36 @@ select { min-width: 0; } +.settings-remote-panel { + grid-template-columns: minmax(720px, 1fr); +} + +.settings-scheduler-panel { + grid-template-columns: minmax(420px, 760px); +} + +.remote-connection-row { + display: grid; + grid-template-columns: minmax(112px, 0.8fr) minmax(220px, 1.8fr) minmax(110px, 0.8fr) minmax(120px, 0.8fr) minmax(116px, 0.7fr); + gap: 12px; + align-items: start; +} + +.remote-passive-field .n-form-item-blank { + align-items: center; + min-height: 34px; +} + +.remote-toggle-row { + display: flex; + flex-wrap: wrap; + gap: 12px 56px; +} + +.remote-toggle-row .n-form-item { + margin-bottom: 0; +} + .settings-rules-grid { grid-template-columns: minmax(280px, 0.72fr) minmax(0, 1.4fr); grid-template-rows: minmax(0, 1fr); @@ -1935,11 +1959,16 @@ select { /* ==================== Responsive ==================== */ @media (max-width: 1200px) { .settings-database-panel, - .settings-remote-grid, + .settings-remote-panel, + .settings-scheduler-panel, .settings-rules-grid { grid-template-columns: 1fr; } + .remote-connection-row { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .settings-rules-grid { grid-template-rows: auto minmax(520px, 1fr); align-items: start; @@ -2032,3 +2061,13 @@ select { grid-template-columns: 1fr; } } + +@media (max-width: 700px) { + .remote-connection-row { + grid-template-columns: 1fr; + } + + .remote-toggle-row { + gap: 12px 24px; + } +}