29 Commits

Author SHA1 Message Date
Pine 7493383f6a feat(users): 建号规则收紧与手机号绑定
- 管理端/园区端创建用户:账号系统随机生成不可指定,手机号必填且全局唯一
- 管理端用户管理支持绑定/更换手机号(PATCH /admin/users/{id}/phone)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-30 22:29:44 +08:00
Pine 4f11931143 feat(content): 资讯发布时间/来源/发布人规范 + 点赞/留言/分享互动体系
- published_at 发布时间(迁移0022):运营端不限、园区端禁早于3天前,双方均支持定时发布;C端/大屏到点才可见
- 发布人:运营端可设(留空显示官方)、园区端固定园区名只能填来源
- 点赞/分享/留言(迁移0023-0025):content_likes 去重点赞、like_count/share_count、留言回复+评论点赞
- 各出口(内容/留言/入驻资料 docs)统一 resolve_url 生成 CDN 直链;入库统一 to_object_path 对象路径
2026-08-28 17:17:49 +08:00
Pine 89396eb6b0 chore: 汇总提交(园区资料/内容审核/任务相关)+迁移0019/0021及部署编排调整 2026-08-27 21:02:47 +08:00
Pine b745328d49 feat(tasks): 运营端任务详情/竞标/报名端点 + 园区发布任务端点
- 运营端 /admin/tasks/{id} 详情、/{id}/bids、/{id}/claims、/{id}/bids/{bid_id}/win 开标定标(余标置lost+进 in_progress)
- 园区端 POST /park/api/park/tasks 发布任务(publisher_role=park/park_id=本园/发布即上架/默认公有)
2026-08-27 20:19:40 +08:00
Pine 084f039d10 feat(园区端): 放宽 release/assign 作用域(本园发布或指派本园均可) + 新增 /park/api/park/tasks/{id}/status 上架下架 2026-08-27 19:48:49 +08:00
Pine ad1bcf5bbf feat(tasks): 阶段A剩余 —— 园区端/大屏任务 + 运营平台资金托管结算
- 大屏 /api/tasks 改为仅展示「当前园区可接」:本园专属(park_id)∪公有(park_public),状态published/claimed/doing
- 园区端 /api/park/tasks(本园发布+指派本园列表) /tasks/{id}/release(园区内发单→park_released+可见性) /tasks/{id}/assign(园区内指派→锁定被指派人)
- 运营托管结算(operator):/admin/escrows(台账) /admin/tasks/{id}/escrow(托管建档/充值,佣金5%) /admin/tasks/{id}/release(验收结算,划佣金+余额代付OPC),全部挂运营平台
2026-08-27 19:07:20 +08:00
Pine 9160183a3c feat(park): GET /park/api/content/feed 大屏资讯流(tenant 解析,含未公开) 2026-08-27 15:53:51 +08:00
Pine 89bd7e8390 feat(content): 发布体系 大/小图 + 公开 + 园区端发布
- 迁移0018:content_items 加 card_mode/is_public/source/tenant_id
- ContentRepository:_to_dict/create/update 含新字段;list 加 public_only/tenant_id 过滤
- /opc/content 仅 published+公开;/opc/content/{id} 非公开→404
- 园区端 POST /park/api/content:发布人强制=园区名、source=carrier、tenant=本园、is_public 默认false(仅大屏)、card_mode默认small
- 园区端 GET /park/api/content:本园区内容(含未公开)供大屏
- schemas 补 card_mode/is_public

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-27 15:42:39 +08:00
Pine 8697119aaa feat(park-company): 园区企业→成员 + 企业算力(折扣%/配额,只增不减) 后端
- 迁移0015:park_companies 加 compute_discount/compute_quota/compute_quota_used/engine_group/owner_user_id;users 加 park_company_id(成员归属一家企业)
- tenants.py:company_members/get/add/remove(写 users.park_company_id)、available_members(候选)、set_company_compute(折扣%/配额 单调非降,越界 ValueError)、sync_company_engine(引擎组倍率同步,best-effort)
- park/routers.py:carrier 端点 company-members GET/POST/DELETE、company-pool、companies/{cid}/compute(monotonic+引擎同步);鉴权 _carrier_user+_my_park 隔离本园区
- compute_client.py:set_user_group_by_username、set_group_group_ratio(组倍率=1-discount%)、grant_user_quota_by_username(解析引擎id后 add_quota)
- rbac_admin.py:平台兜底 GET /park/tenants/{tid}/companies、PUT .../companies/{cid}/compute(monotonic+audit)
- _user_to_dict 暴露 park_company_id
- 单调校验服务端强判:折扣降/配额负增 → 400

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-26 19:57:37 +08:00
Pine 97f0a0698c feat(park): 平台园区/屏幕绑定 + OPC认证入园转园审核 + 园区端carrier修复
- rbac_admin 新增 /admin/park/screens|tenants|devices/{id}/bind|unbind 及 OPC认证/入园/转园审核端点
- tenants.list_all_screens 带 online(MQTT心跳),bind/unbind 完备
- park/routers: tenant_bind 绑定即 set_role(carrier);_my_park 兜底 username→admin_username 解析园区(修"未关联任何园区")

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-26 19:02:58 +08:00
Pine bc6265eb67 feat(opc): OPC认证/入园/转园 端点 + 园区端方案B审核 + 迁移0013
- rbac_opc.py: /opc/certification/apply|mine、/opc/park-transfer/apply|mine
- rbac_admin.py: platform operator 兜底 list/review (opc-certifications/park-admissions/park-transfers),通过回填 users.set_classification
- park/routers.py: carrier 角色凭 operator_user_id 定位本园区,/park/api park-admissions|transfers view+review
- park/tenants.py: bind_admin 写 operator_user_id + find_by_operator_user_id
- 迁移 0013: opc_certifications + park_transfers + park_tenants.operator_user_id
2026-08-26 15:43:34 +08:00
Pine ea904d3a50 feat(task): 完善任务系统 —— 分类字典/字段/四种接单方式/独占限额/交付时限
- Task 加 published_at/delivery_days/headcount/exclusive/publisher_id/category_id;新增 TaskCategory 分类字典表(35 类)。
- mode 归一 grab/bid/assign/recommend(旧 designated→assign、dispatch→recommend);TaskService 加 assign/recommend/select_recommend,claim 支持独占/限额、published+claimed 均可抢(多人)。
- TaskClaim 支持 source=assign/recommend、status=assigned/recommended/withdrawn + count_active_by_task;TaskCategoryRepository;Database 装配 task_categories。
- 端口:operator GET /admin/task-categories + POST tasks/{id}/assign|recommend|select;opc 同;park /api/tasks 返回 mode/deadline/delivery_days/headcount/exclusive/publisher_name。
- 迁移 0009(tasks 加列+task_categories)已应用+stamp;seed 35 分类字典 + task 新字段(含独占/推荐演示) + 补种已初始化库。
- 测试 test_task_system.py(独占/限额/指派/推荐/list_published/publish/category)+补齐 test_task_claim 语义, 15 passed。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 19:30:16 +08:00
Pine b9b5e2e2ff feat(task): 任务中心扫码接单(多端) —— 服务端任务状态机/端口/迁移
- Task 加 task_code/tags/display_priority/claimed_by/claimed_at/doing_at;新增 TaskClaim 流水表。
- TaskService 加 claimed/doing/completed 状态机(claim/start_doing/complete),grab 并入 claim。
- TaskRepository 加 list_published/get_by_code/update/claim/set_doing + TaskClaimRepository;挂 Database。
- 端口:
  · opc  /tasks/grab-by-code、/tasks/{id}/doing、/tasks/{id}/complete
  · operator POST /tasks(auto task_code) + PATCH /tasks/:id
  · park  /park/api/tasks(大屏展示,含 scan_payload 二维码载荷)
  · training /api/tasks/claim-by-code、/api/tasks/my(小程序 C 端账号→OPC 身份 find-or-create 领单)
- 迁移 0008(tasks 加列 + task_claims)已应用+stamp;seed 补 task_code/tags/grab demo。
- tests/test_task_claim.py(自包含内存库, 状态机+流水+list_published), 直接 async 校验通过。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 18:40:35 +08:00
Pine 5f0acfa79e feat(park): 视频识别剥离,per-tenant 配置接入 park-vision 独立服务
- 删除 vision_yolo/vision_llm 及路由 /api/vision/frame|llm(保留遥测 event),去除 ultralytics 依赖
- 视频识别改为每园区(per-tenant)配置,经 park_settings(kv) 键 vision_api:<tid> 存取
- /park/api/vision/config GET/PUT(园区端读写本园区识别地址,可局域网);bind 下发含 vision_api
- 新增 alembic 0004(tenant_id 可空) / 0005(park_settings 表),迁移脚本执行
2026-08-25 01:52:23 +08:00
Pine 634ed22dcd fix(park): 园区子应用加 CORS(allow_origins=*) — 大屏跨域预检 405/ACAO 拒绝
大屏(Vite dev :1420 / Tauri tauri.localhost)与 server-core(:8090) 不同源;app.park 独立
FastAPI 未加 CORS → OPTIONS 预检 405、ACAO 拒绝。加 CORSMiddleware(allow_origins=['*']),
TestClient 验证 /park/api/config 与预检均 200 且带 ACAO。
2026-08-24 20:38:32 +08:00
Pine 585277b724 fix(park): /park/api/config 补顶层 mqtt_url/username/password — 兼容大屏 bootstrap 取 MQTT/API 引导
大屏 main.jsx 读 cfg.mqtt_url/mqtt_username/mqtt_password;此前仅返回嵌套 mqtt{},
大屏回退到构建期旧地址。补顶层字段(取 server-core .env MQTT_WS_URL/凭据)。
2026-08-24 20:33:15 +08:00
Pine b6315f69b0 feat(park): 大屏设备绑定流 — 永久设备ID+连接码+园区端绑定+MQTT下发设备token
- park_screens 加 status/code/code_expires/bound_at、tenant_id 可空(alembic 0002)。
- auth 加 create/parse_device_token {tenant_id,device_id}。
- tenants 加 ensures_device/set_device_code/find_device_by_code/bind_device/unbind_device。
- 端点:/park/api/devices/register、/park/api/devices/{device_id}/code(8位码TTL10min)、
  /park/tenants/{tid}/screens/bind-by-code(校验码→绑定→MQTT opc/display/bind/<dev> 下发 token)、
  /park/api/devices/{device_id}/unbind。_resolve_tenant 支持设备 token。
- 验证(TestClient):register→code→建园区→绑码(bound/命名)→设备token取数据返回绑定园区。
2026-08-24 20:10:46 +08:00
Pine 5752b3816d refactor(park): 园区数据层迁唯一总库(async SQLAlchemy) — 去 raw sqlite3/park.db
- tenants.py 改为 async SQLAlchemy(ParkTenant/Company/KbDoc/Screen,共享 _ASYNC_ENGINE),
  不再开独立 park.db、不再 init_db;建表/种子走 alembic+seed.py。
- 同步只读 accessor(list_tenants_sync/list_companies_sync/get_tenant_data_sync/get_agent_sync)
  供 sim_engine 同步 tick/tools 用。
- sim_engine.get_engine 改读 get_tenant_data_sync;refresh_engine(tenant_id, data)。
- routers 全部 tenants 调用改 await,_resolve_tenant 改 async;app.py 移除 init_db;
  tools._query_companies 用 list_companies_sync。修复 ensure_default_tenant(T001)、Row→dict。
- 验证(migrate+seed+TestClient):tenants/companies/screens/screen/data/agent/kb/snapshot/display 全 200。
2026-08-24 20:01:03 +08:00
Pine e4d4dbd8c9 fix(park): 大屏前端契约对齐 — update_check download_url=/download、media 返回 relative_path
大屏 api.js 以 getApiBase()(=/park) + 相对路径拼接,download_url 应 '/' 相对、media 应 relative_path。
2026-08-24 19:45:28 +08:00
Pine 47d2a1b62b feat(park): 补全大屏迁移端点+静态资源 — 迁自 park-desktop/backend(可删原后端)
- 新增 /park/api/upload、/api/state、/api/control、/api/playlist(|add/remove/play)、/api/media/add-url、
  /api/delete、/park/download、/park/api/update/check(安装包取 serverdata/park/installers)。
- 迁入 app/park/static(admin.css/js + voice-worklets),挂 /park/static。
- media/data.json/安装包 落 serverdata/park/(gitignored 运行数据)。
- TestClient 冒烟:health/settings/playlist/media/control/download/update/static 均 200。
2026-08-24 19:44:26 +08:00
Pine 88882553a9 feat(园区端): 园区状态(禁用/启用)+联级删除 — 禁用禁止登录,删除一并删资源
park_tenants 增 status 列(migration)、set_status、/park/tenants/{id}/status 端点;
/ park/auth/login 对被禁用园区返回 403;delete_tenant 联级删 企业/知识库/屏幕+引擎缓存;
_summary 含 status。TestClient:禁用→登录403、启用→200、删除→资源清零。
2026-08-24 19:05:16 +08:00
Pine 6458d5eb98 feat(园区端): 园区不再自建账号 — 改为绑定已有平台账号为管理员
create_tenant 不再建账号(admin 留空);/park/tenants POST 仅名称/简介;新增 /park/tenants/{id}/bind|unbind;
/park/auth/login 改为校验平台账号密码 + 该账号已绑定为某园区管理员(签发 tenant token)。
park_tenants 增 admin_username 列(init_db 迁移)。TestClient:创建(无账号)→绑定pine→pine登录园区端成功。
2026-08-24 18:46:41 +08:00
Pine 0448ab57ab fix(park): /park/tenants PUT 改用 TenantPatch(exclude_none) — 仅改管理员账号不再清空名称/简介
平台端管理园区账号(改 username/password)时,原 TenantBody 默认 name/intro 会被写入覆盖;
改用全可选 TenantPatch + exclude_none,只 patch 提供的字段。TestClient 验证保存账号保留名称/简介。
2026-08-24 18:28:14 +08:00
Pine d26d3dc3fa feat(park): /park/api/screen/data 支持全量数据编辑(动态/区域/产业构成/营收/成立时间等)
ScreenBody 增 intro/feed/zones/industryMix/address/phone/email/region/revenue_total/revenue_tax;
update_screen 全量写入 data_json 并 refresh_engine;screen_view 返回 zones/industryMix/feed/region。
TestClient:PUT 名称+两段简介+动态+区域+产业+营收+成立时间 → snapshot 反映。
2026-08-24 18:09:23 +08:00
Pine 81f4dfd0ad feat(park): 园区多租户 — SQLite(tenants表+companies+kb) + 每租户引擎 + 认证 + 作用域隔离
- tenants.py:park_tenants/park_companies/park_kb_docs 三表(serverdata/park/park.db),
  每园区独立 name/intro(两段式)/auth(账密 salted hash)/data(大屏锚点)/agent/kb;
  ensure_default_tenant 自愈建默认园区+灌 39 家企业。
- sim_engine 重构为 SimEngine(data)——每租户独立实例,get_engine(tid)/refresh_engine(tid)。
- auth.py:/park/auth/login(账密→长效 tenant JWT)、/park/auth/me、require_tenant(401)。
- mqtt:register/publish_command/publish_tick 按 tenant_id 作用域(拓扑为 command/tid/clientId)。
- routers:/park/tenants CRUD + 全部数据/指令端点租户作用域(authorization token 或 ?tenant_id)。
- app.py lifespan init_db + 逐租户 tick/publish;tools._query_companies 读租户库。
- .gitignore 增 serverdata/park/。TestClient:建租户/登录/快照隔离/企业CRUD/指令鉴权(无token401) 全过。
2026-08-24 18:06:51 +08:00
Pine 21cfab58fa feat(park): 子应用 lifespan 接入 s2s 实时语音栈(S2S_ENABLED=1 时后台起 :8765)
导入 .s2s_bridge.start_s2s_backend 并以 stop 事件控制;依赖 speech_to_speech
(vendor/s2s-cloud),启用前需 uv pip install -e app/park/vendor/s2s-cloud。
2026-08-24 17:29:37 +08:00
Pine 064b06ecf0 feat(park): 全量迁入园区重模块 llm/rag/asr/s2s/vision + 重依赖
迁入 app/park:llm(对话)、rag(双路向量知识库)、tools/ai_tools(智能体工具)、
asr(语音识别)、s2s_bridge(实时语音桥)、vision_yolo/vision_llm(人脸/多模态)、
knowledge/*.md、vendor/s2s-cloud(s2s 云化栈);routers 补 /api/ai|kb|asr|vision|
s2s|tools 端点。智能体提示词/企业名录改读 park_config 主数据源。pyproject 加重依赖
(dashscope/numpy/openai/torch/transformers/ultralytics/websockets/soundfile/scipy/
nltk/jinja2)。TestClient 冒烟:ai/chat(无 Key 走本地规则)、kb、s2s、tools、display 均 200。
2026-08-24 17:28:53 +08:00
Pine 03ba0810ae feat(park): 园区主数据源 park_config + /park 写端点(企业/智能体/知识库/大屏数据)
新增 app/park/park_config.py(serverdata/park/park_config.json 主数据源,企业默认自 sim_engine
COMPANIES 39 家导入);routers.py 增 /park/api/park/companies CRUD、/park/api/agent/config、
/park/api/kb/docs CRUD+reindex、/park/api/screen/data GET/PUT;/park/api/config 的 api_base
修正为 /park 前缀(避免大屏 request() /api 双写)。TestClient 冒烟通过。
2026-08-24 17:11:17 +08:00
Pine 4d4d38fe0f feat(park): 园区子应用 app/park 骨架迁入 — dispatcher /park 前缀分流
迁自 park-desktop/backend/app:config(数据目录→serverdata/park)/storage/sim_engine/
mqtt/event_bus + 精简 routers(health/settings/config/dashboard/park/companies/display/
events) + app.py 子应用(lifespan 起 MQTT hub+tick 线程, include_router prefix=/park)。
dispatcher.py 增 ROUTE_PARK_PREFIX + _prefix_app,与 app.training(/api)、app.main 分流。
pyproject 增 paho-mqtt(MQTT 必需)。AI/知识库/语音/视觉重模块延后全量迁入。
2026-08-24 16:57:27 +08:00