commit 3d175d75af395888224f4f626d7fee4256a2d25e Author: yfan Date: Fri Jan 30 16:57:44 2026 +0800 first commit diff --git a/.cnb.yml b/.cnb.yml new file mode 100644 index 0000000..3437d23 --- /dev/null +++ b/.cnb.yml @@ -0,0 +1,5 @@ +include: + - https://cnb.cool/ilay1678/templates/-/blob/main/ci/docker.cnb.yml + - https://cnb.cool/ilay1678/templates/-/blob/main/ci/docker.ghcr.yml + - https://cnb.cool/ilay1678/templates/-/blob/main/ci/sync_to_github.yml + - https://cnb.cool/ilay1678/templates/-/blob/main/ci/ide.node.yml \ No newline at end of file diff --git a/.cnb/web_trigger.yml b/.cnb/web_trigger.yml new file mode 100644 index 0000000..f14d29c --- /dev/null +++ b/.cnb/web_trigger.yml @@ -0,0 +1,14 @@ +branch: + # 如下按钮在分支名以 release 开头的分支详情页面显示 + - reg: "^main" + buttons: + - name: 构建 + # 如存在,则将作为流水线 title,否则流水线使用默认 title + description: 构建docker镜像 + event: web_trigger # 触发的 CI 事件名 + # 权限控制,不配置则有仓库写权限的用户可触发构建 + # 如果配置,则需要有仓库写权限,并且满足 roles 或 users 其中之一才有权限触发构建 + permissions: + # roles 和 users 配置其中之一或都配置均可,二者满足其一即可 + roles: + - owner \ No newline at end of file diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e8d8a77 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,20 @@ +node_modules +.next +.git +.github +.dockerignore +Dockerfile +build-and-push.sh +.DS_Store +*.log +.env +.env.* +.wrangler +.dev.vars +.vercel +.open-next +.cursor +.ai_memory +.claude +.fleet +.idea diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..7d83a28 --- /dev/null +++ b/.env.example @@ -0,0 +1,6 @@ +# 测试点生成 - 阿里云通义大模型(可选) +# 配置后将优先使用 AI 生成测试用例,失败时自动回退到本地智能算法 +ENABLE_AI=true +DASHSCOPE_API_KEY=sk-xxxxxxxxxxxxxxxx +# 可选,默认 qwen-max +# QWEN_MODEL=qwen-max diff --git a/.github/workflows/clean-up.yml b/.github/workflows/clean-up.yml new file mode 100644 index 0000000..bf1cd7a --- /dev/null +++ b/.github/workflows/clean-up.yml @@ -0,0 +1,51 @@ +name: Delete old workflow runs +on: + schedule: + - cron: '0 0 * * *' + +jobs: + del_runs: + runs-on: ubuntu-latest + if: github.event.repository.fork == false + permissions: + actions: write + contents: read + id-token: write + steps: + - name: Delete workflow runs + uses: Mattraks/delete-workflow-runs@v2 + with: + token: ${{ github.token }} + repository: ${{ github.repository }} + retain_days: 30 + keep_minimum_runs: 6 + + # Points to a recent commit instead of `main` to avoid supply chain attacks. (The latest tag is very old.) + - name: 🎟 Get GitHub App token + uses: actions/create-github-app-token@v1 + id: get-token + with: + app-id: ${{ secrets.GH_APP_ID }} + private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} + + - name: Delete workflow runs for current repo + uses: Mattraks/delete-workflow-runs@v2 + with: + token: ${{ github.token }} + repository: ${{ github.repository }} + retain_days: 7 + keep_minimum_runs: 6 + + - name: Delete deployment + uses: strumwolf/delete-deployment-environment@v2.3.0 + with: + token: ${{ steps.get-token.outputs.token }} + environment: Preview + onlyRemoveDeployments: true + + - name: Delete MAIN deployment + uses: strumwolf/delete-deployment-environment@v2.3.0 + with: + token: ${{ steps.get-token.outputs.token }} + environment: Production + onlyRemoveDeployments: true \ No newline at end of file diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml new file mode 100644 index 0000000..97387db --- /dev/null +++ b/.github/workflows/docker-build.yml @@ -0,0 +1,75 @@ +name: Build and Push Docker Image + +on: + push: + branches: + - main + paths-ignore: + - 'README.md' + - '.cnb.yml' + - '.gitignore' + - '.github/workflows/clean-up.yml' + - '.cnb/web_trigger.yml' + pull_request: + branches: + - main + paths-ignore: + - 'README.md' + - '.gitignore' + - '.cnb.yml' + - '.github/workflows/clean-up.yml' + - '.cnb/web_trigger.yml' +permissions: + contents: read + packages: write + id-token: write + actions: write + +jobs: + build: + runs-on: ubuntu-latest + if: github.event.repository.fork == false + steps: + + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log into GHCR + uses: docker/login-action@master + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ github.token }} + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: set lower case owner name + run: | + echo "OWNER_LC=${OWNER,,}" >>${GITHUB_ENV} + env: + OWNER: "${{ github.repository_owner }}" + + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64,linux/arm64/v8 + file: ./Dockerfile + push: true + tags: | + ghcr.io/${{ env.OWNER_LC }}/i-tools:latest + ${{ vars.DOCKERHUB_USERNAME }}/i-tools:latest + + - name: Post build cleanup + run: docker builder prune --force diff --git a/.github/workflows/sync-to-cnb.yml b/.github/workflows/sync-to-cnb.yml new file mode 100644 index 0000000..07c1807 --- /dev/null +++ b/.github/workflows/sync-to-cnb.yml @@ -0,0 +1,23 @@ +name: Sync to CNB +on: [push] + +jobs: + sync: + runs-on: ubuntu-latest + if: github.event.repository.fork == false + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Sync to CNB Repository + run: | + docker run --rm \ + -v ${{ github.workspace }}:${{ github.workspace }} \ + -w ${{ github.workspace }} \ + -e PLUGIN_TARGET_URL="https://cnb.cool/ilay1678/i-tools.git" \ + -e PLUGIN_AUTH_TYPE="https" \ + -e PLUGIN_USERNAME="cnb" \ + -e PLUGIN_PASSWORD=${{ secrets.CNB_TOKEN }} \ + -e PLUGIN_SYNC_MODE="rebase" \ + tencentcom/git-sync diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml new file mode 100644 index 0000000..8e95ee0 --- /dev/null +++ b/.github/workflows/sync.yml @@ -0,0 +1,36 @@ +name: Upstream Sync + +permissions: + contents: write + +on: + schedule: + - cron: "0 4 * * *" # At 12PM UTC+8 + workflow_dispatch: + +jobs: + sync_latest_from_upstream: + name: Sync latest commits from upstream repo + runs-on: ubuntu-latest + if: ${{ github.repository != 'iLay1678/i-tools' }} + + steps: + # Step 1: run a standard checkout action + - name: Checkout target repo + uses: actions/checkout@v4 + + # Step 2: run the sync action + - name: Sync upstream changes + id: sync + uses: aormsby/Fork-Sync-With-Upstream-action@v3.4.1 + with: + upstream_sync_repo: iLay1678/i-tools + upstream_sync_branch: main + target_sync_branch: main + target_repo_token: ${{ github.token }} + + - name: Sync check + if: failure() + run: | + echo "[Error] Due to a change in the workflow file of the upstream repository, GitHub has automatically suspended the scheduled automatic update. You need to manually sync your fork." + exit 1 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c3cd3e4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# Nuxt dev/build outputs +.output +.data +.nuxt +.nitro +.cache +dist + +# Node dependencies +node_modules + +# Logs +logs +*.log + +# Misc +.DS_Store +.fleet +.idea + +# Local env files +.env +.env.* +!.env.example + +# wrangler files +.wrangler +.dev.vars +.vercel +.next +.open-next +.spec-workflow +.claude +.ai_memory \ No newline at end of file diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..2a393af --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +20.18.0 diff --git a/DEPLOY.md b/DEPLOY.md new file mode 100644 index 0000000..726ff97 --- /dev/null +++ b/DEPLOY.md @@ -0,0 +1,250 @@ +# 信奥工具箱 - 服务器部署指南 + +## 前置要求 + +1. **服务器环境** + - Linux 系统(推荐 Ubuntu 20.04+ 或 CentOS 7+) + - Docker 已安装(版本 20.10+) + - Docker Compose 已安装(可选,推荐) + +2. **网络访问** + - 能够访问阿里云镜像仓库:`registry.cn-hangzhou.aliyuncs.com` + - 服务器端口开放(默认 3000 端口) + +## 快速部署 + +### 方法一:使用 Docker Compose(推荐) + +1. **登录阿里云镜像仓库** + ```bash + docker login --username=<您的用户名> registry.cn-hangzhou.aliyuncs.com + ``` + +2. **上传部署文件到服务器** + - `docker-compose.yml` + - `deploy.sh`(可选) + +3. **执行部署** + ```bash + # 使用部署脚本 + chmod +x deploy.sh + ./deploy.sh --compose + + # 或直接使用 docker-compose + docker-compose pull + docker-compose up -d + ``` + +4. **验证部署** + ```bash + # 查看容器状态 + docker-compose ps + + # 查看日志 + docker-compose logs -f + + # 访问服务 + curl http://localhost:3000 + ``` + +### 方法二:使用 Docker 命令 + +1. **登录阿里云镜像仓库** + ```bash + docker login --username=<您的用户名> registry.cn-hangzhou.aliyuncs.com + ``` + +2. **使用部署脚本** + ```bash + chmod +x deploy.sh + ./deploy.sh + ``` + +3. **或手动执行** + ```bash + # 拉取镜像 + docker pull registry.cn-hangzhou.aliyuncs.com/nick-x86/i-tools:latest + + # 停止并删除旧容器(如果存在) + docker stop i-tools 2>/dev/null || true + docker rm i-tools 2>/dev/null || true + + # 启动新容器 + docker run -d \ + --name i-tools \ + --restart unless-stopped \ + -p 3000:3000 \ + -e NODE_ENV=production \ + registry.cn-hangzhou.aliyuncs.com/nick-x86/i-tools:latest + ``` + +## 配置说明 + +### 端口配置 + +默认端口为 `3000`,如需修改: + +**Docker Compose 方式:** +编辑 `docker-compose.yml`,修改 `ports` 配置: +```yaml +ports: + - "8080:3000" # 主机端口:容器端口 +``` + +**Docker 命令方式:** +```bash +./deploy.sh -p 8080 +# 或 +docker run -d --name i-tools -p 8080:3000 ... +``` + +### 环境变量 + +可以在 `docker-compose.yml` 或 `docker run` 命令中添加环境变量: + +```yaml +environment: + - NODE_ENV=production + - PORT=3000 + # 添加其他环境变量 +``` + +## 常用操作 + +### 查看日志 +```bash +# Docker Compose +docker-compose logs -f i-tools + +# Docker 命令 +docker logs -f i-tools +``` + +### 重启服务 +```bash +# Docker Compose +docker-compose restart i-tools + +# Docker 命令 +docker restart i-tools +``` + +### 停止服务 +```bash +# Docker Compose +docker-compose stop i-tools + +# Docker 命令 +docker stop i-tools +``` + +### 更新部署 +```bash +# 使用部署脚本(推荐) +./deploy.sh --compose + +# 或手动更新 +docker-compose pull +docker-compose up -d +``` + +### 查看容器状态 +```bash +# Docker Compose +docker-compose ps + +# Docker 命令 +docker ps | grep i-tools +``` + +## Nginx 反向代理配置(可选) + +如果需要通过域名访问,可以配置 Nginx 反向代理: + +```nginx +server { + listen 80; + server_name your-domain.com; + + location / { + proxy_pass http://localhost:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + } +} +``` + +## 故障排查 + +### 容器无法启动 +```bash +# 查看详细日志 +docker logs i-tools + +# 检查端口是否被占用 +netstat -tulpn | grep 3000 +# 或 +lsof -i :3000 +``` + +### 无法访问服务 +1. 检查防火墙设置 + ```bash + # Ubuntu/Debian + sudo ufw allow 3000 + + # CentOS/RHEL + sudo firewall-cmd --add-port=3000/tcp --permanent + sudo firewall-cmd --reload + ``` + +2. 检查容器是否运行 + ```bash + docker ps | grep i-tools + ``` + +3. 检查端口映射 + ```bash + docker port i-tools + ``` + +### 镜像拉取失败 +1. 确认已登录镜像仓库 + ```bash + docker login registry.cn-hangzhou.aliyuncs.com + ``` + +2. 检查网络连接 + ```bash + ping registry.cn-hangzhou.aliyuncs.com + ``` + +## 资源限制 + +默认配置的资源限制: +- CPU: 0.5-1 核心 +- 内存: 256MB-512MB + +如需调整,编辑 `docker-compose.yml` 中的 `deploy.resources` 部分。 + +## 安全建议 + +1. **使用非 root 用户运行容器**(已在 Dockerfile 中配置) +2. **定期更新镜像**:`docker-compose pull && docker-compose up -d` +3. **配置防火墙**:只开放必要端口 +4. **使用 HTTPS**:通过 Nginx 配置 SSL 证书 +5. **监控日志**:定期检查容器日志 + +## 联系支持 + +如遇到问题,请检查: +1. Docker 版本是否符合要求 +2. 服务器资源是否充足 +3. 网络连接是否正常 +4. 查看容器日志获取详细错误信息 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ef44df7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,36 @@ +FROM node:20-alpine AS base + +FROM base AS deps +RUN apk add --no-cache libc6-compat +WORKDIR /app +COPY package.json package-lock.json ./ +# 提高超时与重试,避免内网/跨平台构建时 npm 拉包 EIDLETIMEOUT +RUN npm config set fetch-timeout 300000 && npm config set fetch-retries 5 && npm ci + +# Rebuild the source code only when needed +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . +ENV NODE_ENV=production +RUN npm run build + +FROM base AS runner +WORKDIR /app +ENV NODE_ENV=production + +RUN addgroup -g 1001 -S nodejs +RUN adduser -S nextjs -u 1001 + +COPY --from=builder /app/public ./public +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +ENV PORT=3000 +EXPOSE 3000 + +CMD ["node", "server.js"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..f2c3b97 --- /dev/null +++ b/README.md @@ -0,0 +1,126 @@ +

