fix: sync/barcode/memory overhaul + detailed logs + preview + result tracking

- Sync: fix GiteaSync constructor + add push()/pull() methods
- Barcode: two-tab layout matching GUI (mapping + special rules)
- Memory: spec→specification unification, manual add, confidence/price tracking
- Processing: TaskLogHandler captures detailed logs (barcode mapping, unit conversion)
- Preview: fullscreen dialog for file preview (image/Excel) in Orders/Tables/Images
- Detail: per-file log filtering in file pages
- Tasks: result files now per-task, add copy path button
- Config: reactive edited state + save_config fix
- Dashboard: sync task isolation, log limit 10

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-05 19:37:10 +08:00
parent c18039f790
commit 81bafaf557
20 changed files with 1610 additions and 502 deletions
+32 -35
View File
@@ -1,5 +1,6 @@
"""Cloud sync endpoints (Gitea-based)."""
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
from fastapi import APIRouter, HTTPException, Depends, Request
@@ -23,7 +24,30 @@ def _get_sync():
from app.core.utils.cloud_sync import GiteaSync
from app.config.settings import ConfigManager
cfg = ConfigManager()
return GiteaSync(cfg)
return GiteaSync.from_config(cfg)
def _run_sync_in_thread(tm, task_id, action_name, sync_method):
"""Run a blocking sync operation in a thread."""
def _run():
try:
tm.update_progress(task_id, 10, "正在初始化同步...")
sync = _get_sync()
if sync is None:
tm.set_failed(task_id, "Gitea 配置不完整,请先在系统配置中设置 base_url/owner/repo/token")
return
tm.update_progress(task_id, 30, f"正在{action_name}文件...")
tm.add_log(task_id, f"[{action_name}] 开始{action_name}")
result = sync_method(sync)
tm.add_log(task_id, f"[{action_name}] 完成: {result}")
tm.set_completed(task_id, message=f"{action_name}完成")
except Exception as e:
tm.set_failed(task_id, str(e))
pool = ThreadPoolExecutor(max_workers=1)
pool.submit(_run)
pool.shutdown(wait=False)
@router.post("/push", response_model=SyncResponse)
@@ -33,21 +57,7 @@ async def sync_push(
):
tm = request.state.task_manager
task = tm.create_task("推送到云端")
async def _run():
try:
tm.update_progress(task.id, 10, "正在初始化同步...")
sync = _get_sync()
tm.update_progress(task.id, 30, "正在推送文件...")
tm.add_log(task.id, "[Push] 开始推送")
result = sync.push()
tm.add_log(task.id, f"[Push] 完成: {result}")
tm.set_completed(task.id, message="推送完成")
except Exception as e:
tm.set_failed(task.id, str(e))
import asyncio
asyncio.create_task(_run())
_run_sync_in_thread(tm, task.id, "Push", lambda s: s.push())
return SyncResponse(task_id=task.id, status="accepted", message="推送任务已创建")
@@ -58,21 +68,7 @@ async def sync_pull(
):
tm = request.state.task_manager
task = tm.create_task("从云端拉取")
async def _run():
try:
tm.update_progress(task.id, 10, "正在初始化同步...")
sync = _get_sync()
tm.update_progress(task.id, 30, "正在拉取文件...")
tm.add_log(task.id, "[Pull] 开始拉取")
result = sync.pull()
tm.add_log(task.id, f"[Pull] 完成: {result}")
tm.set_completed(task.id, message="拉取完成")
except Exception as e:
tm.set_failed(task.id, str(e))
import asyncio
asyncio.create_task(_run())
_run_sync_in_thread(tm, task.id, "Pull", lambda s: s.pull())
return SyncResponse(task_id=task.id, status="accepted", message="拉取任务已创建")
@@ -83,10 +79,11 @@ async def sync_status(
try:
from app.config.settings import ConfigManager
cfg = ConfigManager()
base_url = cfg.get("Gitea", "base_url", fallback="")
owner = cfg.get("Gitea", "owner", fallback="")
repo = cfg.get("Gitea", "repo", fallback="")
enabled = bool(base_url and owner and repo)
base_url = cfg.get("Gitea", "base_url", fallback="").strip()
owner = cfg.get("Gitea", "owner", fallback="").strip()
repo = cfg.get("Gitea", "repo", fallback="").strip()
token = cfg.get("Gitea", "token", fallback="").strip()
enabled = bool(base_url and owner and repo and token)
repo_url = f"{base_url}/{owner}/{repo}" if enabled else ""
return {"enabled": enabled, "repo_url": repo_url}
except Exception: