Files
hms/crates/erp-points/src/dto/points_dto.rs
iven ac1033dbaf
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled
refactor: 积分系统拆分为独立 erp-points crate
- 新建 erp-points crate(8 Entity + account/product service + handler)
- 商品 CRUD 和账户管理完整实现,订单/签到/规则端点暂返回 501
- 注册到 workspace + erp-server 路由 /api/v1/points/*
- API 路径不变,前端无需修改
2026-04-28 14:32:16 +08:00

315 lines
9.3 KiB
Rust

use chrono::NaiveDate;
use erp_core::sanitize::sanitize_option;
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use uuid::Uuid;
// ---------------------------------------------------------------------------
// 积分账户
// ---------------------------------------------------------------------------
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PointsAccountResp {
pub id: Uuid,
pub patient_id: Uuid,
pub balance: i32,
pub total_earned: i32,
pub total_spent: i32,
pub total_expired: i32,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
pub version: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct CreateAccountReq {
pub patient_id: Uuid,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct CheckinStatusResp {
pub checked_in_today: bool,
pub consecutive_days: i32,
pub next_streak_milestone: Option<i32>,
}
// ---------------------------------------------------------------------------
// 积分流水
// ---------------------------------------------------------------------------
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PointsTransactionResp {
pub id: Uuid,
pub account_id: Uuid,
pub transaction_type: String,
pub amount: i32,
pub remaining_amount: i32,
pub status: String,
pub expires_at: Option<chrono::DateTime<chrono::Utc>>,
pub balance_after: i32,
pub description: Option<String>,
pub created_at: chrono::DateTime<chrono::Utc>,
}
// ---------------------------------------------------------------------------
// 积分规则
// ---------------------------------------------------------------------------
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct CreatePointsRuleReq {
pub event_type: String,
pub name: String,
pub description: Option<String>,
pub points_value: i32,
#[serde(default)]
pub daily_cap: i32,
#[serde(default)]
pub streak_7d_bonus: i32,
#[serde(default)]
pub streak_14d_bonus: i32,
#[serde(default)]
pub streak_30d_bonus: i32,
}
impl CreatePointsRuleReq {
pub fn sanitize(&mut self) {
self.description = sanitize_option(self.description.take());
}
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct UpdatePointsRuleReq {
pub name: Option<String>,
pub description: Option<String>,
pub points_value: Option<i32>,
pub daily_cap: Option<i32>,
pub streak_7d_bonus: Option<i32>,
pub streak_14d_bonus: Option<i32>,
pub streak_30d_bonus: Option<i32>,
pub is_active: Option<bool>,
}
impl UpdatePointsRuleReq {
pub fn sanitize(&mut self) {
self.description = sanitize_option(self.description.take());
}
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PointsRuleResp {
pub id: Uuid,
pub event_type: String,
pub name: String,
pub description: Option<String>,
pub points_value: i32,
pub daily_cap: i32,
pub streak_7d_bonus: i32,
pub streak_14d_bonus: i32,
pub streak_30d_bonus: i32,
pub is_active: bool,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
pub version: i32,
}
// ---------------------------------------------------------------------------
// 兑换商品
// ---------------------------------------------------------------------------
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct CreatePointsProductReq {
pub name: String,
pub product_type: Option<String>,
pub points_cost: i32,
pub stock: Option<i32>,
pub image_url: Option<String>,
pub description: Option<String>,
pub service_config: Option<serde_json::Value>,
pub sort_order: Option<i32>,
}
impl CreatePointsProductReq {
pub fn sanitize(&mut self) {
self.description = sanitize_option(self.description.take());
}
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct UpdatePointsProductReq {
pub name: Option<String>,
pub product_type: Option<String>,
pub points_cost: Option<i32>,
pub stock: Option<i32>,
pub image_url: Option<String>,
pub description: Option<String>,
pub service_config: Option<serde_json::Value>,
pub is_active: Option<bool>,
pub sort_order: Option<i32>,
}
impl UpdatePointsProductReq {
pub fn sanitize(&mut self) {
self.description = sanitize_option(self.description.take());
}
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PointsProductResp {
pub id: Uuid,
pub name: String,
pub product_type: String,
pub points_cost: i32,
pub stock: i32,
pub image_url: Option<String>,
pub description: Option<String>,
pub is_active: bool,
pub sort_order: i32,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
pub version: i32,
}
// ---------------------------------------------------------------------------
// 兑换订单
// ---------------------------------------------------------------------------
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct CreateOrderReq {
pub product_id: Uuid,
pub patient_id: Uuid,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PointsOrderResp {
pub id: Uuid,
pub patient_id: Uuid,
pub product_id: Uuid,
pub product_name: Option<String>,
pub points_cost: i32,
pub status: String,
pub qr_code: Option<Uuid>,
pub verified_by: Option<Uuid>,
pub verified_at: Option<chrono::DateTime<chrono::Utc>>,
pub expires_at: Option<chrono::DateTime<chrono::Utc>>,
pub notes: Option<String>,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
pub version: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct VerifyOrderReq {
pub qr_code: Uuid,
}
// ---------------------------------------------------------------------------
// 线下活动
// ---------------------------------------------------------------------------
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct CreateOfflineEventReq {
pub title: String,
pub description: Option<String>,
pub event_date: NaiveDate,
pub start_time: Option<chrono::NaiveTime>,
pub end_time: Option<chrono::NaiveTime>,
pub location: Option<String>,
pub points_reward: Option<i32>,
pub max_participants: Option<i32>,
pub image_url: Option<String>,
}
impl CreateOfflineEventReq {
pub fn sanitize(&mut self) {
self.description = sanitize_option(self.description.take());
self.location = sanitize_option(self.location.take());
}
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct UpdateOfflineEventReq {
pub title: Option<String>,
pub description: Option<String>,
pub event_date: Option<NaiveDate>,
pub start_time: Option<chrono::NaiveTime>,
pub end_time: Option<chrono::NaiveTime>,
pub location: Option<String>,
pub points_reward: Option<i32>,
pub max_participants: Option<i32>,
pub status: Option<String>,
pub image_url: Option<String>,
}
impl UpdateOfflineEventReq {
pub fn sanitize(&mut self) {
self.description = sanitize_option(self.description.take());
self.location = sanitize_option(self.location.take());
}
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct OfflineEventResp {
pub id: Uuid,
pub title: String,
pub description: Option<String>,
pub event_date: NaiveDate,
pub start_time: Option<chrono::NaiveTime>,
pub end_time: Option<chrono::NaiveTime>,
pub location: Option<String>,
pub points_reward: i32,
pub max_participants: i32,
pub current_participants: i32,
pub status: String,
pub image_url: Option<String>,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
pub version: i32,
}
// ---------------------------------------------------------------------------
// 管理端:带版本号的更新/删除包装
// ---------------------------------------------------------------------------
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct UpdateRuleWithVersion {
pub data: UpdatePointsRuleReq,
pub version: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct UpdateProductWithVersion {
pub data: UpdatePointsProductReq,
pub version: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct UpdateOfflineEventWithVersion {
pub data: UpdateOfflineEventReq,
pub version: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct AdminCheckinReq {
pub patient_id: Uuid,
}
// ---------------------------------------------------------------------------
// 积分统计
// ---------------------------------------------------------------------------
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PointsStatisticsResp {
pub total_issued: i64,
pub total_spent: i64,
pub total_expired: i64,
pub active_accounts: i64,
pub top_earners: Vec<TopEarner>,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct TopEarner {
pub account_id: Uuid,
pub patient_id: Uuid,
pub total_earned: i32,
}