i-Tools | 信奥工具箱

+ +
+ +[![Stars](https://img.shields.io/github/stars/iLay1678/i-tools?style=flat)](https://github.com/iLay1678/i-tools) +![badge](https://cnb.cool/ilay1678/i-tools/-/badge/git/latest/ci/status/tag_push) +[![License](https://img.shields.io/github/license/iLay1678/i-tools)](LICENSE) + +
+ +

+ 简约、高效、现代化的在线信奥工具集合
+ 基于 Next.js 16 + Tailwind CSS 4 + TypeScript 构建 +

+ +## ✨ 特性 + +- **现代化设计**:精美的 UI,支持明亮/暗黑模式自适应。 +- **高性能**:基于 React Server Components 和静态生成。 +- **纯前端处理**:大部分数据处理(如格式化、转换)在本地浏览器完成,保护隐私。 +- **全能工具库**:涵盖开发、文本、编码、加密、转换、生成、生活等 40+ 款实用工具。 + +## 🛠️ 工具列表 + +### 👨‍💻 开发工具 (Dev Tools) +1. **JSON 格式化** (`/json-formatter`): 格式化、压缩、验证、Diff 对比。 +2. **YAML 格式化** (`/yaml-formatter`): YAML 校验与美化。 +3. **HTML 格式化** (`/html-formatter`): HTML 代码美化。 +4. **SQL 格式化** (`/sql-formatter`): 支持多种数据库方言的 SQL 美化。 +5. **文本 Diff 对比** (`/diff`): Monaco Editor 驱动并排代码差异对比。 +6. **Markdown 编辑器** (`/markdown`): 实时预览、GFM 支持、导出 Markdown。 +7. **HTML 转义** (`/html-escape`): HTML 实体编码/解码。 + +### 📝 文本工具 (Text Tools) +1. **文字格式化** (`/text-formatter`): 中英文盘古之白空格、符号修正。 +2. **大小写转换** (`/case-converter`): 驼峰、蛇形、大写、小写互转。 +3. **Lorem Ipsum** (`/lorem-ipsum`): 生成乱数假文。 + +### 🔐 加密与编码 (Crypto & Encoding) +1. **Base64 编解码** (`/base64`): 文本与 Base64 互转。 +2. **URL 编解码** (`/url-encode`): URL 参数编码处理。 +3. **Unicode 转换** (`/unicode`): Unicode 编码转换。 +4. **Base32/Base58** (`/base32`, `/base58`): 其他常用编码。 +5. **MD5/SHA 哈希** (`/hash`): 计算 MD5, SHA1, SHA256, SHA512。 +6. **Bcrypt 哈希** (`/bcrypt`): 生成与验证 Bcrypt 密码哈希。 +7. **AES/DES 加密** (`/aes-des`): 对称加密解密工具。 +8. **JWT 解码** (`/jwt`): JWT Token 解析查看。 + +### 🎨 图像与可视化 (Visual) +1. **二维码生成** (`/qrcode`): 自定义颜色、Logo 的二维码生成。 +2. **条形码生成** (`/barcode`): 生成 EAN, UPC, Code128 等条形码。 +3. **ASCII 艺术** (`/ascii-art`): 文字转字符画。 +4. **图片转像素画** (`/image-to-pixel`): 图片像素化风格转换。 +5. **图片 Base64** (`/image-base64`): 图片文件与 Base64 字符串互转。 + +### 🧮 转换与计算 (Converters & Calc) +1. **时间戳转换** (`/timestamp`): Unix 时间戳与日期互转。 +2. **进制转换器** (`/radix-converter`): 二/八/十/十六进制任意互转。 +3. **IP 进制转换** (`/ip-radix`): IP 地址与整数/二进制转换。 +4. **IP 子网计算** (`/ip-calc`): CIDR 子网划分计算。 +5. **CSV/JSON 互转** (`/csv-json`): 数据格式互相转换。 + +### 🎲 生成与随机 (Generation) +1. **UUID 生成** (`/uuid`): 批量生成 Version 1/4 UUID。 +2. **随机密码生成** (`/random-string`): 高强度随机密码生成器。 +3. **大转盘抽奖** (`/wheel`): 随机决策工具。 +4. **随机分组** (`/random-group`): 名单随机分组工具。 +5. **抛硬币** (`/coin-flip`): 简单的概率工具。 + +### 🔧 实用工具 (Utilities) +1. **Cron 解析** (`/cron`): Cron 表达式翻译与执行时间预测。 +2. **正则测试** (`/regex`): 正则表达式实时测试。 +3. **颜色选择器** (`/color-picker`): HEX, RGB, HSL 转换与拾色。 +4. **UA 解析** (`/user-agent`): 解析 User-Agent 字符串详情。 +5. **键盘按键检测** (`/keyboard`): KeyCode 与按键事件查看。 +6. **挪车码牌** (`/move-car`): 生成微信挪车通知码。 +7. **番茄钟/秒表/倒计时**: 时间管理三件套。 +8. **阿里云盘 TV Token**: 扫码获取 Token。 + +## 💻 技术栈 + +- **框架**: [Next.js 16](https://nextjs.org/) (App Directory) +- **语言**: [TypeScript](https://www.typescriptlang.org/) +- **样式**: [Tailwind CSS 4](https://tailwindcss.com/) +- **UI 组件**: [Radix UI](https://www.radix-ui.com/) + [Lucide Icons](https://lucide.dev/) +- **Linting**: [Oxc (Oxlint)](https://github.com/oxc-project/oxc) - 高性能 Linter,替代 ESLint。 + +## 🚀 快速开始 + +### 开发 + +1. 克隆项目 +```bash +git clone https://git.istudy.xin/yangfan/i-tools.git +cd i-tools +``` + +2. 安装依赖 +```bash +npm install +``` + +3. 启动开发服务器 +```bash +npm run dev +``` + +4. 代码检查 (使用 Oxc) +```bash +npm run lint +``` + +### 构建 + +```bash +npm run build +``` + +## 📦 部署 + + +### Docker 部署 + +```bash +docker run --name=i-tools -d -p 3000:3000 registry.cn-hangzhou.aliyuncs.com/nick-x86/i-tools:1.0.8 +``` diff --git a/app/aes-des/page.tsx b/app/aes-des/page.tsx new file mode 100644 index 0000000..d4c558d --- /dev/null +++ b/app/aes-des/page.tsx @@ -0,0 +1,154 @@ +"use client"; + +import React, { useState } from "react"; +import CryptoJS from "crypto-js"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Shield, Lock, Unlock, Copy } from "lucide-react"; +import { toast } from "sonner"; + +const ALGORITHMS = [ + { value: "AES", label: "AES" }, + { value: "DES", label: "DES" }, + { value: "TripleDES", label: "TripleDES" }, + { value: "Rabbit", label: "Rabbit" }, + { value: "RC4", label: "RC4" }, +]; + +export default function AesDesPage() { + const [input, setInput] = useState(""); + const [key, setKey] = useState(""); + const [algorithm, setAlgorithm] = useState("AES"); + const [output, setOutput] = useState(""); + + const handleProcess = (mode: "encrypt" | "decrypt") => { + if (!input) return; + if (!key) { + toast.error("请输入密钥"); + return; + } + + try { + let result = ""; + const algo = (CryptoJS as any)[algorithm]; + + if (mode === "encrypt") { + result = algo.encrypt(input, key).toString(); + toast.success("加密成功"); + } else { + const bytes = algo.decrypt(input, key); + result = bytes.toString(CryptoJS.enc.Utf8); + if (!result) throw new Error("解密失败(可能是密钥错误)"); + toast.success("解密成功"); + } + setOutput(result); + } catch (e: any) { + toast.error("处理失败: " + e.message); + setOutput(""); + } + }; + + const copyToClipboard = async (text: string) => { + try { + await navigator.clipboard.writeText(text); + toast.success("已复制到剪贴板"); + } catch { + toast.error("复制失败"); + } + }; + + return ( +
+
+
+ +
+
+

对称加密/解密

+

支持 AES, DES, RC4 等常用对称加密算法

+
+
+ +
+ + + 文本内容 + + +
+ +