Переглянути джерело

feat:更新readme文件和其他相关的文件

yangyi 1 місяць тому
батько
коміт
ea282cae7e
6 змінених файлів з 2331 додано та 0 видалено
  1. 137 0
      AGENTS.md
  2. 301 0
      README.md
  3. 385 0
      doc/UIDesign.md
  4. 37 0
      doc/demand.md
  5. 903 0
      doc/design.md
  6. 568 0
      doc/serverDesign.md

+ 137 - 0
AGENTS.md

@@ -0,0 +1,137 @@
+# Campus Used Book Trading System
+
+C/S architecture: JavaFX client → RESTful API → Spring Boot server → MySQL.
+
+## Tech stack
+
+| Layer | Technology | Version |
+|-------|-----------|---------|
+| Client | JavaFX + FXML + Scene Builder | 23.0.2 |
+| Client HTTP | JDK `java.net.http.HttpClient` | built-in |
+| JSON | Jackson (`jackson-databind` + `jackson-datatype-jsr310`) | 2.17.3 |
+| Server | Spring Boot Web | 3.4.4 |
+| ORM | MyBatis-Plus (`mybatis-plus-spring-boot3-starter`) | 3.5.9 |
+| Database | MySQL 8.0+ (connector 8.4.0) | |
+| Build | Maven (no wrapper, requires system `mvn`) | 3.9+ |
+| Java | corretto-23 (`JAVA_HOME` must target JDK 23) | |
+| Lombok | 1.18.36 (annotation processor configured in parent POM) | |
+
+**Must compile with JDK 23.** The system JDK may be newer; always set `JAVA_HOME`:
+```sh
+JAVA_HOME=/path/to/corretto-23.0.2 mvn clean install
+```
+
+On this machine: `JAVA_HOME=/home/yangyi/.jdks/corretto-23.0.2`
+
+## Modules
+
+```
+common/   space.anyi.common    — entities, DTOs (LoginRequest, RegisterRequest, R<T>, PageResult<T>), enums
+server/   space.anyi.server    — Spring Boot app (controllers → services → MyBatis-Plus mappers)
+client/   space.anyi.client    — JavaFX app (App.java entry, FXML views, controllers, HTTP service layer)
+```
+
+Dependency: `server → common`, `client → common`. Client and server communicate only via HTTP; no direct dependency.
+
+## Build & run
+
+```sh
+# Full build (use JDK 23!)
+JAVA_HOME=/path/to/corretto-23 mvn clean install
+
+# Build single module (common must be installed first for server/client)
+mvn install -pl common
+mvn compile -pl server
+mvn compile -pl client
+
+# Run server
+mvn spring-boot:run -pl server
+
+# Run client
+mvn javafx:run -pl client          # via plugin
+# or directly run space.anyi.client.UIApplication main class
+```
+
+## Database
+
+- MySQL 8.0+, database `campus_book_trade`, charset `utf8mb4`
+- Schema: `sql/campus_book_trade.sql` (tables: `user`, `book`, `transaction_record`)
+- Default credentials: `root`/`root` on `localhost:3306`
+- Config: `server/src/main/resources/application.yml`
+- Run SQL directly against local instance before starting server
+
+## Architecture
+
+### Server REST API
+
+All under `/api`, unified response `R<T>` = `{code, message, data}`. Port 8080.
+
+| Method | Path | Purpose |
+|--------|------|---------|
+| POST | `/api/user/login` | Login |
+| POST | `/api/user/register` | Register |
+| GET | `/api/user` | List all users (paginated: `?page=&size=`) |
+| GET | `/api/user/{id}` | Get user |
+| PUT | `/api/user/{id}` | Update user |
+| DELETE | `/api/user/{id}` | Delete user |
+| GET | `/api/book?keyword=&category=&page=&size=` | Search books (paginated) |
+| GET | `/api/book/all` | List all books |
+| GET | `/api/book/{id}` | Book detail |
+| GET | `/api/book/my?sellerId=` | Seller's own books |
+| POST | `/api/book` | Create listing |
+| PUT | `/api/book/{id}` | Update book |
+| DELETE | `/api/book/{id}` | Delete book |
+| POST | `/api/transaction` | Purchase |
+| GET | `/api/transaction` | List all transactions (paginated) |
+| GET | `/api/transaction/{id}` | Transaction detail |
+| GET | `/api/transaction/user/{userId}` | User's transactions |
+| PUT | `/api/transaction/{id}` | Update transaction |
+| DELETE | `/api/transaction/{id}` | Delete transaction |
+| GET | `/api/statistics/summary` | Total transaction amount & count |
+| GET | `/api/statistics/top-departments` | Top 3 departments by sales |
+| GET | `/api/statistics/top-books` | Top 5 best-selling books |
+| GET | `/api/statistics/discount-rates` | Avg discount rate by department |
+
+### Client JavaFX views
+
+```
+login.fxml → LoginController
+register.fxml → RegisterController
+main.fxml → MainController (TabPane with 6 tabs: Browse, Transactions, Profile, Seller Dashboard, Statistics, Admin)
+```
+
+FXML location: `client/src/main/resources/fxml/*.fxml`
+
+### Identity
+
+Simplified auth: login stores `User` object in `LoginUserHolder` (in-memory). Client sends `userId` in request body/params. No JWT.
+
+### Key packages
+
+```
+server/
+  config/WebConfig.java          — CORS config
+  controller/*Controller.java    — REST endpoints
+  service/*Service.java          — business logic
+  service/impl/*ServiceImpl.java
+  mapper/*Mapper.java            — MyBatis-Plus BaseMapper
+
+client/
+  App.java                       — JavaFX entry, scene switching
+  controller/*Controller.java    — JavaFX controllers
+  service/*Service.java          — HTTP call wrappers
+  util/HttpClientUtil.java       — singleton HttpClient + Jackson JSON
+  util/LoginUserHolder.java      — current user session
+  resources/fxml/*.fxml          — Scene Builder layouts
+  resources/css/style.css
+```
+
+## Notes
+
+- No test framework configured yet
+- No CI, no formatter, no linter
+- IntelliJ IDEA project (`.idea/` tracked, configured for JDK 23)
+- Lombok `@Data` on entities/DTOs; annotation processor configured in parent POM's `maven-compiler-plugin`
+- MyBatis-Plus entity annotations (`@TableName`, `@TableId`, `@TableField`) live in `common` entities alongside Lombok; the `mybatis-plus-spring-boot3-starter` dependency brings in the annotation JAR
+- `PageResult<T>` DTO wraps MyBatis-Plus `IPage` for clean Jackson serialization across the HTTP boundary
+- Client uses BootstrapFX (`org.kordamp.bootstrapfx:bootstrapfx-core:0.4.0`) for UI styling

+ 301 - 0
README.md

@@ -0,0 +1,301 @@
+# CampusUsedBookTradingSystem
+
+校园二手书交易系统 — C/S 架构,JavaFX 客户端 + Spring Boot 服务端 + MySQL 数据库。
+
+## 项目概述
+
+为学生提供便捷的二手书籍买卖平台,支持买家浏览/搜索/购买书籍,卖家上架/管理书籍,管理员进行用户/商品/交易管理及数据分析。集成 Spring AI 提供基于 LLM 的运营分析报告。
+
+## 技术栈
+
+| 层次 | 技术 | 版本 |
+|------|------|------|
+| 客户端 UI | JavaFX + FXML + Scene Builder | 23.0.2 |
+| 客户端 HTTP | `java.net.http.HttpClient` | JDK 内置 |
+| JSON | Jackson (`jackson-databind` + `jackson-datatype-jsr310`) | 2.17.3 |
+| 服务端框架 | Spring Boot Web | 3.4.4 |
+| ORM | MyBatis-Plus (`mybatis-plus-spring-boot3-starter`) | 3.5.9 |
+| 数据库 | MySQL 8.0+ (Connector 8.4.0) | |
+| AI | Spring AI (OpenAI) | 1.1.8 |
+| UI 主题 | BootstrapFX | 0.4.0 |
+| 构建工具 | Maven (3.9+) | |
+| 编译运行 | JDK 23 (Corretto-23.0.2) | |
+| 注解 | Lombok 1.18.36 | |
+
+## 系统架构
+
+```mermaid
+flowchart TB
+    subgraph Client["JavaFX 客户端 (space.anyi.client)"]
+        VIEW["FXML 视图层"]
+        CTRL["Controller 层"]
+        HSVC["HTTP Service 层"]
+    end
+    subgraph Server["Spring Boot 服务端 (space.anyi.server)"]
+        CTL["Controller 层"]
+        SVC["Service 层"]
+        MPR["Mapper 层"]
+    end
+    subgraph DB["MySQL 8.0"]
+        D[("campus_book_trade")]
+    end
+
+    Client <-->|HTTP/JSON RESTful API| Server
+    MPR <--> D
+```
+
+三层 Maven 模块:
+- **`common`** — 共享实体、DTO、枚举(被 `server` 和 `client` 依赖)
+- **`server`** — Spring Boot 服务端 (Controller → Service → Mapper → MySQL)
+- **`client`** — JavaFX 客户端 (Controller → HTTP Service → UI)
+
+依赖:`server → common`,`client → common`。客户端与服务端仅通过 HTTP RESTful API 通信。
+
+## 用户角色与权限
+
+| 角色 | 权限 |
+|------|------|
+| **买家** (role=0, isSeller=0) | 浏览/搜索书籍、查看详情、购买、查看个人交易记录、修改个人信息 |
+| **卖家** (role=0, isSeller=1) | 买家权限 + 上架/编辑/下架书籍、查看自己发布的书籍及销售记录 |
+| **管理员** (role=1) | 全部权限 + 用户 CRUD/重置密码、商品审核、交易管理、数据统计、AI 分析 |
+
+## 功能清单
+
+### 买家功能
+- 登录/注册
+- 浏览书籍(卡片网格展示,支持按书名/作者关键词搜索 + 分类筛选)
+- 查看书籍详情
+- 购买书籍(库存校验,事务保证数据一致性)
+- 查看个人交易记录
+- 修改个人信息(昵称、邮箱、电话、院系、切换卖家身份)
+
+### 卖家功能
+- 上架书籍(自动进入待审核状态)
+- 编辑/下架书籍
+- 查看自己的书籍列表
+- 查看书籍销售记录(谁在何时买了多少本)
+- 销售统计概览(在售数、总库存、已售数量)
+
+### 管理员功能
+- 用户管理(浏览/添加/编辑/删除/重置密码/修改信用分)
+- 商品管理(浏览所有书籍、删除书籍)
+- 书籍审核(通过/拒绝待审核书籍)
+- 交易管理(查看全部交易记录、删除交易)
+- 数据统计(交易总金额/总笔数、热门院系 Top 3、热门书籍 Top 5、各院系平均折扣率)
+- AI 分析报告(基于统计数据生成;支持流式 LLM 调用)
+
+## 服务端 REST API
+
+所有 API 基路径:`/api`,统一响应格式 `R<T>` = `{code, message, data}`。
+
+### 用户模块 — `/api/user`
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| POST | `/api/user/login` | 登录 |
+| POST | `/api/user/register` | 注册 |
+| GET | `/api/user?page=&size=` | 分页用户列表 |
+| GET | `/api/user/{id}` | 获取用户 |
+| PUT | `/api/user/{id}` | 更新用户 |
+| DELETE | `/api/user/{id}` | 删除用户 |
+
+### 书籍模块 — `/api/book`
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| GET | `/api/book?keyword=&category=&page=&size=` | 搜索书籍(仅返回已上架) |
+| GET | `/api/book/all` | 所有书籍(含卖家名) |
+| GET | `/api/book/{id}` | 书籍详情 |
+| GET | `/api/book/my?sellerId=` | 卖家的书籍 |
+| GET | `/api/book/{id}/sales` | 销售记录 |
+| GET | `/api/book/pending` | 待审核书籍 |
+| GET | `/api/book/sales-summary?sellerId=` | 卖家总销量 |
+| POST | `/api/book` | 上架书籍 |
+| PUT | `/api/book/{id}` | 更新书籍 |
+| PUT | `/api/book/{id}/audit?status=` | 审核书籍 |
+| DELETE | `/api/book/{id}` | 删除书籍 |
+
+### 交易模块 — `/api/transaction`
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| POST | `/api/transaction` | 购买 |
+| GET | `/api/transaction?page=&size=` | 交易列表(含详情) |
+| GET | `/api/transaction/{id}` | 交易详情 |
+| GET | `/api/transaction/user/{userId}` | 用户交易记录 |
+| GET | `/api/transaction/user/{userId}/detail` | 用户交易记录(含书名) |
+| PUT | `/api/transaction/{id}` | 更新交易 |
+| DELETE | `/api/transaction/{id}` | 删除交易 |
+
+### 统计模块 — `/api/statistics`
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| GET | `/api/statistics/summary` | 交易总金额 & 总笔数 |
+| GET | `/api/statistics/top-departments` | 销售额 Top 3 院系 |
+| GET | `/api/statistics/top-books` | 销量 Top 5 书籍 |
+| GET | `/api/statistics/discount-rates` | 各院系平均折扣率 |
+
+### AI 分析模块 — `/api/ai`
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| GET | `/api/ai/analysis` | 固定模板分析报告 |
+| GET | `/api/ai/analysis/stream` | 流式 LLM 分析报告 |
+
+## 数据库
+
+- MySQL 8.0+,数据库 `campus_book_trade`,字符集 `utf8mb4`
+- 三张表:`user`、`book`、`transaction_record`
+- DDL 脚本:`sql/campus_book_trade.sql`(含示例数据)
+- 默认连接:`root`/`root` @ `localhost:3306`
+- 配置位置:`server/src/main/resources/application.yml`
+
+### ER 图
+
+```mermaid
+erDiagram
+    USER {
+        int userid PK
+        varchar username
+        varchar password
+        varchar nickname
+        varchar email
+        varchar phone
+        varchar dept
+        int credit
+        int role
+        int is_seller
+        datetime created_at
+    }
+
+    BOOK {
+        int book_id PK
+        int seller_id FK
+        varchar title
+        varchar author
+        varchar category
+        decimal original_price
+        decimal selling_price
+        varchar image_url
+        datetime created_at
+        int stock
+        int status
+    }
+
+    TRANSACTION_RECORD {
+        int trans_id PK
+        int book_id FK
+        int buyer_id FK
+        int transaction_num
+        decimal transaction_price
+        datetime transaction_time
+    }
+
+    USER ||--o{ BOOK : "seller"
+    USER ||--o{ TRANSACTION_RECORD : "buyer"
+    BOOK ||--o{ TRANSACTION_RECORD : "contains"
+```
+
+### 核心流程
+- **登录**:用户名+密码匹配 → 存入客户端 `LoginUserHolder`(无 JWT)
+- **注册**:创建用户,默认 credit=100, role=0, isSeller=0
+- **购买**:`@Transactional` 事务 → 校验库存 → 扣减库存 → 生成交易记录
+- **搜索**:动态 `LambdaQueryWrapper`,关键词模糊匹配书名/作者,分类精确匹配
+
+## 构建与运行
+
+**注意:必须使用 JDK 23 编译。** 本项目在 `corretto-23.0.2` 下开发测试。
+
+```bash
+# 设置 JDK
+export JAVA_HOME=/home/yangyi/.jdks/corretto-23.0.2
+
+# 初始化数据库(执行一次)
+mysql -u root -p < sql/campus_book_trade.sql
+
+# 全量构建
+mvn clean install
+
+# 单独构建公共模块(依赖模块需先安装)
+mvn install -pl common
+
+# 启动服务端(端口 8080)
+mvn spring-boot:run -pl server
+
+# 启动客户端
+mvn javafx:run -pl client
+```
+
+## 项目结构
+
+```mermaid
+flowchart LR
+    subgraph root["CampusUsedBookTradingSystem/"]
+        POM["pom.xml<br/>父 POM(多模块)"]
+        COMMON["common<br/>共享模块"]
+        SERVER["server<br/>Spring Boot 服务端"]
+        CLIENT["client<br/>JavaFX 客户端"]
+        SQL["sql<br/>建表脚本"]
+    end
+
+    subgraph common_detail["common/"]
+        C_ENTITY["entity/<br/>User, Book,<br/>TransactionRecord"]
+        C_DTO["dto/<br/>R&lt;T&gt;, PageResult,<br/>各种 DTO"]
+        C_ENUM["enums/<br/>UserRole"]
+    end
+
+    subgraph server_detail["server/"]
+        S_APP["ServerApplication.java"]
+        S_CONFIG["config/<br/>CORS, 分页, 异常处理"]
+        S_CTRL["controller/<br/>User, Book, Transaction,<br/>Statistics, Ai"]
+        S_SVC["service + impl/<br/>业务接口 + 实现"]
+        S_MAP["mapper/<br/>MyBatis-Plus Mapper"]
+    end
+
+    subgraph client_detail["client/"]
+        C_CLI["Client.java<br/>启动入口"]
+        C_APP["UIApplication.java<br/>场景切换"]
+        C_CTRL["controller/<br/>Login, Register, Main"]
+        C_SVC["service/<br/>HTTP 调用封装"]
+        C_UTIL["util/<br/>HttpClientUtil,<br/>LoginUserHolder"]
+        C_RES["resources/<br/>fxml/ + css/"]
+    end
+
+    root --> COMMON --> common_detail
+    root --> SERVER --> server_detail
+    root --> CLIENT --> client_detail
+    root --> SQL
+```
+
+## 客户端 UI
+
+基于 JavaFX 23 + BootstrapFX 主题框架 + 自定义 `style.css` 覆盖层。
+
+| 视图 | 说明 |
+|------|------|
+| **登录页** | 居中卡片,用户名/密码输入 |
+| **注册页** | 表单填写(用户名、密码、昵称、邮箱、电话、院系) |
+| **主界面** | 顶部导航栏 + 内容区,6 个导航标签 |
+| 浏览书籍 | 搜索栏 + 图书卡片网格 + 详情面板 + 购买功能 |
+| 我的交易 | 表格展示交易记录,含书名、数量、总价、时间 |
+| 个人信息 | 编辑昵称/邮箱/电话/院系,切换卖家身份 |
+| 卖家中心 | 书籍表格 + 统计概览 + 添加/编辑/删除书籍 + 查看销售记录 |
+| 数据统计 | KPI 卡片 + 热门院系进度条 + 畅销书籍表格 + 折扣率表格 + 图表 |
+| 管理 | 侧边菜单:用户管理、商品管理、待审核书籍、交易管理、AI 分析 |
+
+## 设计文档
+
+- [需求文档](doc/demand.md)
+- [详细设计文档](doc/design.md)
+- [服务端设计文档](doc/serverDesign.md)
+- [UI 设计文档](doc/UIDesign.md)
+- [AGENTS.md](AGENTS.md) — 开发助手配置
+
+## 注意事项
+
+- 当前密码明文存储,无 JWT 认证,适合校园局域网环境
+- 服务端未实现权限拦截,生产环境建议引入 Spring Security
+- 新上架书籍默认 `status=0`(待审核),需要管理员审核后才可被搜索到
+- Spring AI 需配置 `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` 环境变量(详见 `application.yml`)
+- 未配置 CI、测试框架、格式化/代码检查工具

+ 385 - 0
doc/UIDesign.md

@@ -0,0 +1,385 @@
+# 校园二手书交易系统 — UI 设计文档
+
+> 版本 1.0 | JavaFX 23 + BootstrapFX 主题框架 | 设计目标:现代化、清晰、易用
+
+---
+
+## 1. 设计原则
+
+- **以 BootstrapFX 为基础**:直接使用 BootstrapFX 提供的 CSS 类(`.btn`, `.btn-primary`, `.table`, `.table-striped`, `.label`, `.badge`, `.well` 等),避免重复造轮子
+- **定制覆盖层**:通过 `style.css` 覆盖少量变量(品牌色、圆角微调),保持整体风格统一
+- **布局优先**:核心价值在布局结构,而非重新定义基础样式
+- **内容层级**:通过间距、卡片、视觉权重引导用户注意力
+
+---
+
+## 2. 色彩定制
+
+BootstrapFX 默认色彩基础上,覆盖以下品牌色:
+
+| BootstrapFX 变量 | 定制值 | 用途 |
+|------------------|--------|------|
+| `-fx-primary` | `#4F6CF7` | 主色调:按钮、链接、激活态 |
+| `-fx-success` | `#10B981` | 成功:通过、上架 |
+| `-fx-warning` | `#F59E0B` | 警告:待审核、等待 |
+| `-fx-danger` | `#EF4444` | 危险:删除、拒绝、退出 |
+| `-fx-info` | `#3B82F6` | 信息:查看详情 |
+| 页面背景 | `#F5F7FA` | 替代纯白,增加层次感 |
+
+> 在 `style.css` 中通过 BootstrapFX 的选择器覆盖即可,无需重新定义全套组件样式。
+
+---
+
+## 3. 布局架构
+
+```
+┌──────────────────────────────────────────────────────────────┐
+│  BootstrapFX Navbar(顶部导航)                                │
+│  🏫 校园二手书市  [浏览] [交易] [个人] [卖家] [统计] [管理]  │ 👤 用户  ⏻ |
+├──────────────────────────────────────────────────────────────┤
+│                                                              │
+│  Main Content — 各 Tab 内容区域                              │
+│  (基于 BootstrapFX .well / .panel / .table 构建)            │
+│                                                              │
+├──────────────────────────────────────────────────────────────┤
+│  底部状态栏(可选)                                            │
+└──────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## 4. 页面详细设计
+
+### 4.1 登录页
+
+```
+┌────────────────────────────────────────────┐
+│                                            │
+│          ┌──────────────────────┐          │
+│          │  .well (圆角卡片)     │          │
+│          │                      │          │
+│          │   📚 校园二手书市      │          │
+│          │                      │          │
+│          │   ┌──────────────┐   │          │
+│          │   │  form-control │   │          │
+│          │   │  用户名       │   │          │
+│          │   └──────────────┘   │          │
+│          │   ┌──────────────┐   │          │
+│          │   │  form-control │   │          │
+│          │   │  密码         │   │          │
+│          │   └──────────────┘   │          │
+│          │                      │          │
+│          │   [ .btn .btn-primary .btn-block ] │
+│          │   │       登 录              │   │
+│          │   └──────────────────────┘   │          │
+│          │                      │          │
+│          │   没有账号?立即注册  │          │
+│          └──────────────────────┘          │
+│                                            │
+└────────────────────────────────────────────┘
+```
+
+- 居中 `.well` 卡片,`max-width: 400px`
+- 输入框使用 `form-control` 类
+- 按钮使用 `btn btn-primary btn-block`
+- 注册链接使用 BootstrapFX 默认链接样式
+
+### 4.2 注册页
+
+与登录页风格一致,增加更多表单字段。布局同上,使用 `.well` 卡片包裹。
+
+### 4.3 浏览书籍(核心改造)
+
+```
+┌──────────────────────────────────────────────────────────────┐
+│  搜索栏(BootstrapFX 行内表单)                                │
+│  ┌────────────────────┐ ┌──────────┐ ┌──────┐              │
+│  │  form-control      │ │  dropdown │ │ .btn │              │
+│  │  搜索书名/作者...   │ │  全部分类 ▾│ │ 🔍   │              │
+│  └────────────────────┘ └──────────┘ └──────┘              │
+│                                                              │
+│  ●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━●          │
+│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐      │
+│  │ .well    │ │ .well    │ │ .well    │ │ .well    │      │
+│  │ 图书卡片  │ │ 图书卡片  │ │ 图书卡片  │ │ 图书卡片  │      │
+│  │          │ │          │ │          │ │          │      │
+│  │ 书名     │ │ 书名     │ │ 书名     │ │ 书名     │      │
+│  │ 作者     │ │ 作者     │ │ 作者     │ │ 作者     │      │
+│  │ ¥价格    │ │ ¥价格    │ │ ¥价格    │ │ ¥价格    │      │
+│  │ 库存:N   │ │ 库存:N   │ │ 库存:N   │ │ 库存:N   │      │
+│  └──────────┘ └──────────┘ └──────────┘ └──────────┘      │
+│                                                              │
+│  分页: [1] [2] [3] ...                                      │
+│                                                              │
+│  ┌─────────────────────────────────────────────────────┐   │
+│  │  .well — 书籍详情面板(右侧滑出 / 底部)              │   │
+│  │  书名:Java程序设计                                   │   │
+│  │  作者:刘晓明    分类:教材                            │   │
+│  │  原价:¥49.90    售价:¥48.00                         │   │
+│  │  ┌──┐ ┌──┐ ┌──┐      [btn-primary] 立即购买         │   │
+│  │  │ -│ │ 1│ │ +│                                      │   │
+│  │  └──┘ └──┘ └──┘                                      │   │
+│  └─────────────────────────────────────────────────────┘   │
+└──────────────────────────────────────────────────────────────┘
+```
+
+**改造重点**:
+- 图书列表从 `TableView` 改为 **FlowPane / TilePane 卡片网格**,每张卡片为 `.well`
+- 卡片内容:书名(粗体)、作者、售价(`label label-success` 或品牌色)、原价(删除线)、库存徽章(`badge`)
+- 每张卡片 hover 时添加 `-fx-effect: dropshadow` 加深阴影
+- 选中卡片→右侧/下方显示详情面板
+- 卡片右上角可显示状态徽章(已上架/待审核)
+
+### 4.4 我的交易
+
+```
+┌──────────────────────────────────────────────────────────────┐
+│  我的交易记录                    [.btn .btn-secondary] 刷新  │
+│                                                              │
+│  ┌──────────────────────────────────────────────────────┐   │
+│  │  .table .table-striped                               │   │
+│  │  ┌────┬──────────┬──────┬────────┬────────────────┐ │   │
+│  │  │ #  │ 书名      │ 数量 │ 总价   │ 时间           │ │   │
+│  │  ├────┼──────────┼──────┼────────┼────────────────┤ │   │
+│  │  │ 1  │ Java...  │ 5    │ ¥240   │ 2026-06-15    │ │   │
+│  │  │ 2  │ Photo... │ 2    │ ¥112   │ 2026-06-15    │ │   │
+│  │  └────┴──────────┴──────┴────────┴────────────────┘ │   │
+│  └──────────────────────────────────────────────────────┘   │
+│                                                              │
+│  空状态:显示友好提示 "还没有交易记录,去逛逛吧~"              │
+└──────────────────────────────────────────────────────────────┘
+```
+
+- 使用 `.table .table-striped` 直接获得斑马纹表格
+- 右上角 `.btn .btn-secondary` 刷新
+
+### 4.5 个人信息
+
+```
+┌──────────────────────────────────────────────┐
+│  .well                                         │
+│  ┌──────────────────────────────────────────┐ │
+│  │  👤 个人资料                              │ │
+│  │                                          │ │
+│  │  用户名  │  [form-control:readonly]       │ │
+│  │  昵称    │  [form-control]                │ │
+│  │  邮箱    │  [form-control]                │ │
+│  │  电话    │  [form-control]                │ │
+│  │  院系    │  [form-control]                │ │
+│  │  信用分  │  ⭐⭐⭐⭐⭐ 100                 │ │
+│  │                                          │ │
+│  │  [.btn .btn-primary] 保存修改             │ │
+│  └──────────────────────────────────────────┘ │
+└──────────────────────────────────────────────┘
+```
+
+- 使用 `.well` 卡片包裹
+- 只读字段使用 `form-control` + disabled 样式
+- 信用分额外显示星级图标
+
+### 4.6 卖家中心
+
+```
+┌──────────────────────────────────────────────────────────────┐
+│  .well — 统计条                                              │
+│  在售: 5本  │  库存: 140本  │  已售: 23本                    │
+│                                                              │
+│  我的书籍                       [.btn-secondary] 刷新        │
+│                                [.btn-success]  + 添加新书    │
+│  ┌──────────────────────────────────────────────────────┐   │
+│  │  .table .table-striped                               │   │
+│  │  ┌──┬──────────┬─────┬────┬────────┬──────────────┐  │   │
+│  │  │# │ 书名      │售价  │库存│ 状态    │ 操作         │  │   │
+│  │  ├──┼──────────┼─────┼────┼────────┼──────────────┤  │   │
+│  │  │1 │ Java     │¥48  │ 90 │ ✅上架  │ ✏️ 🗑️ 📊     │  │   │
+│  │  │2 │ Photo    │¥56  │ 50 │ ⏳待审核│ ✏️ 🗑️ 📊     │  │   │
+│  │  └──┴──────────┴─────┴────┴────────┴──────────────┘  │   │
+│  └──────────────────────────────────────────────────────┘   │
+│                                                              │
+│  ┌──────────────────────────────────────────────────────┐   │
+│  │  ▼ 添加新书 / 编辑书籍 (TitledPane)                   │   │
+│  │  书名  [      ]  作者  [      ]                      │   │
+│  │  分类  [      ]  原价  [      ]                      │   │
+│  │  售价  [      ]  库存  [      ]                      │   │
+│  │                        [.btn-primary] 保存           │   │
+│  └──────────────────────────────────────────────────────┘   │
+└──────────────────────────────────────────────────────────────┘
+```
+
+- 顶部统计条使用 `.label` 或自定义 HBox
+- 状态列:`label label-success` / `label label-warning` / `label label-danger`
+- 操作列使用图标文字混合按钮(BootstrapFX 默认按钮风格)
+- 表单使用 `form-control`,按钮使用 `.btn .btn-success`/`.btn .btn-primary`
+- 查看销售记录:弹出 Dialog,内部使用 `.table .table-striped`
+
+### 4.7 数据统计
+
+```
+┌──────────────────────────────────────────────────────────────┐
+│  数据洞察                        [.btn-secondary] 刷新数据   │
+│                                                              │
+│  ┌──────────────────┐  ┌──────────────────┐                 │
+│  │  .well           │  │  .well           │                 │
+│  │  交易总金额       │  │  交易总笔数       │                 │
+│  │  ¥5,720.00       │  │  12 笔           │                 │
+│  └──────────────────┘  └──────────────────┘                 │
+│                                                              │
+│  ┌──────────────────────────────────────────────────────┐   │
+│  │  🔥 热门院系 TOP 3 (.well)                           │   │
+│  │  1. 计算机学院  ████████████████░░░░  ¥3,200         │   │
+│  │  2. 经济学院    ██████████░░░░░░░░░░  ¥1,800         │   │
+│  │  3. 东语学院    ████░░░░░░░░░░░░░░░░  ¥720           │   │
+│  └──────────────────────────────────────────────────────┘   │
+│                                                              │
+│  ┌──────────────────────────────────────────────────────┐   │
+│  │  📚 畅销书籍 TOP 5 (.well)                           │   │
+│  │  ┌──┬──────────┬──────┬────┐                         │   │
+│  │  │# │ 书名      │ 作者  │ 销量│                         │   │
+│  │  │1 │ Java     │ 刘晓明│ 15 │                         │   │
+│  │  │2 │ Photo    │ 王艳梅│ 8  │                         │   │
+│  │  └──┴──────────┴──────┴────┘                         │   │
+│  └──────────────────────────────────────────────────────┘   │
+│                                                              │
+│  ┌──────────────────────────────────────────────────────┐   │
+│  │  📊 各院系平均折扣率 (.well)                          │   │
+│  │  ┌──────────┬────────┬──────────────────────────┐   │   │
+│  │  │ 院系      │ 折扣率  │ 进度条 (.progress-bar)    │   │   │
+│  │  │ 计算机学院│ 85%    │ ████████░░ 85%            │   │   │
+│  │  │ 经济学院  │ 92%    │ █████████░ 92%            │   │   │
+│  │  └──────────┴────────┴──────────────────────────┘   │   │
+│  └──────────────────────────────────────────────────────┘   │
+└──────────────────────────────────────────────────────────────┘
+```
+
+- 顶部 KPI 使用两个 `.well` 并排显示,金额用大号字体 + `.text-success` 颜色
+- 热门院系使用自定义进度条(或用 BootstrapFX `.progress-bar` 模拟)
+- 畅销书籍使用 `.table` 精简显示
+- 折扣率展示使用 BootstrapFX 进度条组件
+
+### 4.8 管理面板
+
+```
+┌──────────────────────────────────────────────────────────────┐
+│  ┌──────────────────────────────────────────────────────┐   │
+│  │  👥 用户管理                   [.btn-secondary] 刷新  │   │
+│  │                               [.btn-success] + 添加  │   │
+│  │  ┌──┬──────┬────┬──────┬────┬───┬───┬────────────┐  │   │
+│  │  │ID│用户名│昵称│ 院系  │信用│角色│卖家│ 操作       │  │   │
+│  │  │1 │张大民│大民│计算机│100 │用户│否 │ ✏️ 🔄 🗑️  │  │   │
+│  │  └──┴──────┴────┴──────┴────┴───┴───┴────────────┘  │   │
+│  └──────────────────────────────────────────────────────┘   │
+│                                                              │
+│  ┌──────────────────────────────────────────────────────┐   │
+│  │  ⏳ 待审核书籍               [.btn-secondary] 刷新   │   │
+│  │  ┌──┬──────────┬──────┬────┬────┬────────────────┐  │   │
+│  │  │ID│ 书名      │ 作者  │卖家│售价│ 操作           │  │   │
+│  │  │3 │ 影视栏目..│ 李大山│ 2  │¥42 │ ✅通过 ❌拒绝 │  │   │
+│  │  └──┴──────────┴──────┴────┴────┴────────────────┘  │   │
+│  └──────────────────────────────────────────────────────┘   │
+│                                                              │
+│  ┌──────────────────────────────────────────────────────┐   │
+│  │  🤖 AI 分析报告              [.btn-primary] 生成报告  │   │
+│  │  ┌──────────────────────────────────────────────────┐│   │
+│  │  │  分析内容(.well 或 textarea)                   ││   │
+│  │  └──────────────────────────────────────────────────┘│   │
+│  └──────────────────────────────────────────────────────┘   │
+└──────────────────────────────────────────────────────────────┘
+```
+
+- 每个管理区域使用独立的 `.well` 包裹
+- 表格使用 `.table .table-striped`
+- 操作按钮使用 BootstrapFX 颜色变体
+- 待审核的「通过」用 `.btn-success`,「拒绝」用 `.btn-danger`
+- 添加用户使用 Dialog 或 TitledPane
+
+---
+
+## 5. 小组件规范
+
+| 组件 | BootstrapFX 类 | 说明 |
+|------|---------------|------|
+| 按钮 | `.btn .btn-{primary/success/danger/warning/info/secondary}` | 全套按钮颜色 |
+| 输入框 | `.form-control` | 统一表单样式 |
+| 表格 | `.table .table-striped` | 斑马纹 + 圆角 |
+| 卡片容器 | `.well` | 浅灰背景圆角面板 |
+| 标签/徽章 | `.label .label-{success/warning/danger/info}`、`.badge` | 状态标记 |
+| 进度条 | `.progress-bar`(需包装在 `.progress` 内) | 折扣率展示 |
+| 导航 | 使用 JavaFX TabPane,应用 BootstrapFX 导航样式 |
+| 提示文字 | `.text-success / .text-danger / .text-warning / .text-info` | 状态文字着色 |
+
+---
+
+## 6. style.css 覆盖层
+
+仅需在 BootstrapFX 基础上覆盖以下内容:
+
+```css
+/* ── 品牌色覆盖 ── */
+.root {
+  -fx-primary: #4F6CF7;
+  -fx-primary-hover: #3B5DE7;
+  -fx-success: #10B981;
+  -fx-warning: #F59E0B;
+  -fx-danger: #EF4444;
+  -fx-info: #3B82F6;
+}
+
+/* ── 页面背景 ── */
+.root {
+  -fx-background-color: #F5F7FA;
+}
+
+/* ── Well 卡片微调 ── */
+.well {
+  -fx-background-radius: 8px;
+  -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.06), 6, 0, 0, 2);
+}
+
+/* ── 卡片 hover ── */
+.well:hover {
+  -fx-effect: dropshadow(gaussian, rgba(0,0,0,0.12), 12, 0, 0, 4);
+}
+
+/* ── 表格微调 ── */
+.table-view {
+  -fx-background-radius: 8px;
+  -fx-border-radius: 8px;
+}
+
+/* ── 导航 Tab ── */
+.tab-pane .tab-header-area .tab {
+  -fx-padding: 8px 16px;
+}
+
+/* ── 输入框高度微调 ── */
+.form-control {
+  -fx-pref-height: 38px;
+}
+```
+
+---
+
+## 7. 实施要点
+
+1. **保留 BootstrapFX**:`App.java` 中 `scene.getStylesheets().add("org/kordamp/bootstrapfx/bootstrapfx.css")` 不变
+2. **style.css 后加载**:在 BootstrapFX 之后加载,确保覆盖生效
+3. **FXML 中添加 styleClass**:统一使用 BootstrapFX 类名,如 `styleClass="btn btn-primary"`
+4. **卡片网格**:浏览页使用 `FlowPane` + `TilePane` 替代 `TableView`,每个子项为 `Pane` 或 `VBox` 加 `.well` 类
+5. **自定义组件**:仅在 BootstrapFX 不支持的功能上自行实现(如进度条排行榜、数量选择器)
+6. **色彩一致性**:所有按钮/标签优先使用 BootstrapFX 内置颜色类,不额外定义
+
+---
+
+## 8. 实施优先级
+
+| Phase | 内容 | 依赖 |
+|-------|------|------|
+| **P1** 样式覆盖 | 编写 `style.css` 覆盖层,配置品牌色 | BootstrapFX 已集成 |
+| **P2** 浏览页改造 | FlowPane 卡片网格代替 TableView,详情卡片 | P1 |
+| **P3** 各页样式 | 统一个人信息、交易、卖家、统计、管理页 | P1 |
+| **P4** 动效细节 | 卡片 hover 阴影、加载状态、空状态 | P2~P3 |
+
+---
+
+> 本文档定位为实施蓝图,所有 UI 组件优先使用 BootstrapFX 提供的基础类,
+> 仅在布局结构和少量品牌样式上进行自定义。

+ 37 - 0
doc/demand.md

@@ -0,0 +1,37 @@
+系统用户分为三类:普通用户(学生)、卖家(可视为普通用户的扩展)和管理员。每类用户的操作权限不同,具体如下:
+1. 普通用户:买家
+   主要指注册登录后的学生用户,主要进行购买、查询和个人信息管理操作。
+   常见操作:
+   浏览书籍列表
+   搜索书籍
+   查看书籍详情
+   购买书籍,生成交易记录
+   查看个人订单记录
+   修改个人资料
+   查看/修改信用积分(由于没有实现付款功能,因此没有修改功能)
+
+2. 普通用户:卖家
+   额外操作(相较于买家):
+   添加//上架书籍
+   修改书籍
+   下架/删除书籍
+   查看自己发布的书籍列表
+   查看自己书籍的销售记录,哪些用户购买了
+
+3. 管理员
+   管理员拥有最高权限,负责平台的日常运维、用户管理和数据监控。
+   常见操作:
+   用户管理:
+   o添加、修改、删除、查看用户信息
+   o重置用户密码
+   商品管理:
+   o添加/上架、修改书籍
+   o删除书籍
+   o审核书籍(如需要审核才能上架)
+   交易管理:
+   o查看所有交易记录
+   数据统计::
+   o数据统计与报表生成(销售统计、用户活跃度等)
+   AI分析(使用SpringAI):
+   o根据提示词AI建议生成
+   o查看AI分析报告

+ 903 - 0
doc/design.md

@@ -0,0 +1,903 @@
+# 校园二手书交易系统 — 详细设计文档
+
+## 1. 引言
+
+### 1.1 项目背景
+校园内二手教材流转需求旺盛,但缺乏统一的线上交易平台。本项目旨在构建一个 C/S 架构的校园二手书交易系统,为学生提供便捷的书籍买卖渠道,为管理员提供数据监控与统计能力。
+
+### 1.2 项目目标
+- 实现学生用户的注册、登录、浏览、搜索、购买书籍及订单管理
+- 支持卖家用户上架、编辑、下架书籍及查看销售记录
+- 提供管理员后台进行用户管理、商品管理、交易管理和数据统计
+- 预留 AI 分析扩展能力(固定流程 + LLM 调用)
+
+### 1.3 适用范围
+本系统面向高校在校学生与管理人员,部署于校园局域网环境。
+
+### 1.4 术语与缩略语
+
+| 术语 | 说明 |
+|------|------|
+| Buyer | 买家/普通学生用户 |
+| Seller | 卖家(买家身份的权限扩展) |
+| Admin | 系统管理员 |
+| C/S | Client/Server 架构 |
+| MyBatis-Plus | MyBatis 增强工具 |
+| LLM | Large Language Model,大语言模型 |
+
+---
+
+## 2. 总体设计
+
+### 2.1 系统架构
+
+本系统采用经典 C/S 两层架构:
+
+```mermaid
+flowchart TB
+    subgraph Client [JavaFX 客户端 space.anyi.client]
+        VIEW[FXML 视图层]
+        CTRL[Controller 层]
+        HSVC[HTTP Service 层]
+    end
+    subgraph Server [Spring Boot 服务端 space.anyi.server]
+        CTL[Controller 层]
+        SVC[Service 层]
+        MPR[Mapper 层]
+    end
+    subgraph DB [MySQL 8.0]
+        D[(campus_book_trade)]
+    end
+
+    Client <-->|HTTP/JSON RESTful API| Server
+    MPR <--> D
+```
+
+客户端与服务端之间仅通过 HTTP RESTful API 通信,无直接依赖。共享模块 `common` 提供实体类、DTO 和工具类。
+
+### 2.2 技术栈
+
+| 层次 | 技术 | 版本 |
+|------|------|------|
+| 客户端 UI | JavaFX + FXML + Scene Builder | 23.0.2 |
+| 客户端 HTTP | `java.net.http.HttpClient` | JDK 内置 |
+| JSON 序列化 | Jackson (`jackson-databind` + `jackson-datatype-jsr310`) | 2.17.3 |
+| 服务端框架 | Spring Boot Web | 3.4.4 |
+| ORM | MyBatis-Plus (`mybatis-plus-spring-boot3-starter`) | 3.5.9 |
+| 数据库 | MySQL 8.0+ (Connector 8.4.0) | |
+| 构建工具 | Maven (3.9+) | |
+| Java | Corretto-23 | 23 |
+
+### 2.3 模块划分
+
+```
+CampusUsedBookTradingSystem/
+├── common/         共享模块 — 实体、DTO、枚举
+├── server/         Spring Boot 服务端
+│   ├── config/        配置类(CORS、MyBatis-Plus、异常处理)
+│   ├── controller/    REST 控制器
+│   ├── service/       业务接口
+│   ├── service/impl/  业务实现
+│   └── mapper/        MyBatis-Plus Mapper + XML
+├── client/         JavaFX 客户端
+│   ├── controller/    JavaFX 控制器
+│   ├── service/       HTTP 调用封装
+│   └── util/          工具类
+└── sql/            数据库建表脚本
+```
+
+依赖关系:`server → common`,`client → common`。
+
+### 2.4 包结构总览
+
+```
+space.anyi
+├── common
+│   ├── entity/          User, Book, TransactionRecord
+│   ├── dto/             LoginRequest, RegisterRequest, R<T>, PageResult<T>,
+│   │                    StatisticsSummary, DeptSalesDTO, DeptDiscountDTO, HotBookDTO
+│   └── enums/           UserRole
+├── server
+│   ├── ServerApplication.java
+│   ├── config/          WebConfig, MyBatisPlusConfig, GlobalExceptionHandler
+│   ├── controller/      UserController, BookController, TransactionController, StatisticsController
+│   ├── service/         UserService, BookService, TransactionService, StatisticsService
+│   ├── service/impl/    UserServiceImpl, BookServiceImpl, TransactionServiceImpl, StatisticsServiceImpl
+│   └── mapper/          UserMapper, BookMapper, TransactionRecordMapper, StatisticsMapper
+└── client
+    ├── App.java, Client.java
+    ├── controller/      LoginController, RegisterController, MainController
+    ├── service/         UserService, BookService, TransactionService, StatisticsService
+    └── util/            HttpClientUtil, LoginUserHolder
+```
+
+---
+
+## 3. 数据库设计
+
+### 3.1 ER 图
+
+```mermaid
+erDiagram
+    USER {
+        int userid PK
+        varchar username
+        varchar password
+        varchar nickname
+        varchar email
+        varchar phone
+        varchar dept
+        int credit
+        int role
+        int is_seller
+        datetime created_at
+    }
+
+    BOOK {
+        int book_id PK
+        int seller_id FK
+        varchar title
+        varchar author
+        varchar category
+        decimal original_price
+        decimal selling_price
+        varchar image_url
+        datetime created_at
+        int stock
+    }
+
+    TRANSACTION_RECORD {
+        int trans_id PK
+        int book_id FK
+        int buyer_id FK
+        int transaction_num
+        decimal transaction_price
+        datetime transaction_time
+    }
+
+    USER ||--o{ BOOK : "seller"
+    USER ||--o{ TRANSACTION_RECORD : "buyer"
+    BOOK ||--o{ TRANSACTION_RECORD : "contains"
+```
+
+### 3.2 表结构
+
+#### 3.2.1 user 表
+
+| 字段 | 类型 | 约束 | 说明 |
+|------|------|------|------|
+| userid | int | PK, AUTO_INCREMENT | 用户ID |
+| username | varchar(255) | | 用户名 |
+| password | varchar(255) | | 密码(明文存储,后续改进) |
+| nickname | varchar(255) | | 昵称 |
+| email | varchar(255) | | 邮箱 |
+| phone | varchar(255) | | 电话 |
+| dept | varchar(255) | | 院系 |
+| credit | int | DEFAULT 100 | 信用分 |
+| role | int | DEFAULT 0 | 角色(0=学生, 1=管理员) |
+| is_seller | int | DEFAULT 0 | 是否为卖家(0=否, 1=是) |
+| created_at | datetime | | 注册时间 |
+
+#### 3.2.2 book 表
+
+| 字段 | 类型 | 约束 | 说明 |
+|------|------|------|------|
+| book_id | int | PK, AUTO_INCREMENT | 书籍ID |
+| seller_id | int | | 卖家ID(逻辑外键→user.userid) |
+| title | varchar(255) | | 书名 |
+| author | varchar(255) | | 作者 |
+| category | varchar(255) | | 分类 |
+| original_price | decimal(10,2) | | 原价 |
+| selling_price | decimal(10,2) | | 售价 |
+| image_url | varchar(255) | | 图片URL(预留) |
+| created_at | datetime | | 上架时间 |
+| stock | int | | 库存数量 |
+
+#### 3.2.3 transaction_record 表
+
+| 字段 | 类型 | 约束 | 说明 |
+|------|------|------|------|
+| trans_id | int | PK, AUTO_INCREMENT | 交易ID |
+| book_id | int | | 书籍ID(逻辑外键→book.book_id) |
+| buyer_id | int | | 买家ID(逻辑外键→user.userid) |
+| transaction_num | int | | 购买数量 |
+| transaction_price | decimal(10,2) | | 交易总价 |
+| transaction_time | datetime | | 交易时间 |
+
+### 3.3 表关系说明
+
+- `book.seller_id` → `user.userid`:一个卖家可发布多本书(一对多)
+- `transaction_record.book_id` → `book.book_id`:一本书可被多次交易(一对多)
+- `transaction_record.buyer_id` → `user.userid`:一个买家可有多笔交易(一对多)
+
+当前 DDL 中未显式声明外键约束,由应用层(事务)保证数据一致性。
+
+### 3.4 SQL 脚本
+
+建库脚本位于 `sql/campus_book_trade.sql`,包含完整 CREATE TABLE 和示例初始数据。字符集采用 `utf8mb4`。
+
+---
+
+## 4. 服务端详细设计
+
+### 4.1 分层架构
+
+```mermaid
+flowchart LR
+    subgraph Controller [Controller 层]
+        direction LR
+        UC[UserController]
+        BC[BookController]
+        TC[TransactionController]
+        SC[StatisticsController]
+    end
+    subgraph Service [Service 层]
+        direction LR
+        US[UserService]
+        BS[BookService]
+        TS[TransactionService]
+        SS[StatisticsService]
+    end
+    subgraph Mapper [Mapper 层]
+        direction LR
+        UM[UserMapper]
+        BM[BookMapper]
+        TM[TransactionRecordMapper]
+        SM[StatisticsMapper]
+    end
+    DB[(MySQL)]
+
+    Controller --> Service
+    Service --> Mapper
+    Mapper --> DB
+```
+
+各层职责:
+
+| 层次 | 职责 |
+|------|------|
+| Controller | 请求映射、参数解析校验、调用 Service、封装 R<T> 响应 |
+| Service | 核心业务逻辑、事务控制、组合操作 |
+| Mapper | 数据访问(继承 BaseMapper 提供 CRUD,自定义 SQL 提供统计) |
+| Config | CORS 跨域配置、MyBatis-Plus 分页插件、全局异常处理 |
+
+### 4.2 RESTful API 接口定义
+
+#### 4.2.1 用户模块 — `/api/user`
+
+| 方法 | 路径 | 请求体/参数 | 响应 | 说明 |
+|------|------|-------------|------|------|
+| POST | `/api/user/login` | `LoginRequest` | `R<User>` | 登录认证 |
+| POST | `/api/user/register` | `RegisterRequest` | `R<User>` | 注册新用户 |
+| GET | `/api/user` | `?page=&size=` | `R<IPage<User>>` | 分页获取用户列表(Admin) |
+| GET | `/api/user/{id}` | | `R<User>` | 获取单个用户 |
+| PUT | `/api/user/{id}` | `User` JSON | `R<User>` | 更新用户信息 |
+| DELETE | `/api/user/{id}` | | `R<Void>` | 删除用户(Admin) |
+
+**LoginRequest**:
+```json
+{"username": "string", "password": "string"}
+```
+
+**RegisterRequest**:
+```json
+{"username": "string", "password": "string", "nickname": "string", "email": "string", "phone": "string", "dept": "string"}
+```
+
+#### 4.2.2 书籍模块 — `/api/book`
+
+| 方法 | 路径 | 参数 | 响应 | 说明 |
+|------|------|------|------|------|
+| GET | `/api/book` | keyword, category, page, size | `R<PageResult<Book>>` | 搜索书籍(分页) |
+| GET | `/api/book/all` | | `R<List<Book>>` | 获取所有书籍 |
+| GET | `/api/book/{id}` | | `R<Book>` | 获取书籍详情 |
+| GET | `/api/book/my` | sellerId | `R<List<Book>>` | 卖家查看自己的书籍 |
+| GET | `/api/book/{id}/sales` | | `R<List<SalesRecordDTO>>` | 查看书籍销售记录(卖家) |
+| GET | `/api/book/pending` | | `R<List<Book>>` | 查看待审核书籍列表(Admin) |
+| POST | `/api/book` | `Book` JSON | `R<Book>` | 创建/上架书籍(默认 status=0) |
+| PUT | `/api/book/{id}` | `Book` JSON | `R<Book>` | 更新书籍 |
+| PUT | `/api/book/{id}/audit` | `?status=` | `R<Book>` | 审核书籍(Admin: 0待审/1通过/2拒绝) |
+| DELETE | `/api/book/{id}` | | `R<Void>` | 删除书籍 |
+
+#### 4.2.3 交易模块 — `/api/transaction`
+
+| 方法 | 路径 | 请求体/参数 | 响应 | 说明 |
+|------|------|-------------|------|------|
+| POST | `/api/transaction` | `{bookId, buyerId, quantity}` | `R<TransactionRecord>` | 购买 |
+| GET | `/api/transaction` | `?page=&size=` | `R<IPage<TransactionRecord>>` | 分页查询所有交易 |
+| GET | `/api/transaction/{id}` | | `R<TransactionRecord>` | 交易详情 |
+| GET | `/api/transaction/user/{userId}` | | `R<List<TransactionRecord>>` | 用户交易记录 |
+| PUT | `/api/transaction/{id}` | `TransactionRecord` JSON | `R<TransactionRecord>` | 更新交易(预留) |
+| DELETE | `/api/transaction/{id}` | | `R<Void>` | 删除交易 |
+
+#### 4.2.4 统计模块 — `/api/statistics`
+
+| 方法 | 路径 | 响应 | 说明 |
+|------|------|------|------|
+| GET | `/api/statistics/summary` | `R<StatisticsSummary>` | 交易总金额和总笔数 |
+| GET | `/api/statistics/top-departments` | `R<List<DeptSalesDTO>>` | 销售额前三的院系 |
+| GET | `/api/statistics/top-books` | `R<List<HotBookDTO>>` | 销量前五的书籍 |
+| GET | `/api/statistics/discount-rates` | `R<List<DeptDiscountDTO>>` | 各院系平均折扣率 |
+
+#### 4.2.5 AI 分析模块 — `/api/ai`
+
+| 方法 | 路径 | 响应 | 说明 |
+|------|------|------|------|
+| GET | `/api/ai/analysis` | `R<String>` | 触发服务端固定分析流程,返回文本分析报告 |
+
+### 4.3 统一响应格式 R\<T\>
+
+所有 API 返回统一结构:
+
+```json
+{
+  "code": 200,
+  "message": "success",
+  "data": { ... }
+}
+```
+
+| code | 含义 |
+|------|------|
+| 200 | 成功 |
+| 400 | 业务错误(参数错误、库存不足等) |
+| 500 | 服务器内部错误 |
+
+### 4.4 分页设计
+
+```mermaid
+sequenceDiagram
+    participant Client as JavaFX 客户端
+    participant Server as Spring Boot 服务端
+    participant DB as MySQL
+
+    Client->>Server: GET /api/book?keyword=&category=&page=1&size=20
+    Server->>DB: MyBatis-Plus Page + LambdaQueryWrapper
+    DB-->>Server: 分页数据 + 总数
+    Server->>Server: 转换为 PageResult<Book>
+    Server-->>Client: R<PageResult<Book>>
+    Client->>Client: FXCollections.observableArrayList(records) → TableView
+```
+
+服务端使用 MyBatis-Plus `IPage` 分页,通过 `PageResult<T>` DTO 传输给客户端。MyBatis-Plus `PaginationInnerInterceptor` 自动拦截并改写分页 SQL。
+
+### 4.5 关键配置
+
+#### WebConfig.java — CORS
+允许跨域访问(开发环境 JavaFX 直连服务端,无代理层)。
+
+#### MyBatisPlusConfig.java
+- 启用分页插件 `PaginationInnerInterceptor(DbType.MYSQL)`
+- 开启 `map-underscore-to-camel-case: true`
+- 主键生成策略:`id-type: auto`(数据库自增)
+
+#### GlobalExceptionHandler
+
+| 异常 | 响应 |
+|------|------|
+| `DuplicateKeyException` | `R.error("用户名已存在")` |
+| `IllegalArgumentException` | `R.error(异常消息)` |
+| `Exception`(兜底) | `R.error("服务器内部错误: " + e.getMessage())` |
+
+### 4.6 核心业务逻辑
+
+#### 4.6.1 注册流程
+
+```mermaid
+sequenceDiagram
+    participant Client as JavaFX 客户端
+    participant Server as 服务端
+    participant DB as MySQL
+
+    Client->>Server: POST /api/user/register (RegisterRequest)
+    Server->>Server: 创建 User 对象
+    Note over Server: 设置默认值: <br/>credit=100, role=0, <br/>isSeller=0, createdAt=now
+    Server->>DB: INSERT INTO user
+    DB-->>Server: User (含自增ID)
+    Server-->>Client: R.ok(user)
+```
+
+#### 4.6.2 登录流程
+
+```mermaid
+sequenceDiagram
+    participant Client as JavaFX 客户端
+    participant Server as 服务端
+    participant DB as MySQL
+
+    Client->>Server: POST /api/user/login (LoginRequest)
+    Server->>DB: SELECT * FROM user WHERE username=? AND password=?
+    DB-->>Server: User / null
+    alt user == null
+        Server-->>Client: R.error("Invalid username or password")
+    else
+        Server-->>Client: R.ok(user)
+        Client->>Client: LoginUserHolder.set(user)
+        Client->>Client: App.showMainScene()
+    end
+```
+
+#### 4.6.3 购买流程(事务)
+
+```mermaid
+sequenceDiagram
+    participant Client as JavaFX 客户端
+    participant Server as 服务端
+    participant DB as MySQL
+
+    Client->>Server: POST /api/transaction {bookId, buyerId, quantity}
+    Server->>Server: @Transactional 开启事务
+    Server->>DB: SELECT * FROM book WHERE book_id=?
+    DB-->>Server: {stock=N, sellingPrice=P}
+    alt stock < quantity
+        Server-->>Client: R.error("Insufficient stock")
+        Server->>Server: 回滚事务
+    else
+        Server->>DB: UPDATE book SET stock = stock - quantity
+        Server->>DB: INSERT INTO transaction_record (bookId, buyerId, transactionNum, transactionPrice, transactionTime)
+        Server->>Server: 提交事务
+        Server-->>Client: R.ok(transactionRecord)
+    end
+```
+
+**事务边界**(`TransactionServiceImpl.purchase()`):
+1. 查询书籍,校验库存
+2. 扣减库存 `book.stock -= quantity`
+3. 创建交易记录(价格 = `sellingPrice × quantity`)
+4. 任一失败则 `@Transactional` 回滚
+
+#### 4.6.4 搜索流程
+
+```
+1. 客户端组装参数:keyword + category + page + size
+2. GET /api/book?keyword=&category=&page=&size=
+3. 服务端构建动态查询条件:
+   - keyword → LIKE title OR LIKE author
+   - category → EQ category
+   - 按 created_at DESC 排序
+4. MyBatis-Plus 分页查询 + 返回 PageResult<Book>
+```
+
+### 4.7 统计实现
+
+统计模块全部使用自定义 SQL 在 `StatisticsMapper` 中通过 `@Select` 注解实现:
+
+| 统计项 | SQL 概要 |
+|--------|----------|
+| summary | `SELECT COALESCE(SUM(transaction_price),0), COUNT(*) FROM transaction_record` |
+| top-departments | JOIN `transaction_record` + `book` + `user`,按 `user.dept` 分组,销售额前3 |
+| top-books | JOIN `transaction_record` + `book`,按 `book` 分组,销量前5 |
+| discount-rates | `AVG((original_price - unit_price) / original_price * 100)`,按 `dept` 分组 |
+
+---
+
+## 5. 客户端详细设计
+
+### 5.1 界面导航
+
+```mermaid
+flowchart LR
+    A[login.fxml] -->|登录成功| C[main.fxml]
+    A -->|点击注册链接| B[register.fxml]
+    B -->|注册成功| A
+    B -->|返回登录| A
+    C -->|退出登录| A
+```
+
+`App.java` 作为 JavaFX Application 入口,通过静态方法实现场景切换。`Client.java` 为启动入口(`Application.launch(App.class, args)`)。
+
+### 5.2 FXML 视图结构
+
+#### login.fxml
+
+```
+VBox (400×350)
+├── Label "校园书市"(标题,22px bold)
+├── TextField #usernameField(用户名输入)
+├── PasswordField #passwordField(密码输入)
+├── Button "登录" → #handleLogin(btn-primary)
+└── Hyperlink "没有账号?立即注册" → #handleRegister
+```
+
+#### register.fxml
+
+```
+VBox (400×500)
+├── Label "创建账号"(标题,20px bold)
+├── TextField #usernameField(用户名 *)
+├── PasswordField #passwordField(密码 *)
+├── TextField #nicknameField(昵称)
+├── TextField #emailField(邮箱)
+├── TextField #phoneField(电话)
+├── TextField #deptField(院系)
+├── Button "注册" → #handleRegister(btn-primary)
+└── Hyperlink "已有账号?去登录" → #handleBack
+```
+
+#### main.fxml
+
+```
+BorderPane (1000×700)
+├── Top: HBox 顶部标题栏
+│   ├── Label #welcomeLabel "欢迎,xxx"
+│   └── Button "退出登录" → #handleLogout(btn-danger)
+│
+└── Center: TabPane(6个Tab)
+    │
+    ├── Tab "浏览书籍"(买家/卖家共有的 browse tab)
+    │   ├── HBox 搜索栏: TextField #searchField + ComboBox #categoryCombo + Button "搜索"
+    │   └── SplitPane (0.6)
+    │       ├── TableView #bookTable [编号,书名,作者,分类,价格,库存]
+    │       └── VBox: 详情 Label 组 + TextField #quantityField + Button "购买"
+    │
+    ├── Tab "我的交易"(买家/卖家)
+    │   ├── Button "刷新" → #handleLoadTransactions
+    │   └── TableView #transTable [交易编号,书籍编号,数量,总价,时间]
+    │
+    ├── Tab "个人信息"(买家/卖家)
+    │   └── VBox: #profileUsername(只读), #profileNickname, #profileEmail, #profilePhone, #profileDept, #profileCredit(只读) + Button "保存修改"
+    │
+    ├── Tab "卖家中心"(isSeller=1 启用)
+    │   ├── Label "我的书籍"
+    │   ├── Button "刷新" → #handleLoadMyBooks
+    │   ├── TableView #myBookTable [编号,书名,价格,库存]
+    │   ├── Button "删除选中" → #handleDeleteBook
+    │   └── TitledPane "添加新书"
+    │       └── GridPane: 书名/作者/分类/原价/售价/库存 输入 + Button "添加书籍"
+    │
+    ├── Tab "数据统计"(所有角色可见)
+    │   └── ScrollPane > VBox
+    │       ├── Button "刷新数据" → #handleLoadStatistics
+    │       ├── TitledPane "总览": statTotalAmount + statTotalCount
+    │       ├── TitledPane "热门院系(销量前三)": TableView #deptTable
+    │       ├── TitledPane "热门书籍(前五)": TableView #hotBookTable
+    │       └── TitledPane "各院系平均折扣率": TableView #discountTable
+    │
+    └── Tab "管理"(role=1 启用)
+        ├── Label "用户管理"
+        ├── Button "刷新用户" → #handleLoadAllUsers
+        ├── TableView #userTable [编号,用户名,昵称,院系,信用分,角色,卖家]
+        ├── Button "删除选中用户" → #handleDeleteUser
+        ├── Label "全部交易"
+        ├── Button "刷新交易" → #handleLoadAllTransactions
+        ├── TableView #allTransTable [交易编号,书籍编号,买家编号,数量,价格,时间]
+        └── Button "删除选中交易" → #handleDeleteTransaction
+```
+
+### 5.3 控制器设计
+
+#### LoginController
+
+| 字段/方法 | 类型 | 说明 |
+|-----------|------|------|
+| usernameField | TextField | 用户名输入框 |
+| passwordField | PasswordField | 密码输入框 |
+| userService | UserService | HTTP 服务层 |
+| handleLogin() | void | 校验非空 → 调用登录 API → 存入会话 → 跳转主界面 |
+| handleRegister() | void | 跳转到注册界面 |
+
+#### RegisterController
+
+| 字段/方法 | 类型 | 说明 |
+|-----------|------|------|
+| usernameField ~ deptField | TextField / PasswordField | 注册表单字段 |
+| userService | UserService | HTTP 服务层 |
+| handleRegister() | void | 校验必填 → 调用注册 API → 提示 → 跳回登录 |
+| handleBack() | void | 返回登录界面 |
+
+#### MainController
+
+| Tab | 核心方法 | 说明 |
+|-----|----------|------|
+| 浏览书籍 | `handleSearch()` | 搜索 + 刷新列表 |
+| | `handlePurchase()` | 校验 → 购买 → 刷新 |
+| | `initialize()` | 绑定表格列、设置角色权限、加载数据 |
+| 我的交易 | `handleLoadTransactions()` | 加载当前用户交易记录 |
+| 个人信息 | `handleUpdateProfile()` | 保存修改 + 更新会话 |
+| 卖家中心 | `handleLoadMyBooks()` | 加载卖家自己的书籍 |
+| | `handleAddBook()` | 上架新书 |
+| | `handleDeleteBook()` | 删除选中书籍 |
+| 数据统计 | `handleLoadStatistics()` | 加载4个统计指标 |
+| 管理 | `handleLoadAllUsers()` | 加载所有用户 |
+| | `handleDeleteUser()` | 删除选中用户 |
+| | `handleLoadAllTransactions()` | 加载所有交易 |
+| | `handleDeleteTransaction()` | 删除选中交易 |
+
+**会话初始化**(`initialize()` 方法):
+1. 从 `LoginUserHolder` 获取当前用户
+2. 设置欢迎语和个人信息回显
+3. 根据 `isSeller` 和 `role` 控制 sellerTab 和 adminTab 的启用状态
+
+### 5.4 HTTP 服务层设计
+
+#### HttpClientUtil
+
+单例模式的 `HttpClient` + Jackson `ObjectMapper`,提供泛型方法:
+
+| 方法 | 说明 |
+|------|------|
+| `get(path, Class<T>)` | GET 请求,简单类型反序列化 |
+| `get(path, TypeReference)` | GET 请求,泛型类型反序列化 |
+| `post(path, body, Class<T>)` | POST 请求 |
+| `put(path, body, Class<T>)` | PUT 请求 |
+| `delete(path, Class<T>)` | DELETE 请求 |
+
+基 URL = `http://localhost:8080`,错误时返回 code=500。
+
+#### 客户端 Service 封装
+
+| Service | 封装方法 | 对应 API |
+|---------|----------|----------|
+| UserService | login, register, getById, update, delete | `/api/user/*` |
+| BookService | search, getById, getMyBooks, listAll, create, update, delete | `/api/book/*` |
+| TransactionService | purchase, getById, getByUser, update, delete | `/api/transaction/*` |
+| StatisticsService | getSummary, getTopDepartments, getTopBooks, getDiscountRates | `/api/statistics/*` |
+
+### 5.5 会话管理
+
+`LoginUserHolder`:基于内存的静态会话管理。
+
+```java
+LoginUserHolder.set(user);      // 登录成功后存入
+LoginUserHolder.get();          // 获取当前用户
+LoginUserHolder.isSeller();     // 判断是否为卖家
+LoginUserHolder.clear();        // 退出时清除
+```
+
+当前无 Token/JWT 机制,userId 通过请求参数/体明文传输。
+
+### 5.6 BootstrapFX 样式整合
+
+引入 `org.kordamp.bootstrapfx:bootstrapfx-core:0.4.0`,在场景加载时添加 bootstrapfx.css。额外定制 `css/style.css`:全局字体、按钮手型光标、表格边框圆角。
+
+---
+
+## 6. 用户角色与权限设计
+
+### 6.1 角色模型
+
+用户角色由两个字段组合定义:
+
+| role | isSeller | 角色 |
+|:----:|:--------:|------|
+| 0 | 0 | 普通学生(买家) |
+| 0 | 1 | 卖家(同时具备买家权限) |
+| 1 | 0/1 | 管理员 |
+
+`UserRole.java` 枚举仅定义 `STUDENT(0)` 和 `ADMIN(1)`,卖家用 `isSeller` 标志区分。
+
+### 6.2 权限矩阵
+
+| 功能模块 | 功能点 | 买家 | 卖家 | 管理员 |
+|----------|--------|:----:|:----:|:------:|
+| 账号 | 注册 | ✅ | ✅ | ✅ |
+| 账号 | 登录 | ✅ | ✅ | ✅ |
+| 书籍 | 浏览/搜索 | ✅ | ✅ | ✅ |
+| 书籍 | 查看详情 | ✅ | ✅ | ✅ |
+| 书籍 | 购买 | ✅ | ✅ | ❌ |
+| 书籍 | 上架 | ❌ | ✅ | ✅ |
+| 书籍 | 编辑 | ❌ | ✅ | ✅ |
+| 书籍 | 下架/删除 | ❌ | ✅ | ✅ |
+| 书籍 | 查看自己的发布 | ❌ | ✅ | ✅ |
+| 书籍 | 审核(待实现) | ❌ | ❌ | ✅ |
+| 订单 | 查看自己的订单 | ✅ | ✅ | ✅ |
+| 订单 | 查看全部订单 | ❌ | ❌ | ✅ |
+| 订单 | 删除订单 | ❌ | ❌ | ✅ |
+| 用户 | CRUD | ❌ | ❌ | ✅ |
+| 用户 | 重置密码 | ❌ | ❌ | ✅ |
+| 统计 | 查看统计数据 | ✅ | ✅ | ✅ |
+| AI | 分析报告(待实现) | ❌ | ❌ | ✅ |
+
+### 6.3 客户端权限控制
+
+在 `MainController.initialize()` 中:
+
+```java
+if (user.getIsSeller() != 1) sellerTab.setDisable(true);  // 非卖家禁用卖家中心
+if (user.getRole() != 1)     adminTab.setDisable(true);    // 非管理员禁用管理Tab
+```
+
+Tab 被禁用后用户无法点击,但 FXML 元素仍保留。
+
+### 6.4 服务端校验(待完善)
+
+当前服务端未实现权限拦截,所有 API 均可被任意客户端调用。生产环境建议引入 Spring Security 或自定义拦截器。
+
+---
+
+## 7. 数据流设计
+
+### 7.1 登录注册流程
+
+```mermaid
+sequenceDiagram
+    actor User as 用户
+    participant Login as 登录界面
+    participant Reg as 注册界面
+    participant Main as 主界面
+    participant Svc as 客户端Service
+    participant API as 服务端API
+    participant DB as 数据库
+
+    Note over User,DB: === 登录流程 ===
+    User->>Login: 输入用户名+密码
+    Login->>Svc: userService.login(username, password)
+    Svc->>API: POST /api/user/login
+    API->>DB: SELECT * FROM user WHERE username=? AND password=?
+    DB-->>API: User
+    API-->>Svc: R.ok(user)
+    Svc-->>Login: R<User>
+    Login->>Login: LoginUserHolder.set(user)
+    Login->>Main: App.showMainScene()
+
+    Note over User,DB: === 注册流程 ===
+    User->>Reg: 填写表单
+    Reg->>Svc: userService.register(RegisterRequest)
+    Svc->>API: POST /api/user/register
+    API->>API: 设置默认值 (credit=100,role=0,isSeller=0)
+    API->>DB: INSERT INTO user
+    DB-->>API: User
+    API-->>Svc: R.ok(user)
+    Svc-->>Reg: 注册成功
+    Reg->>Login: App.showLoginScene()
+```
+
+### 7.2 购买交易流程
+
+```mermaid
+sequenceDiagram
+    actor Buyer as 买家
+    participant Browse as 浏览Tab
+    participant Svc as TransactionService
+    participant API as 服务端
+    participant DB as 数据库
+
+    Buyer->>Browse: 选择书籍 → 输入数量 → 点击购买
+    Browse->>Svc: purchase(bookId, buyerId, quantity)
+    Svc->>API: POST /api/transaction
+    API->>API: @Transactional 开启
+    API->>DB: SELECT stock FROM book WHERE book_id=?
+    DB-->>API: stock=N
+    alt N < quantity
+        API-->>Svc: R.error("Insufficient stock")
+        Svc-->>Browse: Alert 警告
+    else
+        API->>DB: UPDATE book SET stock = stock - quantity
+        API->>DB: INSERT INTO transaction_record
+        API->>API: 提交事务
+        API-->>Svc: R.ok(record)
+        Svc-->>Browse: Alert 成功 + 刷新列表
+    end
+```
+
+### 7.3 搜索书籍流程
+
+```mermaid
+sequenceDiagram
+    actor User as 用户
+    participant Browse as 浏览Tab
+    participant Svc as BookService
+    participant API as 服务端
+    participant DB as 数据库
+
+    User->>Browse: 输入关键字 / 选择分类
+    User->>Browse: 点击"搜索"
+    Browse->>Svc: search(keyword, category, page, size)
+    Svc->>API: GET /api/book?keyword=&category=
+    API->>API: LambdaQueryWrapper 动态条件
+    API->>DB: SELECT ... WHERE title LIKE ? OR author LIKE ? AND category=? ORDER BY created_at DESC
+    DB-->>API: 分页结果
+    API-->>Svc: R.ok(PageResult<Book>)
+    Svc-->>Browse: 数据列表
+    Browse->>Browse: bookTable.setItems(...)
+```
+
+---
+
+## 8. 已实现功能清单
+
+以下列出所有基于 `demand.md` 需求已实现的功能及其对应代码位置:
+
+### 8.1 卖家-编辑书籍 — ✅ 已实现
+
+| 组件 | 说明 |
+|------|------|
+| FXML | 卖家中心 Tab 新增"编辑选中"按钮 (`main.fxml:92`) |
+| Controller | `handleEditBook()` — 选中书籍回填表单,切换为编辑模式 (`MainController.java`) |
+| 复用 | `handleAddBook()` — 检测 `editingBook` 字段,区分新增/更新逻辑 |
+| 重置 | `clearBookForm()` — 编辑完成后重置表单状态 |
+
+### 8.2 卖家-查看销售记录 — ✅ 已实现
+
+| 组件 | 说明 |
+|------|------|
+| API | `GET /api/book/{id}/sales` — 返回 `List<SalesRecordDTO>` (`BookController.java:56`) |
+| DTO | `SalesRecordDTO` — bookId, title, buyerId, buyerName, quantity, totalPrice, transactionTime |
+| Mapper | `BookMapper.selectSalesByBookId()` — JOIN transaction_record + book + user |
+| 客户端 | `handleViewSales()` — 弹出 Dialog 展示销售记录表格 (`MainController.java`) |
+
+### 8.3 管理员-用户管理完善 — ✅ 已实现
+
+| 组件 | 说明 |
+|------|------|
+| 编辑用户 | `handleEditUser()` — 选中用户回填表单,支持修改 (`MainController.java`) |
+| 添加用户 | `handleSaveUser()` — 创建用户(调用 Register API) |
+| 重置密码 | `handleResetPassword()` — 密码重置为 `123456` |
+| FXML | 用户表单 TitledPane (`main.fxml`) |
+
+### 8.4 管理员-商品管理 — ✅ 已实现
+
+| 组件 | 说明 |
+|------|------|
+| TableView | `adminBookTable` — 显示所有书籍(编号、书名、作者、分类、售价、库存、卖家ID) |
+| 刷新 | `handleLoadAllBooksAdmin()` — 调用 `GET /api/book/all` |
+| 删除 | `handleDeleteBookAdmin()` — 删除选中书籍 |
+
+### 8.5 管理员-审核书籍 — ✅ 已实现
+
+| 组件 | 说明 |
+|------|------|
+| Schema | `book` 表增加 `status` 字段: 0=待审核, 1=已上架, 2=已下架 |
+| Entity | `Book.java` 增加 `@TableField("status") private Integer status;` |
+| API | `GET /api/book/pending` — 获取待审核书籍 |
+| API | `PUT /api/book/{id}/audit?status=` — 审核通过/拒绝 |
+| 搜索过滤 | `searchBooks()` 仅返回 `status=1` 的书籍 |
+| 新书上架 | `create()` 默认 `status=0`(待审核) |
+| 客户端 | `pendingBookTable` + "通过"/"拒绝" 按钮 |
+
+### 8.6 AI 分析 — ✅ 已实现
+
+| 组件 | 说明 |
+|------|------|
+| Service | `AiServiceImpl.generateAnalysis()` — 汇总统计数据 → 格式化分析报告 |
+| Controller | `GET /api/ai/analysis` — 返回 `R<String>` 文本报告 |
+| 客户端 | `AiService` — HTTP 调用封装 |
+| UI | 管理 Tab 增加"AI 分析"区域: "生成分析报告"按钮 + `TextArea` 展示区 |
+| 后续 | LLM 接入方案(API Key、模型选择、固定提示词模板)待补充 |
+
+### 8.7 信用分修改 — ✅ 已实现
+
+| 组件 | 说明 |
+|------|------|
+| UI | 管理 Tab 用户管理区增加"修改信用分"按钮 |
+| 交互 | `TextInputDialog` 输入新分值 → 调用 `PUT /api/user/{id}` 更新 |
+
+---
+
+## 附录 A:配置文件
+
+### application.yml
+
+```yaml
+server:
+  port: 8080
+  servlet:
+    context-path: /api
+
+spring:
+  datasource:
+    url: jdbc:mysql://localhost:3306/campus_book_trade?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
+    username: root
+    password: root
+    driver-class-name: com.mysql.cj.jdbc.Driver
+
+mybatis-plus:
+  configuration:
+    map-underscore-to-camel-case: true
+  global-config:
+    db-config:
+      id-type: auto
+```
+
+## 附录 B:构建命令
+
+```sh
+# 全量构建(需 JDK 23)
+JAVA_HOME=/path/to/corretto-23 mvn clean install
+
+# 运行服务端
+mvn spring-boot:run -pl server
+
+# 运行客户端
+mvn javafx:run -pl client
+```

+ 568 - 0
doc/serverDesign.md

@@ -0,0 +1,568 @@
+# 校园二手书交易系统 — 服务端详细设计文档
+
+> 版本:1.0  
+> 对应设计:`design.md` 第 4 章
+
+---
+
+## 1. 分层架构
+
+```
+space.anyi.server
+├── ServerApplication.java          — Spring Boot 入口
+├── config/                         — 配置层
+│   ├── WebConfig.java              — CORS 跨域配置
+│   ├── MyBatisPlusConfig.java      — MyBatis-Plus 分页插件
+│   └── GlobalExceptionHandler.java — 全局异常处理
+├── controller/                     — Controller 层(REST 接口)
+│   ├── UserController.java
+│   ├── BookController.java
+│   ├── TransactionController.java
+│   ├── StatisticsController.java
+│   └── AiController.java
+├── service/                        — Service 接口层
+│   ├── UserService.java
+│   ├── BookService.java
+│   ├── TransactionService.java
+│   ├── StatisticsService.java
+│   └── AiService.java
+├── service/impl/                   — Service 实现层
+│   ├── UserServiceImpl.java
+│   ├── BookServiceImpl.java
+│   ├── TransactionServiceImpl.java
+│   ├── StatisticsServiceImpl.java
+│   └── AiServiceImpl.java
+└── mapper/                         — Mapper 层(数据访问)
+    ├── UserMapper.java
+    ├── BookMapper.java
+    ├── TransactionRecordMapper.java
+    └── StatisticsMapper.java
+```
+
+### 1.1 各层职责
+
+| 层次 | 职责 |
+|------|------|
+| **Config** | CORS 跨域、MyBatis-Plus 分页拦截器、全局异常处理 |
+| **Controller** | `@RestController`,请求映射、参数解析、调用 Service 并封装 `R<T>` 响应 |
+| **Service 接口** | 业务逻辑抽象,继承 `IService` 获得通用 CRUD |
+| **Service 实现** | 核心业务逻辑、事务控制(`@Transactional`)、组合 Mapper 调用 |
+| **Mapper** | `BaseMapper` 扩展提供 CRUD,`@Select` 自定义 SQL 提供统计查询 |
+
+### 1.2 依赖关系
+
+```
+Controller → Service → Mapper → MySQL
+```
+
+所有 API 返回统一响应格式 `R<T>`(定义在 `common` 模块)。
+
+### 1.3 Maven 依赖(server/pom.xml)
+
+| 依赖 | 说明 |
+|------|------|
+| `spring-boot-starter-web` | Spring Boot Web 容器 |
+| `mybatis-plus-spring-boot3-starter` | MyBatis-Plus ORM(适配 Spring Boot 3) |
+| `mybatis-plus-jsqlparser` | MyBatis-Plus SQL 解析器(分页插件依赖) |
+| `mysql-connector-j` | MySQL JDBC 驱动 |
+| `lombok` | 编译期注解生成 getter/setter |
+| `common` | 项目共享模块(实体、DTO、枚举) |
+
+---
+
+## 2. 配置层
+
+### 2.1 WebConfig.java — CORS 跨域
+
+允许所有来源的跨域请求,用于开发环境 JavaFX 客户端直连服务端。
+
+```java
+registry.addMapping("/**")
+        .allowedOriginPatterns("*")
+        .allowedMethods("*")
+        .allowedHeaders("*")
+        .allowCredentials(true);
+```
+
+### 2.2 MyBatisPlusConfig.java — 分页插件
+
+注册 `PaginationInnerInterceptor(DbType.MYSQL)`,自动拦截并改写分页 SQL。
+
+配合 `application.yml` 配置:
+
+```yaml
+mybatis-plus:
+  configuration:
+    map-underscore-to-camel-case: true
+  global-config:
+    db-config:
+      id-type: auto
+```
+
+### 2.3 GlobalExceptionHandler.java — 全局异常处理
+
+| 异常 | 响应 |
+|------|------|
+| `DuplicateKeyException` | `R.error("用户名已存在")` → code=400 |
+| `IllegalArgumentException` | `R.error(e.getMessage())` → code=400 |
+| `Exception`(兜底) | `R.error("服务器内部错误: " + e.getMessage())` → code=500 |
+
+---
+
+## 3. 公共模块(common)
+
+### 3.1 实体类(`space.anyi.common.entity`)
+
+#### User
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| `userid` | Integer | PK,自增 |
+| `username` | String | 用户名 |
+| `password` | String | 密码 |
+| `nickname` | String | 昵称 |
+| `email` | String | 邮箱 |
+| `phone` | String | 电话 |
+| `dept` | String | 院系 |
+| `credit` | Integer | 信用分,默认 100 |
+| `role` | Integer | 角色(0=学生, 1=管理员) |
+| `isSeller` | Integer | `@TableField("is_seller")`,是否为卖家(0=否, 1=是) |
+| `createdAt` | LocalDateTime | 注册时间 |
+
+#### Book
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| `bookId` | Integer | PK,自增 |
+| `sellerId` | Integer | 卖家 ID(逻辑外键 → user.userid) |
+| `title` | String | 书名 |
+| `author` | String | 作者 |
+| `category` | String | 分类 |
+| `originalPrice` | BigDecimal | 原价 |
+| `sellingPrice` | BigDecimal | 售价 |
+| `imageUrl` | String | 图片 URL(预留) |
+| `createdAt` | LocalDateTime | 上架时间 |
+| `stock` | Integer | 库存数量 |
+| `status` | Integer | `@TableField("status")`,0=待审核, 1=已上架, 2=已下架 |
+
+#### TransactionRecord
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| `transId` | Integer | PK,自增 |
+| `bookId` | Integer | 书籍 ID(逻辑外键 → book.book_id) |
+| `buyerId` | Integer | 买家 ID(逻辑外键 → user.userid) |
+| `transactionNum` | Integer | 购买数量 |
+| `transactionPrice` | BigDecimal | 交易总价(= sellingPrice × quantity) |
+| `transactionTime` | LocalDateTime | 交易时间 |
+
+### 3.2 DTO 类(`space.anyi.common.dto`)
+
+#### R\<T\> — 统一响应
+
+```json
+{"code": 200, "message": "success", "data": ...}
+```
+
+| 静态方法 | 说明 |
+|----------|------|
+| `R.ok(data)` | 成功,code=200 |
+| `R.ok()` | 成功无数据 |
+| `R.error(message)` | 错误,code=400 |
+| `R.error(code, message)` | 自定义错误码 |
+
+#### PageResult\<T\> — 分页结果
+
+```json
+{"records": [...], "total": 100, "size": 20, "current": 1}
+```
+
+#### LoginRequest
+
+```json
+{"username": "string", "password": "string"}
+```
+
+#### RegisterRequest
+
+```json
+{"username": "string", "password": "string", "nickname": "string", "email": "string", "phone": "string", "dept": "string"}
+```
+
+#### SalesRecordDTO
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| `bookId` | Integer | 书籍ID |
+| `title` | String | 书名 |
+| `buyerId` | Integer | 买家ID |
+| `buyerName` | String | 买家昵称(JOIN user 表) |
+| `quantity` | Integer | 购买数量 |
+| `totalPrice` | BigDecimal | 成交金额 |
+| `transactionTime` | LocalDateTime | 交易时间 |
+
+#### StatisticsSummary
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| `totalAmount` | BigDecimal | 交易总金额 |
+| `totalCount` | long | 交易总笔数 |
+
+#### DeptSalesDTO
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| `dept` | String | 院系名称 |
+| `salesAmount` | BigDecimal | 销售额 |
+
+#### HotBookDTO
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| `bookId` | Integer | 书籍ID |
+| `title` | String | 书名 |
+| `author` | String | 作者 |
+| `totalSold` | int | 总销量 |
+
+#### DeptDiscountDTO
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| `dept` | String | 院系名称 |
+| `avgDiscountRate` | BigDecimal | 平均折扣率(百分比) |
+
+### 3.3 枚举类(`space.anyi.common.enums`)
+
+#### UserRole
+
+| 常量 | 值 | 说明 |
+|------|:----:|------|
+| `STUDENT` | 0 | 学生 |
+| `ADMIN` | 1 | 管理员 |
+
+提供 `fromValue(int)` 工厂方法。
+
+---
+
+## 4. RESTful API 接口定义
+
+所有接口基路径:`/api`(通过 `server.servlet.context-path` 配置)
+
+### 4.1 用户模块 — `/api/user`
+
+| 方法 | 路径 | 请求 | 响应 | 说明 |
+|------|------|------|------|------|
+| POST | `/api/user/login` | `LoginRequest` JSON | `R<User>` | 登录认证 |
+| POST | `/api/user/register` | `RegisterRequest` JSON | `R<User>` | 注册新用户 |
+| GET | `/api/user` | `?page=&size=` | `R<IPage<User>>` | 分页获取用户列表(Admin) |
+| GET | `/api/user/{id}` | | `R<User>` | 获取单个用户 |
+| PUT | `/api/user/{id}` | `User` JSON | `R<User>` | 更新用户信息 |
+| DELETE | `/api/user/{id}` | | `R<Void>` | 删除用户(Admin) |
+
+**Controller:** `UserController.java`
+
+- `login()`: 调用 `userService.login(username, password)`,匹配则返回 User,否则 `R.error`
+- `register()`: 创建 User 对象,调用 `userService.register(user)`
+- `listAll()`: MyBatis-Plus `page()` 分页查询
+- `getById()`: 按主键查询,不存在则返回错误
+- `update()`: 设置 userId 后 `updateById()`,再返回最新数据
+- `delete()`: `removeById()` 物理删除
+
+### 4.2 书籍模块 — `/api/book`
+
+| 方法 | 路径 | 参数 | 响应 | 说明 |
+|------|------|------|------|------|
+| GET | `/api/book` | keyword, category, page, size | `R<PageResult<Book>>` | 搜索书籍(仅返回 status=1) |
+| GET | `/api/book/all` | | `R<List<Book>>` | 获取所有书籍(不分页) |
+| GET | `/api/book/{id}` | | `R<Book>` | 获取书籍详情 |
+| GET | `/api/book/my` | sellerId | `R<List<Book>>` | 卖家查看自己的书籍 |
+| GET | `/api/book/{id}/sales` | | `R<List<SalesRecordDTO>>` | 查看书籍销售记录(卖家) |
+| GET | `/api/book/pending` | | `R<List<Book>>` | 查看待审核书籍列表(Admin) |
+| POST | `/api/book` | `Book` JSON | `R<Book>` | 创建/上架书籍(默认 status=0) |
+| PUT | `/api/book/{id}` | `Book` JSON | `R<Book>` | 更新书籍 |
+| PUT | `/api/book/{id}/audit` | `?status=` | `R<Book>` | 审核书籍(Admin:0 待审/1 通过/2 拒绝) |
+| DELETE | `/api/book/{id}` | | `R<Void>` | 删除书籍 |
+
+**Controller:** `BookController.java`
+
+- `search()`: 调用 `bookService.searchBooks()`,返回 `PageResult<Book>`
+- `listAll()`: 返回所有书籍(按创建时间降序)
+- `getById()`: 按主键查询
+- `getMyBooks()`: 按 sellerId 查询
+- `getSales()`: JOIN 查询销售记录,返回 `List<SalesRecordDTO>`
+- `getPendingBooks()`: 查询 `status=0` 的书籍
+- `create()`: 设置 `createdAt=now`, `status=0`,保存后返回
+- `update()`: 设置 bookId 后 `updateById()`
+- `audit()`: 查询书籍 → 设置新 status → 更新
+- `delete()`: `removeById()` 物理删除
+
+**Service 方法:** `BookServiceImpl.java`
+
+| 方法 | 说明 |
+|------|------|
+| `searchBooks(keyword, category, page, size)` | 动态条件:keyword 模糊匹配 title 或 author;category 精确匹配;仅返回 status=1;按 created_at DESC 排序 |
+| `getBySellerId(sellerId)` | 按卖家 ID 查询,按创建时间降序 |
+| `listAll()` | 返回所有书籍,按创建时间降序 |
+| `getSalesByBookId(bookId)` | 委托 `bookMapper.selectSalesByBookId()` JOIN 查询 |
+| `getPendingBooks()` | 查询 `status=0` 的书籍 |
+
+### 4.3 交易模块 — `/api/transaction`
+
+| 方法 | 路径 | 请求 | 响应 | 说明 |
+|------|------|------|------|------|
+| POST | `/api/transaction` | `{bookId, buyerId, quantity}` | `R<TransactionRecord>` | 购买(需事务) |
+| GET | `/api/transaction` | `?page=&size=` | `R<IPage<TransactionRecord>>` | 分页查询所有交易 |
+| GET | `/api/transaction/{id}` | | `R<TransactionRecord>` | 交易详情 |
+| GET | `/api/transaction/user/{userId}` | | `R<List<TransactionRecord>>` | 用户交易记录 |
+| PUT | `/api/transaction/{id}` | `TransactionRecord` JSON | `R<TransactionRecord>` | 更新交易(预留) |
+| DELETE | `/api/transaction/{id}` | | `R<Void>` | 删除交易 |
+
+**Controller:** `TransactionController.java`
+
+- `purchase()`: 从 Map 中提取 bookId/buyerId/quantity,调用 `transactionService.purchase()`,捕获运行时异常返回错误
+- `listAll()`: MyBatis-Plus 分页查询
+- `getById()`: 按主键查询
+- `getByUser()`: 调用 `transactionService.getByUserId()`
+- `update()`/`delete()`: MyBatis-Plus 通用操作
+
+### 4.4 统计模块 — `/api/statistics`
+
+| 方法 | 路径 | 响应 | 说明 |
+|------|------|------|------|
+| GET | `/api/statistics/summary` | `R<StatisticsSummary>` | 交易总金额和总笔数 |
+| GET | `/api/statistics/top-departments` | `R<List<DeptSalesDTO>>` | 销售额前三的院系 |
+| GET | `/api/statistics/top-books` | `R<List<HotBookDTO>>` | 销量前五的书籍 |
+| GET | `/api/statistics/discount-rates` | `R<List<DeptDiscountDTO>>` | 各院系平均折扣率 |
+
+**Controller:** `StatisticsController.java` — 直接委托 `StatisticsService` 的四个方法。
+
+### 4.5 AI 分析模块 — `/api/ai`
+
+| 方法 | 路径 | 响应 | 说明 |
+|------|------|------|------|
+| GET | `/api/ai/analysis` | `R<String>` | 触发服务端固定分析流程,返回文本分析报告 |
+
+**Controller:** `AiController.java` — 调用 `aiService.generateAnalysis()`。
+
+**Service 实现:** `AiServiceImpl.java`
+
+流程:
+1. 调用 `StatisticsService` 获取全部统计指标(summary、topDepartments、topBooks、discountRates)
+2. 格式化拼接为纯文本分析报告
+3. 报告包含:交易总览、热门院系 Top 3、热门书籍 Top 5、各院系折扣率、分析结论
+
+---
+
+## 5. 核心业务逻辑
+
+### 5.1 注册流程
+
+1. Controller 接收 `RegisterRequest`
+2. 构造 `User` 对象,设置默认值:`credit=100`, `role=0`, `isSeller=0`, `createdAt=now`
+3. 调用 `userService.register()` → `save(user)`
+4. 返回 `R.ok(user)`(含自增 ID)
+
+**服务端代码位置:** `UserServiceImpl.register()`
+
+### 5.2 登录流程
+
+1. Controller 接收 `LoginRequest`
+2. 调用 `userService.login(username, password)`
+3. 构建 `LambdaQueryWrapper`:`eq(username) AND eq(password)`
+4. 匹配则返回 `R.ok(user)`,否则返回 `R.error("Invalid username or password")`
+
+**服务端代码位置:** `UserServiceImpl.login()`
+
+### 5.3 购买流程(事务)
+
+```
+@Transactional 开启事务
+  1. bookService.getById(bookId) → 查询书籍
+  2. 校验 stock >= quantity,否则抛异常回滚
+  3. book.setStock(stock - quantity) → bookService.updateById()
+  4. 创建 TransactionRecord:
+     - bookId, buyerId, transactionNum
+     - transactionPrice = sellingPrice × quantity
+     - transactionTime = now
+  5. save(record)
+提交事务
+```
+
+**事务边界:** `TransactionServiceImpl.purchase()` 方法标注 `@Transactional`
+
+### 5.4 搜索书籍流程
+
+1. Controller 接收 keyword、category、page、size
+2. 构建 `LambdaQueryWrapper<Book>`:
+   - 固定条件:`eq(Book::getStatus, 1)`(仅返回已上架书籍)
+   - keyword 非空 → `like(title, keyword) OR like(author, keyword)`
+   - category 非空 → `eq(category)`
+   - 排序:`orderByDesc(createdAt)`
+3. 调用 `page(new Page<>(page, size), wrapper)` 分页查询
+4. 转换为 `PageResult<Book>` 返回
+
+**服务端代码位置:** `BookServiceImpl.searchBooks()`
+
+---
+
+## 6. 数据访问层
+
+### 6.1 Mapper 结构
+
+| Mapper | 父类 | 自定义方法 | SQL 类型 |
+|--------|------|-----------|----------|
+| `UserMapper` | `BaseMapper<User>` | 无 | — |
+| `BookMapper` | `BaseMapper<Book>` | `selectSalesByBookId()` | `@Select` JOIN 查询 |
+| `TransactionRecordMapper` | `BaseMapper<TransactionRecord>` | 无 | — |
+| `StatisticsMapper` | 无(不是实体 Mapper) | 4 个统计方法 | 全部 `@Select` 自定义 SQL |
+
+### 6.2 自定义 SQL
+
+#### BookMapper.selectSalesByBookId()
+
+```sql
+SELECT b.book_id, b.title, t.buyer_id, u.nickname AS buyerName,
+       t.transaction_num AS quantity, t.transaction_price AS totalPrice,
+       t.transaction_time
+FROM transaction_record t
+JOIN book b ON t.book_id = b.book_id
+JOIN user u ON t.buyer_id = u.userid
+WHERE b.book_id = #{bookId}
+ORDER BY t.transaction_time DESC
+```
+
+#### StatisticsMapper
+
+| 方法 | SQL |
+|------|-----|
+| `selectSummary()` | `SELECT COALESCE(SUM(transaction_price), 0), COUNT(*) FROM transaction_record` |
+| `selectTopDepartments()` | JOIN `transaction_record` + `book` + `user`,按 `user.dept` 分组,销售额前 3 |
+| `selectTopBooks()` | JOIN `transaction_record` + `book`,按 `book` 分组,销量前 5 |
+| `selectDeptDiscountRates()` | `AVG((original_price - unit_price) / original_price * 100)`,按 `dept` 分组 |
+
+---
+
+## 7. 统一响应与分页
+
+### 7.1 响应格式
+
+所有 API 返回统一 JSON:
+
+```json
+{
+  "code": 200,
+  "message": "success",
+  "data": { ... }
+}
+```
+
+| code | 含义 |
+|:----:|------|
+| 200 | 成功 |
+| 400 | 业务错误(参数错误、库存不足、用户名已存在等) |
+| 500 | 服务器内部错误 |
+
+### 7.2 分页机制
+
+```
+Client → GET /api/book?keyword=&category=&page=1&size=20
+Server → MyBatis-Plus Page + LambdaQueryWrapper
+       → PaginationInnerInterceptor 自动拦截改写 SQL
+       → 返回 IPage<Book> → 转换为 PageResult<Book>
+Client → FXCollections.observableArrayList(records) → TableView
+```
+
+分页查询步骤:
+1. Controller 接收 page 和 size 参数(默认 page=1, size=20)
+2. 构建 `Page<T>` 对象 + `LambdaQueryWrapper` 条件
+3. MyBatis-Plus 分页插件自动添加 `LIMIT` 和 `COUNT` 子句
+4. 返回 `IPage<T>`,包含 records、total、size、current
+
+---
+
+## 8. 运行配置
+
+### 8.1 application.yml
+
+```yaml
+server:
+  port: 8080
+  servlet:
+    context-path: /api
+
+spring:
+  datasource:
+    url: jdbc:mysql://localhost:3306/campus_book_trade?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
+    username: root
+    password: root
+    driver-class-name: com.mysql.cj.jdbc.Driver
+
+mybatis-plus:
+  configuration:
+    map-underscore-to-camel-case: true
+  global-config:
+    db-config:
+      id-type: auto
+```
+
+### 8.2 启动入口
+
+`ServerApplication.java`:
+- `@SpringBootApplication` + `@MapperScan("space.anyi.server.mapper")`
+- 运行 `main()` 监听 8080 端口
+
+### 8.3 构建与运行
+
+```sh
+# 全量构建
+JAVA_HOME=/home/yangyi/.jdks/corretto-23.0.2 mvn clean install
+
+# 单独启动服务端
+mvn spring-boot:run -pl server
+```
+
+---
+
+## 9. 已实现功能清单与代码位置
+
+### 9.1 基础功能
+
+| 功能 | Controller | Service 实现 | Mapper |
+|------|-----------|-------------|--------|
+| 登录 | `UserController.java:22` | `UserServiceImpl.java:15` | `UserMapper` (BaseMapper) |
+| 注册 | `UserController.java:31` | `UserServiceImpl.java:22` | `UserMapper` (BaseMapper) |
+| 用户 CRUD | `UserController.java:44-70` | `ServiceImpl` 继承 | `UserMapper` (BaseMapper) |
+| 书籍搜索 | `BookController.java:22` | `BookServiceImpl.java:24` | `BookMapper` (BaseMapper) |
+| 书籍 CRUD | `BookController.java:38-98` | `ServiceImpl` 继承 | `BookMapper` (BaseMapper) |
+| 购买交易 | `TransactionController.java:22` | `TransactionServiceImpl.java:26` | `TransactionRecordMapper` + `BookMapper` |
+| 交易 CRUD | `TransactionController.java:35-66` | `ServiceImpl` 继承 | `TransactionRecordMapper` (BaseMapper) |
+| 统计数据 | `StatisticsController.java` | `StatisticsServiceImpl.java` | `StatisticsMapper.java`(4 个 @Select) |
+
+### 9.2 扩展功能
+
+| 功能 | Controller | Service 实现 | Mapper |
+|------|-----------|-------------|--------|
+| 销售记录 | `BookController.java:56` | `BookServiceImpl.java:52` | `BookMapper.selectSalesByBookId()` |
+| 待审核书籍 | `BookController.java:61` | `BookServiceImpl.java:57` | `BookMapper` (BaseMapper) |
+| 审核书籍 | `BookController.java:66` | —(直接在 Controller 中操作) | `BookMapper` (BaseMapper) |
+| AI 分析 | `AiController.java` | `AiServiceImpl.java` | —(依赖 StatisticsService) |
+
+---
+
+## 10. 设计补充说明
+
+### 10.1 数据库约束
+
+- 未显式声明外键约束,由应用层保证数据一致性
+- `transaction_record` 和 `book` 的 `price` 字段使用 `decimal(10,2)` 确保精度
+
+### 10.2 安全性
+
+- 当前无 Token/JWT 机制,userId 通过请求体或参数明文传输
+- 密码明文存储,后续建议引入加密和 Spring Security
+
+### 10.3 待扩展
+
+- 分页返回类型不一致:用户模块使用 `IPage<User>`,书籍模块使用 `PageResult<Book>`,建议统一
+- `@Transactional` 仅应用于购买流程,其他批量操作未加事务
+- 服务端未实现权限拦截,所有 API 均可被任意客户端调用