Files
zclaw_openfang/crates/zclaw-saas/src/industry/handlers.rs
iven 5d1050bf6f
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
feat(industry): Phase 1 行业配置基础 — 数据模型 + 四行业内置配置 + ButlerRouter 动态关键词
- 新增 SaaS industry 模块 (types/service/handlers/mod/builtin)
- 4 行业内置配置: healthcare/education/garment/ecommerce
- 数据库迁移: industries + account_industries 表
- 8 个 API 端点 (CRUD + 用户行业关联)
- ButlerRouter 改造: 支持 IndustryKeywordConfig 动态注入
- 12 个测试全通过 (含动态行业分类测试)
2026-04-12 15:42:35 +08:00

112 lines
3.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 行业配置 API handlers
use axum::extract::{Path, Query, State};
use axum::Extension;
use axum::Json;
use crate::error::SaasResult;
use crate::state::AppState;
use crate::auth::types::AuthContext;
use super::types::*;
use super::service;
/// GET /api/v1/industries — 行业列表(公开,已认证用户可访问)
pub async fn list_industries(
State(state): State<AppState>,
Query(query): Query<ListIndustriesQuery>,
) -> SaasResult<Json<crate::common::PaginatedResponse<IndustryListItem>>> {
let result = service::list_industries(&state.db, &query).await?;
Ok(Json(result))
}
/// GET /api/v1/industries/:id — 行业详情(公开)
pub async fn get_industry(
State(state): State<AppState>,
Path(id): Path<String>,
) -> SaasResult<Json<Industry>> {
let industry = service::get_industry(&state.db, &id).await?;
Ok(Json(industry))
}
/// POST /api/v1/industries — 创建行业 (admin: config:write)
pub async fn create_industry(
State(state): State<AppState>,
Extension(ctx): Extension<AuthContext>,
Json(body): Json<CreateIndustryRequest>,
) -> SaasResult<Json<Industry>> {
require_config_write(&ctx)?;
let industry = service::create_industry(&state.db, &body).await?;
Ok(Json(industry))
}
/// PATCH /api/v1/industries/:id — 更新行业 (admin: config:write)
pub async fn update_industry(
State(state): State<AppState>,
Extension(ctx): Extension<AuthContext>,
Path(id): Path<String>,
Json(body): Json<UpdateIndustryRequest>,
) -> SaasResult<Json<Industry>> {
require_config_write(&ctx)?;
let industry = service::update_industry(&state.db, &id, &body).await?;
Ok(Json(industry))
}
/// GET /api/v1/industries/:id/full-config — 完整配置含关键词、prompt等
pub async fn get_industry_full_config(
State(state): State<AppState>,
Path(id): Path<String>,
) -> SaasResult<Json<IndustryFullConfig>> {
let config = service::get_industry_full_config(&state.db, &id).await?;
Ok(Json(config))
}
/// GET /api/v1/accounts/:id/industries — 用户授权行业列表
pub async fn list_account_industries(
State(state): State<AppState>,
Path(account_id): Path<String>,
) -> SaasResult<Json<Vec<AccountIndustryItem>>> {
let items = service::list_account_industries(&state.db, &account_id).await?;
Ok(Json(items))
}
/// PUT /api/v1/accounts/:id/industries — 设置用户行业 (admin: account:admin)
pub async fn set_account_industries(
State(state): State<AppState>,
Extension(ctx): Extension<AuthContext>,
Path(account_id): Path<String>,
Json(body): Json<SetAccountIndustriesRequest>,
) -> SaasResult<Json<Vec<AccountIndustryItem>>> {
require_account_admin(&ctx)?;
let items = service::set_account_industries(&state.db, &account_id, &body).await?;
Ok(Json(items))
}
/// GET /api/v1/accounts/me/industries — 当前用户行业
pub async fn list_my_industries(
State(state): State<AppState>,
Extension(ctx): Extension<AuthContext>,
) -> SaasResult<Json<Vec<AccountIndustryItem>>> {
let account_id = &ctx.account_id;
let items = service::list_account_industries(&state.db, account_id).await?;
Ok(Json(items))
}
// ============ Helpers ============
fn require_config_write(ctx: &AuthContext) -> SaasResult<()> {
if !ctx.permissions.contains(&"config:write".to_string())
&& !ctx.permissions.contains(&"admin:full".to_string())
{
return Err(crate::error::SaasError::Forbidden("需要 config:write 权限".to_string()));
}
Ok(())
}
fn require_account_admin(ctx: &AuthContext) -> SaasResult<()> {
if !ctx.permissions.contains(&"account:admin".to_string())
&& !ctx.permissions.contains(&"admin:full".to_string())
{
return Err(crate::error::SaasError::Forbidden("需要 account:admin 权限".to_string()));
}
Ok(())
}