feat(api,ui,db): add address, guest users, image URLs; update API

- Backend:
  - Add address column to tickets and migration script
  - Create guest users when user_id is missing; accept user_name and address
  - Normalize stored image paths and expose absolute image_url
  - Introduce utils for path normalization and ticket serialization
  - Add CORS configuration for dashboard/emulator origins
  - Tickets API:
    - Serialize via ticket_to_dict with consistent schema
    - Change status update to PATCH /api/tickets/{id}/status with JSON body
    - Add DELETE /api/tickets/{id} with safe file removal
- Dashboard:
  - Fetch tickets from backend, show thumbnails, absolute image URLs
  - Status select + PATCH updates, toasts for feedback
  - Add i18n key btn.viewDetails
- Mobile app:
  - Persist device user_id via SharedPreferences
  - Fetch and merge API tickets; prefer network imageUrl
  - Submit user_name and address; delete via API when available
  - Make location acquisition robust with fallbacks and non-blocking UX
- Android/deps:
  - Disable Geolocator NMEA listener to prevent crashes
  - Downgrade geolocator to ^11.0.0 for stability

BREAKING CHANGE:
- Status endpoint changed from PATCH /api/tickets/{id}?new_status=... to
  PATCH /api/tickets/{id}/status with JSON body: {"status":"in_progress"}.
- /api/tickets and /api/tickets/{id} responses now use "id" (replacing
  "ticket_id"), include "image_url", and normalize fields for clients. Update
  consumers to use the new schema.
This commit is contained in:
2025-09-27 09:31:40 +08:00
parent 0e3eea7de9
commit 77d5be8fd1
27 changed files with 800 additions and 256 deletions

View File

@@ -3,6 +3,7 @@ import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from app.database import Base, engine
from app.routes import report, tickets, analytics, users
from app.services.global_ai import init_ai_service
@@ -44,6 +45,25 @@ UPLOAD_DIR = "static/uploads"
os.makedirs(UPLOAD_DIR, exist_ok=True)
app.mount("/static", StaticFiles(directory="static"), name="static")
# ----------------------
# CORS - allow dashboard & emulator origins
# ----------------------
DEFAULT_ORIGINS = "http://localhost:3000,http://127.0.0.1:3000,http://10.0.2.2:3000,http://192.168.100.59:3000"
origins_env = os.environ.get("FIXMATE_CORS_ORIGINS", DEFAULT_ORIGINS)
allowed_origins = [o.strip() for o in origins_env.split(",") if o.strip()]
# Ensure common development origins are always allowed (localhost, emulator, LAN)
for origin in ("http://localhost:3000", "http://127.0.0.1:3000", "http://10.0.2.2:3000", "http://192.168.100.59:3000"):
if origin not in allowed_origins:
allowed_origins.append(origin)
app.add_middleware(
CORSMiddleware,
allow_origins=allowed_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ----------------------
# Include routers
# ----------------------