面向中国药科大学学生的校园服务聚合站点,由在校学生自主研发。
翻訳待ち
Loading the full README.
Read the full README ↗药大拾间是一个面向中国药科大学学生的校园信息聚合站点。当前仓库已经不是单纯的 Web MVP,而是一个完整的多端项目,包含:
web/:Vue 3 前端站点与 /schedule PWA 课表页server/:Express + Prisma + PostgreSQL 后端voicehub/:药苑之声 Nuxt 全栈子应用(完整保留 VoiceHub 点歌系统)android/:Android WebView 壳与桌面课表小组件harmony/:HarmonyOS WebView 壳与 JS Bridgedesktop/:Windows / Apple Silicon macOS 桌面端(Electron 单窗口标签页,OAuth2 登录 + 校园网自动连接 + 学习通标签页)仓库地址:https://github.com/sx120609/CPU-web
想先用不那么专业的方式了解整个项目,可以阅读: 《药大拾间完整技术路线》,也可以直接下载排版好的 PDF 版本。
说明
- 本项目为学生自发聚合站,非中国药科大学官方平台。
- 学校统一认证只用于用户授权后的教务数据获取;项目不保存学校密码和验证码。
- 二手功能是论坛信息交流板块;本站不提供站内下单、支付、担保、退款或结算。
| 模块 | 典型路径 | 访问要求 | 说明 |
|---|---|---|---|
| 首页 / 搜索 / 公告 | /home /search /announcements | 公开 | 展示站内聚合内容与公告源 |
| 论坛入口 / 板块 / 帖子 | /forum /forum/b/:slug /forum/topic/:id | 公开或受社区权限控制 | 公开入口可访问,具体社区内容仍会受服务端权限与功能开关拦截 |
| 热榜 / 最新 / 二手交流 / 课程点评 | /forum/hot /forum/latest /market /coursereview | 浏览按社区权限控制,发布需站内登录 | 受 forum / market / coursereview 功能开关与社区权限控制 |
| 发帖 / 编辑 / 回复 / 点赞 / 消息 | /post /post/:id/edit /messages | 站内登录 | 帖子正文支持 Markdown、匿名、图片上传与审核 |
| 教务页壳 | /jwxt /schedule | 页面可公开访问 | 真正拉取课表、成绩、考试等数据时需要学校 SSO 授权得到 jwxtToken |
| 校园服务导航 | /services | 公开 | 聚合校内外常用入口与说明 |
| 校园小工具入口 | /services/tools /services/tools/:slug | 公开 | 具体工具是否要求登录由工具配置决定 |
| 三维校园 | /services/tools/yaoda-can-fly/campus-3d | 公开 | 联机时游客显示随机名,登录后显示站内昵称 |
| 药苑之声 | /voicehub/ | 排期与歌曲公开,投稿/投票/后台需登录 | 复用本站会话,无需在 VoiceHub 二次注册或登录 |
| 问卷填写 / 文件提交 | /services/tools/questionnaires/:slug /services/tools/filestore/submit/:slug | 通常公开 | 支持按工具设置切换是否要求登录 |
| 成绩核对查询 | /services/tools/grade-checks/:slug | 默认需登录 | 登录后只看自己的学号记录 |
| 个人中心 / 赞助 / QQBot 绑定 | /profile /u/:id /sponsor-wall | 部分公开、部分登录 | 鸣谢墙公开;个人资料、赞助订单、QQBot 绑定需登录 |
| 管理后台 | /admin | mod / admin | 含用户、板块、站务、AI 审核、支付、QQBot、数据库等后台 |
| 层级 | 技术 |
|---|---|
| 前端 | Vue 3、Vite、TypeScript、Vue Router、Pinia、Element Plus、Axios、ECharts |
| 后端 | Node.js、Express、TypeScript、Prisma 5、PostgreSQL |
| 内容处理 | marked、DOMPurify、Cheerio、Turndown、iconv-lite、@resvg/resvg-js |
| 文件与表格 | multer、xlsx、viewerjs、html-to-image |
| 鉴权与安全 | JWT、bcryptjs、学校统一认证会话、Zod |
| 辅助子系统 | Filestore 文件收集、Android WebView、HarmonyOS ArkUI Web 容器 |
| 药苑之声 | Nuxt 4、Nitro、Drizzle ORM、独立 PostgreSQL、WebSocket 音乐状态同步 |
| 三维校园 | three.js 0.160(WebGL2、EffectComposer 后处理)、Shadow DOM 隔离 |
CPU-web/
├── android/ # Android WebView 壳 + 课表桌面小组件
├── harmony/ # HarmonyOS Stage 工程 + JS Bridge
├── ios/ # 旧版 iOS WebView 客户端(独立保留)
├── ios_next/ # 当前 SwiftUI iOS 客户端 + Apple Watch + WidgetKit
├── desktop/ # Electron 桌面端(不参与主站部署链路,单独构建)
├── server/
│ ├── prisma/ # Prisma schema、迁移、种子数据
│ ├── scripts/ # 调试脚本与数据修复脚本
│ └── src/
│ ├── routes/ # auth / forum / jwxt / payments / tools / admin 等接口
│ ├── services/ # 公告抓取、教务、QQBot、赞助、AI 审核、Filestore 等服务
│ ├── middleware/ # 鉴权、参数校验、错误处理
│ └── utils/ # JWT、密码、响应格式、客户端识别等工具
├── voicehub/ # 药苑之声:原 VoiceHub 全量源码 + CPU-web 用户桥接
├── web/
│ ├── public/ # PWA manifest、图标、离线缓存脚本、静态资源
│ └── src/
│ ├── api/ # 前端 API 封装
│ ├── components/ # 通用组件、论坛组件、教务组件等
│ ├── data/ # 服务工具元数据
│ ├── layouts/ # 主布局
│ ├── router/ # 路由与守卫
│ ├── stores/ # Pinia 状态
│ ├── styles/ # 全局样式
│ ├── utils/ # 客户端桥接、Markdown、缓存与格式化工具
│ └── views/ # 页面视图
├── deploy.sh # Debian / Ubuntu 一键部署脚本(主站 + 教务代理)
├── deploy-agent.ps1 # Windows 出站教务 Agent 部署脚本
├── deploy-agent.cmd # Windows 命令行入口(自动绕过脚本执行策略)
├── package.json # 根目录脚本入口
└── README.md
>= 22>= 9>= 14npm run install:all
该命令按各目录已提交的 lockfile 依次对根目录、server/、web/ 和 voicehub/ 执行 npm ci,不会改写 lockfile。根目录的 npm install 只安装根目录工具,不再自动安装子项目。
复制示例配置并按部署环境修改:
cp server/.env.example server/.env
核心配置示例:
PORT=3000
NODE_ENV=development
DATABASE_URL="postgresql://user:[email protected]:5432/cpu_web?schema=public"
VOICEHUB_DATABASE_URL="postgresql://user:[email protected]:5432/cpu_web_voicehub"
VOICEHUB_ORIGIN="http://127.0.0.1:3001"
VOICEHUB_PORT=3001
JWT_SECRET="please-change-this-in-production"
JWT_EXPIRES_IN="7d"
JWXT_PROXY_URL=""
JWXT_PROXY_AUTH=""
# 首次保存“管理后台 -> 教务节点”后,节点配置改由数据库接管
# SSO_LOGIN_LOCAL_ENABLED=false
SSO_LOGIN_LOCAL_WEIGHT=1
SSO_LOGIN_TIMEOUT_MS=15000
PROXY_AUTH=""
PROXY_PORT=23334
MEDIA_STORAGE_PROVIDER="local"
MEDIA_STORAGE_IMAGE_PROVIDER="local"
MEDIA_STORAGE_VIDEO_PROVIDER="local"
MEDIA_STORAGE_REMOTE_PREFIXES="forum"
ONEDRIVE_CN_TENANT_ID=""
ONEDRIVE_CN_CLIENT_ID=""
ONEDRIVE_CN_CLIENT_SECRET=""
ONEDRIVE_CN_DRIVE_ID=""
ONEDRIVE_CN_ROOT_PATH="cpu-web-media"
This is the beginning of the README. Read the rest at the original. Read the full README ↗