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