Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
performance-score
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ai-tools
performance-score
Commits
db1f4347
Commit
db1f4347
authored
Aug 30, 2025
by
luoqi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat:接口标准
parent
d91e197b
Pipeline
#3222
passed with stage
in 9 seconds
Changes
6
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
339 additions
and
98 deletions
+339
-98
README.md
+149
-17
backend/routers/history.py
+23
-9
backend/routers/institutions.py
+62
-31
backend/routers/system_config.py
+28
-14
backend/routers/users.py
+55
-25
src/services/api.js
+22
-2
No files found.
README.md
View file @
db1f4347
...
@@ -248,6 +248,58 @@ python migrate.py --rollback 001
...
@@ -248,6 +248,58 @@ python migrate.py --rollback 001
## 📚 API文档
## 📚 API文档
### 🔗 前后端接口标准约定
#### 📋 统一响应格式
**标准响应格式(所有接口):**
```
json
{
"success"
:
true
,
"message"
:
"操作成功"
,
"data"
:
[
实际数据内容
]
}
```
**特殊响应格式(认证相关接口):**
```
json
{
"success"
:
true
,
"access_token"
:
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
,
"refresh_token"
:
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
,
"token_type"
:
"bearer"
,
"expires_in"
:
86400
,
"user"
:
{
...
},
"message"
:
"登录成功"
}
```
#### 🔧 前端自动解包机制
前端API客户端自动处理响应格式:
-
**自动检测**
:识别
`BaseResponse`
格式(包含
`success`
字段)
-
**自动解包**
:提取
`data`
字段内容,透明返回给业务代码
-
**错误处理**
:检查
`success`
字段,失败时自动抛出异常
-
**兼容性**
:对特殊格式接口(如login)保持原样返回
#### 📊 状态码约定
| 状态码 | 含义 | 使用场景 |
|--------|------|----------|
| 200 | 成功 | 正常请求成功 |
| 400 | 请求错误 | 参数验证失败、业务逻辑错误 |
| 401 | 未授权 | Token无效、未登录 |
| 403 | 禁止访问 | 权限不足 |
| 404 | 资源不存在 | 数据不存在 |
| 500 | 服务器错误 | 系统内部错误 |
#### 🔐 认证机制
-
**认证方式**
:JWT Bearer Token
-
**Token类型**
:Access Token(短期)+ Refresh Token(长期)
-
**自动刷新**
:前端自动检测401错误并尝试刷新Token
-
**安全登出**
:服务端Token黑名单机制
### 接口概览
### 接口概览
系统提供完整的RESTful API,支持前后端分离架构。
系统提供完整的RESTful API,支持前后端分离架构。
...
@@ -260,30 +312,110 @@ python migrate.py --rollback 001
...
@@ -260,30 +312,110 @@ python migrate.py --rollback 001
### 主要接口
### 主要接口
| 模块 | 方法 | 路径 | 描述 |
| 模块 | 方法 | 路径 | 描述 | 响应格式 |
|------|------|------|------|
|------|------|------|------|----------|
| 认证 | POST |
`/users/login`
| 用户登录 |
| 认证 | POST |
`/users/login`
| 用户登录 | 特殊格式 |
| 认证 | POST |
`/users/refresh`
| 刷新Token |
| 认证 | POST |
`/users/logout`
| 用户登出 | 标准格式 |
| 用户 | GET |
`/users`
| 获取用户列表 |
| 认证 | POST |
`/users/refresh`
| 刷新Token | 特殊格式 |
| 用户 | POST |
`/users`
| 创建用户 |
| 用户 | GET |
`/users`
| 获取用户列表 | 标准格式 |
| 用户 | PUT |
`/users/{id}`
| 更新用户 |
| 用户 | GET |
`/users/{id}`
| 获取用户信息 | 标准格式 |
| 用户 | DELETE |
`/users/{id}`
| 删除用户 |
| 用户 | POST |
`/users`
| 创建用户 | 标准格式 |
| 机构 | GET |
`/institutions`
| 获取机构列表 |
| 用户 | PUT |
`/users/{id}`
| 更新用户 | 标准格式 |
| 机构 | POST |
`/institutions`
| 创建机构 |
| 用户 | DELETE |
`/users/{id}`
| 删除用户 | 标准格式 |
| 历史 | GET |
`/history`
| 获取历史数据 |
| 机构 | GET |
`/institutions`
| 获取机构列表 | 标准格式 |
| 配置 | GET |
`/config`
| 获取系统配置 |
| 机构 | GET |
`/institutions/{id}`
| 获取机构信息 | 标准格式 |
| 机构 | POST |
`/institutions`
| 创建机构 | 标准格式 |
### 认证示例
| 机构 | PUT |
`/institutions/{id}`
| 更新机构 | 标准格式 |
| 机构 | DELETE |
`/institutions/{id}`
| 删除机构 | 标准格式 |
| 历史 | GET |
`/history`
| 获取历史数据列表 | 标准格式 |
| 历史 | GET |
`/history/{month}`
| 获取指定月份历史 | 标准格式 |
| 历史 | POST |
`/history`
| 保存月度历史 | 标准格式 |
| 历史 | DELETE |
`/history`
| 清空历史数据 | 标准格式 |
| 配置 | GET |
`/config`
| 获取系统配置 | 标准格式 |
| 配置 | GET |
`/config/{key}`
| 获取指定配置项 | 标准格式 |
### 🔧 API使用示例
#### 认证流程
```
bash
```
bash
#
登录获取Token
#
1. 用户登录(特殊格式响应)
curl
-X
POST
"http://localhost:8000/api/users/login"
\
curl
-X
POST
"http://localhost:8000/api/users/login"
\
-H
"Content-Type: application/json"
\
-H
"Content-Type: application/json"
\
-d
'{"phone":"admin","password":"admin123"}'
-d
'{"phone":"admin","password":"admin123"}'
# 使用Token访问API
# 响应示例:
{
"success"
:
true
,
"access_token"
:
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
,
"refresh_token"
:
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
,
"token_type"
:
"bearer"
,
"expires_in"
: 86400,
"user"
:
{
"id"
:
"admin"
,
"phone"
:
"admin"
,
"name"
:
"系统管理员"
,
"role"
:
"admin"
}
,
"message"
:
"登录成功"
}
# 2. 使用Token访问API(标准格式响应)
curl
-X
GET
"http://localhost:8000/api/users"
\
curl
-X
GET
"http://localhost:8000/api/users"
\
-H
"Authorization: Bearer YOUR_TOKEN_HERE"
-H
"Authorization: Bearer YOUR_ACCESS_TOKEN"
# 响应示例:
{
"success"
:
true
,
"message"
:
"获取用户列表成功"
,
"data"
:
[
{
"id"
:
"admin"
,
"phone"
:
"admin"
,
"name"
:
"系统管理员"
,
"role"
:
"admin"
,
"institutions"
:
[]
,
"created_at"
:
"2025-08-30T10:00:00"
,
"updated_at"
:
"2025-08-30T10:00:00"
}
]
}
# 3. 刷新Token
curl
-X
POST
"http://localhost:8000/api/users/refresh"
\
-H
"Content-Type: application/json"
\
-d
'{"refresh_token":"YOUR_REFRESH_TOKEN"}'
# 4. 用户登出
curl
-X
POST
"http://localhost:8000/api/users/logout"
\
-H
"Authorization: Bearer YOUR_ACCESS_TOKEN"
```
#### 业务接口示例
```
bash
# 获取机构列表
curl
-X
GET
"http://localhost:8000/api/institutions"
\
-H
"Authorization: Bearer YOUR_ACCESS_TOKEN"
# 创建机构
curl
-X
POST
"http://localhost:8000/api/institutions"
\
-H
"Authorization: Bearer YOUR_ACCESS_TOKEN"
\
-H
"Content-Type: application/json"
\
-d
'{
"id": "inst_001",
"name": "测试机构",
"institution_id": "TEST001",
"owner_id": "user_001"
}'
# 获取历史数据
curl
-X
GET
"http://localhost:8000/api/history"
\
-H
"Authorization: Bearer YOUR_ACCESS_TOKEN"
# 获取系统配置
curl
-X
GET
"http://localhost:8000/api/config"
\
-H
"Authorization: Bearer YOUR_ACCESS_TOKEN"
```
```
## 🔧 环境配置
## 🔧 环境配置
...
...
backend/routers/history.py
View file @
db1f4347
...
@@ -16,7 +16,7 @@ from dependencies import get_current_active_user, require_admin
...
@@ -16,7 +16,7 @@ from dependencies import get_current_active_user, require_admin
router
=
APIRouter
()
router
=
APIRouter
()
@router.get
(
""
,
response_model
=
List
[
MonthlyHistoryResponse
]
,
summary
=
"获取所有历史记录"
)
@router.get
(
""
,
response_model
=
BaseResponse
,
summary
=
"获取所有历史记录"
)
async
def
get_all_history
(
async
def
get_all_history
(
db
:
DatabaseManager
=
Depends
(
get_database
),
db
:
DatabaseManager
=
Depends
(
get_database
),
current_user
:
UserResponse
=
Depends
(
get_current_active_user
)
current_user
:
UserResponse
=
Depends
(
get_current_active_user
)
...
@@ -54,18 +54,26 @@ async def get_all_history(
...
@@ -54,18 +54,26 @@ async def get_all_history(
# 跳过有问题的记录,继续处理其他记录
# 跳过有问题的记录,继续处理其他记录
continue
continue
return
result
return
BaseResponse
(
success
=
True
,
message
=
"获取历史记录成功"
,
data
=
result
)
except
Exception
as
e
:
except
Exception
as
e
:
logger
.
error
(
f
"获取历史记录失败: {e}"
)
logger
.
error
(
f
"获取历史记录失败: {e}"
)
# 如果是表不存在或字段不存在的错误,返回空列表而不是抛出异常
# 如果是表不存在或字段不存在的错误,返回空列表而不是抛出异常
if
"does not exist"
in
str
(
e
)
.
lower
():
if
"does not exist"
in
str
(
e
)
.
lower
():
logger
.
info
(
"历史记录表或字段不存在,返回空列表"
)
logger
.
info
(
"历史记录表或字段不存在,返回空列表"
)
return
[]
return
BaseResponse
(
success
=
True
,
message
=
"获取历史记录成功"
,
data
=
[]
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取历史记录失败"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取历史记录失败"
)
@router.get
(
"/{month}"
,
response_model
=
MonthlyHistory
Response
,
summary
=
"获取指定月份历史记录"
)
@router.get
(
"/{month}"
,
response_model
=
Base
Response
,
summary
=
"获取指定月份历史记录"
)
async
def
get_history_by_month
(
async
def
get_history_by_month
(
month
:
str
,
month
:
str
,
db
:
DatabaseManager
=
Depends
(
get_database
),
db
:
DatabaseManager
=
Depends
(
get_database
),
...
@@ -76,19 +84,19 @@ async def get_history_by_month(
...
@@ -76,19 +84,19 @@ async def get_history_by_month(
# 验证月份格式
# 验证月份格式
if
not
month
or
len
(
month
)
!=
7
or
month
[
4
]
!=
'-'
:
if
not
month
or
len
(
month
)
!=
7
or
month
[
4
]
!=
'-'
:
raise
HTTPException
(
status_code
=
400
,
detail
=
"月份格式错误,应为 YYYY-MM"
)
raise
HTTPException
(
status_code
=
400
,
detail
=
"月份格式错误,应为 YYYY-MM"
)
query
=
monthly_history_table
.
select
()
.
where
(
monthly_history_table
.
c
.
month
==
month
)
query
=
monthly_history_table
.
select
()
.
where
(
monthly_history_table
.
c
.
month
==
month
)
history
=
await
db
.
fetch_one
(
query
)
history
=
await
db
.
fetch_one
(
query
)
if
not
history
:
if
not
history
:
raise
HTTPException
(
status_code
=
404
,
detail
=
"指定月份的历史记录不存在"
)
raise
HTTPException
(
status_code
=
404
,
detail
=
"指定月份的历史记录不存在"
)
# 安全地获取 institutions_data,确保兼容性
# 安全地获取 institutions_data,确保兼容性
institutions_data
=
history
[
"institutions_data"
]
if
"institutions_data"
in
history
.
_mapping
else
[]
institutions_data
=
history
[
"institutions_data"
]
if
"institutions_data"
in
history
.
_mapping
else
[]
if
institutions_data
is
None
:
if
institutions_data
is
None
:
institutions_data
=
[]
institutions_data
=
[]
return
MonthlyHistoryResponse
(
history_data
=
MonthlyHistoryResponse
(
id
=
history
[
"id"
],
id
=
history
[
"id"
],
month
=
history
[
"month"
],
month
=
history
[
"month"
],
save_time
=
history
[
"save_time"
],
save_time
=
history
[
"save_time"
],
...
@@ -99,7 +107,13 @@ async def get_history_by_month(
...
@@ -99,7 +107,13 @@ async def get_history_by_month(
institutions_data
=
institutions_data
,
institutions_data
=
institutions_data
,
created_at
=
history
[
"created_at"
]
created_at
=
history
[
"created_at"
]
)
)
return
BaseResponse
(
success
=
True
,
message
=
"获取历史记录成功"
,
data
=
history_data
)
except
HTTPException
:
except
HTTPException
:
raise
raise
except
Exception
as
e
:
except
Exception
as
e
:
...
...
backend/routers/institutions.py
View file @
db1f4347
...
@@ -59,7 +59,7 @@ async def get_institution_with_images(institution_id: str, db: DatabaseManager):
...
@@ -59,7 +59,7 @@ async def get_institution_with_images(institution_id: str, db: DatabaseManager):
)
)
@router.get
(
""
,
response_model
=
List
[
InstitutionResponse
]
,
summary
=
"获取机构列表"
)
@router.get
(
""
,
response_model
=
BaseResponse
,
summary
=
"获取机构列表"
)
async
def
get_all_institutions
(
async
def
get_all_institutions
(
db
:
DatabaseManager
=
Depends
(
get_database
),
db
:
DatabaseManager
=
Depends
(
get_database
),
current_user
:
UserResponse
=
Depends
(
get_current_active_user
)
current_user
:
UserResponse
=
Depends
(
get_current_active_user
)
...
@@ -85,14 +85,19 @@ async def get_all_institutions(
...
@@ -85,14 +85,19 @@ async def get_all_institutions(
result
.
append
(
inst_with_images
)
result
.
append
(
inst_with_images
)
logger
.
info
(
f
"用户 {current_user.name}({current_user.role}) 获取到 {len(result)} 个机构"
)
logger
.
info
(
f
"用户 {current_user.name}({current_user.role}) 获取到 {len(result)} 个机构"
)
return
result
return
BaseResponse
(
success
=
True
,
message
=
"获取机构列表成功"
,
data
=
result
)
except
Exception
as
e
:
except
Exception
as
e
:
logger
.
error
(
f
"获取机构列表失败: {e}"
)
logger
.
error
(
f
"获取机构列表失败: {e}"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取机构列表失败"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取机构列表失败"
)
@router.get
(
"/{institution_id}"
,
response_model
=
Institution
Response
,
summary
=
"根据ID获取机构"
)
@router.get
(
"/{institution_id}"
,
response_model
=
Base
Response
,
summary
=
"根据ID获取机构"
)
async
def
get_institution_by_id
(
async
def
get_institution_by_id
(
institution_id
:
str
,
institution_id
:
str
,
db
:
DatabaseManager
=
Depends
(
get_database
),
db
:
DatabaseManager
=
Depends
(
get_database
),
...
@@ -101,12 +106,16 @@ async def get_institution_by_id(
...
@@ -101,12 +106,16 @@ async def get_institution_by_id(
"""根据机构ID获取机构信息"""
"""根据机构ID获取机构信息"""
try
:
try
:
institution
=
await
get_institution_with_images
(
institution_id
,
db
)
institution
=
await
get_institution_with_images
(
institution_id
,
db
)
if
not
institution
:
if
not
institution
:
raise
HTTPException
(
status_code
=
404
,
detail
=
"机构不存在"
)
raise
HTTPException
(
status_code
=
404
,
detail
=
"机构不存在"
)
return
institution
return
BaseResponse
(
success
=
True
,
message
=
"获取机构信息成功"
,
data
=
institution
)
except
HTTPException
:
except
HTTPException
:
raise
raise
except
Exception
as
e
:
except
Exception
as
e
:
...
@@ -114,7 +123,7 @@ async def get_institution_by_id(
...
@@ -114,7 +123,7 @@ async def get_institution_by_id(
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取机构失败"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取机构失败"
)
@router.get
(
"/owner/{owner_id}"
,
response_model
=
List
[
InstitutionResponse
]
,
summary
=
"根据负责人ID获取机构"
)
@router.get
(
"/owner/{owner_id}"
,
response_model
=
BaseResponse
,
summary
=
"根据负责人ID获取机构"
)
async
def
get_institutions_by_owner
(
async
def
get_institutions_by_owner
(
owner_id
:
str
,
owner_id
:
str
,
db
:
DatabaseManager
=
Depends
(
get_database
),
db
:
DatabaseManager
=
Depends
(
get_database
),
...
@@ -125,23 +134,27 @@ async def get_institutions_by_owner(
...
@@ -125,23 +134,27 @@ async def get_institutions_by_owner(
query
=
institutions_table
.
select
()
.
where
(
query
=
institutions_table
.
select
()
.
where
(
institutions_table
.
c
.
owner_id
==
owner_id
institutions_table
.
c
.
owner_id
==
owner_id
)
.
order_by
(
institutions_table
.
c
.
created_at
)
)
.
order_by
(
institutions_table
.
c
.
created_at
)
institutions
=
await
db
.
fetch_all
(
query
)
institutions
=
await
db
.
fetch_all
(
query
)
result
=
[]
result
=
[]
for
institution
in
institutions
:
for
institution
in
institutions
:
inst_with_images
=
await
get_institution_with_images
(
institution
[
"id"
],
db
)
inst_with_images
=
await
get_institution_with_images
(
institution
[
"id"
],
db
)
if
inst_with_images
:
if
inst_with_images
:
result
.
append
(
inst_with_images
)
result
.
append
(
inst_with_images
)
return
result
return
BaseResponse
(
success
=
True
,
message
=
"获取机构列表成功"
,
data
=
result
)
except
Exception
as
e
:
except
Exception
as
e
:
logger
.
error
(
f
"根据负责人获取机构失败: {e}"
)
logger
.
error
(
f
"根据负责人获取机构失败: {e}"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取机构失败"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取机构失败"
)
@router.post
(
""
,
response_model
=
Institution
Response
,
summary
=
"创建机构"
)
@router.post
(
""
,
response_model
=
Base
Response
,
summary
=
"创建机构"
)
async
def
create_institution
(
async
def
create_institution
(
institution_data
:
InstitutionCreate
,
institution_data
:
InstitutionCreate
,
db
:
DatabaseManager
=
Depends
(
get_database
),
db
:
DatabaseManager
=
Depends
(
get_database
),
...
@@ -155,7 +168,7 @@ async def create_institution(
...
@@ -155,7 +168,7 @@ async def create_institution(
)
)
if
existing_inst
:
if
existing_inst
:
raise
HTTPException
(
status_code
=
400
,
detail
=
"机构ID已存在"
)
raise
HTTPException
(
status_code
=
400
,
detail
=
"机构ID已存在"
)
# 检查机构编号是否已存在(如果提供了编号)
# 检查机构编号是否已存在(如果提供了编号)
if
institution_data
.
institution_id
:
if
institution_data
.
institution_id
:
existing_inst_id
=
await
db
.
fetch_one
(
existing_inst_id
=
await
db
.
fetch_one
(
...
@@ -165,7 +178,7 @@ async def create_institution(
...
@@ -165,7 +178,7 @@ async def create_institution(
)
)
if
existing_inst_id
:
if
existing_inst_id
:
raise
HTTPException
(
status_code
=
400
,
detail
=
"机构编号已存在"
)
raise
HTTPException
(
status_code
=
400
,
detail
=
"机构编号已存在"
)
# 插入新机构
# 插入新机构
query
=
institutions_table
.
insert
()
.
values
(
query
=
institutions_table
.
insert
()
.
values
(
id
=
institution_data
.
id
,
id
=
institution_data
.
id
,
...
@@ -173,12 +186,18 @@ async def create_institution(
...
@@ -173,12 +186,18 @@ async def create_institution(
institution_id
=
institution_data
.
institution_id
,
institution_id
=
institution_data
.
institution_id
,
owner_id
=
institution_data
.
owner_id
owner_id
=
institution_data
.
owner_id
)
)
await
db
.
execute
(
query
)
await
db
.
execute
(
query
)
# 返回创建的机构信息
# 获取创建的机构信息
return
await
get_institution_by_id
(
institution_data
.
id
,
db
)
created_institution
=
await
get_institution_with_images
(
institution_data
.
id
,
db
)
return
BaseResponse
(
success
=
True
,
message
=
"创建机构成功"
,
data
=
created_institution
)
except
HTTPException
:
except
HTTPException
:
raise
raise
except
Exception
as
e
:
except
Exception
as
e
:
...
@@ -186,7 +205,7 @@ async def create_institution(
...
@@ -186,7 +205,7 @@ async def create_institution(
raise
HTTPException
(
status_code
=
500
,
detail
=
"创建机构失败"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"创建机构失败"
)
@router.put
(
"/{institution_id}"
,
response_model
=
Institution
Response
,
summary
=
"更新机构"
)
@router.put
(
"/{institution_id}"
,
response_model
=
Base
Response
,
summary
=
"更新机构"
)
async
def
update_institution
(
async
def
update_institution
(
institution_id
:
str
,
institution_id
:
str
,
institution_data
:
InstitutionUpdate
,
institution_data
:
InstitutionUpdate
,
...
@@ -201,7 +220,7 @@ async def update_institution(
...
@@ -201,7 +220,7 @@ async def update_institution(
)
)
if
not
existing_inst
:
if
not
existing_inst
:
raise
HTTPException
(
status_code
=
404
,
detail
=
"机构不存在"
)
raise
HTTPException
(
status_code
=
404
,
detail
=
"机构不存在"
)
# 构建更新数据
# 构建更新数据
update_data
=
{}
update_data
=
{}
if
institution_data
.
name
is
not
None
:
if
institution_data
.
name
is
not
None
:
...
@@ -219,19 +238,25 @@ async def update_institution(
...
@@ -219,19 +238,25 @@ async def update_institution(
update_data
[
"institution_id"
]
=
institution_data
.
institution_id
update_data
[
"institution_id"
]
=
institution_data
.
institution_id
if
institution_data
.
owner_id
is
not
None
:
if
institution_data
.
owner_id
is
not
None
:
update_data
[
"owner_id"
]
=
institution_data
.
owner_id
update_data
[
"owner_id"
]
=
institution_data
.
owner_id
if
not
update_data
:
if
not
update_data
:
raise
HTTPException
(
status_code
=
400
,
detail
=
"没有提供更新数据"
)
raise
HTTPException
(
status_code
=
400
,
detail
=
"没有提供更新数据"
)
# 执行更新
# 执行更新
query
=
institutions_table
.
update
()
.
where
(
query
=
institutions_table
.
update
()
.
where
(
institutions_table
.
c
.
id
==
institution_id
institutions_table
.
c
.
id
==
institution_id
)
.
values
(
**
update_data
)
)
.
values
(
**
update_data
)
await
db
.
execute
(
query
)
await
db
.
execute
(
query
)
# 返回更新后的机构信息
# 获取更新后的机构信息
return
await
get_institution_by_id
(
institution_id
,
db
)
updated_institution
=
await
get_institution_with_images
(
institution_id
,
db
)
return
BaseResponse
(
success
=
True
,
message
=
"更新机构成功"
,
data
=
updated_institution
)
except
HTTPException
:
except
HTTPException
:
raise
raise
except
Exception
as
e
:
except
Exception
as
e
:
...
@@ -359,7 +384,7 @@ async def delete_institution_image(
...
@@ -359,7 +384,7 @@ async def delete_institution_image(
raise
HTTPException
(
status_code
=
500
,
detail
=
"删除图片失败"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"删除图片失败"
)
@router.get
(
"/institution-id/{inst_id}"
,
response_model
=
Institution
Response
,
summary
=
"根据机构编号获取机构"
)
@router.get
(
"/institution-id/{inst_id}"
,
response_model
=
Base
Response
,
summary
=
"根据机构编号获取机构"
)
async
def
get_institution_by_institution_id
(
async
def
get_institution_by_institution_id
(
inst_id
:
str
,
inst_id
:
str
,
db
:
DatabaseManager
=
Depends
(
get_database
),
db
:
DatabaseManager
=
Depends
(
get_database
),
...
@@ -373,7 +398,13 @@ async def get_institution_by_institution_id(
...
@@ -373,7 +398,13 @@ async def get_institution_by_institution_id(
if
not
institution
:
if
not
institution
:
raise
HTTPException
(
status_code
=
404
,
detail
=
"机构不存在"
)
raise
HTTPException
(
status_code
=
404
,
detail
=
"机构不存在"
)
return
await
get_institution_with_images
(
institution
[
"id"
],
db
)
institution_data
=
await
get_institution_with_images
(
institution
[
"id"
],
db
)
return
BaseResponse
(
success
=
True
,
message
=
"获取机构信息成功"
,
data
=
institution_data
)
except
HTTPException
:
except
HTTPException
:
raise
raise
...
...
backend/routers/system_config.py
View file @
db1f4347
...
@@ -14,7 +14,7 @@ from dependencies import get_current_active_user, require_admin
...
@@ -14,7 +14,7 @@ from dependencies import get_current_active_user, require_admin
router
=
APIRouter
()
router
=
APIRouter
()
@router.get
(
""
,
response_model
=
Dict
[
str
,
Any
]
,
summary
=
"获取所有系统配置"
)
@router.get
(
""
,
response_model
=
BaseResponse
,
summary
=
"获取所有系统配置"
)
async
def
get_all_config
(
async
def
get_all_config
(
db
:
DatabaseManager
=
Depends
(
get_database
),
db
:
DatabaseManager
=
Depends
(
get_database
),
current_user
:
UserResponse
=
Depends
(
get_current_active_user
)
current_user
:
UserResponse
=
Depends
(
get_current_active_user
)
...
@@ -23,27 +23,31 @@ async def get_all_config(
...
@@ -23,27 +23,31 @@ async def get_all_config(
try
:
try
:
query
=
system_config_table
.
select
()
query
=
system_config_table
.
select
()
configs
=
await
db
.
fetch_all
(
query
)
configs
=
await
db
.
fetch_all
(
query
)
# 转换为键值对格式,与前端localStorage格式保持一致
# 转换为键值对格式,与前端localStorage格式保持一致
result
=
{}
result
=
{}
for
config
in
configs
:
for
config
in
configs
:
result
[
config
[
"config_key"
]]
=
config
[
"config_value"
]
result
[
config
[
"config_key"
]]
=
config
[
"config_value"
]
return
result
return
BaseResponse
(
success
=
True
,
message
=
"获取系统配置成功"
,
data
=
result
)
except
Exception
as
e
:
except
Exception
as
e
:
logger
.
error
(
f
"获取系统配置失败: {e}"
)
logger
.
error
(
f
"获取系统配置失败: {e}"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取系统配置失败"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取系统配置失败"
)
@router.get
(
"/list"
,
response_model
=
List
[
SystemConfigResponse
]
,
summary
=
"获取系统配置列表"
)
@router.get
(
"/list"
,
response_model
=
BaseResponse
,
summary
=
"获取系统配置列表"
)
async
def
get_config_list
(
db
:
DatabaseManager
=
Depends
(
get_database
)):
async
def
get_config_list
(
db
:
DatabaseManager
=
Depends
(
get_database
)):
"""获取系统配置列表(详细格式)"""
"""获取系统配置列表(详细格式)"""
try
:
try
:
query
=
system_config_table
.
select
()
.
order_by
(
system_config_table
.
c
.
config_key
)
query
=
system_config_table
.
select
()
.
order_by
(
system_config_table
.
c
.
config_key
)
configs
=
await
db
.
fetch_all
(
query
)
configs
=
await
db
.
fetch_all
(
query
)
return
[
config_list
=
[
SystemConfigResponse
(
SystemConfigResponse
(
id
=
config
[
"id"
],
id
=
config
[
"id"
],
config_key
=
config
[
"config_key"
],
config_key
=
config
[
"config_key"
],
...
@@ -54,24 +58,34 @@ async def get_config_list(db: DatabaseManager = Depends(get_database)):
...
@@ -54,24 +58,34 @@ async def get_config_list(db: DatabaseManager = Depends(get_database)):
)
)
for
config
in
configs
for
config
in
configs
]
]
return
BaseResponse
(
success
=
True
,
message
=
"获取系统配置列表成功"
,
data
=
config_list
)
except
Exception
as
e
:
except
Exception
as
e
:
logger
.
error
(
f
"获取系统配置列表失败: {e}"
)
logger
.
error
(
f
"获取系统配置列表失败: {e}"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取系统配置列表失败"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取系统配置列表失败"
)
@router.get
(
"/{config_key}"
,
response_model
=
Any
,
summary
=
"获取指定配置项"
)
@router.get
(
"/{config_key}"
,
response_model
=
BaseResponse
,
summary
=
"获取指定配置项"
)
async
def
get_config_by_key
(
config_key
:
str
,
db
:
DatabaseManager
=
Depends
(
get_database
)):
async
def
get_config_by_key
(
config_key
:
str
,
db
:
DatabaseManager
=
Depends
(
get_database
)):
"""根据配置键名获取配置值"""
"""根据配置键名获取配置值"""
try
:
try
:
query
=
system_config_table
.
select
()
.
where
(
system_config_table
.
c
.
config_key
==
config_key
)
query
=
system_config_table
.
select
()
.
where
(
system_config_table
.
c
.
config_key
==
config_key
)
config
=
await
db
.
fetch_one
(
query
)
config
=
await
db
.
fetch_one
(
query
)
if
not
config
:
if
not
config
:
raise
HTTPException
(
status_code
=
404
,
detail
=
"配置项不存在"
)
raise
HTTPException
(
status_code
=
404
,
detail
=
"配置项不存在"
)
return
config
[
"config_value"
]
return
BaseResponse
(
success
=
True
,
message
=
"获取配置项成功"
,
data
=
config
[
"config_value"
]
)
except
HTTPException
:
except
HTTPException
:
raise
raise
except
Exception
as
e
:
except
Exception
as
e
:
...
...
backend/routers/users.py
View file @
db1f4347
...
@@ -22,7 +22,7 @@ from config import settings
...
@@ -22,7 +22,7 @@ from config import settings
router
=
APIRouter
()
router
=
APIRouter
()
@router.get
(
""
,
response_model
=
List
[
UserResponse
]
,
summary
=
"获取所有用户"
)
@router.get
(
""
,
response_model
=
BaseResponse
,
summary
=
"获取所有用户"
)
async
def
get_all_users
(
async
def
get_all_users
(
db
:
DatabaseManager
=
Depends
(
get_database
),
db
:
DatabaseManager
=
Depends
(
get_database
),
current_user
:
UserResponse
=
Depends
(
require_admin
)
current_user
:
UserResponse
=
Depends
(
require_admin
)
...
@@ -31,8 +31,8 @@ async def get_all_users(
...
@@ -31,8 +31,8 @@ async def get_all_users(
try
:
try
:
query
=
users_table
.
select
()
query
=
users_table
.
select
()
users
=
await
db
.
fetch_all
(
query
)
users
=
await
db
.
fetch_all
(
query
)
return
[
user_list
=
[
UserResponse
(
UserResponse
(
id
=
user
[
"id"
],
id
=
user
[
"id"
],
phone
=
user
[
"phone"
],
phone
=
user
[
"phone"
],
...
@@ -44,6 +44,12 @@ async def get_all_users(
...
@@ -44,6 +44,12 @@ async def get_all_users(
)
)
for
user
in
users
for
user
in
users
]
]
return
BaseResponse
(
success
=
True
,
message
=
"获取用户列表成功"
,
data
=
user_list
)
except
Exception
as
e
:
except
Exception
as
e
:
logger
.
error
(
f
"获取用户列表失败: {e}"
)
logger
.
error
(
f
"获取用户列表失败: {e}"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取用户列表失败"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取用户列表失败"
)
...
@@ -55,7 +61,7 @@ async def get_current_user_info(current_user: UserResponse = Depends(get_current
...
@@ -55,7 +61,7 @@ async def get_current_user_info(current_user: UserResponse = Depends(get_current
return
current_user
return
current_user
@router.get
(
"/{user_id}"
,
response_model
=
User
Response
,
summary
=
"根据ID获取用户"
)
@router.get
(
"/{user_id}"
,
response_model
=
Base
Response
,
summary
=
"根据ID获取用户"
)
async
def
get_user_by_id
(
async
def
get_user_by_id
(
user_id
:
str
,
user_id
:
str
,
db
:
DatabaseManager
=
Depends
(
get_database
),
db
:
DatabaseManager
=
Depends
(
get_database
),
...
@@ -69,7 +75,7 @@ async def get_user_by_id(
...
@@ -69,7 +75,7 @@ async def get_user_by_id(
if
not
user
:
if
not
user
:
raise
HTTPException
(
status_code
=
404
,
detail
=
"用户不存在"
)
raise
HTTPException
(
status_code
=
404
,
detail
=
"用户不存在"
)
return
UserResponse
(
user_data
=
UserResponse
(
id
=
user
[
"id"
],
id
=
user
[
"id"
],
phone
=
user
[
"phone"
],
phone
=
user
[
"phone"
],
name
=
user
[
"name"
],
name
=
user
[
"name"
],
...
@@ -78,6 +84,12 @@ async def get_user_by_id(
...
@@ -78,6 +84,12 @@ async def get_user_by_id(
created_at
=
user
[
"created_at"
],
created_at
=
user
[
"created_at"
],
updated_at
=
user
[
"updated_at"
]
updated_at
=
user
[
"updated_at"
]
)
)
return
BaseResponse
(
success
=
True
,
message
=
"获取用户信息成功"
,
data
=
user_data
)
except
HTTPException
:
except
HTTPException
:
raise
raise
except
Exception
as
e
:
except
Exception
as
e
:
...
@@ -85,7 +97,7 @@ async def get_user_by_id(
...
@@ -85,7 +97,7 @@ async def get_user_by_id(
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取用户失败"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"获取用户失败"
)
@router.post
(
""
,
response_model
=
User
Response
,
summary
=
"创建用户"
)
@router.post
(
""
,
response_model
=
Base
Response
,
summary
=
"创建用户"
)
async
def
create_user
(
async
def
create_user
(
user_data
:
UserCreate
,
user_data
:
UserCreate
,
db
:
DatabaseManager
=
Depends
(
get_database
),
db
:
DatabaseManager
=
Depends
(
get_database
),
...
@@ -99,7 +111,7 @@ async def create_user(
...
@@ -99,7 +111,7 @@ async def create_user(
)
)
if
existing_user
:
if
existing_user
:
raise
HTTPException
(
status_code
=
400
,
detail
=
"用户ID已存在"
)
raise
HTTPException
(
status_code
=
400
,
detail
=
"用户ID已存在"
)
# 检查手机号是否已存在
# 检查手机号是否已存在
existing_phone
=
await
db
.
fetch_one
(
existing_phone
=
await
db
.
fetch_one
(
users_table
.
select
()
.
where
(
users_table
.
c
.
phone
==
user_data
.
phone
)
users_table
.
select
()
.
where
(
users_table
.
c
.
phone
==
user_data
.
phone
)
...
@@ -121,10 +133,16 @@ async def create_user(
...
@@ -121,10 +133,16 @@ async def create_user(
)
)
await
db
.
execute
(
query
)
await
db
.
execute
(
query
)
# 返回创建的用户信息
# 获取创建的用户信息
return
await
get_user_by_id
(
user_data
.
id
,
db
)
created_user_response
=
await
get_user_by_id
(
user_data
.
id
,
db
,
current_user
)
return
BaseResponse
(
success
=
True
,
message
=
"创建用户成功"
,
data
=
created_user_response
.
data
)
except
HTTPException
:
except
HTTPException
:
raise
raise
except
Exception
as
e
:
except
Exception
as
e
:
...
@@ -132,7 +150,7 @@ async def create_user(
...
@@ -132,7 +150,7 @@ async def create_user(
raise
HTTPException
(
status_code
=
500
,
detail
=
"创建用户失败"
)
raise
HTTPException
(
status_code
=
500
,
detail
=
"创建用户失败"
)
@router.put
(
"/{user_id}"
,
response_model
=
User
Response
,
summary
=
"更新用户"
)
@router.put
(
"/{user_id}"
,
response_model
=
Base
Response
,
summary
=
"更新用户"
)
async
def
update_user
(
async
def
update_user
(
user_id
:
str
,
user_id
:
str
,
user_data
:
UserUpdate
,
user_data
:
UserUpdate
,
...
@@ -147,21 +165,21 @@ async def update_user(
...
@@ -147,21 +165,21 @@ async def update_user(
)
)
if
not
existing_user
:
if
not
existing_user
:
raise
HTTPException
(
status_code
=
404
,
detail
=
"用户不存在"
)
raise
HTTPException
(
status_code
=
404
,
detail
=
"用户不存在"
)
# 构建更新数据
# 构建更新数据
update_data
=
{}
update_data
=
{}
if
user_data
.
phone
is
not
None
:
if
user_data
.
phone
is
not
None
:
# 检查手机号是否被其他用户使用
# 检查手机号是否被其他用户使用
phone_check
=
await
db
.
fetch_one
(
phone_check
=
await
db
.
fetch_one
(
users_table
.
select
()
.
where
(
users_table
.
select
()
.
where
(
(
users_table
.
c
.
phone
==
user_data
.
phone
)
&
(
users_table
.
c
.
phone
==
user_data
.
phone
)
&
(
users_table
.
c
.
id
!=
user_id
)
(
users_table
.
c
.
id
!=
user_id
)
)
)
)
)
if
phone_check
:
if
phone_check
:
raise
HTTPException
(
status_code
=
400
,
detail
=
"手机号已被其他用户使用"
)
raise
HTTPException
(
status_code
=
400
,
detail
=
"手机号已被其他用户使用"
)
update_data
[
"phone"
]
=
user_data
.
phone
update_data
[
"phone"
]
=
user_data
.
phone
if
user_data
.
name
is
not
None
:
if
user_data
.
name
is
not
None
:
update_data
[
"name"
]
=
user_data
.
name
update_data
[
"name"
]
=
user_data
.
name
if
user_data
.
password
is
not
None
:
if
user_data
.
password
is
not
None
:
...
@@ -171,17 +189,23 @@ async def update_user(
...
@@ -171,17 +189,23 @@ async def update_user(
update_data
[
"role"
]
=
user_data
.
role
update_data
[
"role"
]
=
user_data
.
role
if
user_data
.
institutions
is
not
None
:
if
user_data
.
institutions
is
not
None
:
update_data
[
"institutions"
]
=
user_data
.
institutions
update_data
[
"institutions"
]
=
user_data
.
institutions
if
not
update_data
:
if
not
update_data
:
raise
HTTPException
(
status_code
=
400
,
detail
=
"没有提供更新数据"
)
raise
HTTPException
(
status_code
=
400
,
detail
=
"没有提供更新数据"
)
# 执行更新
# 执行更新
query
=
users_table
.
update
()
.
where
(
users_table
.
c
.
id
==
user_id
)
.
values
(
**
update_data
)
query
=
users_table
.
update
()
.
where
(
users_table
.
c
.
id
==
user_id
)
.
values
(
**
update_data
)
await
db
.
execute
(
query
)
await
db
.
execute
(
query
)
# 返回更新后的用户信息
# 获取更新后的用户信息
return
await
get_user_by_id
(
user_id
,
db
)
updated_user_response
=
await
get_user_by_id
(
user_id
,
db
,
current_user
)
return
BaseResponse
(
success
=
True
,
message
=
"更新用户成功"
,
data
=
updated_user_response
.
data
)
except
HTTPException
:
except
HTTPException
:
raise
raise
except
Exception
as
e
:
except
Exception
as
e
:
...
@@ -344,7 +368,7 @@ async def logout(
...
@@ -344,7 +368,7 @@ async def logout(
@router.get
(
"/phone/{phone}"
,
response_model
=
User
Response
,
summary
=
"根据手机号获取用户"
)
@router.get
(
"/phone/{phone}"
,
response_model
=
Base
Response
,
summary
=
"根据手机号获取用户"
)
async
def
get_user_by_phone
(
async
def
get_user_by_phone
(
phone
:
str
,
phone
:
str
,
db
:
DatabaseManager
=
Depends
(
get_database
),
db
:
DatabaseManager
=
Depends
(
get_database
),
...
@@ -354,11 +378,11 @@ async def get_user_by_phone(
...
@@ -354,11 +378,11 @@ async def get_user_by_phone(
try
:
try
:
query
=
users_table
.
select
()
.
where
(
users_table
.
c
.
phone
==
phone
)
query
=
users_table
.
select
()
.
where
(
users_table
.
c
.
phone
==
phone
)
user
=
await
db
.
fetch_one
(
query
)
user
=
await
db
.
fetch_one
(
query
)
if
not
user
:
if
not
user
:
raise
HTTPException
(
status_code
=
404
,
detail
=
"用户不存在"
)
raise
HTTPException
(
status_code
=
404
,
detail
=
"用户不存在"
)
return
UserResponse
(
user_data
=
UserResponse
(
id
=
user
[
"id"
],
id
=
user
[
"id"
],
phone
=
user
[
"phone"
],
phone
=
user
[
"phone"
],
name
=
user
[
"name"
],
name
=
user
[
"name"
],
...
@@ -367,6 +391,12 @@ async def get_user_by_phone(
...
@@ -367,6 +391,12 @@ async def get_user_by_phone(
created_at
=
user
[
"created_at"
],
created_at
=
user
[
"created_at"
],
updated_at
=
user
[
"updated_at"
]
updated_at
=
user
[
"updated_at"
]
)
)
return
BaseResponse
(
success
=
True
,
message
=
"获取用户信息成功"
,
data
=
user_data
)
except
HTTPException
:
except
HTTPException
:
raise
raise
except
Exception
as
e
:
except
Exception
as
e
:
...
...
src/services/api.js
View file @
db1f4347
...
@@ -131,7 +131,8 @@ class ApiClient {
...
@@ -131,7 +131,8 @@ class ApiClient {
})
})
if
(
retryResponse
.
ok
)
{
if
(
retryResponse
.
ok
)
{
return
await
retryResponse
.
json
()
const
retryData
=
await
retryResponse
.
json
()
return
this
.
unwrapResponse
(
retryData
)
}
}
}
}
...
@@ -146,7 +147,9 @@ class ApiClient {
...
@@ -146,7 +147,9 @@ class ApiClient {
throw
new
Error
(
errorData
.
detail
||
`HTTP
${
response
.
status
}
:
${
response
.
statusText
}
`
)
throw
new
Error
(
errorData
.
detail
||
`HTTP
${
response
.
status
}
:
${
response
.
statusText
}
`
)
}
}
return
await
response
.
json
()
const
responseData
=
await
response
.
json
()
// 自动解包BaseResponse格式的响应
return
this
.
unwrapResponse
(
responseData
)
}
catch
(
error
)
{
}
catch
(
error
)
{
if
(
error
.
name
===
'AbortError'
)
{
if
(
error
.
name
===
'AbortError'
)
{
throw
new
Error
(
'请求超时,请检查网络连接'
)
throw
new
Error
(
'请求超时,请检查网络连接'
)
...
@@ -157,6 +160,23 @@ class ApiClient {
...
@@ -157,6 +160,23 @@ class ApiClient {
}
}
/**
/**
* 自动解包BaseResponse格式的响应
*/
unwrapResponse
(
responseData
)
{
// 如果响应包含success字段,说明是BaseResponse格式
if
(
responseData
&&
typeof
responseData
===
'object'
&&
'success'
in
responseData
)
{
// 检查请求是否成功
if
(
!
responseData
.
success
)
{
throw
new
Error
(
responseData
.
message
||
'请求失败'
)
}
// 返回data字段的内容,如果没有data字段则返回整个响应
return
responseData
.
data
!==
undefined
?
responseData
.
data
:
responseData
}
// 如果不是BaseResponse格式,直接返回原始数据(如login/logout等特殊接口)
return
responseData
}
/**
* 刷新访问token
* 刷新访问token
*/
*/
async
refreshAccessToken
()
{
async
refreshAccessToken
()
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment