208 changed files with 12398 additions and 5227 deletions
@ -0,0 +1,460 @@ |
|||
# 健康 AI 助手 - 后端服务文档 |
|||
|
|||
> 基于 go-zero 微服务框架重构 |
|||
|
|||
--- |
|||
|
|||
## 一、服务概述 |
|||
|
|||
### 1.1 原架构(Gin) |
|||
|
|||
``` |
|||
server/ |
|||
├── cmd/server/main.go # 入口 |
|||
├── internal/ |
|||
│ ├── api/handler/ # HTTP 处理器 |
|||
│ ├── api/middleware/ # 中间件 |
|||
│ ├── api/router.go # 路由定义 |
|||
│ ├── config/ # 配置 |
|||
│ ├── database/ # 数据库初始化 |
|||
│ ├── model/ # GORM 模型 |
|||
│ ├── repository/ # 数据访问层 |
|||
│ └── service/ # 业务逻辑层 |
|||
└── pkg/ # 公共包 |
|||
``` |
|||
|
|||
### 1.2 目标架构(go-zero) |
|||
|
|||
``` |
|||
backend/ |
|||
├── health-api/ # REST API 服务 |
|||
│ ├── etc/config.yaml # 配置 |
|||
│ ├── health.api # API 定义 |
|||
│ ├── internal/ |
|||
│ │ ├── config/ # 配置结构 |
|||
│ │ ├── handler/ # Handler 层 |
|||
│ │ ├── logic/ # Logic 业务层 |
|||
│ │ ├── svc/ # ServiceContext |
|||
│ │ └── types/ # 请求/响应类型 |
|||
│ └── health.go # 入口 |
|||
├── health-rpc/ # RPC 服务(可选) |
|||
└── model/ # 数据模型 |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## 二、功能模块 |
|||
|
|||
### 2.1 认证模块 (Auth) |
|||
|
|||
| API | 方法 | 路径 | 描述 | |
|||
| ---------- | ---- | ------------------- | ------------------- | |
|||
| 注册 | POST | /api/auth/register | 手机号/邮箱注册 | |
|||
| 登录 | POST | /api/auth/login | 登录获取 Token | |
|||
| 刷新 Token | POST | /api/auth/refresh | 刷新 JWT Token | |
|||
| 发送验证码 | POST | /api/auth/send-code | 发送短信/邮箱验证码 | |
|||
|
|||
**请求/响应示例:** |
|||
|
|||
```go |
|||
// 注册请求 |
|||
type RegisterReq struct { |
|||
Phone string `json:"phone,optional"` |
|||
Email string `json:"email,optional"` |
|||
Password string `json:"password"` |
|||
Code string `json:"code,optional"` |
|||
} |
|||
|
|||
// 登录响应 |
|||
type LoginResp struct { |
|||
Token string `json:"token"` |
|||
ExpiresAt int64 `json:"expires_at"` |
|||
User UserInfo `json:"user"` |
|||
} |
|||
``` |
|||
|
|||
### 2.2 用户模块 (User) |
|||
|
|||
| API | 方法 | 路径 | 描述 | 认证 | |
|||
| -------- | ---- | ----------------- | ---------------- | ---- | |
|||
| 获取信息 | GET | /api/user/profile | 获取用户基本信息 | ✅ | |
|||
| 更新资料 | PUT | /api/user/profile | 更新昵称/头像 | ✅ | |
|||
|
|||
### 2.3 健康档案模块 (Health) |
|||
|
|||
| API | 方法 | 路径 | 描述 | 认证 | |
|||
| ------------ | ------ | ----------------------------- | ------------------ | ---- | |
|||
| 获取完整档案 | GET | /api/user/health-profile | 获取所有健康信息 | ✅ | |
|||
| 更新档案 | PUT | /api/user/health-profile | 更新健康档案 | ✅ | |
|||
| 获取基础档案 | GET | /api/user/basic-profile | 获取基础信息 | ✅ | |
|||
| 获取生活习惯 | GET | /api/user/lifestyle | 获取生活习惯 | ✅ | |
|||
| 更新生活习惯 | PUT | /api/user/lifestyle | 更新生活习惯 | ✅ | |
|||
| 获取病史 | GET | /api/user/medical-history | 获取病史列表 | ✅ | |
|||
| 删除病史 | DELETE | /api/user/medical-history/:id | 删除单条病史 | ✅ | |
|||
| 获取家族史 | GET | /api/user/family-history | 获取家族病史 | ✅ | |
|||
| 删除家族史 | DELETE | /api/user/family-history/:id | 删除单条家族史 | ✅ | |
|||
| 获取过敏记录 | GET | /api/user/allergy-records | 获取过敏记录 | ✅ | |
|||
| 删除过敏记录 | DELETE | /api/user/allergy-records/:id | 删除单条过敏记录 | ✅ | |
|||
| 获取购买历史 | GET | /api/user/purchase-history | 获取保健品购买记录 | ✅ | |
|||
|
|||
### 2.4 健康调查模块 (Survey) |
|||
|
|||
| API | 方法 | 路径 | 描述 | 认证 | |
|||
| -------------- | ---- | --------------------------------- | ---------------- | ---- | |
|||
| 获取状态 | GET | /api/survey/status | 获取调查完成状态 | ✅ | |
|||
| 提交基础信息 | POST | /api/survey/basic-info | 提交基础健康信息 | ✅ | |
|||
| 提交生活习惯 | POST | /api/survey/lifestyle | 提交生活习惯 | ✅ | |
|||
| 提交病史 | POST | /api/survey/medical-history | 提交单条病史 | ✅ | |
|||
| 批量提交病史 | POST | /api/survey/medical-history/batch | 批量提交病史 | ✅ | |
|||
| 提交家族史 | POST | /api/survey/family-history | 提交单条家族史 | ✅ | |
|||
| 批量提交家族史 | POST | /api/survey/family-history/batch | 批量提交家族史 | ✅ | |
|||
| 提交过敏信息 | POST | /api/survey/allergy | 提交单条过敏信息 | ✅ | |
|||
| 批量提交过敏 | POST | /api/survey/allergy/batch | 批量提交过敏信息 | ✅ | |
|||
| 完成调查 | POST | /api/survey/complete | 标记调查完成 | ✅ | |
|||
|
|||
### 2.5 体质辨识模块 (Constitution) |
|||
|
|||
| API | 方法 | 路径 | 描述 | 认证 | |
|||
| ------------ | ---- | ----------------------------------- | ---------------- | ---- | |
|||
| 获取问卷 | GET | /api/constitution/questions | 获取所有题目 | ✅ | |
|||
| 获取分组问卷 | GET | /api/constitution/questions/grouped | 按体质分组获取 | ✅ | |
|||
| 提交测评 | POST | /api/constitution/submit | 提交问卷答案 | ✅ | |
|||
| 获取结果 | GET | /api/constitution/result | 获取最新测评结果 | ✅ | |
|||
| 获取历史 | GET | /api/constitution/history | 获取测评历史 | ✅ | |
|||
| 获取建议 | GET | /api/constitution/recommendations | 获取调养建议 | ✅ | |
|||
|
|||
**体质类型:** |
|||
|
|||
- pinghe (平和质) |
|||
- qixu (气虚质) |
|||
- yangxu (阳虚质) |
|||
- yinxu (阴虚质) |
|||
- tanshi (痰湿质) |
|||
- shire (湿热质) |
|||
- xueyu (血瘀质) |
|||
- qiyu (气郁质) |
|||
- tebing (特禀质) |
|||
|
|||
### 2.6 AI 对话模块 (Conversation) |
|||
|
|||
| API | 方法 | 路径 | 描述 | 认证 | |
|||
| -------------- | ------ | -------------------------------------- | -------------------- | ---- | |
|||
| 获取列表 | GET | /api/conversations | 获取对话列表 | ✅ | |
|||
| 创建对话 | POST | /api/conversations | 创建新对话 | ✅ | |
|||
| 获取详情 | GET | /api/conversations/:id | 获取对话消息 | ✅ | |
|||
| 删除对话 | DELETE | /api/conversations/:id | 删除对话 | ✅ | |
|||
| 发送消息 | POST | /api/conversations/:id/messages | 发送消息(非流式) | ✅ | |
|||
| 发送消息(流式) | POST | /api/conversations/:id/messages/stream | 发送消息(SSE 流式) | ✅ | |
|||
|
|||
**AI 服务配置:** |
|||
|
|||
- 阿里云通义千问(主要) |
|||
- OpenAI 兼容接口(备选) |
|||
|
|||
### 2.7 产品模块 (Product) |
|||
|
|||
| API | 方法 | 路径 | 描述 | 认证 | |
|||
| ---------- | ---- | ----------------------- | ---------------- | ------- | |
|||
| 获取列表 | GET | /api/products | 分页获取产品 | ❌ | |
|||
| 获取详情 | GET | /api/products/:id | 获取产品详情 | ❌ | |
|||
| 按分类获取 | GET | /api/products/category | 按分类筛选 | ❌ | |
|||
| 搜索产品 | GET | /api/products/search | 关键词搜索 | ❌ | |
|||
| 获取推荐 | GET | /api/products/recommend | 基于体质推荐 | ✅ | |
|||
| 同步购买 | POST | /api/sync/purchase | 商城同步购买记录 | API Key | |
|||
|
|||
--- |
|||
|
|||
## 三、数据模型 |
|||
|
|||
### 3.1 用户相关 |
|||
|
|||
```sql |
|||
-- 用户表 |
|||
CREATE TABLE users ( |
|||
id BIGINT PRIMARY KEY, |
|||
phone VARCHAR(20) UNIQUE, |
|||
email VARCHAR(100) UNIQUE, |
|||
password_hash VARCHAR(255) NOT NULL, |
|||
nickname VARCHAR(50), |
|||
avatar VARCHAR(255), |
|||
survey_completed BOOLEAN DEFAULT FALSE, |
|||
created_at TIMESTAMP, |
|||
updated_at TIMESTAMP, |
|||
deleted_at TIMESTAMP |
|||
); |
|||
|
|||
-- 健康档案表 |
|||
CREATE TABLE health_profiles ( |
|||
id BIGINT PRIMARY KEY, |
|||
user_id BIGINT UNIQUE NOT NULL, |
|||
name VARCHAR(50), |
|||
birth_date DATE, |
|||
gender VARCHAR(10), |
|||
height DECIMAL(5,2), |
|||
weight DECIMAL(5,2), |
|||
bmi DECIMAL(4,2), |
|||
blood_type VARCHAR(10), |
|||
occupation VARCHAR(50), |
|||
marital_status VARCHAR(20), |
|||
region VARCHAR(100) |
|||
); |
|||
|
|||
-- 生活习惯表 |
|||
CREATE TABLE lifestyle_infos ( |
|||
id BIGINT PRIMARY KEY, |
|||
user_id BIGINT UNIQUE NOT NULL, |
|||
sleep_time TIME, |
|||
wake_time TIME, |
|||
sleep_quality VARCHAR(20), |
|||
meal_regularity VARCHAR(20), |
|||
diet_preference VARCHAR(20), |
|||
daily_water_ml INT, |
|||
exercise_frequency VARCHAR(20), |
|||
exercise_type VARCHAR(50), |
|||
exercise_duration_min INT, |
|||
is_smoker BOOLEAN, |
|||
alcohol_frequency VARCHAR(20) |
|||
); |
|||
``` |
|||
|
|||
### 3.2 健康记录 |
|||
|
|||
```sql |
|||
-- 病史表 |
|||
CREATE TABLE medical_histories ( |
|||
id BIGINT PRIMARY KEY, |
|||
health_profile_id BIGINT NOT NULL, |
|||
disease_name VARCHAR(100) NOT NULL, |
|||
disease_type VARCHAR(50), |
|||
diagnosed_date DATE, |
|||
status VARCHAR(20), |
|||
notes TEXT |
|||
); |
|||
|
|||
-- 家族病史表 |
|||
CREATE TABLE family_histories ( |
|||
id BIGINT PRIMARY KEY, |
|||
health_profile_id BIGINT NOT NULL, |
|||
relation VARCHAR(20) NOT NULL, |
|||
disease_name VARCHAR(100) NOT NULL, |
|||
notes TEXT |
|||
); |
|||
|
|||
-- 过敏记录表 |
|||
CREATE TABLE allergy_records ( |
|||
id BIGINT PRIMARY KEY, |
|||
health_profile_id BIGINT NOT NULL, |
|||
allergy_type VARCHAR(50) NOT NULL, |
|||
allergen VARCHAR(100) NOT NULL, |
|||
severity VARCHAR(20), |
|||
reaction_desc TEXT |
|||
); |
|||
``` |
|||
|
|||
### 3.3 体质辨识 |
|||
|
|||
```sql |
|||
-- 体质测评表 |
|||
CREATE TABLE constitution_assessments ( |
|||
id BIGINT PRIMARY KEY, |
|||
user_id BIGINT NOT NULL, |
|||
assessed_at TIMESTAMP NOT NULL, |
|||
scores JSON, -- 各体质得分 |
|||
primary_constitution VARCHAR(20), |
|||
secondary_constitutions JSON, -- 兼夹体质 |
|||
recommendations JSON -- 调养建议 |
|||
); |
|||
|
|||
-- 测评答案表 |
|||
CREATE TABLE assessment_answers ( |
|||
id BIGINT PRIMARY KEY, |
|||
assessment_id BIGINT NOT NULL, |
|||
question_id INT NOT NULL, |
|||
score INT CHECK (score >= 1 AND score <= 5) |
|||
); |
|||
|
|||
-- 问卷题库表 |
|||
CREATE TABLE question_banks ( |
|||
id INT PRIMARY KEY, |
|||
constitution_type VARCHAR(20) NOT NULL, |
|||
question_text TEXT NOT NULL, |
|||
options JSON, |
|||
order_num INT |
|||
); |
|||
``` |
|||
|
|||
### 3.4 对话 |
|||
|
|||
```sql |
|||
-- 对话表 |
|||
CREATE TABLE conversations ( |
|||
id BIGINT PRIMARY KEY, |
|||
user_id BIGINT NOT NULL, |
|||
title VARCHAR(200), |
|||
created_at TIMESTAMP, |
|||
updated_at TIMESTAMP, |
|||
deleted_at TIMESTAMP |
|||
); |
|||
|
|||
-- 消息表 |
|||
CREATE TABLE messages ( |
|||
id BIGINT PRIMARY KEY, |
|||
conversation_id BIGINT NOT NULL, |
|||
role VARCHAR(20) NOT NULL, -- user/assistant/system |
|||
content TEXT NOT NULL, |
|||
created_at TIMESTAMP |
|||
); |
|||
``` |
|||
|
|||
### 3.5 产品 |
|||
|
|||
```sql |
|||
-- 产品表 |
|||
CREATE TABLE products ( |
|||
id BIGINT PRIMARY KEY, |
|||
name VARCHAR(200) NOT NULL, |
|||
category VARCHAR(50), |
|||
description TEXT, |
|||
efficacy TEXT, |
|||
suitable TEXT, |
|||
price DECIMAL(10,2), |
|||
image_url VARCHAR(500), |
|||
mall_url VARCHAR(500), |
|||
is_active BOOLEAN DEFAULT TRUE |
|||
); |
|||
|
|||
-- 体质-产品关联表 |
|||
CREATE TABLE constitution_products ( |
|||
id BIGINT PRIMARY KEY, |
|||
constitution_type VARCHAR(20) NOT NULL, |
|||
product_id BIGINT NOT NULL, |
|||
priority INT DEFAULT 0, |
|||
reason TEXT |
|||
); |
|||
|
|||
-- 购买历史表 |
|||
CREATE TABLE purchase_histories ( |
|||
id BIGINT PRIMARY KEY, |
|||
user_id BIGINT NOT NULL, |
|||
order_no VARCHAR(50), |
|||
product_id BIGINT, |
|||
product_name VARCHAR(200), |
|||
purchased_at TIMESTAMP, |
|||
source VARCHAR(50) |
|||
); |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## 四、配置说明 |
|||
|
|||
### 4.1 服务配置 |
|||
|
|||
```yaml |
|||
Name: health-api |
|||
Host: 0.0.0.0 |
|||
Port: 8080 |
|||
Mode: dev |
|||
|
|||
# JWT 认证 |
|||
Auth: |
|||
AccessSecret: health-ai-secret-key-change-in-production |
|||
AccessExpire: 86400 # 24小时 |
|||
|
|||
# 数据库 |
|||
Database: |
|||
Driver: sqlite |
|||
DataSource: ./data/health.db |
|||
# PostgreSQL |
|||
# Driver: postgres |
|||
# DataSource: host=localhost port=5432 user=postgres password=xxx dbname=health_app sslmode=disable |
|||
|
|||
# AI 服务 |
|||
AI: |
|||
Provider: aliyun |
|||
MaxHistoryMessages: 10 |
|||
MaxTokens: 2000 |
|||
Aliyun: |
|||
ApiKey: sk-xxx |
|||
Model: qwen-plus |
|||
OpenAI: |
|||
ApiKey: sk-xxx |
|||
BaseUrl: https://api.openai.com/v1 |
|||
Model: gpt-3.5-turbo |
|||
``` |
|||
|
|||
### 4.2 中间件 |
|||
|
|||
1. **JWT 认证中间件** |
|||
|
|||
- 验证 Authorization Header |
|||
- 解析 Token 获取 userID |
|||
- 注入上下文 |
|||
|
|||
2. **CORS 中间件** |
|||
|
|||
- 允许跨域请求 |
|||
- 配置允许的方法和头部 |
|||
|
|||
3. **日志中间件** |
|||
- 请求日志记录 |
|||
- 响应时间统计 |
|||
|
|||
--- |
|||
|
|||
## 五、API 统计 |
|||
|
|||
| 模块 | API 数量 | 需认证 | 说明 | |
|||
| -------- | -------- | ------ | --------------------- | |
|||
| 认证 | 4 | 0 | 注册/登录/刷新/验证码 | |
|||
| 用户 | 2 | 2 | 获取/更新资料 | |
|||
| 健康档案 | 12 | 12 | 完整健康信息 CRUD | |
|||
| 健康调查 | 10 | 10 | 分步提交流程 | |
|||
| 体质辨识 | 6 | 6 | 问卷/测评/结果 | |
|||
| AI 对话 | 6 | 6 | 对话管理/消息 | |
|||
| 产品 | 6 | 1 | 产品查询/推荐 | |
|||
| **总计** | **46** | **37** | | |
|||
|
|||
--- |
|||
|
|||
## 六、迁移计划 |
|||
|
|||
### 6.1 阶段一:基础框架 ✅ 已完成 |
|||
|
|||
- [x] 创建 backend 目录 |
|||
- [x] 使用 mcp-zero 创建 API 服务结构 |
|||
- [x] 定义 .api 文件(46 个 API 端点) |
|||
- [x] 生成基础代码(47 个 Handler + 47 个 Logic) |
|||
|
|||
### 6.2 阶段二:核心功能 |
|||
|
|||
- [ ] 迁移认证模块 |
|||
- [ ] 迁移用户模块 |
|||
- [ ] 迁移健康档案模块 |
|||
|
|||
### 6.3 阶段三:业务功能 |
|||
|
|||
- [ ] 迁移体质辨识模块 |
|||
- [ ] 迁移 AI 对话模块 |
|||
- [ ] 迁移产品模块 |
|||
|
|||
### 6.4 阶段四:优化完善 |
|||
|
|||
- [ ] 添加弹性模式(熔断/限流) |
|||
- [ ] 优化数据库访问 |
|||
- [ ] 添加监控和日志 |
|||
|
|||
--- |
|||
|
|||
## 七、技术栈对比 |
|||
|
|||
| 项目 | 原架构 (Gin) | 目标架构 (go-zero) | |
|||
| -------- | -------------------------- | ------------------- | |
|||
| Web 框架 | Gin | go-zero rest | |
|||
| ORM | GORM | sqlx / goctl model | |
|||
| 配置 | Viper | go-zero conf | |
|||
| 路由 | Gin Router | .api 文件生成 | |
|||
| 中间件 | Gin Middleware | go-zero Middleware | |
|||
| 依赖注入 | 手动 | ServiceContext | |
|||
| 代码生成 | 无 | goctl | |
|||
| 分层架构 | Handler/Service/Repository | Handler/Logic/Model | |
|||
@ -0,0 +1,29 @@ |
|||
Name: healthapi-api |
|||
Host: 0.0.0.0 |
|||
Port: 8080 |
|||
Mode: dev |
|||
Timeout: 300000 # 5分钟超时,用于 AI 流式响应 |
|||
|
|||
# JWT 认证配置 |
|||
Auth: |
|||
AccessSecret: health-ai-secret-key-change-in-production |
|||
AccessExpire: 86400 # 24小时 |
|||
|
|||
# 数据库配置 |
|||
Database: |
|||
Driver: sqlite |
|||
DataSource: ./data/health.db |
|||
|
|||
# AI 服务配置 |
|||
AI: |
|||
Provider: aliyun |
|||
MaxHistoryMessages: 10 |
|||
MaxTokens: 2000 |
|||
Aliyun: |
|||
ApiKey: sk-53b4777561624ba98246c7b9990c5e8b |
|||
Model: qwen-plus |
|||
AppID: "" # 可选:百炼应用 ID(与原 server 保持一致,暂不启用) |
|||
OpenAI: |
|||
ApiKey: ${AI_OPENAI_API_KEY} |
|||
BaseUrl: https://api.openai.com/v1 |
|||
Model: gpt-3.5-turbo |
|||
@ -0,0 +1,68 @@ |
|||
module healthapi |
|||
|
|||
go 1.25.5 |
|||
|
|||
require ( |
|||
github.com/golang-jwt/jwt/v5 v5.3.1 |
|||
github.com/zeromicro/go-zero v1.9.4 |
|||
golang.org/x/crypto v0.47.0 |
|||
gorm.io/driver/mysql v1.6.0 |
|||
gorm.io/driver/postgres v1.6.0 |
|||
gorm.io/driver/sqlite v1.6.0 |
|||
gorm.io/gorm v1.31.1 |
|||
) |
|||
|
|||
require ( |
|||
filippo.io/edwards25519 v1.1.0 // indirect |
|||
github.com/beorn7/perks v1.0.1 // indirect |
|||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect |
|||
github.com/cespare/xxhash/v2 v2.3.0 // indirect |
|||
github.com/fatih/color v1.18.0 // indirect |
|||
github.com/go-logr/logr v1.4.2 // indirect |
|||
github.com/go-logr/stdr v1.2.2 // indirect |
|||
github.com/go-sql-driver/mysql v1.9.0 // indirect |
|||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect |
|||
github.com/google/uuid v1.6.0 // indirect |
|||
github.com/grafana/pyroscope-go v1.2.7 // indirect |
|||
github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect |
|||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect |
|||
github.com/jackc/pgpassfile v1.0.0 // indirect |
|||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect |
|||
github.com/jackc/pgx/v5 v5.7.4 // indirect |
|||
github.com/jackc/puddle/v2 v2.2.2 // indirect |
|||
github.com/jinzhu/inflection v1.0.0 // indirect |
|||
github.com/jinzhu/now v1.1.5 // indirect |
|||
github.com/klauspost/compress v1.17.11 // indirect |
|||
github.com/mattn/go-colorable v0.1.13 // indirect |
|||
github.com/mattn/go-isatty v0.0.20 // indirect |
|||
github.com/mattn/go-sqlite3 v1.14.22 // indirect |
|||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect |
|||
github.com/openzipkin/zipkin-go v0.4.3 // indirect |
|||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect |
|||
github.com/prometheus/client_golang v1.21.1 // indirect |
|||
github.com/prometheus/client_model v0.6.1 // indirect |
|||
github.com/prometheus/common v0.62.0 // indirect |
|||
github.com/prometheus/procfs v0.15.1 // indirect |
|||
github.com/spaolacci/murmur3 v1.1.0 // indirect |
|||
go.opentelemetry.io/otel v1.24.0 // indirect |
|||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect |
|||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect |
|||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect |
|||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect |
|||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 // indirect |
|||
go.opentelemetry.io/otel/exporters/zipkin v1.24.0 // indirect |
|||
go.opentelemetry.io/otel/metric v1.24.0 // indirect |
|||
go.opentelemetry.io/otel/sdk v1.24.0 // indirect |
|||
go.opentelemetry.io/otel/trace v1.24.0 // indirect |
|||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect |
|||
go.uber.org/automaxprocs v1.6.0 // indirect |
|||
golang.org/x/net v0.48.0 // indirect |
|||
golang.org/x/sync v0.19.0 // indirect |
|||
golang.org/x/sys v0.40.0 // indirect |
|||
golang.org/x/text v0.33.0 // indirect |
|||
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect |
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect |
|||
google.golang.org/grpc v1.65.0 // indirect |
|||
google.golang.org/protobuf v1.36.5 // indirect |
|||
gopkg.in/yaml.v2 v2.4.0 // indirect |
|||
) |
|||
@ -0,0 +1,166 @@ |
|||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= |
|||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= |
|||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= |
|||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= |
|||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= |
|||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= |
|||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= |
|||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= |
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= |
|||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= |
|||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= |
|||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= |
|||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= |
|||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= |
|||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= |
|||
github.com/go-sql-driver/mysql v1.9.0 h1:Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1vtvo= |
|||
github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw= |
|||
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= |
|||
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= |
|||
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= |
|||
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= |
|||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= |
|||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= |
|||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= |
|||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
|||
github.com/grafana/pyroscope-go v1.2.7 h1:VWBBlqxjyR0Cwk2W6UrE8CdcdD80GOFNutj0Kb1T8ac= |
|||
github.com/grafana/pyroscope-go v1.2.7/go.mod h1:o/bpSLiJYYP6HQtvcoVKiE9s5RiNgjYTj1DhiddP2Pc= |
|||
github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og= |
|||
github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= |
|||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= |
|||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= |
|||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= |
|||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= |
|||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= |
|||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= |
|||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= |
|||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= |
|||
github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg= |
|||
github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= |
|||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= |
|||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= |
|||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= |
|||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= |
|||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= |
|||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= |
|||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= |
|||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= |
|||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= |
|||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= |
|||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= |
|||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= |
|||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= |
|||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= |
|||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= |
|||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= |
|||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= |
|||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= |
|||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= |
|||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= |
|||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= |
|||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= |
|||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= |
|||
github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= |
|||
github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= |
|||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= |
|||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= |
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
|||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= |
|||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= |
|||
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= |
|||
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= |
|||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= |
|||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= |
|||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= |
|||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= |
|||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= |
|||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= |
|||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= |
|||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= |
|||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= |
|||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= |
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= |
|||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= |
|||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= |
|||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= |
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= |
|||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
|||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
|||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= |
|||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= |
|||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= |
|||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= |
|||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= |
|||
github.com/zeromicro/go-zero v1.9.4 h1:aRLFoISqAYijABtkbliQC5SsI5TbizJpQvoHc9xup8k= |
|||
github.com/zeromicro/go-zero v1.9.4/go.mod h1:a17JOTch25SWxBcUgJZYps60hygK3pIYdw7nGwlcS38= |
|||
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= |
|||
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= |
|||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= |
|||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= |
|||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= |
|||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= |
|||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE= |
|||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM= |
|||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs= |
|||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM= |
|||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 h1:s0PHtIkN+3xrbDOpt2M8OTG92cWqUESvzh2MxiR5xY8= |
|||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0/go.mod h1:hZlFbDbRt++MMPCCfSJfmhkGIWnX1h3XjkfxZUjLrIA= |
|||
go.opentelemetry.io/otel/exporters/zipkin v1.24.0 h1:3evrL5poBuh1KF51D9gO/S+N/1msnm4DaBqs/rpXUqY= |
|||
go.opentelemetry.io/otel/exporters/zipkin v1.24.0/go.mod h1:0EHgD8R0+8yRhUYJOGR8Hfg2dpiJQxDOszd5smVO9wM= |
|||
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= |
|||
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= |
|||
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= |
|||
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= |
|||
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= |
|||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= |
|||
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= |
|||
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= |
|||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= |
|||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= |
|||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= |
|||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= |
|||
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= |
|||
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= |
|||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= |
|||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= |
|||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= |
|||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= |
|||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
|||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |
|||
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= |
|||
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= |
|||
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= |
|||
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= |
|||
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d h1:kHjw/5UfflP/L5EbledDrcG4C2597RtymmGRZvHiCuY= |
|||
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0= |
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= |
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= |
|||
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= |
|||
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= |
|||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= |
|||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= |
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= |
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= |
|||
gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= |
|||
gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= |
|||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= |
|||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= |
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
|||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= |
|||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
|||
gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg= |
|||
gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo= |
|||
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4= |
|||
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo= |
|||
gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= |
|||
gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8= |
|||
gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg= |
|||
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= |
|||
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= |
|||
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= |
|||
@ -0,0 +1,931 @@ |
|||
syntax = "v1" |
|||
|
|||
info ( |
|||
title: "健康AI助手API" |
|||
desc: "健康AI问询助手后端服务" |
|||
author: "healthApps" |
|||
version: "v1" |
|||
) |
|||
|
|||
// ==================== 公共类型 ==================== |
|||
type ( |
|||
// 通用响应 |
|||
CommonResp { |
|||
Code int `json:"code"` |
|||
Message string `json:"message"` |
|||
Data interface{} `json:"data,omitempty"` |
|||
} |
|||
// 分页请求 |
|||
PageReq { |
|||
Page int `form:"page,default=1"` |
|||
PageSize int `form:"page_size,default=10"` |
|||
} |
|||
// 分页响应 |
|||
PageInfo { |
|||
Total int64 `json:"total"` |
|||
Page int `json:"page"` |
|||
PageSize int `json:"page_size"` |
|||
} |
|||
) |
|||
|
|||
// ==================== 认证模块 ==================== |
|||
type ( |
|||
// 注册请求 |
|||
RegisterReq { |
|||
Phone string `json:"phone,optional"` |
|||
Email string `json:"email,optional"` |
|||
Password string `json:"password"` |
|||
Code string `json:"code,optional"` |
|||
} |
|||
// 登录请求 |
|||
LoginReq { |
|||
Phone string `json:"phone,optional"` |
|||
Email string `json:"email,optional"` |
|||
Password string `json:"password"` |
|||
} |
|||
// 登录响应 |
|||
LoginResp { |
|||
Token string `json:"token"` |
|||
ExpiresAt int64 `json:"expires_at"` |
|||
User UserInfo `json:"user"` |
|||
} |
|||
// 用户信息 |
|||
UserInfo { |
|||
ID uint `json:"id"` |
|||
Phone string `json:"phone,omitempty"` |
|||
Email string `json:"email,omitempty"` |
|||
Nickname string `json:"nickname"` |
|||
Avatar string `json:"avatar"` |
|||
SurveyCompleted bool `json:"survey_completed"` |
|||
} |
|||
// 刷新Token请求 |
|||
RefreshTokenReq { |
|||
Token string `json:"token"` |
|||
} |
|||
// 发送验证码请求 |
|||
SendCodeReq { |
|||
Phone string `json:"phone,optional"` |
|||
Email string `json:"email,optional"` |
|||
Type string `json:"type"` // register/login/reset |
|||
} |
|||
// 更新用户资料请求 |
|||
UpdateProfileReq { |
|||
Nickname string `json:"nickname,optional"` |
|||
Avatar string `json:"avatar,optional"` |
|||
} |
|||
) |
|||
|
|||
// ==================== 健康档案模块 ==================== |
|||
type ( |
|||
// 健康档案 |
|||
HealthProfile { |
|||
ID uint `json:"id"` |
|||
UserID uint `json:"user_id"` |
|||
Name string `json:"name"` |
|||
BirthDate string `json:"birth_date"` |
|||
Gender string `json:"gender"` |
|||
Height float64 `json:"height"` |
|||
Weight float64 `json:"weight"` |
|||
BMI float64 `json:"bmi"` |
|||
BloodType string `json:"blood_type"` |
|||
Occupation string `json:"occupation"` |
|||
MaritalStatus string `json:"marital_status"` |
|||
Region string `json:"region"` |
|||
} |
|||
// 生活习惯 |
|||
LifestyleInfo { |
|||
ID uint `json:"id"` |
|||
UserID uint `json:"user_id"` |
|||
SleepTime string `json:"sleep_time"` |
|||
WakeTime string `json:"wake_time"` |
|||
SleepQuality string `json:"sleep_quality"` |
|||
MealRegularity string `json:"meal_regularity"` |
|||
DietPreference string `json:"diet_preference"` |
|||
DailyWaterML int `json:"daily_water_ml"` |
|||
ExerciseFrequency string `json:"exercise_frequency"` |
|||
ExerciseType string `json:"exercise_type"` |
|||
ExerciseDurationMin int `json:"exercise_duration_min"` |
|||
IsSmoker bool `json:"is_smoker"` |
|||
AlcoholFrequency string `json:"alcohol_frequency"` |
|||
} |
|||
// 病史 |
|||
MedicalHistory { |
|||
ID uint `json:"id"` |
|||
HealthProfileID uint `json:"health_profile_id"` |
|||
DiseaseName string `json:"disease_name"` |
|||
DiseaseType string `json:"disease_type"` |
|||
DiagnosedDate string `json:"diagnosed_date"` |
|||
Status string `json:"status"` |
|||
Notes string `json:"notes"` |
|||
} |
|||
// 家族病史 |
|||
FamilyHistory { |
|||
ID uint `json:"id"` |
|||
HealthProfileID uint `json:"health_profile_id"` |
|||
Relation string `json:"relation"` |
|||
DiseaseName string `json:"disease_name"` |
|||
Notes string `json:"notes"` |
|||
} |
|||
// 过敏记录 |
|||
AllergyRecord { |
|||
ID uint `json:"id"` |
|||
HealthProfileID uint `json:"health_profile_id"` |
|||
AllergyType string `json:"allergy_type"` |
|||
Allergen string `json:"allergen"` |
|||
Severity string `json:"severity"` |
|||
ReactionDesc string `json:"reaction_desc"` |
|||
} |
|||
// 完整健康档案响应 |
|||
FullHealthProfileResp { |
|||
Profile HealthProfile `json:"profile"` |
|||
Lifestyle LifestyleInfo `json:"lifestyle"` |
|||
MedicalHistory []MedicalHistory `json:"medical_history"` |
|||
FamilyHistory []FamilyHistory `json:"family_history"` |
|||
AllergyRecords []AllergyRecord `json:"allergy_records"` |
|||
} |
|||
// 更新健康档案请求 |
|||
UpdateHealthProfileReq { |
|||
Name string `json:"name,optional"` |
|||
BirthDate string `json:"birth_date,optional"` |
|||
Gender string `json:"gender,optional"` |
|||
Height float64 `json:"height,optional"` |
|||
Weight float64 `json:"weight,optional"` |
|||
BloodType string `json:"blood_type,optional"` |
|||
Occupation string `json:"occupation,optional"` |
|||
MaritalStatus string `json:"marital_status,optional"` |
|||
Region string `json:"region,optional"` |
|||
} |
|||
// 更新生活习惯请求 |
|||
UpdateLifestyleReq { |
|||
SleepTime string `json:"sleep_time,optional"` |
|||
WakeTime string `json:"wake_time,optional"` |
|||
SleepQuality string `json:"sleep_quality,optional"` |
|||
MealRegularity string `json:"meal_regularity,optional"` |
|||
DietPreference string `json:"diet_preference,optional"` |
|||
DailyWaterML int `json:"daily_water_ml,optional"` |
|||
ExerciseFrequency string `json:"exercise_frequency,optional"` |
|||
ExerciseType string `json:"exercise_type,optional"` |
|||
ExerciseDurationMin int `json:"exercise_duration_min,optional"` |
|||
IsSmoker bool `json:"is_smoker,optional"` |
|||
AlcoholFrequency string `json:"alcohol_frequency,optional"` |
|||
} |
|||
// ID路径参数 |
|||
IdPathReq { |
|||
Id uint `path:"id"` |
|||
} |
|||
) |
|||
|
|||
// ==================== 健康调查模块 ==================== |
|||
type ( |
|||
// 调查状态响应 |
|||
SurveyStatusResp { |
|||
Completed bool `json:"completed"` |
|||
BasicInfo bool `json:"basic_info"` |
|||
Lifestyle bool `json:"lifestyle"` |
|||
MedicalHistory bool `json:"medical_history"` |
|||
FamilyHistory bool `json:"family_history"` |
|||
Allergy bool `json:"allergy"` |
|||
} |
|||
// 提交基础信息请求 |
|||
SubmitBasicInfoReq { |
|||
Name string `json:"name"` |
|||
BirthDate string `json:"birth_date"` |
|||
Gender string `json:"gender"` |
|||
Height float64 `json:"height"` |
|||
Weight float64 `json:"weight"` |
|||
BloodType string `json:"blood_type,optional"` |
|||
Occupation string `json:"occupation,optional"` |
|||
MaritalStatus string `json:"marital_status,optional"` |
|||
Region string `json:"region,optional"` |
|||
} |
|||
// 提交生活习惯请求 |
|||
SubmitLifestyleReq { |
|||
SleepTime string `json:"sleep_time"` |
|||
WakeTime string `json:"wake_time"` |
|||
SleepQuality string `json:"sleep_quality"` |
|||
MealRegularity string `json:"meal_regularity"` |
|||
DietPreference string `json:"diet_preference,optional"` |
|||
DailyWaterML int `json:"daily_water_ml,optional"` |
|||
ExerciseFrequency string `json:"exercise_frequency"` |
|||
ExerciseType string `json:"exercise_type,optional"` |
|||
ExerciseDurationMin int `json:"exercise_duration_min,optional"` |
|||
IsSmoker bool `json:"is_smoker"` |
|||
AlcoholFrequency string `json:"alcohol_frequency"` |
|||
} |
|||
// 提交病史请求 |
|||
SubmitMedicalHistoryReq { |
|||
DiseaseName string `json:"disease_name"` |
|||
DiseaseType string `json:"disease_type,optional"` |
|||
DiagnosedDate string `json:"diagnosed_date,optional"` |
|||
Status string `json:"status,optional"` |
|||
Notes string `json:"notes,optional"` |
|||
} |
|||
// 批量提交病史请求 |
|||
BatchMedicalHistoryReq { |
|||
Items []SubmitMedicalHistoryReq `json:"items"` |
|||
} |
|||
// 提交家族史请求 |
|||
SubmitFamilyHistoryReq { |
|||
Relation string `json:"relation"` |
|||
DiseaseName string `json:"disease_name"` |
|||
Notes string `json:"notes,optional"` |
|||
} |
|||
// 批量提交家族史请求 |
|||
BatchFamilyHistoryReq { |
|||
Items []SubmitFamilyHistoryReq `json:"items"` |
|||
} |
|||
// 提交过敏信息请求 |
|||
SubmitAllergyReq { |
|||
AllergyType string `json:"allergy_type"` |
|||
Allergen string `json:"allergen"` |
|||
Severity string `json:"severity,optional"` |
|||
ReactionDesc string `json:"reaction_desc,optional"` |
|||
} |
|||
// 批量提交过敏信息请求 |
|||
BatchAllergyReq { |
|||
Items []SubmitAllergyReq `json:"items"` |
|||
} |
|||
) |
|||
|
|||
// ==================== 体质辨识模块 ==================== |
|||
type ( |
|||
// 问卷题目 |
|||
Question { |
|||
ID int `json:"id"` |
|||
ConstitutionType string `json:"constitution_type"` |
|||
QuestionText string `json:"question_text"` |
|||
Options []string `json:"options"` |
|||
OrderNum int `json:"order_num"` |
|||
} |
|||
// 问卷题目列表响应 |
|||
QuestionsResp { |
|||
Questions []Question `json:"questions"` |
|||
} |
|||
// 分组问卷响应 |
|||
GroupedQuestionsResp { |
|||
Groups map[string][]Question `json:"groups"` |
|||
} |
|||
// 提交测评请求 |
|||
SubmitAssessmentReq { |
|||
Answers []AnswerItem `json:"answers"` |
|||
} |
|||
// 答题项 |
|||
AnswerItem { |
|||
QuestionID int `json:"question_id"` |
|||
Score int `json:"score"` // 1-5 |
|||
} |
|||
// 测评结果 |
|||
AssessmentResult { |
|||
ID uint `json:"id"` |
|||
UserID uint `json:"user_id"` |
|||
AssessedAt string `json:"assessed_at"` |
|||
Scores map[string]float64 `json:"scores"` |
|||
PrimaryConstitution string `json:"primary_constitution"` |
|||
SecondaryConstitutions []string `json:"secondary_constitutions"` |
|||
Recommendations map[string]string `json:"recommendations"` |
|||
} |
|||
// 测评历史响应 |
|||
AssessmentHistoryResp { |
|||
History []AssessmentResult `json:"history"` |
|||
} |
|||
// 调养建议响应 |
|||
RecommendationsResp { |
|||
Constitution string `json:"constitution"` |
|||
Recommendations map[string]string `json:"recommendations"` |
|||
} |
|||
) |
|||
|
|||
// ==================== AI对话模块 ==================== |
|||
type ( |
|||
// 对话列表项 |
|||
ConversationItem { |
|||
ID uint `json:"id"` |
|||
Title string `json:"title"` |
|||
CreatedAt string `json:"created_at"` |
|||
UpdatedAt string `json:"updated_at"` |
|||
} |
|||
// 对话列表响应 |
|||
ConversationListResp { |
|||
Conversations []ConversationItem `json:"conversations"` |
|||
} |
|||
// 创建对话请求 |
|||
CreateConversationReq { |
|||
Title string `json:"title,optional"` |
|||
} |
|||
// 消息 |
|||
Message { |
|||
ID uint `json:"id"` |
|||
ConversationID uint `json:"conversation_id"` |
|||
Role string `json:"role"` // user/assistant/system |
|||
Content string `json:"content"` |
|||
CreatedAt string `json:"created_at"` |
|||
} |
|||
// 对话详情响应 |
|||
ConversationDetailResp { |
|||
ID uint `json:"id"` |
|||
Title string `json:"title"` |
|||
Messages []Message `json:"messages"` |
|||
CreatedAt string `json:"created_at"` |
|||
} |
|||
// 对话ID路径参数 |
|||
ConversationIdReq { |
|||
Id uint `path:"id"` |
|||
} |
|||
// 发送消息请求 |
|||
SendMessageReq { |
|||
Id uint `path:"id"` |
|||
Content string `json:"content"` |
|||
} |
|||
// 消息响应 |
|||
MessageResp { |
|||
UserMessage Message `json:"user_message"` |
|||
AssistantMessage Message `json:"assistant_message"` |
|||
} |
|||
) |
|||
|
|||
// ==================== 产品模块 ==================== |
|||
type ( |
|||
// 产品 |
|||
Product { |
|||
ID uint `json:"id"` |
|||
Name string `json:"name"` |
|||
Category string `json:"category"` |
|||
Description string `json:"description"` |
|||
Efficacy string `json:"efficacy"` |
|||
Suitable string `json:"suitable"` |
|||
Price float64 `json:"price"` |
|||
ImageURL string `json:"image_url"` |
|||
MallURL string `json:"mall_url"` |
|||
IsActive bool `json:"is_active"` |
|||
} |
|||
// 产品列表请求 |
|||
ProductListReq { |
|||
Page int `form:"page,default=1"` |
|||
PageSize int `form:"page_size,default=10"` |
|||
Category string `form:"category,optional"` |
|||
} |
|||
// 产品列表响应 |
|||
ProductListResp { |
|||
Products []Product `json:"products"` |
|||
PageInfo PageInfo `json:"page_info"` |
|||
} |
|||
// 产品搜索请求 |
|||
ProductSearchReq { |
|||
Keyword string `form:"keyword"` |
|||
Page int `form:"page,default=1"` |
|||
PageSize int `form:"page_size,default=10"` |
|||
} |
|||
// 推荐产品响应 |
|||
RecommendProductsResp { |
|||
Products []Product `json:"products"` |
|||
Constitution string `json:"constitution"` |
|||
Reason string `json:"reason"` |
|||
} |
|||
// 购买历史 |
|||
PurchaseHistory { |
|||
ID uint `json:"id"` |
|||
UserID uint `json:"user_id"` |
|||
OrderNo string `json:"order_no"` |
|||
ProductID uint `json:"product_id"` |
|||
ProductName string `json:"product_name"` |
|||
PurchasedAt string `json:"purchased_at"` |
|||
Source string `json:"source"` |
|||
} |
|||
// 购买历史响应 |
|||
PurchaseHistoryResp { |
|||
History []PurchaseHistory `json:"history"` |
|||
PageInfo PageInfo `json:"page_info"` |
|||
} |
|||
// 同步购买请求 |
|||
SyncPurchaseReq { |
|||
OrderNo string `json:"order_no"` |
|||
ProductID uint `json:"product_id"` |
|||
ProductName string `json:"product_name"` |
|||
UserID uint `json:"user_id"` |
|||
PurchasedAt string `json:"purchased_at"` |
|||
Source string `json:"source"` |
|||
} |
|||
) |
|||
|
|||
// ==================== 路由定义 ==================== |
|||
// 无需认证的路由 |
|||
@server ( |
|||
prefix: /api |
|||
) |
|||
service healthapi-api { |
|||
// 健康检查 |
|||
@handler HealthCheckHandler |
|||
get /health returns (CommonResp) |
|||
|
|||
// 认证模块 |
|||
@handler RegisterHandler |
|||
post /auth/register (RegisterReq) returns (LoginResp) |
|||
|
|||
@handler LoginHandler |
|||
post /auth/login (LoginReq) returns (LoginResp) |
|||
|
|||
@handler RefreshTokenHandler |
|||
post /auth/refresh (RefreshTokenReq) returns (LoginResp) |
|||
|
|||
@handler SendCodeHandler |
|||
post /auth/send-code (SendCodeReq) returns (CommonResp) |
|||
|
|||
// 产品模块(公开) |
|||
@handler GetProductListHandler |
|||
get /products (ProductListReq) returns (ProductListResp) |
|||
|
|||
@handler GetProductHandler |
|||
get /products/:id (IdPathReq) returns (Product) |
|||
|
|||
@handler GetProductsByCategoryHandler |
|||
get /products/category (ProductListReq) returns (ProductListResp) |
|||
|
|||
@handler SearchProductsHandler |
|||
get /products/search (ProductSearchReq) returns (ProductListResp) |
|||
|
|||
// 商城同步(需要API Key,在handler中验证) |
|||
@handler SyncPurchaseHandler |
|||
post /sync/purchase (SyncPurchaseReq) returns (CommonResp) |
|||
} |
|||
|
|||
// 需要认证的路由 |
|||
@server ( |
|||
prefix: /api |
|||
jwt: Auth |
|||
) |
|||
service healthapi-api { |
|||
// 用户模块 |
|||
@handler GetUserProfileHandler |
|||
get /user/profile returns (UserInfo) |
|||
|
|||
@handler UpdateUserProfileHandler |
|||
put /user/profile (UpdateProfileReq) returns (UserInfo) |
|||
|
|||
// 健康档案模块 |
|||
@handler GetHealthProfileHandler |
|||
get /user/health-profile returns (FullHealthProfileResp) |
|||
|
|||
@handler UpdateHealthProfileHandler |
|||
put /user/health-profile (UpdateHealthProfileReq) returns (HealthProfile) |
|||
|
|||
@handler GetBasicProfileHandler |
|||
get /user/basic-profile returns (HealthProfile) |
|||
|
|||
@handler GetLifestyleHandler |
|||
get /user/lifestyle returns (LifestyleInfo) |
|||
|
|||
@handler UpdateLifestyleHandler |
|||
put /user/lifestyle (UpdateLifestyleReq) returns (LifestyleInfo) |
|||
|
|||
@handler GetMedicalHistoryHandler |
|||
get /user/medical-history returns ([]MedicalHistory) |
|||
|
|||
@handler DeleteMedicalHistoryHandler |
|||
delete /user/medical-history/:id (IdPathReq) returns (CommonResp) |
|||
|
|||
@handler GetFamilyHistoryHandler |
|||
get /user/family-history returns ([]FamilyHistory) |
|||
|
|||
@handler DeleteFamilyHistoryHandler |
|||
delete /user/family-history/:id (IdPathReq) returns (CommonResp) |
|||
|
|||
@handler GetAllergyRecordsHandler |
|||
get /user/allergy-records returns ([]AllergyRecord) |
|||
|
|||
@handler DeleteAllergyRecordHandler |
|||
delete /user/allergy-records/:id (IdPathReq) returns (CommonResp) |
|||
|
|||
@handler GetPurchaseHistoryHandler |
|||
get /user/purchase-history (PageReq) returns (PurchaseHistoryResp) |
|||
|
|||
// 健康调查模块 |
|||
@handler GetSurveyStatusHandler |
|||
get /survey/status returns (SurveyStatusResp) |
|||
|
|||
@handler SubmitBasicInfoHandler |
|||
post /survey/basic-info (SubmitBasicInfoReq) returns (CommonResp) |
|||
|
|||
@handler SubmitLifestyleHandler |
|||
post /survey/lifestyle (SubmitLifestyleReq) returns (CommonResp) |
|||
|
|||
@handler SubmitMedicalHistoryHandler |
|||
post /survey/medical-history (SubmitMedicalHistoryReq) returns (CommonResp) |
|||
|
|||
@handler BatchSubmitMedicalHistoryHandler |
|||
post /survey/medical-history/batch (BatchMedicalHistoryReq) returns (CommonResp) |
|||
|
|||
@handler SubmitFamilyHistoryHandler |
|||
post /survey/family-history (SubmitFamilyHistoryReq) returns (CommonResp) |
|||
|
|||
@handler BatchSubmitFamilyHistoryHandler |
|||
post /survey/family-history/batch (BatchFamilyHistoryReq) returns (CommonResp) |
|||
|
|||
@handler SubmitAllergyHandler |
|||
post /survey/allergy (SubmitAllergyReq) returns (CommonResp) |
|||
|
|||
@handler BatchSubmitAllergyHandler |
|||
post /survey/allergy/batch (BatchAllergyReq) returns (CommonResp) |
|||
|
|||
@handler CompleteSurveyHandler |
|||
post /survey/complete returns (CommonResp) |
|||
|
|||
// 体质辨识模块 |
|||
@handler GetQuestionsHandler |
|||
get /constitution/questions returns (QuestionsResp) |
|||
|
|||
@handler GetGroupedQuestionsHandler |
|||
get /constitution/questions/grouped returns (GroupedQuestionsResp) |
|||
|
|||
@handler SubmitAssessmentHandler |
|||
post /constitution/submit (SubmitAssessmentReq) returns (AssessmentResult) |
|||
|
|||
@handler GetAssessmentResultHandler |
|||
get /constitution/result returns (AssessmentResult) |
|||
|
|||
@handler GetAssessmentHistoryHandler |
|||
get /constitution/history returns (AssessmentHistoryResp) |
|||
|
|||
@handler GetRecommendationsHandler |
|||
get /constitution/recommendations returns (RecommendationsResp) |
|||
|
|||
// AI对话模块 |
|||
@handler GetConversationsHandler |
|||
get /conversations returns (ConversationListResp) |
|||
|
|||
@handler CreateConversationHandler |
|||
post /conversations (CreateConversationReq) returns (ConversationItem) |
|||
|
|||
@handler GetConversationHandler |
|||
get /conversations/:id (ConversationIdReq) returns (ConversationDetailResp) |
|||
|
|||
@handler DeleteConversationHandler |
|||
delete /conversations/:id (ConversationIdReq) returns (CommonResp) |
|||
|
|||
@handler SendMessageHandler |
|||
post /conversations/:id/messages (SendMessageReq) returns (MessageResp) |
|||
|
|||
// 流式消息需要特殊处理,在handler中实现SSE |
|||
@handler SendMessageStreamHandler |
|||
post /conversations/:id/messages/stream (SendMessageReq) |
|||
|
|||
// 产品推荐(需要认证,基于用户体质) |
|||
@handler GetRecommendProductsHandler |
|||
get /products/recommend returns (RecommendProductsResp) |
|||
} |
|||
|
|||
// ==================== 会员系统模块 ==================== |
|||
type ( |
|||
// 会员信息 |
|||
MemberInfo { |
|||
Level string `json:"level"` // normal/silver/gold/diamond |
|||
LevelName string `json:"level_name"` // 等级名称 |
|||
TotalSpent float64 `json:"total_spent"` // 累计消费 |
|||
Points int `json:"points"` // 当前积分 |
|||
MemberSince string `json:"member_since"` // 首次消费时间 |
|||
NextLevel string `json:"next_level"` // 下一等级 |
|||
NextLevelSpent float64 `json:"next_level_spent"` // 升级还需消费 |
|||
Discount float64 `json:"discount"` // 当前折扣 |
|||
PointsMultiplier float64 `json:"points_multiplier"` // 积分倍率 |
|||
FreeShippingMin float64 `json:"free_shipping_min"` // 包邮门槛 |
|||
} |
|||
// 积分记录 |
|||
PointsRecord { |
|||
ID uint `json:"id"` |
|||
Type string `json:"type"` // earn/spend/expire/adjust |
|||
Points int `json:"points"` // 变动积分 |
|||
Balance int `json:"balance"` // 变动后余额 |
|||
Source string `json:"source"` // order/activity/system |
|||
Remark string `json:"remark"` |
|||
CreatedAt string `json:"created_at"` |
|||
} |
|||
// 积分记录列表响应 |
|||
PointsRecordsResp { |
|||
Records []PointsRecord `json:"records"` |
|||
PageInfo PageInfo `json:"page_info"` |
|||
} |
|||
// 积分兑换请求(积分抵扣现金) |
|||
UsePointsReq { |
|||
Points int `json:"points"` // 使用积分数 |
|||
OrderNo string `json:"order_no,optional"` // 关联订单 |
|||
} |
|||
) |
|||
|
|||
// ==================== 商城商品模块 ==================== |
|||
type ( |
|||
// 商品分类 |
|||
ProductCategory { |
|||
ID uint `json:"id"` |
|||
Name string `json:"name"` |
|||
ParentID uint `json:"parent_id"` |
|||
Icon string `json:"icon"` |
|||
Description string `json:"description"` |
|||
Sort int `json:"sort"` |
|||
} |
|||
// 分类列表响应 |
|||
CategoryListResp { |
|||
Categories []ProductCategory `json:"categories"` |
|||
} |
|||
// 商品SKU |
|||
ProductSku { |
|||
ID uint `json:"id"` |
|||
ProductID uint `json:"product_id"` |
|||
SkuCode string `json:"sku_code"` |
|||
Name string `json:"name"` |
|||
Attributes string `json:"attributes"` |
|||
Price float64 `json:"price"` |
|||
Stock int `json:"stock"` |
|||
Image string `json:"image"` |
|||
} |
|||
// 商品详情(包含SKU) |
|||
ProductDetail { |
|||
ID uint `json:"id"` |
|||
CategoryID uint `json:"category_id"` |
|||
Name string `json:"name"` |
|||
Description string `json:"description"` |
|||
MainImage string `json:"main_image"` |
|||
Images []string `json:"images"` |
|||
Price float64 `json:"price"` |
|||
OriginalPrice float64 `json:"original_price"` |
|||
Stock int `json:"stock"` |
|||
SalesCount int `json:"sales_count"` |
|||
IsFeatured bool `json:"is_featured"` |
|||
ConstitutionTypes []string `json:"constitution_types"` |
|||
HealthTags []string `json:"health_tags"` |
|||
Efficacy string `json:"efficacy"` |
|||
Ingredients string `json:"ingredients"` |
|||
Usage string `json:"usage"` |
|||
Contraindications string `json:"contraindications"` |
|||
Skus []ProductSku `json:"skus"` |
|||
} |
|||
) |
|||
|
|||
// ==================== 购物车模块 ==================== |
|||
type ( |
|||
// 购物车项 |
|||
CartItem { |
|||
ID uint `json:"id"` |
|||
ProductID uint `json:"product_id"` |
|||
SkuID uint `json:"sku_id"` |
|||
ProductName string `json:"product_name"` |
|||
SkuName string `json:"sku_name"` |
|||
Image string `json:"image"` |
|||
Price float64 `json:"price"` |
|||
Quantity int `json:"quantity"` |
|||
Selected bool `json:"selected"` |
|||
Stock int `json:"stock"` // 当前库存 |
|||
} |
|||
// 购物车响应 |
|||
CartResp { |
|||
Items []CartItem `json:"items"` |
|||
TotalCount int `json:"total_count"` |
|||
SelectedCount int `json:"selected_count"` |
|||
TotalAmount float64 `json:"total_amount"` |
|||
} |
|||
// 添加购物车请求 |
|||
AddCartReq { |
|||
ProductID uint `json:"product_id"` |
|||
SkuID uint `json:"sku_id,optional"` |
|||
Quantity int `json:"quantity,default=1"` |
|||
} |
|||
// 更新购物车请求 |
|||
UpdateCartReq { |
|||
Id uint `path:"id"` |
|||
Quantity int `json:"quantity,optional"` |
|||
Selected bool `json:"selected,optional"` |
|||
} |
|||
// 批量选择请求 |
|||
BatchSelectCartReq { |
|||
Ids []uint `json:"ids"` |
|||
Selected bool `json:"selected"` |
|||
} |
|||
) |
|||
|
|||
// ==================== 收货地址模块 ==================== |
|||
type ( |
|||
// 收货地址 |
|||
Address { |
|||
ID uint `json:"id"` |
|||
ReceiverName string `json:"receiver_name"` |
|||
Phone string `json:"phone"` |
|||
Province string `json:"province"` |
|||
City string `json:"city"` |
|||
District string `json:"district"` |
|||
DetailAddr string `json:"detail_addr"` |
|||
PostalCode string `json:"postal_code"` |
|||
IsDefault bool `json:"is_default"` |
|||
Tag string `json:"tag"` // home/company/other |
|||
} |
|||
// 地址列表响应 |
|||
AddressListResp { |
|||
Addresses []Address `json:"addresses"` |
|||
} |
|||
// 创建/更新地址请求 |
|||
SaveAddressReq { |
|||
ReceiverName string `json:"receiver_name"` |
|||
Phone string `json:"phone"` |
|||
Province string `json:"province"` |
|||
City string `json:"city"` |
|||
District string `json:"district"` |
|||
DetailAddr string `json:"detail_addr"` |
|||
PostalCode string `json:"postal_code,optional"` |
|||
IsDefault bool `json:"is_default,optional"` |
|||
Tag string `json:"tag,optional"` |
|||
} |
|||
// 地址ID请求 |
|||
AddressIdReq { |
|||
Id uint `path:"id"` |
|||
} |
|||
) |
|||
|
|||
// ==================== 订单模块 ==================== |
|||
type ( |
|||
// 订单商品项 |
|||
OrderItem { |
|||
ID uint `json:"id"` |
|||
ProductID uint `json:"product_id"` |
|||
SkuID uint `json:"sku_id"` |
|||
ProductName string `json:"product_name"` |
|||
SkuName string `json:"sku_name"` |
|||
Image string `json:"image"` |
|||
Price float64 `json:"price"` |
|||
Quantity int `json:"quantity"` |
|||
TotalAmount float64 `json:"total_amount"` |
|||
} |
|||
// 订单 |
|||
Order { |
|||
ID uint `json:"id"` |
|||
OrderNo string `json:"order_no"` |
|||
Status string `json:"status"` |
|||
TotalAmount float64 `json:"total_amount"` |
|||
DiscountAmount float64 `json:"discount_amount"` |
|||
ShippingFee float64 `json:"shipping_fee"` |
|||
PayAmount float64 `json:"pay_amount"` |
|||
PointsUsed int `json:"points_used"` |
|||
PointsEarned int `json:"points_earned"` |
|||
PayMethod string `json:"pay_method"` |
|||
PayTime string `json:"pay_time"` |
|||
ShipTime string `json:"ship_time"` |
|||
ReceiveTime string `json:"receive_time"` |
|||
ReceiverName string `json:"receiver_name"` |
|||
ReceiverPhone string `json:"receiver_phone"` |
|||
ReceiverAddr string `json:"receiver_addr"` |
|||
ShippingCompany string `json:"shipping_company"` |
|||
TrackingNo string `json:"tracking_no"` |
|||
Remark string `json:"remark"` |
|||
CancelReason string `json:"cancel_reason"` |
|||
Items []OrderItem `json:"items"` |
|||
CreatedAt string `json:"created_at"` |
|||
} |
|||
// 订单列表响应 |
|||
OrderListResp { |
|||
Orders []Order `json:"orders"` |
|||
PageInfo PageInfo `json:"page_info"` |
|||
} |
|||
// 订单列表请求 |
|||
OrderListReq { |
|||
Page int `form:"page,default=1"` |
|||
PageSize int `form:"page_size,default=10"` |
|||
Status string `form:"status,optional"` // 筛选状态 |
|||
} |
|||
// 创建订单请求 |
|||
CreateOrderReq { |
|||
AddressID uint `json:"address_id"` |
|||
CartItemIDs []uint `json:"cart_item_ids"` // 购物车项ID |
|||
PointsUsed int `json:"points_used,optional"` // 使用积分 |
|||
Remark string `json:"remark,optional"` |
|||
} |
|||
// 订单预览(结算页) |
|||
OrderPreview { |
|||
Items []CartItem `json:"items"` |
|||
TotalAmount float64 `json:"total_amount"` |
|||
DiscountAmount float64 `json:"discount_amount"` |
|||
ShippingFee float64 `json:"shipping_fee"` |
|||
PayAmount float64 `json:"pay_amount"` |
|||
MaxPointsUse int `json:"max_points_use"` // 最多可用积分 |
|||
PointsDiscount float64 `json:"points_discount"` // 积分可抵扣金额 |
|||
} |
|||
// 订单预览请求 |
|||
OrderPreviewReq { |
|||
CartItemIDs []uint `json:"cart_item_ids"` |
|||
AddressID uint `json:"address_id,optional"` |
|||
} |
|||
// 订单ID请求 |
|||
OrderIdReq { |
|||
Id uint `path:"id"` |
|||
} |
|||
// 支付订单请求 |
|||
PayOrderReq { |
|||
Id uint `path:"id"` |
|||
PayMethod string `json:"pay_method"` // wechat/alipay |
|||
} |
|||
// 取消订单请求 |
|||
CancelOrderReq { |
|||
Id uint `path:"id"` |
|||
Reason string `json:"reason,optional"` |
|||
} |
|||
) |
|||
|
|||
// ==================== 商城公开路由 ==================== |
|||
@server ( |
|||
prefix: /api/mall |
|||
) |
|||
service healthapi-api { |
|||
// 商品分类 |
|||
@handler GetCategoriesHandler |
|||
get /categories returns (CategoryListResp) |
|||
|
|||
// 商品列表(支持分类筛选) |
|||
@handler GetMallProductsHandler |
|||
get /products (ProductListReq) returns (ProductListResp) |
|||
|
|||
// 商品详情 |
|||
@handler GetMallProductDetailHandler |
|||
get /products/:id (IdPathReq) returns (ProductDetail) |
|||
|
|||
// 搜索商品 |
|||
@handler SearchMallProductsHandler |
|||
get /products/search (ProductSearchReq) returns (ProductListResp) |
|||
|
|||
// 推荐/热门商品 |
|||
@handler GetFeaturedProductsHandler |
|||
get /products/featured (PageReq) returns (ProductListResp) |
|||
} |
|||
|
|||
// ==================== 商城认证路由 ==================== |
|||
@server ( |
|||
prefix: /api/mall |
|||
jwt: Auth |
|||
) |
|||
service healthapi-api { |
|||
// ===== 会员 ===== |
|||
@handler GetMemberInfoHandler |
|||
get /member/info returns (MemberInfo) |
|||
|
|||
@handler GetPointsRecordsHandler |
|||
get /member/points/records (PageReq) returns (PointsRecordsResp) |
|||
|
|||
// ===== 购物车 ===== |
|||
@handler GetCartHandler |
|||
get /cart returns (CartResp) |
|||
|
|||
@handler AddCartHandler |
|||
post /cart (AddCartReq) returns (CartItem) |
|||
|
|||
@handler UpdateCartHandler |
|||
put /cart/:id (UpdateCartReq) returns (CartItem) |
|||
|
|||
@handler DeleteCartHandler |
|||
delete /cart/:id (IdPathReq) returns (CommonResp) |
|||
|
|||
@handler BatchSelectCartHandler |
|||
post /cart/batch-select (BatchSelectCartReq) returns (CommonResp) |
|||
|
|||
@handler ClearCartHandler |
|||
delete /cart/clear returns (CommonResp) |
|||
|
|||
// ===== 收货地址 ===== |
|||
@handler GetAddressesHandler |
|||
get /addresses returns (AddressListResp) |
|||
|
|||
@handler GetAddressHandler |
|||
get /addresses/:id (AddressIdReq) returns (Address) |
|||
|
|||
@handler CreateAddressHandler |
|||
post /addresses (SaveAddressReq) returns (Address) |
|||
|
|||
@handler UpdateAddressHandler |
|||
put /addresses/:id (AddressIdReq) |
|||
|
|||
@handler DeleteAddressHandler |
|||
delete /addresses/:id (AddressIdReq) returns (CommonResp) |
|||
|
|||
@handler SetDefaultAddressHandler |
|||
put /addresses/:id/default (AddressIdReq) returns (CommonResp) |
|||
|
|||
// ===== 订单 ===== |
|||
@handler GetOrdersHandler |
|||
get /orders (OrderListReq) returns (OrderListResp) |
|||
|
|||
@handler GetOrderHandler |
|||
get /orders/:id (OrderIdReq) returns (Order) |
|||
|
|||
@handler PreviewOrderHandler |
|||
post /orders/preview (OrderPreviewReq) returns (OrderPreview) |
|||
|
|||
@handler CreateOrderHandler |
|||
post /orders (CreateOrderReq) returns (Order) |
|||
|
|||
@handler PayOrderHandler |
|||
post /orders/:id/pay (PayOrderReq) returns (CommonResp) |
|||
|
|||
@handler CancelOrderHandler |
|||
post /orders/:id/cancel (CancelOrderReq) returns (CommonResp) |
|||
|
|||
@handler ConfirmReceiveHandler |
|||
post /orders/:id/receive (OrderIdReq) returns (CommonResp) |
|||
|
|||
// ===== 基于体质的商品推荐 ===== |
|||
@handler GetConstitutionProductsHandler |
|||
get /products/constitution-recommend returns (RecommendProductsResp) |
|||
} |
|||
|
|||
@ -0,0 +1,50 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"flag" |
|||
"fmt" |
|||
"net/http" |
|||
|
|||
"healthapi/internal/config" |
|||
"healthapi/internal/handler" |
|||
"healthapi/internal/svc" |
|||
|
|||
"github.com/zeromicro/go-zero/core/conf" |
|||
"github.com/zeromicro/go-zero/rest" |
|||
) |
|||
|
|||
var configFile = flag.String("f", "etc/healthapi-api.yaml", "the config file") |
|||
|
|||
func main() { |
|||
flag.Parse() |
|||
|
|||
var c config.Config |
|||
conf.MustLoad(*configFile, &c) |
|||
|
|||
// 创建服务器并配置 CORS
|
|||
server := rest.MustNewServer(c.RestConf, rest.WithCors("*")) |
|||
defer server.Stop() |
|||
|
|||
// 添加 CORS 中间件处理 OPTIONS 预检请求
|
|||
server.Use(func(next http.HandlerFunc) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
w.Header().Set("Access-Control-Allow-Origin", "*") |
|||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH") |
|||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With") |
|||
w.Header().Set("Access-Control-Max-Age", "86400") |
|||
|
|||
if r.Method == http.MethodOptions { |
|||
w.WriteHeader(http.StatusNoContent) |
|||
return |
|||
} |
|||
|
|||
next(w, r) |
|||
} |
|||
}) |
|||
|
|||
ctx := svc.NewServiceContext(c) |
|||
handler.RegisterHandlers(server, ctx) |
|||
|
|||
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) |
|||
server.Start() |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
package config |
|||
|
|||
import "github.com/zeromicro/go-zero/rest" |
|||
|
|||
type Config struct { |
|||
rest.RestConf |
|||
Auth AuthConfig |
|||
Database DatabaseConfig |
|||
AI AIConfig |
|||
} |
|||
|
|||
type AuthConfig struct { |
|||
AccessSecret string |
|||
AccessExpire int64 |
|||
} |
|||
|
|||
type DatabaseConfig struct { |
|||
Driver string |
|||
DataSource string |
|||
} |
|||
|
|||
type AIConfig struct { |
|||
Provider string |
|||
MaxHistoryMessages int |
|||
MaxTokens int |
|||
Aliyun AliyunConfig |
|||
OpenAI OpenAIConfig |
|||
} |
|||
|
|||
type AliyunConfig struct { |
|||
ApiKey string |
|||
Model string |
|||
AppID string // 百炼应用 ID(可选)
|
|||
} |
|||
|
|||
type OpenAIConfig struct { |
|||
ApiKey string |
|||
BaseUrl string |
|||
Model string |
|||
} |
|||
@ -0,0 +1,115 @@ |
|||
package database |
|||
|
|||
import ( |
|||
"healthapi/internal/config" |
|||
"healthapi/internal/model" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
"golang.org/x/crypto/bcrypt" |
|||
"gorm.io/driver/mysql" |
|||
"gorm.io/driver/postgres" |
|||
"gorm.io/driver/sqlite" |
|||
"gorm.io/gorm" |
|||
"gorm.io/gorm/logger" |
|||
) |
|||
|
|||
// NewDB 创建数据库连接
|
|||
func NewDB(cfg config.DatabaseConfig) (*gorm.DB, error) { |
|||
var dialector gorm.Dialector |
|||
|
|||
switch cfg.Driver { |
|||
case "sqlite": |
|||
dialector = sqlite.Open(cfg.DataSource) |
|||
case "mysql": |
|||
dialector = mysql.Open(cfg.DataSource) |
|||
case "postgres": |
|||
dialector = postgres.Open(cfg.DataSource) |
|||
default: |
|||
dialector = sqlite.Open(cfg.DataSource) |
|||
} |
|||
|
|||
db, err := gorm.Open(dialector, &gorm.Config{ |
|||
Logger: logger.Default.LogMode(logger.Info), |
|||
}) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
// 自动迁移
|
|||
if err := model.AutoMigrate(db); err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
logx.Info("Database connected successfully") |
|||
return db, nil |
|||
} |
|||
|
|||
// SeedQuestionBank 初始化问卷题库
|
|||
func SeedQuestionBank(db *gorm.DB) error { |
|||
var count int64 |
|||
db.Model(&model.QuestionBank{}).Count(&count) |
|||
if count > 0 { |
|||
return nil // 已有数据,跳过
|
|||
} |
|||
|
|||
questions := []model.QuestionBank{ |
|||
// 平和质问题
|
|||
{ConstitutionType: model.ConstitutionPinghe, QuestionText: "您精力充沛吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 1}, |
|||
{ConstitutionType: model.ConstitutionPinghe, QuestionText: "您容易疲乏吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 2}, |
|||
{ConstitutionType: model.ConstitutionPinghe, QuestionText: "您说话声音低弱无力吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 3}, |
|||
// 气虚质问题
|
|||
{ConstitutionType: model.ConstitutionQixu, QuestionText: "您容易气短,呼吸短促吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 1}, |
|||
{ConstitutionType: model.ConstitutionQixu, QuestionText: "您容易心慌吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 2}, |
|||
{ConstitutionType: model.ConstitutionQixu, QuestionText: "您容易头晕或站起时晕眩吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 3}, |
|||
// 阳虚质问题
|
|||
{ConstitutionType: model.ConstitutionYangxu, QuestionText: "您手脚发凉吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 1}, |
|||
{ConstitutionType: model.ConstitutionYangxu, QuestionText: "您胃脘部、背部或腰膝部怕冷吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 2}, |
|||
{ConstitutionType: model.ConstitutionYangxu, QuestionText: "您比一般人耐受不了寒冷吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 3}, |
|||
// 阴虚质问题
|
|||
{ConstitutionType: model.ConstitutionYinxu, QuestionText: "您感到手脚心发热吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 1}, |
|||
{ConstitutionType: model.ConstitutionYinxu, QuestionText: "您感觉身体、脸上发热吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 2}, |
|||
{ConstitutionType: model.ConstitutionYinxu, QuestionText: "您口唇干吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 3}, |
|||
// 痰湿质问题
|
|||
{ConstitutionType: model.ConstitutionTanshi, QuestionText: "您感到胸闷或腹部胀满吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 1}, |
|||
{ConstitutionType: model.ConstitutionTanshi, QuestionText: "您感到身体沉重不轻松吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 2}, |
|||
{ConstitutionType: model.ConstitutionTanshi, QuestionText: "您腹部肥满松软吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 3}, |
|||
// 湿热质问题
|
|||
{ConstitutionType: model.ConstitutionShire, QuestionText: "您面部或鼻部有油腻感或者油亮发光吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 1}, |
|||
{ConstitutionType: model.ConstitutionShire, QuestionText: "您容易生痤疮或疮疖吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 2}, |
|||
{ConstitutionType: model.ConstitutionShire, QuestionText: "您感到口苦或嘴里有异味吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 3}, |
|||
// 血瘀质问题
|
|||
{ConstitutionType: model.ConstitutionXueyu, QuestionText: "您皮肤常在不知不觉中出现青紫瘀斑吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 1}, |
|||
{ConstitutionType: model.ConstitutionXueyu, QuestionText: "您两颧部有细微红丝吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 2}, |
|||
{ConstitutionType: model.ConstitutionXueyu, QuestionText: "您身体上有哪里疼痛吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 3}, |
|||
// 气郁质问题
|
|||
{ConstitutionType: model.ConstitutionQiyu, QuestionText: "您感到闷闷不乐、情绪低沉吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 1}, |
|||
{ConstitutionType: model.ConstitutionQiyu, QuestionText: "您容易精神紧张、焦虑不安吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 2}, |
|||
{ConstitutionType: model.ConstitutionQiyu, QuestionText: "您多愁善感、容易感到害怕吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 3}, |
|||
// 特禀质问题
|
|||
{ConstitutionType: model.ConstitutionTebing, QuestionText: "您没有感冒时也会打喷嚏吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 1}, |
|||
{ConstitutionType: model.ConstitutionTebing, QuestionText: "您没有感冒时也会鼻塞、流鼻涕吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 2}, |
|||
{ConstitutionType: model.ConstitutionTebing, QuestionText: "您对某些药物、食物、气味或花粉过敏吗?", Options: `["没有","很少","有时","经常","总是"]`, OrderNum: 3}, |
|||
} |
|||
|
|||
return db.Create(&questions).Error |
|||
} |
|||
|
|||
// SeedTestUser 创建测试用户
|
|||
func SeedTestUser(db *gorm.DB) error { |
|||
var count int64 |
|||
db.Model(&model.User{}).Count(&count) |
|||
if count > 0 { |
|||
return nil |
|||
} |
|||
|
|||
// 测试用户,密码: 123456
|
|||
passwordHash, _ := bcrypt.GenerateFromPassword([]byte("123456"), bcrypt.DefaultCost) |
|||
testUser := model.User{ |
|||
Phone: "13800138000", |
|||
Email: "test@example.com", |
|||
PasswordHash: string(passwordHash), |
|||
Nickname: "测试用户", |
|||
} |
|||
|
|||
return db.Create(&testUser).Error |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func AddCartHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.AddCartReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewAddCartLogic(r.Context(), svcCtx) |
|||
resp, err := l.AddCart(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func BatchSelectCartHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.BatchSelectCartReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewBatchSelectCartLogic(r.Context(), svcCtx) |
|||
resp, err := l.BatchSelectCart(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func BatchSubmitAllergyHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.BatchAllergyReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewBatchSubmitAllergyLogic(r.Context(), svcCtx) |
|||
resp, err := l.BatchSubmitAllergy(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func BatchSubmitFamilyHistoryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.BatchFamilyHistoryReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewBatchSubmitFamilyHistoryLogic(r.Context(), svcCtx) |
|||
resp, err := l.BatchSubmitFamilyHistory(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func BatchSubmitMedicalHistoryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.BatchMedicalHistoryReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewBatchSubmitMedicalHistoryLogic(r.Context(), svcCtx) |
|||
resp, err := l.BatchSubmitMedicalHistory(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func CancelOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.CancelOrderReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewCancelOrderLogic(r.Context(), svcCtx) |
|||
resp, err := l.CancelOrder(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
) |
|||
|
|||
func ClearCartHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewClearCartLogic(r.Context(), svcCtx) |
|||
resp, err := l.ClearCart() |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func CompleteSurveyHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewCompleteSurveyLogic(r.Context(), svcCtx) |
|||
resp, err := l.CompleteSurvey() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func ConfirmReceiveHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.OrderIdReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewConfirmReceiveLogic(r.Context(), svcCtx) |
|||
resp, err := l.ConfirmReceive(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func CreateAddressHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.SaveAddressReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewCreateAddressLogic(r.Context(), svcCtx) |
|||
resp, err := l.CreateAddress(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func CreateConversationHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.CreateConversationReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewCreateConversationLogic(r.Context(), svcCtx) |
|||
resp, err := l.CreateConversation(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func CreateOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.CreateOrderReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewCreateOrderLogic(r.Context(), svcCtx) |
|||
resp, err := l.CreateOrder(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func DeleteAddressHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.AddressIdReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewDeleteAddressLogic(r.Context(), svcCtx) |
|||
resp, err := l.DeleteAddress(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func DeleteAllergyRecordHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.IdPathReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewDeleteAllergyRecordLogic(r.Context(), svcCtx) |
|||
resp, err := l.DeleteAllergyRecord(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func DeleteCartHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.IdPathReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewDeleteCartLogic(r.Context(), svcCtx) |
|||
resp, err := l.DeleteCart(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func DeleteConversationHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.ConversationIdReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewDeleteConversationLogic(r.Context(), svcCtx) |
|||
resp, err := l.DeleteConversation(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func DeleteFamilyHistoryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.IdPathReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewDeleteFamilyHistoryLogic(r.Context(), svcCtx) |
|||
resp, err := l.DeleteFamilyHistory(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func DeleteMedicalHistoryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.IdPathReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewDeleteMedicalHistoryLogic(r.Context(), svcCtx) |
|||
resp, err := l.DeleteMedicalHistory(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func GetAddressHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.AddressIdReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewGetAddressLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetAddress(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
) |
|||
|
|||
func GetAddressesHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetAddressesLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetAddresses() |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetAllergyRecordsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetAllergyRecordsLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetAllergyRecords() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetAssessmentHistoryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetAssessmentHistoryLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetAssessmentHistory() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetAssessmentResultHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetAssessmentResultLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetAssessmentResult() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetBasicProfileHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetBasicProfileLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetBasicProfile() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
) |
|||
|
|||
func GetCartHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetCartLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetCart() |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
) |
|||
|
|||
func GetCategoriesHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetCategoriesLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetCategories() |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
) |
|||
|
|||
func GetConstitutionProductsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetConstitutionProductsLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetConstitutionProducts() |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetConversationHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.ConversationIdReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewGetConversationLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetConversation(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetConversationsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetConversationsLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetConversations() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetFamilyHistoryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetFamilyHistoryLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetFamilyHistory() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func GetFeaturedProductsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.PageReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewGetFeaturedProductsLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetFeaturedProducts(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetGroupedQuestionsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetGroupedQuestionsLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetGroupedQuestions() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetHealthProfileHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetHealthProfileLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetHealthProfile() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetLifestyleHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetLifestyleLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetLifestyle() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func GetMallProductDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.IdPathReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewGetMallProductDetailLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetMallProductDetail(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func GetMallProductsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.ProductListReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewGetMallProductsLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetMallProducts(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetMedicalHistoryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetMedicalHistoryLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetMedicalHistory() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
) |
|||
|
|||
func GetMemberInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetMemberInfoLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetMemberInfo() |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func GetOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.OrderIdReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewGetOrderLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetOrder(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func GetOrdersHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.OrderListReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewGetOrdersLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetOrders(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func GetPointsRecordsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.PageReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewGetPointsRecordsLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetPointsRecords(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetProductHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.IdPathReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewGetProductLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetProduct(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetProductListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.ProductListReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewGetProductListLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetProductList(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetProductsByCategoryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.ProductListReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewGetProductsByCategoryLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetProductsByCategory(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetPurchaseHistoryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.PageReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewGetPurchaseHistoryLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetPurchaseHistory(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetQuestionsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetQuestionsLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetQuestions() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetRecommendProductsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetRecommendProductsLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetRecommendProducts() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetRecommendationsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetRecommendationsLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetRecommendations() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetSurveyStatusHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetSurveyStatusLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetSurveyStatus() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func GetUserProfileHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewGetUserProfileLogic(r.Context(), svcCtx) |
|||
resp, err := l.GetUserProfile() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func HealthCheckHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
l := logic.NewHealthCheckLogic(r.Context(), svcCtx) |
|||
resp, err := l.HealthCheck() |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
) |
|||
|
|||
func LoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.LoginReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewLoginLogic(r.Context(), svcCtx) |
|||
resp, err := l.Login(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func PayOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.PayOrderReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewPayOrderLogic(r.Context(), svcCtx) |
|||
resp, err := l.PayOrder(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func PreviewOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.OrderPreviewReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewPreviewOrderLogic(r.Context(), svcCtx) |
|||
resp, err := l.PreviewOrder(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func RefreshTokenHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.RefreshTokenReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewRefreshTokenLogic(r.Context(), svcCtx) |
|||
resp, err := l.RefreshToken(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
) |
|||
|
|||
func RegisterHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.RegisterReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewRegisterLogic(r.Context(), svcCtx) |
|||
resp, err := l.Register(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,410 @@ |
|||
// Code generated by goctl. DO NOT EDIT.
|
|||
// goctl 1.8.4
|
|||
|
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/svc" |
|||
|
|||
"github.com/zeromicro/go-zero/rest" |
|||
) |
|||
|
|||
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { |
|||
server.AddRoutes( |
|||
[]rest.Route{ |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/auth/login", |
|||
Handler: LoginHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/auth/refresh", |
|||
Handler: RefreshTokenHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/auth/register", |
|||
Handler: RegisterHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/auth/send-code", |
|||
Handler: SendCodeHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/health", |
|||
Handler: HealthCheckHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/products", |
|||
Handler: GetProductListHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/products/:id", |
|||
Handler: GetProductHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/products/category", |
|||
Handler: GetProductsByCategoryHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/products/search", |
|||
Handler: SearchProductsHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/sync/purchase", |
|||
Handler: SyncPurchaseHandler(serverCtx), |
|||
}, |
|||
}, |
|||
rest.WithPrefix("/api"), |
|||
) |
|||
|
|||
server.AddRoutes( |
|||
[]rest.Route{ |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/constitution/history", |
|||
Handler: GetAssessmentHistoryHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/constitution/questions", |
|||
Handler: GetQuestionsHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/constitution/questions/grouped", |
|||
Handler: GetGroupedQuestionsHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/constitution/recommendations", |
|||
Handler: GetRecommendationsHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/constitution/result", |
|||
Handler: GetAssessmentResultHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/constitution/submit", |
|||
Handler: SubmitAssessmentHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/conversations", |
|||
Handler: GetConversationsHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/conversations", |
|||
Handler: CreateConversationHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/conversations/:id", |
|||
Handler: GetConversationHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodDelete, |
|||
Path: "/conversations/:id", |
|||
Handler: DeleteConversationHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/conversations/:id/messages", |
|||
Handler: SendMessageHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/conversations/:id/messages/stream", |
|||
Handler: SendMessageStreamHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/products/recommend", |
|||
Handler: GetRecommendProductsHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/survey/allergy", |
|||
Handler: SubmitAllergyHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/survey/allergy/batch", |
|||
Handler: BatchSubmitAllergyHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/survey/basic-info", |
|||
Handler: SubmitBasicInfoHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/survey/complete", |
|||
Handler: CompleteSurveyHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/survey/family-history", |
|||
Handler: SubmitFamilyHistoryHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/survey/family-history/batch", |
|||
Handler: BatchSubmitFamilyHistoryHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/survey/lifestyle", |
|||
Handler: SubmitLifestyleHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/survey/medical-history", |
|||
Handler: SubmitMedicalHistoryHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/survey/medical-history/batch", |
|||
Handler: BatchSubmitMedicalHistoryHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/survey/status", |
|||
Handler: GetSurveyStatusHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/user/allergy-records", |
|||
Handler: GetAllergyRecordsHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodDelete, |
|||
Path: "/user/allergy-records/:id", |
|||
Handler: DeleteAllergyRecordHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/user/basic-profile", |
|||
Handler: GetBasicProfileHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/user/family-history", |
|||
Handler: GetFamilyHistoryHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodDelete, |
|||
Path: "/user/family-history/:id", |
|||
Handler: DeleteFamilyHistoryHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/user/health-profile", |
|||
Handler: GetHealthProfileHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPut, |
|||
Path: "/user/health-profile", |
|||
Handler: UpdateHealthProfileHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/user/lifestyle", |
|||
Handler: GetLifestyleHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPut, |
|||
Path: "/user/lifestyle", |
|||
Handler: UpdateLifestyleHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/user/medical-history", |
|||
Handler: GetMedicalHistoryHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodDelete, |
|||
Path: "/user/medical-history/:id", |
|||
Handler: DeleteMedicalHistoryHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/user/profile", |
|||
Handler: GetUserProfileHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPut, |
|||
Path: "/user/profile", |
|||
Handler: UpdateUserProfileHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/user/purchase-history", |
|||
Handler: GetPurchaseHistoryHandler(serverCtx), |
|||
}, |
|||
}, |
|||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret), |
|||
rest.WithPrefix("/api"), |
|||
) |
|||
|
|||
server.AddRoutes( |
|||
[]rest.Route{ |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/categories", |
|||
Handler: GetCategoriesHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/products", |
|||
Handler: GetMallProductsHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/products/:id", |
|||
Handler: GetMallProductDetailHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/products/featured", |
|||
Handler: GetFeaturedProductsHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/products/search", |
|||
Handler: SearchMallProductsHandler(serverCtx), |
|||
}, |
|||
}, |
|||
rest.WithPrefix("/api/mall"), |
|||
) |
|||
|
|||
server.AddRoutes( |
|||
[]rest.Route{ |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/addresses", |
|||
Handler: GetAddressesHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/addresses", |
|||
Handler: CreateAddressHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/addresses/:id", |
|||
Handler: GetAddressHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPut, |
|||
Path: "/addresses/:id", |
|||
Handler: UpdateAddressHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodDelete, |
|||
Path: "/addresses/:id", |
|||
Handler: DeleteAddressHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPut, |
|||
Path: "/addresses/:id/default", |
|||
Handler: SetDefaultAddressHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/cart", |
|||
Handler: GetCartHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/cart", |
|||
Handler: AddCartHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPut, |
|||
Path: "/cart/:id", |
|||
Handler: UpdateCartHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodDelete, |
|||
Path: "/cart/:id", |
|||
Handler: DeleteCartHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/cart/batch-select", |
|||
Handler: BatchSelectCartHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodDelete, |
|||
Path: "/cart/clear", |
|||
Handler: ClearCartHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/member/info", |
|||
Handler: GetMemberInfoHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/member/points/records", |
|||
Handler: GetPointsRecordsHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/orders", |
|||
Handler: GetOrdersHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/orders", |
|||
Handler: CreateOrderHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/orders/:id", |
|||
Handler: GetOrderHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/orders/:id/cancel", |
|||
Handler: CancelOrderHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/orders/:id/pay", |
|||
Handler: PayOrderHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/orders/:id/receive", |
|||
Handler: ConfirmReceiveHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodPost, |
|||
Path: "/orders/preview", |
|||
Handler: PreviewOrderHandler(serverCtx), |
|||
}, |
|||
{ |
|||
Method: http.MethodGet, |
|||
Path: "/products/constitution-recommend", |
|||
Handler: GetConstitutionProductsHandler(serverCtx), |
|||
}, |
|||
}, |
|||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret), |
|||
rest.WithPrefix("/api/mall"), |
|||
) |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func SearchMallProductsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.ProductSearchReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewSearchMallProductsLogic(r.Context(), svcCtx) |
|||
resp, err := l.SearchMallProducts(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func SearchProductsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.ProductSearchReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewSearchProductsLogic(r.Context(), svcCtx) |
|||
resp, err := l.SearchProducts(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
) |
|||
|
|||
func SendCodeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.SendCodeReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewSendCodeLogic(r.Context(), svcCtx) |
|||
resp, err := l.SendCode(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func SendMessageHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.SendMessageReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewSendMessageLogic(r.Context(), svcCtx) |
|||
resp, err := l.SendMessage(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,311 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"encoding/json" |
|||
"fmt" |
|||
"net/http" |
|||
"strings" |
|||
"time" |
|||
|
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/ai" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
) |
|||
|
|||
func SendMessageStreamHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.SendMessageReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
// 获取用户 ID
|
|||
userID, err := logic.GetUserIDFromCtx(r.Context()) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, errorx.ErrUnauthorized) |
|||
return |
|||
} |
|||
|
|||
// 验证对话属于该用户
|
|||
var conversation model.Conversation |
|||
if err := svcCtx.DB.Where("id = ? AND user_id = ?", req.Id, userID).First(&conversation).Error; err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, errorx.ErrNotFound) |
|||
return |
|||
} |
|||
|
|||
// 保存用户消息
|
|||
userMessage := model.Message{ |
|||
ConversationID: conversation.ID, |
|||
Role: model.RoleUser, |
|||
Content: req.Content, |
|||
} |
|||
if err := svcCtx.DB.Create(&userMessage).Error; err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, errorx.ErrServerError) |
|||
return |
|||
} |
|||
|
|||
// 设置 SSE 响应头(与原 server 保持一致)
|
|||
w.Header().Set("Content-Type", "text/event-stream") |
|||
w.Header().Set("Cache-Control", "no-cache") |
|||
w.Header().Set("Connection", "keep-alive") |
|||
w.Header().Set("X-Accel-Buffering", "no") // 禁用 nginx 缓冲
|
|||
w.Header().Set("Access-Control-Allow-Origin", "*") |
|||
|
|||
// 发送用户消息 ID
|
|||
msgData, _ := json.Marshal(map[string]interface{}{ |
|||
"type": "user_message", |
|||
"message_id": userMessage.ID, |
|||
}) |
|||
fmt.Fprintf(w, "data: %s\n\n", msgData) |
|||
if flusher, ok := w.(http.Flusher); ok { |
|||
flusher.Flush() |
|||
} |
|||
|
|||
// 获取历史消息
|
|||
var historyMessages []model.Message |
|||
svcCtx.DB.Where("conversation_id = ?", conversation.ID). |
|||
Order("created_at DESC"). |
|||
Limit(svcCtx.Config.AI.MaxHistoryMessages). |
|||
Find(&historyMessages) |
|||
|
|||
// 构建系统提示
|
|||
systemPrompt := buildSystemPromptForStream(svcCtx, userID) |
|||
|
|||
// 构建 AI 消息
|
|||
aiMessages := []ai.Message{{Role: "system", Content: systemPrompt}} |
|||
for i := len(historyMessages) - 1; i >= 0; i-- { |
|||
aiMessages = append(aiMessages, ai.Message{ |
|||
Role: historyMessages[i].Role, |
|||
Content: historyMessages[i].Content, |
|||
}) |
|||
} |
|||
|
|||
// 创建收集器
|
|||
collector := &responseCollector{writer: w} |
|||
|
|||
// 调用 AI 流式服务
|
|||
err = svcCtx.AIClient.ChatStream(r.Context(), aiMessages, collector) |
|||
if err != nil { |
|||
errData, _ := json.Marshal(map[string]interface{}{ |
|||
"type": "error", |
|||
"error": err.Error(), |
|||
}) |
|||
fmt.Fprintf(w, "data: %s\n\n", errData) |
|||
if flusher, ok := w.(http.Flusher); ok { |
|||
flusher.Flush() |
|||
} |
|||
return |
|||
} |
|||
|
|||
// 保存 AI 回复
|
|||
assistantMessage := model.Message{ |
|||
ConversationID: conversation.ID, |
|||
Role: model.RoleAssistant, |
|||
Content: collector.content, |
|||
} |
|||
svcCtx.DB.Create(&assistantMessage) |
|||
|
|||
// 更新对话标题
|
|||
if conversation.Title == "新对话" { |
|||
title := req.Content |
|||
if len(title) > 50 { |
|||
title = title[:50] + "..." |
|||
} |
|||
svcCtx.DB.Model(&conversation).Update("title", title) |
|||
} |
|||
|
|||
// 发送完成消息(使用 "end" 类型,与原 server 和前端保持一致)
|
|||
endData, _ := json.Marshal(map[string]interface{}{ |
|||
"type": "end", |
|||
"message_id": assistantMessage.ID, |
|||
}) |
|||
fmt.Fprintf(w, "data: %s\n\n", endData) |
|||
if flusher, ok := w.(http.Flusher); ok { |
|||
flusher.Flush() |
|||
} |
|||
} |
|||
} |
|||
|
|||
// responseCollector 收集响应内容(使用缓冲区按行解析,与原 server 一致)
|
|||
type responseCollector struct { |
|||
writer http.ResponseWriter |
|||
content string |
|||
buffer string |
|||
} |
|||
|
|||
func (c *responseCollector) Write(p []byte) (n int, err error) { |
|||
// 累积数据到 buffer
|
|||
c.buffer += string(p) |
|||
|
|||
// 按行处理
|
|||
for { |
|||
idx := strings.Index(c.buffer, "\n") |
|||
if idx == -1 { |
|||
break |
|||
} |
|||
line := c.buffer[:idx] |
|||
c.buffer = c.buffer[idx+1:] |
|||
|
|||
// 解析 SSE 数据提取内容
|
|||
line = strings.TrimSpace(line) |
|||
if strings.HasPrefix(line, "data: ") { |
|||
jsonStr := strings.TrimPrefix(line, "data: ") |
|||
jsonStr = strings.TrimSpace(jsonStr) |
|||
if jsonStr != "" && jsonStr != "[DONE]" { |
|||
var data struct { |
|||
Type string `json:"type"` |
|||
Content string `json:"content"` |
|||
} |
|||
if err := json.Unmarshal([]byte(jsonStr), &data); err == nil { |
|||
if data.Type == "content" { |
|||
c.content += data.Content |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 同时写入原始 writer
|
|||
return c.writer.Write(p) |
|||
} |
|||
|
|||
// 系统提示词模板(与原 server 保持一致)
|
|||
const systemPromptTemplate = `# 用户相关信息 |
|||
|
|||
## 用户信息 |
|||
%s |
|||
|
|||
## 用户体质 |
|||
%s |
|||
|
|||
## 用户病史 |
|||
%s |
|||
|
|||
## 用户家族病史 |
|||
%s |
|||
|
|||
## 用户过敏记录 |
|||
%s |
|||
|
|||
` |
|||
|
|||
func buildSystemPromptForStream(svcCtx *svc.ServiceContext, userID uint) string { |
|||
var userProfile, constitutionInfo, medicalInfo, familyInfo, allergyInfo string |
|||
|
|||
// 获取用户健康档案
|
|||
var profile model.HealthProfile |
|||
if err := svcCtx.DB.Where("user_id = ?", userID).First(&profile).Error; err == nil && profile.ID > 0 { |
|||
// 基本信息
|
|||
age := calculateAge(profile.BirthDate) |
|||
gender := "未知" |
|||
if profile.Gender == "male" { |
|||
gender = "男" |
|||
} else if profile.Gender == "female" { |
|||
gender = "女" |
|||
} |
|||
bmi := float64(0) |
|||
if profile.Height > 0 && profile.Weight > 0 { |
|||
heightM := float64(profile.Height) / 100 |
|||
bmi = float64(profile.Weight) / (heightM * heightM) |
|||
} |
|||
userProfile = fmt.Sprintf("性别:%s,年龄:%d岁,BMI:%.1f", gender, age, bmi) |
|||
|
|||
// 获取病史记录
|
|||
var medicalHistories []model.MedicalHistory |
|||
svcCtx.DB.Where("health_profile_id = ?", profile.ID).Find(&medicalHistories) |
|||
if len(medicalHistories) > 0 { |
|||
var items []string |
|||
for _, h := range medicalHistories { |
|||
status := "治疗中" |
|||
if h.Status == "cured" { |
|||
status = "已治愈" |
|||
} else if h.Status == "controlled" { |
|||
status = "已控制" |
|||
} |
|||
items = append(items, fmt.Sprintf("- %s(%s,%s)", h.DiseaseName, h.DiagnosedDate, status)) |
|||
} |
|||
medicalInfo = fmt.Sprintf("共%d条记录:\n%s", len(medicalHistories), strings.Join(items, "\n")) |
|||
} else { |
|||
medicalInfo = "暂无病史记录" |
|||
} |
|||
|
|||
// 获取家族病史
|
|||
var familyHistories []model.FamilyHistory |
|||
svcCtx.DB.Where("health_profile_id = ?", profile.ID).Find(&familyHistories) |
|||
if len(familyHistories) > 0 { |
|||
var items []string |
|||
for _, h := range familyHistories { |
|||
relation := h.Relation |
|||
switch relation { |
|||
case "father": |
|||
relation = "父亲" |
|||
case "mother": |
|||
relation = "母亲" |
|||
case "grandparent": |
|||
relation = "祖父母" |
|||
case "sibling": |
|||
relation = "兄弟姐妹" |
|||
} |
|||
items = append(items, fmt.Sprintf("- %s:%s", relation, h.DiseaseName)) |
|||
} |
|||
familyInfo = fmt.Sprintf("共%d条记录:\n%s", len(familyHistories), strings.Join(items, "\n")) |
|||
} else { |
|||
familyInfo = "暂无家族病史" |
|||
} |
|||
|
|||
// 获取过敏记录
|
|||
var allergyRecords []model.AllergyRecord |
|||
svcCtx.DB.Where("health_profile_id = ?", profile.ID).Find(&allergyRecords) |
|||
if len(allergyRecords) > 0 { |
|||
var items []string |
|||
for _, r := range allergyRecords { |
|||
severity := "轻度" |
|||
if r.Severity == "moderate" { |
|||
severity = "中度" |
|||
} else if r.Severity == "severe" { |
|||
severity = "重度" |
|||
} |
|||
items = append(items, fmt.Sprintf("- %s(%s,%s)", r.Allergen, r.AllergyType, severity)) |
|||
} |
|||
allergyInfo = fmt.Sprintf("共%d条记录:\n%s", len(allergyRecords), strings.Join(items, "\n")) |
|||
} else { |
|||
allergyInfo = "暂无过敏记录" |
|||
} |
|||
} else { |
|||
userProfile = "暂无基本信息" |
|||
medicalInfo = "暂无病史记录" |
|||
familyInfo = "暂无家族病史" |
|||
allergyInfo = "暂无过敏记录" |
|||
} |
|||
|
|||
// 获取用户体质信息
|
|||
var assessment model.ConstitutionAssessment |
|||
if err := svcCtx.DB.Where("user_id = ?", userID).Order("assessed_at DESC").First(&assessment).Error; err == nil && assessment.ID > 0 { |
|||
constitutionName := model.ConstitutionNames[assessment.PrimaryConstitution] |
|||
description := model.ConstitutionDescriptions[assessment.PrimaryConstitution] |
|||
constitutionInfo = fmt.Sprintf("主体质:%s\n特征:%s", constitutionName, description) |
|||
} else { |
|||
constitutionInfo = "暂未进行体质测评" |
|||
} |
|||
|
|||
return fmt.Sprintf(systemPromptTemplate, userProfile, constitutionInfo, medicalInfo, familyInfo, allergyInfo) |
|||
} |
|||
|
|||
// calculateAge 计算年龄
|
|||
func calculateAge(birthDate *time.Time) int { |
|||
if birthDate == nil { |
|||
return 0 |
|||
} |
|||
now := time.Now() |
|||
age := now.Year() - birthDate.Year() |
|||
if now.YearDay() < birthDate.YearDay() { |
|||
age-- |
|||
} |
|||
return age |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func SetDefaultAddressHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.AddressIdReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewSetDefaultAddressLogic(r.Context(), svcCtx) |
|||
resp, err := l.SetDefaultAddress(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func SubmitAllergyHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.SubmitAllergyReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewSubmitAllergyLogic(r.Context(), svcCtx) |
|||
resp, err := l.SubmitAllergy(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func SubmitAssessmentHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.SubmitAssessmentReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewSubmitAssessmentLogic(r.Context(), svcCtx) |
|||
resp, err := l.SubmitAssessment(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func SubmitBasicInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.SubmitBasicInfoReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewSubmitBasicInfoLogic(r.Context(), svcCtx) |
|||
resp, err := l.SubmitBasicInfo(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func SubmitFamilyHistoryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.SubmitFamilyHistoryReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewSubmitFamilyHistoryLogic(r.Context(), svcCtx) |
|||
resp, err := l.SubmitFamilyHistory(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func SubmitLifestyleHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.SubmitLifestyleReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewSubmitLifestyleLogic(r.Context(), svcCtx) |
|||
resp, err := l.SubmitLifestyle(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func SubmitMedicalHistoryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.SubmitMedicalHistoryReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewSubmitMedicalHistoryLogic(r.Context(), svcCtx) |
|||
resp, err := l.SubmitMedicalHistory(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func SyncPurchaseHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.SyncPurchaseReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewSyncPurchaseLogic(r.Context(), svcCtx) |
|||
resp, err := l.SyncPurchase(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func UpdateAddressHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.AddressIdReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewUpdateAddressLogic(r.Context(), svcCtx) |
|||
err := l.UpdateAddress(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.Ok(w) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
) |
|||
|
|||
func UpdateCartHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.UpdateCartReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewUpdateCartLogic(r.Context(), svcCtx) |
|||
resp, err := l.UpdateCart(&req) |
|||
if err != nil { |
|||
httpx.ErrorCtx(r.Context(), w, err) |
|||
} else { |
|||
httpx.OkJsonCtx(r.Context(), w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func UpdateHealthProfileHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.UpdateHealthProfileReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewUpdateHealthProfileLogic(r.Context(), svcCtx) |
|||
resp, err := l.UpdateHealthProfile(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func UpdateLifestyleHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.UpdateLifestyleReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewUpdateLifestyleLogic(r.Context(), svcCtx) |
|||
resp, err := l.UpdateLifestyle(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
package handler |
|||
|
|||
import ( |
|||
"net/http" |
|||
|
|||
"github.com/zeromicro/go-zero/rest/httpx" |
|||
"healthapi/internal/logic" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/response" |
|||
) |
|||
|
|||
func UpdateUserProfileHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { |
|||
return func(w http.ResponseWriter, r *http.Request) { |
|||
var req types.UpdateProfileReq |
|||
if err := httpx.Parse(r, &req); err != nil { |
|||
response.Error(w, err) |
|||
return |
|||
} |
|||
|
|||
l := logic.NewUpdateUserProfileLogic(r.Context(), svcCtx) |
|||
resp, err := l.UpdateUserProfile(&req) |
|||
if err != nil { |
|||
response.Error(w, err) |
|||
} else { |
|||
response.Success(w, resp) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,135 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
"errors" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
"gorm.io/gorm" |
|||
) |
|||
|
|||
type AddCartLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewAddCartLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddCartLogic { |
|||
return &AddCartLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *AddCartLogic) AddCart(req *types.AddCartReq) (resp *types.CartItem, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
// 验证商品存在且上架
|
|||
var product model.Product |
|||
if err := l.svcCtx.DB.First(&product, req.ProductID).Error; err != nil { |
|||
return nil, errorx.NewCodeError(404, "商品不存在") |
|||
} |
|||
if !product.IsActive { |
|||
return nil, errorx.NewCodeError(400, "商品已下架") |
|||
} |
|||
|
|||
price := product.Price |
|||
stock := product.Stock |
|||
skuName := "" |
|||
image := product.MainImage |
|||
|
|||
// 如果有 SKU,验证 SKU
|
|||
if req.SkuID > 0 { |
|||
var sku model.ProductSku |
|||
if err := l.svcCtx.DB.First(&sku, req.SkuID).Error; err != nil { |
|||
return nil, errorx.NewCodeError(404, "商品规格不存在") |
|||
} |
|||
if sku.ProductID != req.ProductID { |
|||
return nil, errorx.NewCodeError(400, "商品规格不匹配") |
|||
} |
|||
if !sku.IsActive { |
|||
return nil, errorx.NewCodeError(400, "该规格已下架") |
|||
} |
|||
price = sku.Price |
|||
stock = sku.Stock |
|||
skuName = sku.Name |
|||
if sku.Image != "" { |
|||
image = sku.Image |
|||
} |
|||
} |
|||
|
|||
// 检查库存
|
|||
if stock < req.Quantity { |
|||
return nil, errorx.NewCodeError(400, "库存不足") |
|||
} |
|||
|
|||
// 检查是否已在购物车中
|
|||
var existingItem model.CartItem |
|||
query := l.svcCtx.DB.Where("user_id = ? AND product_id = ?", userID, req.ProductID) |
|||
if req.SkuID > 0 { |
|||
query = query.Where("sku_id = ?", req.SkuID) |
|||
} else { |
|||
query = query.Where("sku_id = 0 OR sku_id IS NULL") |
|||
} |
|||
|
|||
if err := query.First(&existingItem).Error; err == nil { |
|||
// 已存在,更新数量
|
|||
newQty := existingItem.Quantity + req.Quantity |
|||
if newQty > stock { |
|||
return nil, errorx.NewCodeError(400, "库存不足") |
|||
} |
|||
existingItem.Quantity = newQty |
|||
l.svcCtx.DB.Save(&existingItem) |
|||
|
|||
resp = &types.CartItem{ |
|||
ID: uint(existingItem.ID), |
|||
ProductID: existingItem.ProductID, |
|||
SkuID: existingItem.SkuID, |
|||
ProductName: product.Name, |
|||
SkuName: skuName, |
|||
Image: image, |
|||
Price: price, |
|||
Quantity: existingItem.Quantity, |
|||
Selected: existingItem.Selected, |
|||
Stock: stock, |
|||
} |
|||
return resp, nil |
|||
} else if !errors.Is(err, gorm.ErrRecordNotFound) { |
|||
return nil, err |
|||
} |
|||
|
|||
// 新增购物车项
|
|||
cartItem := model.CartItem{ |
|||
UserID: userID, |
|||
ProductID: req.ProductID, |
|||
SkuID: req.SkuID, |
|||
Quantity: req.Quantity, |
|||
Selected: true, |
|||
} |
|||
if err := l.svcCtx.DB.Create(&cartItem).Error; err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
resp = &types.CartItem{ |
|||
ID: uint(cartItem.ID), |
|||
ProductID: cartItem.ProductID, |
|||
SkuID: cartItem.SkuID, |
|||
ProductName: product.Name, |
|||
SkuName: skuName, |
|||
Image: image, |
|||
Price: price, |
|||
Quantity: cartItem.Quantity, |
|||
Selected: cartItem.Selected, |
|||
Stock: stock, |
|||
} |
|||
return resp, nil |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
) |
|||
|
|||
type BatchSelectCartLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewBatchSelectCartLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BatchSelectCartLogic { |
|||
return &BatchSelectCartLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *BatchSelectCartLogic) BatchSelectCart(req *types.BatchSelectCartReq) (resp *types.CommonResp, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
if len(req.Ids) == 0 { |
|||
// 全选/全不选
|
|||
l.svcCtx.DB.Model(&model.CartItem{}).Where("user_id = ?", userID).Update("selected", req.Selected) |
|||
} else { |
|||
// 批量选择指定项
|
|||
l.svcCtx.DB.Model(&model.CartItem{}). |
|||
Where("user_id = ? AND id IN ?", userID, req.Ids). |
|||
Update("selected", req.Selected) |
|||
} |
|||
|
|||
return &types.CommonResp{ |
|||
Code: 0, |
|||
Message: "操作成功", |
|||
}, nil |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
) |
|||
|
|||
type BatchSubmitAllergyLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewBatchSubmitAllergyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BatchSubmitAllergyLogic { |
|||
return &BatchSubmitAllergyLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *BatchSubmitAllergyLogic) BatchSubmitAllergy(req *types.BatchAllergyReq) (resp *types.CommonResp, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
var profile model.HealthProfile |
|||
if err := l.svcCtx.DB.Where("user_id = ?", userID).First(&profile).Error; err != nil { |
|||
return nil, errorx.NewCodeError(errorx.CodeBadRequest, "请先填写基础信息") |
|||
} |
|||
|
|||
// 清除旧数据
|
|||
l.svcCtx.DB.Where("health_profile_id = ?", profile.ID).Delete(&model.AllergyRecord{}) |
|||
|
|||
// 创建新数据
|
|||
if len(req.Items) > 0 { |
|||
records := make([]model.AllergyRecord, len(req.Items)) |
|||
for i, a := range req.Items { |
|||
records[i] = model.AllergyRecord{ |
|||
HealthProfileID: profile.ID, |
|||
AllergyType: a.AllergyType, |
|||
Allergen: a.Allergen, |
|||
Severity: a.Severity, |
|||
ReactionDesc: a.ReactionDesc, |
|||
} |
|||
} |
|||
if err := l.svcCtx.DB.Create(&records).Error; err != nil { |
|||
return nil, errorx.ErrServerError |
|||
} |
|||
} |
|||
|
|||
return &types.CommonResp{Code: 0, Message: "提交成功"}, nil |
|||
} |
|||
@ -0,0 +1,59 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
) |
|||
|
|||
type BatchSubmitFamilyHistoryLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewBatchSubmitFamilyHistoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BatchSubmitFamilyHistoryLogic { |
|||
return &BatchSubmitFamilyHistoryLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *BatchSubmitFamilyHistoryLogic) BatchSubmitFamilyHistory(req *types.BatchFamilyHistoryReq) (resp *types.CommonResp, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
var profile model.HealthProfile |
|||
if err := l.svcCtx.DB.Where("user_id = ?", userID).First(&profile).Error; err != nil { |
|||
return nil, errorx.NewCodeError(errorx.CodeBadRequest, "请先填写基础信息") |
|||
} |
|||
|
|||
// 清除旧数据
|
|||
l.svcCtx.DB.Where("health_profile_id = ?", profile.ID).Delete(&model.FamilyHistory{}) |
|||
|
|||
// 创建新数据
|
|||
if len(req.Items) > 0 { |
|||
histories := make([]model.FamilyHistory, len(req.Items)) |
|||
for i, h := range req.Items { |
|||
histories[i] = model.FamilyHistory{ |
|||
HealthProfileID: profile.ID, |
|||
Relation: h.Relation, |
|||
DiseaseName: h.DiseaseName, |
|||
Notes: h.Notes, |
|||
} |
|||
} |
|||
if err := l.svcCtx.DB.Create(&histories).Error; err != nil { |
|||
return nil, errorx.ErrServerError |
|||
} |
|||
} |
|||
|
|||
return &types.CommonResp{Code: 0, Message: "提交成功"}, nil |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
) |
|||
|
|||
type BatchSubmitMedicalHistoryLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewBatchSubmitMedicalHistoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BatchSubmitMedicalHistoryLogic { |
|||
return &BatchSubmitMedicalHistoryLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *BatchSubmitMedicalHistoryLogic) BatchSubmitMedicalHistory(req *types.BatchMedicalHistoryReq) (resp *types.CommonResp, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
var profile model.HealthProfile |
|||
if err := l.svcCtx.DB.Where("user_id = ?", userID).First(&profile).Error; err != nil { |
|||
return nil, errorx.NewCodeError(errorx.CodeBadRequest, "请先填写基础信息") |
|||
} |
|||
|
|||
// 清除旧数据
|
|||
l.svcCtx.DB.Where("health_profile_id = ?", profile.ID).Delete(&model.MedicalHistory{}) |
|||
|
|||
// 创建新数据
|
|||
if len(req.Items) > 0 { |
|||
histories := make([]model.MedicalHistory, len(req.Items)) |
|||
for i, h := range req.Items { |
|||
histories[i] = model.MedicalHistory{ |
|||
HealthProfileID: profile.ID, |
|||
DiseaseName: h.DiseaseName, |
|||
DiseaseType: h.DiseaseType, |
|||
DiagnosedDate: h.DiagnosedDate, |
|||
Status: h.Status, |
|||
Notes: h.Notes, |
|||
} |
|||
} |
|||
if err := l.svcCtx.DB.Create(&histories).Error; err != nil { |
|||
return nil, errorx.ErrServerError |
|||
} |
|||
} |
|||
|
|||
return &types.CommonResp{Code: 0, Message: "提交成功"}, nil |
|||
} |
|||
@ -0,0 +1,94 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
"fmt" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
"gorm.io/gorm" |
|||
) |
|||
|
|||
type CancelOrderLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewCancelOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CancelOrderLogic { |
|||
return &CancelOrderLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *CancelOrderLogic) CancelOrder(req *types.CancelOrderReq) (resp *types.CommonResp, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
var order model.Order |
|||
if err := l.svcCtx.DB.Where("id = ? AND user_id = ?", req.Id, userID).First(&order).Error; err != nil { |
|||
return nil, errorx.NewCodeError(404, "订单不存在") |
|||
} |
|||
|
|||
if order.Status != model.OrderStatusPending { |
|||
return nil, errorx.NewCodeError(400, "只能取消待支付订单") |
|||
} |
|||
|
|||
err = l.svcCtx.DB.Transaction(func(tx *gorm.DB) error { |
|||
// 更新订单状态
|
|||
if err := tx.Model(&order).Updates(map[string]interface{}{ |
|||
"status": model.OrderStatusCancelled, |
|||
"cancel_reason": req.Reason, |
|||
}).Error; err != nil { |
|||
return err |
|||
} |
|||
|
|||
// 恢复库存
|
|||
var items []model.OrderItem |
|||
tx.Where("order_id = ?", order.ID).Find(&items) |
|||
for _, item := range items { |
|||
if item.SkuID > 0 { |
|||
tx.Model(&model.ProductSku{}).Where("id = ?", item.SkuID). |
|||
Update("stock", gorm.Expr("stock + ?", item.Quantity)) |
|||
} else { |
|||
tx.Model(&model.Product{}).Where("id = ?", item.ProductID). |
|||
Update("stock", gorm.Expr("stock + ?", item.Quantity)) |
|||
} |
|||
} |
|||
|
|||
// 退还积分
|
|||
if order.PointsUsed > 0 { |
|||
var user model.User |
|||
tx.First(&user, userID) |
|||
tx.Model(&user).Update("points", gorm.Expr("points + ?", order.PointsUsed)) |
|||
tx.Create(&model.PointsRecord{ |
|||
UserID: userID, |
|||
Type: model.PointsTypeAdjust, |
|||
Points: order.PointsUsed, |
|||
Balance: user.Points + order.PointsUsed, |
|||
Source: model.PointsSourceRefund, |
|||
ReferenceID: uint(order.ID), |
|||
Remark: fmt.Sprintf("订单 %s 取消,退还积分", order.OrderNo), |
|||
}) |
|||
} |
|||
|
|||
return nil |
|||
}) |
|||
|
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
return &types.CommonResp{ |
|||
Code: 0, |
|||
Message: "订单已取消", |
|||
}, nil |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
) |
|||
|
|||
type ClearCartLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewClearCartLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ClearCartLogic { |
|||
return &ClearCartLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *ClearCartLogic) ClearCart() (resp *types.CommonResp, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
l.svcCtx.DB.Where("user_id = ?", userID).Delete(&model.CartItem{}) |
|||
|
|||
return &types.CommonResp{ |
|||
Code: 0, |
|||
Message: "购物车已清空", |
|||
}, nil |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
) |
|||
|
|||
type CompleteSurveyLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewCompleteSurveyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CompleteSurveyLogic { |
|||
return &CompleteSurveyLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *CompleteSurveyLogic) CompleteSurvey() (resp *types.CommonResp, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
// 检查基础信息
|
|||
var profile model.HealthProfile |
|||
if err := l.svcCtx.DB.Where("user_id = ?", userID).First(&profile).Error; err != nil { |
|||
return nil, errorx.NewCodeError(errorx.CodeBadRequest, "请先完成基础信息填写") |
|||
} |
|||
|
|||
// 检查生活习惯
|
|||
var lifestyle model.LifestyleInfo |
|||
if err := l.svcCtx.DB.Where("user_id = ?", userID).First(&lifestyle).Error; err != nil { |
|||
return nil, errorx.NewCodeError(errorx.CodeBadRequest, "请先完成生活习惯填写") |
|||
} |
|||
|
|||
// 标记调查完成
|
|||
if err := l.svcCtx.DB.Model(&model.User{}).Where("id = ?", userID).Update("survey_completed", true).Error; err != nil { |
|||
return nil, errorx.ErrServerError |
|||
} |
|||
|
|||
return &types.CommonResp{Code: 0, Message: "调查完成"}, nil |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
"time" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
) |
|||
|
|||
type ConfirmReceiveLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewConfirmReceiveLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ConfirmReceiveLogic { |
|||
return &ConfirmReceiveLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *ConfirmReceiveLogic) ConfirmReceive(req *types.OrderIdReq) (resp *types.CommonResp, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
var order model.Order |
|||
if err := l.svcCtx.DB.Where("id = ? AND user_id = ?", req.Id, userID).First(&order).Error; err != nil { |
|||
return nil, errorx.NewCodeError(404, "订单不存在") |
|||
} |
|||
|
|||
if order.Status != model.OrderStatusShipped { |
|||
return nil, errorx.NewCodeError(400, "只能确认已发货订单") |
|||
} |
|||
|
|||
now := time.Now() |
|||
if err := l.svcCtx.DB.Model(&order).Updates(map[string]interface{}{ |
|||
"status": model.OrderStatusCompleted, |
|||
"receive_time": now, |
|||
}).Error; err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
return &types.CommonResp{ |
|||
Code: 0, |
|||
Message: "确认收货成功", |
|||
}, nil |
|||
} |
|||
@ -0,0 +1,76 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
) |
|||
|
|||
type CreateAddressLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewCreateAddressLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateAddressLogic { |
|||
return &CreateAddressLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *CreateAddressLogic) CreateAddress(req *types.SaveAddressReq) (resp *types.Address, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
// 如果设为默认,先取消其他默认地址
|
|||
if req.IsDefault { |
|||
l.svcCtx.DB.Model(&model.Address{}).Where("user_id = ?", userID).Update("is_default", false) |
|||
} |
|||
|
|||
// 检查是否是第一个地址,如果是则自动设为默认
|
|||
var count int64 |
|||
l.svcCtx.DB.Model(&model.Address{}).Where("user_id = ?", userID).Count(&count) |
|||
if count == 0 { |
|||
req.IsDefault = true |
|||
} |
|||
|
|||
addr := model.Address{ |
|||
UserID: userID, |
|||
ReceiverName: req.ReceiverName, |
|||
Phone: req.Phone, |
|||
Province: req.Province, |
|||
City: req.City, |
|||
District: req.District, |
|||
DetailAddr: req.DetailAddr, |
|||
PostalCode: req.PostalCode, |
|||
IsDefault: req.IsDefault, |
|||
Tag: req.Tag, |
|||
} |
|||
|
|||
if err := l.svcCtx.DB.Create(&addr).Error; err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
resp = &types.Address{ |
|||
ID: uint(addr.ID), |
|||
ReceiverName: addr.ReceiverName, |
|||
Phone: addr.Phone, |
|||
Province: addr.Province, |
|||
City: addr.City, |
|||
District: addr.District, |
|||
DetailAddr: addr.DetailAddr, |
|||
PostalCode: addr.PostalCode, |
|||
IsDefault: addr.IsDefault, |
|||
Tag: addr.Tag, |
|||
} |
|||
return resp, nil |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
) |
|||
|
|||
type CreateConversationLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewCreateConversationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateConversationLogic { |
|||
return &CreateConversationLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *CreateConversationLogic) CreateConversation(req *types.CreateConversationReq) (resp *types.ConversationItem, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
title := req.Title |
|||
if title == "" { |
|||
title = "新对话" |
|||
} |
|||
|
|||
conversation := model.Conversation{ |
|||
UserID: userID, |
|||
Title: title, |
|||
} |
|||
|
|||
if err := l.svcCtx.DB.Create(&conversation).Error; err != nil { |
|||
return nil, errorx.ErrServerError |
|||
} |
|||
|
|||
return &types.ConversationItem{ |
|||
ID: uint(conversation.ID), |
|||
Title: conversation.Title, |
|||
CreatedAt: conversation.CreatedAt.Format("2006-01-02 15:04:05"), |
|||
UpdatedAt: conversation.UpdatedAt.Format("2006-01-02 15:04:05"), |
|||
}, nil |
|||
} |
|||
@ -0,0 +1,256 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
"fmt" |
|||
"time" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
"gorm.io/gorm" |
|||
) |
|||
|
|||
type CreateOrderLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewCreateOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateOrderLogic { |
|||
return &CreateOrderLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *CreateOrderLogic) CreateOrder(req *types.CreateOrderReq) (resp *types.Order, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
// 获取用户信息(会员等级)
|
|||
var user model.User |
|||
if err := l.svcCtx.DB.First(&user, userID).Error; err != nil { |
|||
return nil, errorx.ErrUserNotFound |
|||
} |
|||
levelConfig := model.MemberLevelConfigs[user.MemberLevel] |
|||
if levelConfig.Level == "" { |
|||
levelConfig = model.MemberLevelConfigs[model.MemberLevelNormal] |
|||
} |
|||
|
|||
// 验证收货地址
|
|||
var address model.Address |
|||
if err := l.svcCtx.DB.Where("id = ? AND user_id = ?", req.AddressID, userID).First(&address).Error; err != nil { |
|||
return nil, errorx.NewCodeError(404, "收货地址不存在") |
|||
} |
|||
|
|||
// 获取购物车项
|
|||
var cartItems []model.CartItem |
|||
if err := l.svcCtx.DB.Where("id IN ? AND user_id = ?", req.CartItemIDs, userID).Find(&cartItems).Error; err != nil { |
|||
return nil, err |
|||
} |
|||
if len(cartItems) == 0 { |
|||
return nil, errorx.NewCodeError(400, "购物车为空") |
|||
} |
|||
|
|||
// 计算订单金额
|
|||
var totalAmount float64 |
|||
orderItems := make([]model.OrderItem, 0, len(cartItems)) |
|||
|
|||
for _, cartItem := range cartItems { |
|||
var product model.Product |
|||
if err := l.svcCtx.DB.First(&product, cartItem.ProductID).Error; err != nil { |
|||
return nil, errorx.NewCodeError(404, fmt.Sprintf("商品 %d 不存在", cartItem.ProductID)) |
|||
} |
|||
if !product.IsActive { |
|||
return nil, errorx.NewCodeError(400, fmt.Sprintf("商品 %s 已下架", product.Name)) |
|||
} |
|||
|
|||
price := product.Price |
|||
stock := product.Stock |
|||
skuName := "" |
|||
image := product.MainImage |
|||
|
|||
if cartItem.SkuID > 0 { |
|||
var sku model.ProductSku |
|||
if err := l.svcCtx.DB.First(&sku, cartItem.SkuID).Error; err != nil { |
|||
return nil, errorx.NewCodeError(404, "商品规格不存在") |
|||
} |
|||
price = sku.Price |
|||
stock = sku.Stock |
|||
skuName = sku.Name |
|||
if sku.Image != "" { |
|||
image = sku.Image |
|||
} |
|||
} |
|||
|
|||
if stock < cartItem.Quantity { |
|||
return nil, errorx.NewCodeError(400, fmt.Sprintf("商品 %s 库存不足", product.Name)) |
|||
} |
|||
|
|||
itemTotal := price * float64(cartItem.Quantity) |
|||
totalAmount += itemTotal |
|||
|
|||
orderItems = append(orderItems, model.OrderItem{ |
|||
ProductID: cartItem.ProductID, |
|||
SkuID: cartItem.SkuID, |
|||
ProductName: product.Name, |
|||
SkuName: skuName, |
|||
Image: image, |
|||
Price: price, |
|||
Quantity: cartItem.Quantity, |
|||
TotalAmount: itemTotal, |
|||
}) |
|||
} |
|||
|
|||
// 计算会员折扣
|
|||
discountAmount := totalAmount * (1 - levelConfig.Discount) |
|||
|
|||
// 计算运费
|
|||
shippingFee := float64(0) |
|||
afterDiscount := totalAmount - discountAmount |
|||
if afterDiscount < levelConfig.FreeShippingMin { |
|||
shippingFee = 10 // 默认运费
|
|||
} |
|||
|
|||
// 计算积分抵扣(100积分=1元)
|
|||
pointsDiscount := float64(0) |
|||
pointsUsed := req.PointsUsed |
|||
if pointsUsed > 0 { |
|||
if pointsUsed > user.Points { |
|||
pointsUsed = user.Points |
|||
} |
|||
maxPointsDiscount := afterDiscount * 0.2 // 最多抵扣20%
|
|||
pointsDiscount = float64(pointsUsed) / 100 |
|||
if pointsDiscount > maxPointsDiscount { |
|||
pointsDiscount = maxPointsDiscount |
|||
pointsUsed = int(maxPointsDiscount * 100) |
|||
} |
|||
} |
|||
|
|||
// 最终支付金额
|
|||
payAmount := afterDiscount + shippingFee - pointsDiscount |
|||
|
|||
// 生成订单号
|
|||
orderNo := fmt.Sprintf("%s%d%04d", time.Now().Format("20060102150405"), userID, time.Now().Nanosecond()%10000) |
|||
|
|||
// 计算获得积分
|
|||
pointsEarned := int(payAmount * levelConfig.PointsMultiplier) |
|||
|
|||
// 创建订单(使用事务)
|
|||
order := model.Order{ |
|||
UserID: userID, |
|||
OrderNo: orderNo, |
|||
Status: model.OrderStatusPending, |
|||
TotalAmount: totalAmount, |
|||
DiscountAmount: discountAmount, |
|||
ShippingFee: shippingFee, |
|||
PayAmount: payAmount, |
|||
PointsUsed: pointsUsed, |
|||
PointsEarned: pointsEarned, |
|||
ReceiverName: address.ReceiverName, |
|||
ReceiverPhone: address.Phone, |
|||
ReceiverAddr: fmt.Sprintf("%s%s%s%s", address.Province, address.City, address.District, address.DetailAddr), |
|||
Remark: req.Remark, |
|||
} |
|||
|
|||
err = l.svcCtx.DB.Transaction(func(tx *gorm.DB) error { |
|||
// 创建订单
|
|||
if err := tx.Create(&order).Error; err != nil { |
|||
return err |
|||
} |
|||
|
|||
// 创建订单项
|
|||
for i := range orderItems { |
|||
orderItems[i].OrderID = uint(order.ID) |
|||
} |
|||
if err := tx.Create(&orderItems).Error; err != nil { |
|||
return err |
|||
} |
|||
|
|||
// 扣减库存
|
|||
for _, cartItem := range cartItems { |
|||
if cartItem.SkuID > 0 { |
|||
if err := tx.Model(&model.ProductSku{}).Where("id = ?", cartItem.SkuID). |
|||
Update("stock", gorm.Expr("stock - ?", cartItem.Quantity)).Error; err != nil { |
|||
return err |
|||
} |
|||
} else { |
|||
if err := tx.Model(&model.Product{}).Where("id = ?", cartItem.ProductID). |
|||
Update("stock", gorm.Expr("stock - ?", cartItem.Quantity)).Error; err != nil { |
|||
return err |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 删除购物车项
|
|||
if err := tx.Where("id IN ?", req.CartItemIDs).Delete(&model.CartItem{}).Error; err != nil { |
|||
return err |
|||
} |
|||
|
|||
// 扣除积分
|
|||
if pointsUsed > 0 { |
|||
if err := tx.Model(&user).Update("points", gorm.Expr("points - ?", pointsUsed)).Error; err != nil { |
|||
return err |
|||
} |
|||
// 记录积分变动
|
|||
tx.Create(&model.PointsRecord{ |
|||
UserID: userID, |
|||
Type: model.PointsTypeSpend, |
|||
Points: -pointsUsed, |
|||
Balance: user.Points - pointsUsed, |
|||
Source: model.PointsSourceOrder, |
|||
ReferenceID: uint(order.ID), |
|||
Remark: fmt.Sprintf("订单 %s 使用积分", orderNo), |
|||
}) |
|||
} |
|||
|
|||
return nil |
|||
}) |
|||
|
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
// 构建响应
|
|||
respItems := make([]types.OrderItem, 0, len(orderItems)) |
|||
for _, item := range orderItems { |
|||
respItems = append(respItems, types.OrderItem{ |
|||
ID: uint(item.ID), |
|||
ProductID: item.ProductID, |
|||
SkuID: item.SkuID, |
|||
ProductName: item.ProductName, |
|||
SkuName: item.SkuName, |
|||
Image: item.Image, |
|||
Price: item.Price, |
|||
Quantity: item.Quantity, |
|||
TotalAmount: item.TotalAmount, |
|||
}) |
|||
} |
|||
|
|||
resp = &types.Order{ |
|||
ID: uint(order.ID), |
|||
OrderNo: order.OrderNo, |
|||
Status: order.Status, |
|||
TotalAmount: order.TotalAmount, |
|||
DiscountAmount: order.DiscountAmount, |
|||
ShippingFee: order.ShippingFee, |
|||
PayAmount: order.PayAmount, |
|||
PointsUsed: order.PointsUsed, |
|||
PointsEarned: order.PointsEarned, |
|||
ReceiverName: order.ReceiverName, |
|||
ReceiverPhone: order.ReceiverPhone, |
|||
ReceiverAddr: order.ReceiverAddr, |
|||
Remark: order.Remark, |
|||
Items: respItems, |
|||
CreatedAt: order.CreatedAt.Format("2006-01-02 15:04:05"), |
|||
} |
|||
|
|||
return resp, nil |
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
) |
|||
|
|||
type DeleteAddressLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewDeleteAddressLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteAddressLogic { |
|||
return &DeleteAddressLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *DeleteAddressLogic) DeleteAddress(req *types.AddressIdReq) (resp *types.CommonResp, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
result := l.svcCtx.DB.Where("id = ? AND user_id = ?", req.Id, userID).Delete(&model.Address{}) |
|||
if result.Error != nil { |
|||
return nil, result.Error |
|||
} |
|||
if result.RowsAffected == 0 { |
|||
return nil, errorx.NewCodeError(404, "地址不存在") |
|||
} |
|||
|
|||
return &types.CommonResp{ |
|||
Code: 0, |
|||
Message: "删除成功", |
|||
}, nil |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
) |
|||
|
|||
type DeleteAllergyRecordLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewDeleteAllergyRecordLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteAllergyRecordLogic { |
|||
return &DeleteAllergyRecordLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *DeleteAllergyRecordLogic) DeleteAllergyRecord(req *types.IdPathReq) (resp *types.CommonResp, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
var profile model.HealthProfile |
|||
if err := l.svcCtx.DB.Where("user_id = ?", userID).First(&profile).Error; err != nil { |
|||
return nil, errorx.ErrNotFound |
|||
} |
|||
|
|||
var record model.AllergyRecord |
|||
if err := l.svcCtx.DB.Where("id = ? AND health_profile_id = ?", req.Id, profile.ID).First(&record).Error; err != nil { |
|||
return nil, errorx.ErrNotFound |
|||
} |
|||
|
|||
if err := l.svcCtx.DB.Delete(&record).Error; err != nil { |
|||
return nil, errorx.ErrServerError |
|||
} |
|||
|
|||
return &types.CommonResp{Code: 0, Message: "删除成功"}, nil |
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
) |
|||
|
|||
type DeleteCartLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewDeleteCartLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteCartLogic { |
|||
return &DeleteCartLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *DeleteCartLogic) DeleteCart(req *types.IdPathReq) (resp *types.CommonResp, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
result := l.svcCtx.DB.Where("id = ? AND user_id = ?", req.Id, userID).Delete(&model.CartItem{}) |
|||
if result.Error != nil { |
|||
return nil, result.Error |
|||
} |
|||
if result.RowsAffected == 0 { |
|||
return nil, errorx.NewCodeError(404, "购物车项不存在") |
|||
} |
|||
|
|||
return &types.CommonResp{ |
|||
Code: 0, |
|||
Message: "删除成功", |
|||
}, nil |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
) |
|||
|
|||
type DeleteConversationLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewDeleteConversationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteConversationLogic { |
|||
return &DeleteConversationLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *DeleteConversationLogic) DeleteConversation(req *types.ConversationIdReq) (resp *types.CommonResp, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
var conversation model.Conversation |
|||
if err := l.svcCtx.DB.Where("id = ? AND user_id = ?", req.Id, userID).First(&conversation).Error; err != nil { |
|||
return nil, errorx.ErrNotFound |
|||
} |
|||
|
|||
// 删除消息
|
|||
l.svcCtx.DB.Where("conversation_id = ?", conversation.ID).Delete(&model.Message{}) |
|||
|
|||
// 删除对话
|
|||
if err := l.svcCtx.DB.Delete(&conversation).Error; err != nil { |
|||
return nil, errorx.ErrServerError |
|||
} |
|||
|
|||
return &types.CommonResp{Code: 0, Message: "删除成功"}, nil |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
package logic |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"healthapi/internal/model" |
|||
"healthapi/internal/svc" |
|||
"healthapi/internal/types" |
|||
"healthapi/pkg/errorx" |
|||
|
|||
"github.com/zeromicro/go-zero/core/logx" |
|||
) |
|||
|
|||
type DeleteFamilyHistoryLogic struct { |
|||
logx.Logger |
|||
ctx context.Context |
|||
svcCtx *svc.ServiceContext |
|||
} |
|||
|
|||
func NewDeleteFamilyHistoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteFamilyHistoryLogic { |
|||
return &DeleteFamilyHistoryLogic{ |
|||
Logger: logx.WithContext(ctx), |
|||
ctx: ctx, |
|||
svcCtx: svcCtx, |
|||
} |
|||
} |
|||
|
|||
func (l *DeleteFamilyHistoryLogic) DeleteFamilyHistory(req *types.IdPathReq) (resp *types.CommonResp, err error) { |
|||
userID, err := GetUserIDFromCtx(l.ctx) |
|||
if err != nil { |
|||
return nil, errorx.ErrUnauthorized |
|||
} |
|||
|
|||
var profile model.HealthProfile |
|||
if err := l.svcCtx.DB.Where("user_id = ?", userID).First(&profile).Error; err != nil { |
|||
return nil, errorx.ErrNotFound |
|||
} |
|||
|
|||
var history model.FamilyHistory |
|||
if err := l.svcCtx.DB.Where("id = ? AND health_profile_id = ?", req.Id, profile.ID).First(&history).Error; err != nil { |
|||
return nil, errorx.ErrNotFound |
|||
} |
|||
|
|||
if err := l.svcCtx.DB.Delete(&history).Error; err != nil { |
|||
return nil, errorx.ErrServerError |
|||
} |
|||
|
|||
return &types.CommonResp{Code: 0, Message: "删除成功"}, nil |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue