Compare commits

...

3 Commits

Author SHA1 Message Date
MangoFanFanw 123cbf1dbb WebUI 更新至 1.1.0 版本
1. 移除重启和关闭 Suan API 的按钮,因为按照目前的设计,这在技术上难以实现。
2. 增加 FastAPI docs 的配置选项。
2026-04-28 20:03:22 +08:00
MangoFanFanw 3a38dcab00 增加 FastAPI docs 功能开关和 docs 页面描述
1. 为 FastAPI 的文档功能增加显示开关,允许从 WebUI 修改;
2. 在 docs 页面增加了项目的简要描述和引导。
2026-04-28 20:02:05 +08:00
MangoFanFanw 39158880ba 补全 webui_router 缺少的 tag 2026-04-28 18:10:20 +08:00
11 changed files with 125 additions and 28 deletions
+10 -2
View File
@@ -7,9 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6 种更新类别:Added、Changed、Deprecated、Removed、Fixed、Security。 6 种更新类别:Added、Changed、Deprecated、Removed、Fixed、Security。
## [Unreleased] ## [0.1.5] - 2026-04-28
等待中... ### Added
- 增加开关 FastAPI 内置文档功能的选项。在此前,文档功能一直默认开启。
### Changed
- WebUI 版本升级至 1.1.0
- 增加开关 FastAPI `/docs` 文档端点的设置项。
- 删除「重启」和「关闭」Suan API 的预留按钮,因为技术上这难以实现。
## [0.1.4] - 2026-04-26 ## [0.1.4] - 2026-04-26
+12 -6
View File
@@ -12,12 +12,18 @@ NJUPT Suan API 是一个 FastAPI 项目,目标在于实现对 NJUPT(南京
## 功能 ## 功能
| 计划功能(芒果画饼中) | 支持进度 | | 计划功能(芒果画饼中) | 支持进度 |
|---------------|------------------| |-------------------|------|
| 教务系统 - 课程表获取 | ✅ | | 教务系统 - 课程表获取 | ✅ |
| 教务系统 - 课程获取 | ⌛️ | | 教务系统 - 课程获取 | ⌛️ |
| 教务系统 - 成绩获取 | ⌛️ | | 教务系统 - 成绩获取 | ⌛️ |
| 体育部系统 - 早锻炼获取 | ❌(无从破解微信小程序 QAQ) | | 教务系统 - 课程表 - 日历订阅 | ⌛️ |
| 体育部系统 - 早锻炼获取 | ❌ |
| 优化待办 | 支持进度 |
|---------------|------|
| 自定义课程表 CSS 样式 | ⌛️ |
| 生成的静态资源有效期管理 | ⌛️ |
## 运行 ## 运行
+1
View File
@@ -61,6 +61,7 @@ class Config:
doc_system["port"] = 8000 doc_system["port"] = 8000
doc_system["reload"] = False doc_system["reload"] = False
doc_system["public_host"] = "http://127.0.0.1:8000" doc_system["public_host"] = "http://127.0.0.1:8000"
doc_system["docs"] = True
doc_schedule["playwright_headless"] = True doc_schedule["playwright_headless"] = True
doc_schedule["jwxt_login_method"] = "sso" doc_schedule["jwxt_login_method"] = "sso"
+1 -1
View File
@@ -9,7 +9,7 @@ WEBUI_INDEX = STATIC_DIR / "index.html"
SCHEDULE_INDEX = STATIC_DIR / "index-schedule.html" SCHEDULE_INDEX = STATIC_DIR / "index-schedule.html"
ASSETS_DIR = STATIC_DIR / "assets" ASSETS_DIR = STATIC_DIR / "assets"
webui_router = APIRouter(prefix="/webui") webui_router = APIRouter(prefix="/webui", tags=["webui"])
@webui_router.get("/", response_class=HTMLResponse) @webui_router.get("/", response_class=HTMLResponse)
+41 -2
View File
@@ -24,10 +24,36 @@ from njupt_suan_api.router.enhance import ReturnDto, create_db_and_tables
DATA_DIR = Path.cwd() / "data" DATA_DIR = Path.cwd() / "data"
description = """
🚀 NJUPT Suan API 的 API 文档在此。你也可以直接在此处测试 API。
**NJUPT Suan API** 是一个为南京邮电大学(NJUPT)开发的项目。
**项目** -
[GitHub](https://github.com/mangofanfan/njupt-suan-api) |
[Mango Gitea](https://gitea.mangofanfan.cn/SuanDev/njupt-suan-api) |
[文档](https://suan.mangofanfan.cn)
**文档** - [SwaggerUI](/docs) | [Redoc](/redoc) | [openapi.json](/openapi.json)
### 如果您是访客
部分 **admin** 分组的端点需要身份验证才能调用,它们一般会被标记。
你可以在这里查看所有端点的详细信息,如果你需要进行针对 Suan API 的开发的话,这一定会对你有所帮助。
### 如果您是管理员
文档功能作为 FastAPI 的特色功能默认开启。
如果你需要,在 Suan API 的设置中可以选择关闭文档功能。
"""
config.sync_load_json()
async def toml_watcher() -> None: async def toml_watcher() -> None:
"""配置文件监听器""" """配置文件监听器"""
await config.load_json()
async for change in awatch(DATA_DIR / "config.json"): async for change in awatch(DATA_DIR / "config.json"):
logger.info(f"配置文件更新,重新加载 | {change=}") logger.info(f"配置文件更新,重新加载 | {change=}")
await config.load_json() await config.load_json()
@@ -48,7 +74,20 @@ async def life_span(_: FastAPI) -> AsyncGenerator[None, None]:
logger.info("配置文件监听任务已结束。") logger.info("配置文件监听任务已结束。")
app = FastAPI(lifespan=combine_lifespans(life_span, mcp_app.lifespan)) # 文档功能是对 FastAPI app 实例进行配置的
enable_docs = config.get("system", "docs", True)
logger.debug(f"FastAPI 文档功能状态 - {enable_docs=}")
app = FastAPI(
title="njupt-suan-api",
lifespan=combine_lifespans(life_span, mcp_app.lifespan),
description=description,
docs_url="/docs" if enable_docs else None,
redoc_url="/redoc" if enable_docs else None,
openapi_url="/openapi.json" if enable_docs else None,
version=__version__,
license_info={"name": "MIT", "identifier": "MIT"},
)
@app.middleware("http") @app.middleware("http")
Generated
+1 -1
View File
@@ -701,7 +701,7 @@ wheels = [
[[package]] [[package]]
name = "njupt-suan-api" name = "njupt-suan-api"
version = "0.1.3" version = "0.1.5"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "aiofiles" }, { name = "aiofiles" },
+2
View File
@@ -38,6 +38,7 @@ declare module 'vue' {
NSwitch: typeof import('naive-ui')['NSwitch'] NSwitch: typeof import('naive-ui')['NSwitch']
NTag: typeof import('naive-ui')['NTag'] NTag: typeof import('naive-ui')['NTag']
NText: typeof import('naive-ui')['NText'] NText: typeof import('naive-ui')['NText']
NTooltip: typeof import('naive-ui')['NTooltip']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
} }
@@ -71,6 +72,7 @@ declare global {
const NSwitch: typeof import('naive-ui')['NSwitch'] const NSwitch: typeof import('naive-ui')['NSwitch']
const NTag: typeof import('naive-ui')['NTag'] const NTag: typeof import('naive-ui')['NTag']
const NText: typeof import('naive-ui')['NText'] const NText: typeof import('naive-ui')['NText']
const NTooltip: typeof import('naive-ui')['NTooltip']
const RouterLink: typeof import('vue-router')['RouterLink'] const RouterLink: typeof import('vue-router')['RouterLink']
const RouterView: typeof import('vue-router')['RouterView'] const RouterView: typeof import('vue-router')['RouterView']
} }
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "webui", "name": "webui",
"version": "1.0.0", "version": "1.1.0",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
+9 -1
View File
@@ -54,6 +54,7 @@ onMounted(async () => {
<sidebar-nav /> <sidebar-nav />
</div> </div>
<div id="center-content"> <div id="center-content">
<div id="extra-control" />
<div id="content-container"> <div id="content-container">
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">
<keep-alive> <keep-alive>
@@ -107,13 +108,20 @@ onMounted(async () => {
#center-content { #center-content {
flex: 1; flex: 1;
min-height: 0; min-height: 0;
display: flex;
flex-direction: column;
#extra-control {
flex: 0;
}
#content-container { #content-container {
border: 1px solid #519f72; border: 1px solid #519f72;
border-radius: 10px; border-radius: 10px;
padding: 10px; padding: 10px;
height: 100%;
overflow: auto; overflow: auto;
height: 100%;
flex: 1;
} }
} }
} }
+46 -14
View File
@@ -38,13 +38,6 @@ function varTag(code: string, description: string) {
<template> <template>
<div id="config-container"> <div id="config-container">
<n-h2 prefix="bar">酸酸设置</n-h2> <n-h2 prefix="bar">酸酸设置</n-h2>
<n-alert title="设置注意" type="info">
<n-p class="no-margin">
<n-text strong type="warning">系统设置</n-text>
- 需要完全重新启动 Suan API 才能应用
</n-p>
<n-p class="no-margin">其他的设置可以即时生效</n-p>
</n-alert>
<n-collapse v-if="CONFIG.dataStatus" style="margin-top: 1rem"> <n-collapse v-if="CONFIG.dataStatus" style="margin-top: 1rem">
<n-collapse-item name="system" title="系统设置"> <n-collapse-item name="system" title="系统设置">
@@ -73,6 +66,25 @@ function varTag(code: string, description: string) {
show-input show-input
title="外部域名 / 主机名" title="外部域名 / 主机名"
/> />
<setting-card
v-model:boolean-value="CONFIG.data.system.docs"
show-switch
title="Fast API 文档功能"
>
<n-p>
FastAPI 提供
<n-code inline>/docs</n-code>
<n-code inline>/redoc</n-code>
两个文档端口以及一个
<n-code inline>/openapi.json</n-code>
结构化 API 数据文件
</n-p>
<n-p
>如果你需要深入研究 Suan API这是来自 FastAPI
的赠礼如有安全方面顾虑也可以关闭</n-p
>
</setting-card>
</n-flex> </n-flex>
</n-collapse-item> </n-collapse-item>
<n-collapse-item name="schedule" title="课表设置"> <n-collapse-item name="schedule" title="课表设置">
@@ -146,12 +158,20 @@ function varTag(code: string, description: string) {
</n-collapse-item> </n-collapse-item>
</n-collapse> </n-collapse>
<teleport v-if="extraVisible" defer to="#center-container"> <teleport v-if="extraVisible" defer to="#extra-control">
<div class="header-card"> <div class="header-card">
<n-flex vertical> <n-flex align="center">
<n-alert type="info">
<n-p class="no-margin">
<n-text strong type="warning">系统设置</n-text>
需要完全重新启动 Suan API 才能应用其他的设置可以即时生效
</n-p>
</n-alert>
<n-button <n-button
circle round
size="large" size="large"
style="margin-left: auto"
type="success" type="success"
@click=" @click="
() => { () => {
@@ -159,14 +179,26 @@ function varTag(code: string, description: string) {
MESSAGE.success('保存设置成功,后端会自动应用新的设置 ~') MESSAGE.success('保存设置成功,后端会自动应用新的设置 ~')
} }
" "
>保存</n-button >保存设置</n-button
> >
<n-button circle size="large" type="warning">重启</n-button>
<n-button circle size="large" type="error">关闭</n-button> <n-popover placement="bottom" trigger="hover">
<template #trigger>
<n-button round size="large" type="tertiary">重启 Suan API</n-button>
</template>
<n-p>由于技术限制无法从 WebUI 重启 Suan API 应用</n-p>
</n-popover>
</n-flex> </n-flex>
</div> </div>
</teleport> </teleport>
</div> </div>
</template> </template>
<style scoped></style> <style scoped>
div.header-card {
border: 1px solid #519f72;
border-radius: 10px;
padding: 10px;
margin-bottom: 10px;
}
</style>
+1
View File
@@ -3,6 +3,7 @@ export interface ConfigSystemDto {
port?: number port?: number
reload?: boolean reload?: boolean
public_host?: string public_host?: string
docs?: boolean
} }
export interface ConfigScheduleDto { export interface ConfigScheduleDto {