- Dockerfile 改为 Node 24 运行时:Vike 产物 + Go API 二进制共用镜像 - docker-compose 双容器:web(:3000 对外 SSR) + api(:3001 内部,持 /data 卷) - entrypoint 改用 gosu 降权(Debian 基础镜像),健康检查用 node fetch - Makefile/build.ps1:build 不再打包前端,新增 serve(本地双进程)与 web-build - README 同步双服务架构、端口/环境变量、部署与开发说明
490 lines
18 KiB
Markdown
490 lines
18 KiB
Markdown
<div align="center">
|
||
|
||
# 姜十三论坛 Jiang13 Forum
|
||
|
||
**能聊 · 好看 · 好装**
|
||
|
||
面向小圈子、团队与同好社群的轻量现代化论坛。
|
||
编译为单个 Go 二进制,前端 SPA(单页应用)内嵌,内置 SQLite,拷到服务器即可运行。
|
||
|
||
<br>
|
||
|
||
[](https://bbs.iioio.com/)
|
||
[](LICENSE)
|
||
[](https://hub.docker.com/r/hangzhang714128/jiang13-forum)
|
||
[](go.mod)
|
||
[](frontend/package.json)
|
||
[](#)
|
||
|
||
[在线演示](https://bbs.iioio.com/) ·
|
||
[快速开始](#-快速开始) ·
|
||
[界面预览](#-界面预览) ·
|
||
[功能亮点](#-功能亮点) ·
|
||
[更新日志](docs/site-posts/changelog.md) ·
|
||
[路线图](ROADMAP.md) ·
|
||
[参与贡献](CONTRIBUTING.md)
|
||
|
||
<br>
|
||
|
||
<img src="docs/screenshots/home-light.png" alt="姜十三论坛首页 - 浅色主题三栏布局" width="92%">
|
||
|
||
<sub>浅色主题 · 三栏布局 · Feed 排序 · 板块导航 · 标签云</sub>
|
||
|
||
<br>
|
||
|
||
> **演示站点:** [https://bbs.iioio.com/](https://bbs.iioio.com/)
|
||
> 项目积极开发中。管理后台已统一为 React SPA(`/admin`),欢迎提 Issue / PR 共建。
|
||
|
||
</div>
|
||
|
||
---
|
||
|
||
## 它是什么
|
||
|
||
姜十三论坛不做大而全的社区平台,只做好一件事:给「几人到几百人」的内部交流,一个干净、顺手、数据在自己手里的地方。
|
||
|
||
| 场景 | 说明 |
|
||
|------|------|
|
||
| 团队 / 工作室 | 需求讨论、进度同步、知识沉淀 |
|
||
| 兴趣小圈子 | 同好交流、作品分享、活动组织 |
|
||
| 项目配套社区 | 可与 Gitea 等通过 OIDC(开放身份连接)做 SSO(单点登录) |
|
||
| 个人站长 | 单机可跑,无需云数据库与一堆微服务 |
|
||
|
||
---
|
||
|
||
## 界面预览
|
||
|
||
截图来自演示站 [bbs.iioio.com](https://bbs.iioio.com/)。
|
||
|
||
<table>
|
||
<tr>
|
||
<td width="50%" align="center">
|
||
<img src="docs/screenshots/home-light.png" alt="浅色主题首页" width="100%">
|
||
<br><b>浅色主题</b><br>
|
||
<sub>左栏板块 · Feed 排序 · 右栏热门 / 标签 / 评论</sub>
|
||
</td>
|
||
<td width="50%" align="center">
|
||
<img src="docs/screenshots/home-dark.png" alt="暗色主题首页" width="100%">
|
||
<br><b>暗色主题</b><br>
|
||
<sub>一键切换 · 护眼阅读 · 全局色彩自适应</sub>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td width="50%" align="center">
|
||
<img src="docs/screenshots/post-detail.png" alt="帖子详情页" width="100%">
|
||
<br><b>帖子详情</b><br>
|
||
<sub>文章目录 · 标签 · 作者卡片 · 修订信息</sub>
|
||
</td>
|
||
<td width="50%" align="center">
|
||
<img src="docs/screenshots/post-rich.png" alt="富文本与代码高亮" width="100%">
|
||
<br><b>富文本渲染</b><br>
|
||
<sub>TipTap 排版 · 图片 · 代码高亮 · 目录导航</sub>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<p align="center">
|
||
<img src="docs/screenshots/mobile-home.png" alt="移动端首页" width="280">
|
||
<br><b>移动端</b> — 板块快捷筛选 · Feed 排序 · 触控友好列表
|
||
</p>
|
||
|
||
---
|
||
|
||
## 功能亮点
|
||
|
||
### 界面与交互
|
||
|
||
| 特性 | 说明 |
|
||
|------|------|
|
||
| **三栏布局** | 左栏板块导航 + 中间虚拟滚动帖列表 + 右栏热门 / 标签 / 最新评论 |
|
||
| **虚拟滚动** | `@tanstack/react-virtual` 驱动长列表,浏览依然流畅 |
|
||
| **帖子排序** | 最新发帖 / 最新回复 / 热门讨论 |
|
||
| **主题切换** | 浅色 / 暗色,跟随系统偏好并本地记忆 |
|
||
| **响应式** | 平板 / 手机自动收起侧栏,搜索、发帖、登录触手可及 |
|
||
|
||
### 社区功能
|
||
|
||
- 用户注册 / 登录(bcrypt + JWT Cookie);**首个注册用户自动成为管理员**
|
||
- 板块、发帖、TipTap 富文本、正文图片上传、标签、置顶 / 精华
|
||
- 帖子修订历史与 diff(差异)对比;可配置普通用户编辑时限
|
||
- 楼层式评论:回复指定楼层、@ 高亮、引用回复;支持回复可见等内容门控
|
||
- 点赞、收藏、热门帖、最新评论、站内私信、公开用户主页
|
||
- 管理后台:仪表盘、删帖 / 删评、禁言、举报、敏感词、限流、SQLite 一键备份
|
||
- 可选:邮件验证码、OIDC Provider、Gitea 仓库同步(开源码桶)、S3 兼容对象存储
|
||
|
||
### 部署体验
|
||
|
||
- **双服务架构** — Node(:3000 对外:SSR + 静态资源 + API 反代)+ Go(:3001 内部:纯 API),职责单一、可独立扩缩
|
||
- **服务端渲染** — 首页 / 板块 / 帖子详情由 Vike SSR 真渲染,SEO 友好、首屏直出;其余页面 SPA 接管
|
||
- **零依赖数据库** — SQLite 内建,数据目录由 `app.ini` 统一管理
|
||
- **跨平台** — Windows / Linux / macOS 一键编译 Go API
|
||
- **系统服务** — 内置 Linux systemd / Windows Service 注册
|
||
- **Docker 双容器** — 同一镜像两种角色,`docker compose up` 一键起
|
||
|
||
---
|
||
|
||
## 快速开始
|
||
|
||
### 1. 编译
|
||
|
||
Go API 二进制(不含前端,Windows):
|
||
|
||
```bat
|
||
build.bat
|
||
```
|
||
|
||
> 请通过 `build.bat` 调用(内部已处理 ExecutionPolicy)。不要直接 `.\build.ps1`,也不要在 Windows 上使用系统自带的 Embarcadero `make`。
|
||
|
||
**Linux / macOS:**
|
||
|
||
```bash
|
||
make build
|
||
```
|
||
|
||
**手动分步(全平台):**
|
||
|
||
```bash
|
||
go build -trimpath -ldflags "-s -w" -o dist/jiang13 ./cmd/jiang13
|
||
```
|
||
|
||
前端构建(Vike,产出 `frontend/dist/client` + `dist/server`):
|
||
|
||
```bash
|
||
cd frontend && npm install && npm run build
|
||
```
|
||
|
||
本地生产模式一键起双服务(Node :3000 对外 + Go API :3001):
|
||
|
||
```bash
|
||
make serve # Linux / macOS
|
||
build.bat -Target serve # Windows
|
||
```
|
||
|
||
跨平台编译:
|
||
|
||
```bat
|
||
build.bat -Target build-windows
|
||
build.bat -Target build-linux
|
||
build.bat -Target build-all
|
||
```
|
||
|
||
### 2. Docker 部署(推荐)
|
||
|
||
**一键启动(本地构建):**
|
||
|
||
```bash
|
||
docker compose up -d --build
|
||
```
|
||
|
||
```bat
|
||
.\build.bat -Target compose-up
|
||
```
|
||
|
||
```bash
|
||
make compose-up
|
||
```
|
||
|
||
浏览器打开 `http://localhost:3000/register` 注册;**首个用户自动成为管理员**。
|
||
|
||
版本变更与升级说明见 **[更新日志](docs/site-posts/changelog.md)**。Docker 与 Windows / Linux 单文件共用同一版本号。
|
||
|
||
- Docker 标签:[hub.docker.com/r/hangzhang714128/jiang13-forum/tags](https://hub.docker.com/r/hangzhang714128/jiang13-forum/tags)
|
||
- 预编译包:[Gitea Releases](https://git.iioio.com/freefire/jiang13-forum/releases)
|
||
|
||
**拉取已构建镜像(Docker Hub):**
|
||
|
||
同一镜像两种角色,建议直接用 `docker-compose.yml`(已含完整配置):
|
||
|
||
```bash
|
||
docker pull hangzhang714128/jiang13-forum:latest
|
||
docker compose up -d
|
||
```
|
||
|
||
Compose 会启动两个容器:
|
||
|
||
| 容器 | 角色 | 端口 | 说明 |
|
||
|------|------|------|------|
|
||
| `web` | Node 渲染服务器 | `3000` 对外 | Vike SSR + 静态资源 + API 反代(`GO_API_URL=http://api:3001`) |
|
||
| `api` | Go API | `3001` 内部 | 纯 API 服务,持有 `/data` 数据卷 |
|
||
|
||
**数据持久化:** `api` 容器内 `/data` 对应 SQLite、上传、日志与 JWT 密钥,与下方「数据目录」结构一致。可用 Docker volume 或绑定宿主机目录。镜像启动时会自动将 `/data` 卷属主修正为 uid `1000`,适配 1Panel 等面板挂载的目录。
|
||
|
||
**若使用旧版镜像仍报 permission denied**,可在宿主机执行:`chown -R 1000:1000 /你的数据目录`
|
||
|
||
**可选环境变量(容器编排):**
|
||
|
||
| 变量 | 容器 | 说明 |
|
||
|------|------|------|
|
||
| `GO_API_URL` | web | Go API 地址(默认 `http://127.0.0.1:3001`,Compose 中为 `http://api:3001`) |
|
||
| `PORT` | web | Node 渲染服务器监听端口(默认 `3000`) |
|
||
| `JIANG13_HTTP_PORT` | api | HTTP 端口(默认 `3000`,Compose 中为 `3001`) |
|
||
| `JIANG13_DATA` | api | 数据目录(默认 `/data`) |
|
||
| `JIANG13_JWT_SECRET` | api | JWT 密钥(留空则自动生成并写入 `/data/.jwt_secret`) |
|
||
| `JIANG13_CONFIG` | api | 配置文件路径 |
|
||
| `JIANG13_WORK_PATH` | api | 工作目录 |
|
||
| `JIANG13_COMMUNITY_HUB` | api | 维护者选项:设为 `1` 时本站作为社区枢纽收报。官方站 `bbs.iioio.com` 会按域名自动成为枢纽,无需此变量;仅非官网的枢纽镜像 / 预发需要显式开启(见 `app.ini.example`) |
|
||
|
||
**健康检查:** Go API `GET /health`、Node 渲染服务器 `GET /healthz`,均返回 200,供 Docker / 负载均衡探活。
|
||
|
||
**发布镜像到 Docker Hub(手动):**
|
||
|
||
```bash
|
||
docker login
|
||
.\build.bat -Target docker # Windows
|
||
# make docker # Linux/macOS
|
||
docker push hangzhang714128/jiang13-forum:1.1.7
|
||
docker push hangzhang714128/jiang13-forum:latest
|
||
```
|
||
|
||
或直接构建:
|
||
|
||
```bash
|
||
docker build --build-arg VERSION=1.1.7 -t hangzhang714128/jiang13-forum:1.1.7 -t hangzhang714128/jiang13-forum:latest .
|
||
docker push hangzhang714128/jiang13-forum:1.1.7
|
||
docker push hangzhang714128/jiang13-forum:latest
|
||
```
|
||
|
||
停止服务:`docker compose down` / `.\build.bat -Target compose-down` / `make compose-down`
|
||
|
||
**构建失败(无法连接 auth.docker.io)?** Dockerfile 已默认经 DaoCloud 拉取基础镜像。若仍超时,可在 Docker Desktop → Settings → Docker Engine 添加:
|
||
|
||
```json
|
||
{
|
||
"registry-mirrors": ["https://docker.m.daocloud.io"]
|
||
}
|
||
```
|
||
|
||
保存并重启 Docker 后重试 `.\build.bat -Target docker`。PowerShell 中请用 `.\build.bat`(带 `.\` 前缀)。
|
||
|
||
**1Panel 部署提示:**
|
||
|
||
1. 用 Compose 编排(`docker-compose.yml`)或手动创建两个容器:`api`(Go,内部 `3001`,挂载 `/data`)与 `web`(Node,映射 `3000:3000`)
|
||
2. `web` 容器环境变量 `GO_API_URL` 指向 `api` 容器(如 `http://api:3001`)
|
||
3. 数据卷只需挂在 `api` 容器的 `/data`(镜像会自动修正目录权限)
|
||
4. 首次访问 `http://服务器IP:3000/register` 注册管理员
|
||
|
||
### 3. 直接启动(二进制)
|
||
|
||
Go 二进制仅提供 API,完整站点需同时运行 Node 渲染服务器(构建前端后 `frontend/server/index.mjs`)。最简单的方式是用上面的 Docker Compose,或本地 `make serve` / `build.bat -Target serve` 一键起双进程。
|
||
|
||
如需手动部署二进制,从 [Gitea Releases](https://git.iioio.com/freefire/jiang13-forum/releases) 下载与 Docker 同版本号的文件:
|
||
|
||
| 文件 | 平台 |
|
||
|------|------|
|
||
| `jiang13-*-windows-amd64.exe` | Windows x64 |
|
||
| `jiang13-*-linux-amd64` | Linux x64 |
|
||
|
||
当前 **1.1.7:** [Windows](https://git.iioio.com/freefire/jiang13-forum/releases/download/v1.1.7/jiang13-1.1.7-windows-amd64.exe) · [Linux](https://git.iioio.com/freefire/jiang13-forum/releases/download/v1.1.7/jiang13-1.1.7-linux-amd64)
|
||
|
||
两个进程一起跑(Go API :3001 + Node :3000 对外):
|
||
|
||
```bash
|
||
# 1) 启动 Go API
|
||
./jiang13 --port 3001 --data ./data
|
||
|
||
# 2) 另开终端,构建并启动 Node 渲染服务器
|
||
cd frontend && npm install && npm run build
|
||
PORT=3000 GO_API_URL=http://127.0.0.1:3001 npm start
|
||
```
|
||
|
||
Windows:
|
||
|
||
```powershell
|
||
.\jiang13.exe --port 3001 --data .\data
|
||
# 另开 PowerShell:
|
||
cd frontend; npm install; npm run build
|
||
$env:PORT = '3000'; $env:GO_API_URL = 'http://127.0.0.1:3001'; npm start
|
||
```
|
||
|
||
### 4. 首次使用
|
||
|
||
1. 浏览器打开 `http://localhost:3000/register` 注册账号
|
||
2. **第一个注册的用户自动成为管理员**
|
||
3. 登录后访问 `http://localhost:3000/admin` 进入后台
|
||
|
||
### 配置文件(`app.ini`)
|
||
|
||
默认读取**工作目录**下的 `app.ini`(工作目录默认可执行文件所在目录)。
|
||
|
||
```ini
|
||
[server]
|
||
HTTP_PORT = 3000
|
||
|
||
[paths]
|
||
DATA = data
|
||
|
||
[security]
|
||
JWT_SECRET =
|
||
```
|
||
|
||
完整示例见 [`app.ini.example`](app.ini.example)。OIDC、邮件、Gitea 同步、对象存储等请在管理后台「系统设置」配置(保存即生效)。
|
||
|
||
**优先级:** 命令行显式参数 > `app.ini` > 内置默认值。
|
||
|
||
### 启动参数
|
||
|
||
| 参数 | 默认值 | 说明 |
|
||
|------|--------|------|
|
||
| `--work-path` | 可执行文件目录 | 工作目录(`app.ini` 与相对 `DATA` 的基准) |
|
||
| `--config` | `{work-path}/app.ini` | 配置文件路径 |
|
||
| `--port` | (读配置 / `3000`) | HTTP 监听端口 |
|
||
| `--data` | (读配置 / `data`) | 数据目录 |
|
||
| `--jwt-secret` | 自动生成 | JWT 签名密钥(留空则持久化到 `data/.jwt_secret`) |
|
||
| `--service` | (空) | `install` / `uninstall` / `start` / `stop` / `restart` / `status` |
|
||
|
||
**环境变量(容器 / 编排,优先级低于命令行):** `JIANG13_HTTP_PORT`、`JIANG13_DATA`、`JIANG13_JWT_SECRET`、`JIANG13_CONFIG`、`JIANG13_WORK_PATH`、`JIANG13_COMMUNITY_HUB`(非官网枢纽镜像用;`bbs.iioio.com` 按域名自动为枢纽,见上表)
|
||
|
||
### 5. 注册为系统服务(可选)
|
||
|
||
将二进制与 `app.ini` 放到同一目录后注册即可。之后改端口或数据目录只需编辑 `app.ini` 并重启服务,不必重新安装。
|
||
|
||
**Ubuntu / Linux(systemd,需 root):**
|
||
|
||
```bash
|
||
sudo mkdir -p /opt/jiang13
|
||
sudo cp jiang13 /opt/jiang13/
|
||
sudo /opt/jiang13/jiang13 --service install
|
||
sudo /opt/jiang13/jiang13 --service start
|
||
sudo systemctl enable jiang13
|
||
```
|
||
|
||
**Windows(Windows Service,需管理员 PowerShell):**
|
||
|
||
```powershell
|
||
New-Item -ItemType Directory -Force -Path C:\jiang13 | Out-Null
|
||
Copy-Item .\jiang13.exe C:\jiang13\
|
||
C:\jiang13\jiang13.exe --service install
|
||
C:\jiang13\jiang13.exe --service start
|
||
```
|
||
|
||
> 改 `app.ini` 后执行 `--service restart`。运行日志写入数据目录下的 `jiang13.log`。
|
||
|
||
---
|
||
|
||
## 技术栈
|
||
|
||
| 层级 | 技术 |
|
||
|------|------|
|
||
| **后端** | Go 1.26 · Gin · GORM · SQLite(纯 API 服务) |
|
||
| **前端** | React 19 · Vike SSR · react-router · TipTap · Radix UI · Tailwind CSS · TanStack Virtual |
|
||
| **构建** | Vite 8(Rolldown)双构建:`dist/client` 静态资源 + `dist/server` SSR 入口 |
|
||
| **渲染** | Node 24 · Express + Vike `renderPage`(:3000 对外,API 反代至 Go :3001) |
|
||
| **认证** | bcrypt · JWT Cookie · 可选 OIDC Provider |
|
||
|
||
---
|
||
|
||
## 前端开发
|
||
|
||
日常改前端不需要重新完整构建,Vike dev 支持秒级热更新(HMR,热模块替换):
|
||
|
||
```bat
|
||
build.bat -Target dev
|
||
```
|
||
|
||
```bash
|
||
make dev
|
||
```
|
||
|
||
浏览器访问 `http://localhost:5173`,API 自动代理到 `http://localhost:3000`。首页 / 板块 / 帖子详情在 dev 下同样走 SSR(`vike dev`),与生产行为一致;其余页面为 SPA 壳。
|
||
|
||
开发后端与 `dist/jiang13` 共用数据目录 `dist/data`(SQLite、上传、JWT 密钥等),避免 dev 与 dist 运行数据不一致。
|
||
|
||
**何时需要完整构建:**
|
||
|
||
- 修改 Go 代码 → `build.bat` / `make build`(仅编译 Go API)
|
||
- 验证生产 SSR / 发布部署 → `make serve`(构建前端 + 双进程起本地产)
|
||
- 更新 README 界面截图 → 见下方「更新截图」
|
||
|
||
> 开发时请访问 `:5173`;`:3000` 只有在生产模式(Node 渲染服务器)下才有页面。
|
||
|
||
### 更新截图
|
||
|
||
默认从演示站抓取到 `docs/screenshots/`(需本机已安装 Playwright):
|
||
|
||
```bash
|
||
npm install -D playwright
|
||
npx playwright install chromium
|
||
node scripts/capture-screenshots.mjs
|
||
```
|
||
|
||
| 环境变量 | 说明 | 默认 |
|
||
|----------|------|------|
|
||
| `J13_URL` | 抓取目标 | `https://bbs.iioio.com` |
|
||
| `J13_POST_ID` | 详情页帖子 ID | `1` |
|
||
| `J13_RICH_POST_ID` | 富文本展示帖 ID | `8` |
|
||
| `J13_USER` / `J13_PASS` | 发帖页登录(可选) | `admin` / `admin123` |
|
||
|
||
本地站点示例:`J13_URL=http://localhost:3000 node scripts/capture-screenshots.mjs`
|
||
|
||
---
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
jiang13-forum/
|
||
├── cmd/jiang13/ # 程序入口(含系统服务注册)
|
||
├── config/ # app.ini 与命令行配置
|
||
├── app.ini.example # 配置文件示例
|
||
├── Dockerfile # 多阶段构建(前端 + Go API 共用镜像,双容器运行)
|
||
├── docker-compose.yml # 双容器 Compose 部署(web :3000 + api :3001)
|
||
├── docker-entrypoint.sh # api 容器启动脚本(修正 /data 卷权限)
|
||
├── .dockerignore
|
||
├── model/ # GORM 模型与数据库迁移
|
||
├── service/ # 业务逻辑
|
||
├── handler/ # HTTP 处理器(API + /api/home-boot SSR 聚合端点)
|
||
├── middleware/ # JWT 鉴权等
|
||
├── router/ # 路由注册(仅 API)
|
||
├── frontend/
|
||
│ ├── pages/ # Vike 页面(feed=SSR 白名单 / spa=catch-all 壳 / _error)
|
||
│ ├── renderer/ # Vike 双端渲染入口(onRenderHtml / onRenderClient)
|
||
│ ├── server/ # Node 渲染服务器(express + renderPage + API 反代)
|
||
│ └── src/ # React 源码(含 src/ssr 服务端取数与作用域管理)
|
||
├── docs/screenshots/ # README 界面截图
|
||
├── ROADMAP.md # 路线图与已知问题
|
||
└── scripts/ # 开发辅助脚本(含截图)
|
||
```
|
||
|
||
---
|
||
|
||
## 数据目录
|
||
|
||
```
|
||
data/
|
||
├── jiang13.db # SQLite 主数据库(不含浏览量)
|
||
├── monitor.db # 网站监控 page_views
|
||
├── jiang13.log # 运行日志
|
||
├── filter_words.txt # 敏感词配置
|
||
├── .jwt_secret # JWT 密钥(自动生成)
|
||
├── logs/access/ # 网站监控请求日志(按日 jsonl)
|
||
├── uploads/avatars/ # 用户头像
|
||
├── uploads/posts/ # 帖子正文图片
|
||
└── jiang13_backup_*.db # 后台导出的主库备份
|
||
```
|
||
|
||
---
|
||
|
||
## 开发状态
|
||
|
||
项目**积极开发中**,欢迎参与共建。完整列表见 **[ROADMAP.md](ROADMAP.md)**。
|
||
|
||
| 类型 | 示例 |
|
||
|------|------|
|
||
| ✅ 已可用 | 三栏布局、暗色主题、虚拟滚动、Feed 排序、楼层评论 |
|
||
| ✅ 发帖体验 | TipTap 富文本、图片上传、修订历史、回复可见等门控 |
|
||
| ✅ 管理后台 | React SPA:仪表盘、置顶 / 精华、禁言、系统设置 |
|
||
| 📋 计划中 | 通知动态优化、邮件提醒 |
|
||
|
||
---
|
||
|
||
## 参与贡献
|
||
|
||
欢迎提交 Issue 和 Pull Request!详见 [CONTRIBUTING.md](CONTRIBUTING.md)。
|
||
|
||
在线体验与反馈也可直接在演示站进行:[https://bbs.iioio.com/](https://bbs.iioio.com/)
|
||
|
||
---
|
||
|
||
## 许可证
|
||
|
||
[MIT](LICENSE) — 自由使用、修改与分发。
|