Enhance form recognition, optimize UI, and unify components (#19)
- **docs**: 完善组件注释、README 目录结构及 AGENTS.md 文档。 - **refactor**: - 提取通用 `PageHeader`、`Button`、`DashboardCard` 及 `ErrorBoundary` 组件。 - 重构消息通信机制,采用 `@webext-core/messaging` 实现类型安全。 - 将全局通知系统重构为 `SnackbarProvider` (后合并至 `GlobalSnackbar`)。 - 迁移样式系统至 MUI 主题,移除冗余 CSS。 - 优化路由配置,支持独立标签页模式及页面懒加载。 - 移除未使用文件、URL 工具及表单映射相关功能。 - **feat**: - 新增配置导出功能(JSON)及状态提示。 - 新增侧边栏状态变化通知机制。 - 新增文本统计及 JWT 解析工具。 - 优化二维码生成与解析逻辑,换用更轻量的 `qrious` 和 `qr-scanner`。 - 增强高亮器功能,支持闪烁效果及 Shadow DOM 穿透。 - **style**: 优化仪表盘响应式网格布局及 UI 细节。 - **fix**: 修复 `useStorageState` 依赖缺失及路由初始化性能问题。 - **test**: 更新单元测试以覆盖新增的工具函数及功能特性。
This commit is contained in:
@@ -1,315 +1,122 @@
|
||||
# AGENTS.md
|
||||
|
||||
This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
|
||||
This file provides guidance to AI agents (such as Gemini, Codex, etc.) when working with the code in this repository.
|
||||
|
||||
## 项目概述
|
||||
|
||||
这是一个基于 WXT 框架的浏览器扩展项目,提供多种测试工具功能,包括时间戳转换、存储管理、URL 管理、二维码生成、表单识别与填充等。
|
||||
**Testing Tools** 是一个基于 WXT (Web Extension Toolkit) 框架的现代化浏览器扩展项目. 它提供了一系列实用的开发和测试工具,包括时间戳转换、存储管理、文本统计、JWT 解析及二维码工具.
|
||||
|
||||
## 核心命令
|
||||
|
||||
### 开发相关
|
||||
### 开发与构建
|
||||
|
||||
- `npm run dev` - 启动 Chrome 浏览器的开发模式
|
||||
- `npm run dev` - 启动 Chrome 浏览器的开发模式(支持 HMR)
|
||||
- `npm run dev:firefox` - 启动 Firefox 浏览器的开发模式
|
||||
- `npm run build` - 构建 Chrome 浏览器的生产版本
|
||||
- `npm run build:firefox` - 构建 Firefox 浏览器的生产版本
|
||||
- `npm run zip` - 打包 Chrome 扩展
|
||||
- `npm run zip:firefox` - 打包 Firefox 扩展
|
||||
- `npm run compile` - TypeScript 类型检查(不生成文件)
|
||||
- `npm run lint` - 运行 ESLint 检查
|
||||
- `npm run zip` - 打包 Chrome 扩展为 ZIP 文件
|
||||
- `npm run zip:firefox` - 打包 Firefox 扩展为 ZIP 文件
|
||||
- `npm run compile` - 执行 TypeScript 类型检查(`tsc --noEmit`)
|
||||
- `npm run lint` - 运行 ESLint 静态代码检查
|
||||
|
||||
### 测试相关
|
||||
### 测试
|
||||
|
||||
- `npm run test` - 运行所有测试(单次执行)
|
||||
- `npm run test:watch` - 运行测试并监听文件变化
|
||||
- `npm run test:coverage` - 运行测试并生成覆盖率报告
|
||||
- `npm run test` - 运行所有单元测试(单次执行)
|
||||
- `npm run test:watch` - 启动 Vitest 交互式监视模式
|
||||
- `npm run test:coverage` - 运行测试并生成代码覆盖率报告
|
||||
|
||||
**运行单个测试文件:**
|
||||
|
||||
```bash
|
||||
npx vitest run components/__tests__/CopyButton.test.tsx
|
||||
npx vitest run path/to/your.test.ts
|
||||
```
|
||||
|
||||
**测试技术栈:**
|
||||
### 依赖管理
|
||||
|
||||
- Vitest v2 - 测试框架
|
||||
- @testing-library/react v16 - React 组件测试
|
||||
- @testing-library/user-event v14 - 用户交互模拟
|
||||
- jsdom v25 - 浏览器环境模拟
|
||||
- `npm install` - 安装项目依赖
|
||||
- `postinstall` 钩子会自动运行 `wxt prepare` 以生成必要的类型定义和入口点.
|
||||
- `prepare` 钩子会自动初始化 Husky 以进行 Git 提交前检查.
|
||||
|
||||
### 依赖与准备
|
||||
|
||||
- `npm install` - 安装依赖
|
||||
- `postinstall` 会自动运行 `wxt prepare` 准备开发环境
|
||||
- `prepare` 钩子会初始化 Husky Git 钩子
|
||||
|
||||
## 项目架构
|
||||
## 项目架构与目录结构
|
||||
|
||||
### 技术栈
|
||||
|
||||
- **框架**: WXT v0.20.6 (Web Extension Toolkit) - 浏览器扩展开发框架
|
||||
- **框架**: WXT v0.20.6 (Web Extension Toolkit)
|
||||
- **前端**: React 19 + TypeScript 5
|
||||
- **UI 库**: Material UI (MUI) v7 + Emotion
|
||||
- **状态管理**: React Hooks + 自定义 Hooks
|
||||
- **路由**: 自定义路由系统(支持 popup/sidepanel/detached 三种模式)
|
||||
- **测试**: Vitest + Testing Library
|
||||
- **代码质量**: ESLint v9 + Prettier + Husky + lint-staged
|
||||
- **UI 库**: Material UI (MUI) @7.x + Emotion
|
||||
- **日期处理**: dayjs (集成 UTC 和 Timezone 插件)
|
||||
- **通信**: `@webext-core/messaging` (用于 Entrypoints 间通信)
|
||||
- **测试**: Vitest + Testing Library (jsdom 环境)
|
||||
- **代码规范**: ESLint v9 + Prettier + Husky + lint-staged
|
||||
|
||||
### 目录结构
|
||||
|
||||
```
|
||||
├── components/ # 可复用 UI 组件
|
||||
│ ├── __tests__/ # 组件测试文件
|
||||
│ ├── Button.tsx # 按钮组件
|
||||
│ ├── CopyButton.tsx # 复制按钮组件
|
||||
│ ├── DashboardCard.tsx # 仪表盘卡片组件
|
||||
│ ├── FieldList.tsx # 字段列表组件
|
||||
│ ├── GlobalSnackbar.tsx # 全局提示消息组件
|
||||
│ ├── PageHeader.tsx # 页面头部组件
|
||||
│ ├── QrCodeToUrlSection.tsx # 二维码解析为 URL 组件
|
||||
│ ├── QrCodeUploader.tsx # 二维码上传组件
|
||||
│ ├── RouterContainer.tsx # 路由容器组件
|
||||
│ ├── StorageCleanerConfirm.tsx # 存储清理确认组件
|
||||
│ ├── ToolCard.tsx # 工具卡片组件
|
||||
│ ├── TopBar.tsx # 顶部导航栏组件
|
||||
│ ├── UrlEntryForm.tsx # URL 录入表单组件
|
||||
│ ├── UrlEntryItem.tsx # URL 条目组件
|
||||
│ ├── UrlEntryList.tsx # URL 列表组件
|
||||
│ └── UrlToQrCodeSection.tsx # URL 转二维码组件
|
||||
├── config/ # 配置文件
|
||||
│ ├── __tests__/ # 配置测试文件
|
||||
│ ├── dashboardCards.tsx # 仪表盘卡片配置
|
||||
│ ├── pageTheme.ts # 页面主题配置
|
||||
│ ├── routes.ts # 路由配置
|
||||
│ └── theme.ts # 全局主题配置
|
||||
├── entrypoints/ # 浏览器扩展入口点
|
||||
│ ├── background.ts # 后台脚本(主进程)
|
||||
│ ├── content.ts # 内容脚本(注入到页面)
|
||||
│ ├── content/
|
||||
│ │ └── messageHandler.ts # 消息处理器
|
||||
│ ├── options/ # 选项页面
|
||||
│ │ ├── App.tsx # 选项应用
|
||||
│ │ ├── index.html # 选项页面 HTML
|
||||
│ │ └── main.tsx # 选项页面入口
|
||||
│ ├── popup/ # 扩展弹窗界面
|
||||
│ │ ├── App.tsx # 弹窗主应用
|
||||
│ │ ├── main.tsx # 弹窗入口
|
||||
│ │ ├── index.html # 弹窗 HTML
|
||||
│ │ ├── pages/ # 弹窗页面
|
||||
│ │ │ ├── components/ # 页面级组件
|
||||
│ │ │ │ ├── AutoRefreshToggle.tsx # 自动刷新开关
|
||||
│ │ │ │ ├── CleaningResult.tsx # 清理结果展示
|
||||
│ │ │ │ ├── DomainHeader.tsx # 域名头部
|
||||
│ │ │ │ ├── ErrorDisplay.tsx # 错误显示
|
||||
│ │ │ │ ├── LiveClock.tsx # 实时时钟
|
||||
│ │ │ │ ├── OptionItem.tsx # 选项条目
|
||||
│ │ │ │ ├── ResultView.tsx # 结果视图
|
||||
│ │ │ │ └── StorageOptionsGrid.tsx # 存储选项网格
|
||||
│ │ │ ├── hooks/ # 自定义 Hooks
|
||||
│ │ │ │ ├── useActiveTabDomain.ts # 当前标签页域名
|
||||
│ │ │ │ ├── useFormRecognizer.ts # 表单识别
|
||||
│ │ │ │ ├── useSidePanelState.ts # 侧边栏状态
|
||||
│ │ │ │ └── useTimestampConverter.ts # 时间戳转换
|
||||
│ │ │ ├── DashboardPage.tsx # 仪表盘页面
|
||||
│ │ │ ├── FormFillPage.tsx # 表单填充页面
|
||||
│ │ │ ├── FormMappingPage.tsx # 表单映射页面
|
||||
│ │ │ ├── FormRecognizerPage.tsx # 表单识别页面
|
||||
│ │ │ ├── OpenUrlPage.tsx # 打开 URL 页面
|
||||
│ │ │ ├── OpenUrlViewerPage.tsx # URL 查看页面
|
||||
│ │ │ ├── QrCodePage.tsx # 二维码页面
|
||||
│ │ │ ├── StorageCleanerPage.tsx # 存储清理页面
|
||||
│ │ │ ├── TimestampPage.tsx # 时间戳页面
|
||||
│ │ │ └── useStorageCleaner.ts # 存储清理 Hook
|
||||
│ └── sidepanel/ # 侧边栏界面
|
||||
│ ├── App.tsx # 侧边栏应用
|
||||
│ ├── index.html # 侧边栏 HTML
|
||||
│ └── main.tsx # 侧边栏入口
|
||||
├── providers/ # React Providers
|
||||
│ └── RouterProvider.tsx # 路由 Provider
|
||||
├── utils/ # 工具函数
|
||||
│ ├── __tests__/ # 工具测试文件
|
||||
│ ├── formMapping/ # 表单映射工具
|
||||
│ │ ├── highlighter.ts # 表单高亮器
|
||||
│ │ ├── scanner.ts # 表单扫描器
|
||||
│ │ ├── smartInjector.ts # 智能注入器
|
||||
│ │ └── ui.ts # UI 工具
|
||||
│ ├── chromeStorage.ts # Chrome 存储工具
|
||||
│ ├── chromeTabs.ts # Chrome 标签页工具
|
||||
│ ├── clipboard.ts # 剪贴板工具
|
||||
│ ├── dataTemplate.ts # 数据模板
|
||||
│ ├── dataValidator.ts # 数据验证器
|
||||
│ ├── dayjs.ts # 日期处理工具
|
||||
│ ├── dummyDataGenerator.ts # 虚拟数据生成器(基于 Faker)
|
||||
│ ├── messages.ts # 消息通信工具
|
||||
│ ├── qrCodeParser.ts # 二维码解析器
|
||||
│ ├── storageCleaner.ts # 存储清理工具
|
||||
│ ├── useStorageState.ts # 存储状态 Hook
|
||||
│ └── useUrlPreferences.ts # URL 偏好设置 Hook
|
||||
├── types/ # 类型定义
|
||||
│ └── storage.d.ts # 存储相关类型
|
||||
├── docs/ # 文档
|
||||
│ └── plans/ # 计划文档
|
||||
├── public/ # 静态资源
|
||||
│ └── icon/ # 扩展图标
|
||||
└── .github/ # GitHub 配置
|
||||
└── workflows/ # CI/CD 工作流
|
||||
├── ci.yml # 持续集成
|
||||
└── release.yml # 发布流程
|
||||
```text
|
||||
├── components/ # 原子级 UI 组件
|
||||
│ ├── __tests__/ # 组件单元测试
|
||||
│ ├── PageHeader.tsx # 标准页面头部
|
||||
│ ├── ToolCard.tsx # 仪表盘卡片基础
|
||||
│ └── ...
|
||||
├── config/ # 核心配置与元数据
|
||||
│ ├── features.tsx # 功能特性定义(路由与元数据的单一事实来源)
|
||||
│ ├── pageTheme.ts # 页面级主题与样式常量
|
||||
│ └── theme.ts # MUI 全局主题配置
|
||||
├── entrypoints/ # 浏览器扩展入口点
|
||||
│ ├── background.ts # 后台 Service Worker (消息中转与生命周期)
|
||||
│ ├── content.ts # 注入页面的内容脚本
|
||||
│ ├── popup/ # 弹窗界面主入口
|
||||
│ ├── options/ # 选项页面主入口
|
||||
│ └── sidepanel/ # 侧边栏界面主入口
|
||||
├── pages/ # 功能模块页面组件
|
||||
│ ├── DashboardPage.tsx # 仪表盘/首页
|
||||
│ ├── JwtPage.tsx # JWT 解析工具
|
||||
│ ├── QrCodePage.tsx # 二维码工具
|
||||
│ ├── StorageCleanerPage.tsx # 存储清理工具
|
||||
│ ├── TextStatisticsPage.tsx # 文本统计工具
|
||||
│ └── TimestampPage.tsx # 时间戳转换工具
|
||||
├── providers/ # React Context Providers (Router, Theme 等)
|
||||
├── utils/ # 业务逻辑与工具函数
|
||||
│ ├── chromeStorage.ts # 类型安全的 Chrome Storage 封装
|
||||
│ ├── jwt.ts # JWT 解析逻辑
|
||||
│ ├── textStatistics.ts # 文本分析逻辑
|
||||
│ └── ...
|
||||
├── types/ # 全局 TypeScript 类型声明
|
||||
└── public/ # 静态资源 (图标等)
|
||||
```
|
||||
|
||||
### 核心功能模块
|
||||
## 核心功能说明
|
||||
|
||||
#### 1. 时间戳转换工具
|
||||
### 1. 路由与功能发现
|
||||
|
||||
- 位置: `entrypoints/popup/pages/TimestampPage.tsx`
|
||||
- Hook: `entrypoints/popup/pages/hooks/useTimestampConverter.ts`
|
||||
- 依赖: dayjs 库进行日期处理
|
||||
- 功能: 支持日期与时间戳的双向转换,支持多种格式,实时时钟显示
|
||||
项目不使用传统的 React Router,而是通过 `config/features.tsx` 中的 `FEATURES` 数组统一管理.
|
||||
|
||||
#### 2. 存储清理工具
|
||||
- 每个功能都有一个唯一的 `PageType` (如 `timestamp`, `jwt`).
|
||||
- `RouterProvider` 负责维护当前的页面状态,并根据 `FEATURES` 配置渲染对应的组件.
|
||||
|
||||
- 位置: `entrypoints/popup/pages/StorageCleanerPage.tsx`
|
||||
- Hook: `entrypoints/popup/pages/useStorageCleaner.ts`
|
||||
- 工具: `utils/storageCleaner.ts`
|
||||
- 功能: 清理缓存、Cookies、本地存储,支持按域名筛选,自动刷新功能
|
||||
### 2. 存储管理 (Chrome Storage)
|
||||
|
||||
#### 3. URL 管理工具
|
||||
- 统一使用 `utils/chromeStorage.ts` 及其对应的 Hook.
|
||||
- 所有的存储键值必须在 `types/storage.d.ts` 的 `StorageSchema` 中定义,以确保存储的类型安全.
|
||||
|
||||
- 打开 URL: `entrypoints/popup/pages/OpenUrlPage.tsx`
|
||||
- 查看 URL: `entrypoints/popup/pages/OpenUrlViewerPage.tsx`
|
||||
- 组件: `components/UrlEntryForm.tsx`, `components/UrlEntryList.tsx`
|
||||
- 功能: 批量打开多个 URL,URL 列表管理
|
||||
### 3. 消息通信 (Messaging)
|
||||
|
||||
#### 4. 二维码工具
|
||||
- 使用 `@webext-core/messaging` 进行 Popup, Sidepanel, Background 和 Content Script 之间的通信.
|
||||
- 消息协议定义在 `utils/messages.ts` 中.
|
||||
|
||||
- 位置: `entrypoints/popup/pages/QrCodePage.tsx`
|
||||
- 组件: `components/QrCodeUploader.tsx`, `components/QrCodeToUrlSection.tsx`, `components/UrlToQrCodeSection.tsx`
|
||||
- 工具: `utils/qrCodeParser.ts`
|
||||
- 依赖: qrcode, jsqr 库
|
||||
- 功能: URL 转二维码生成,二维码图片解析为 URL
|
||||
### 4. 样式系统
|
||||
|
||||
#### 5. 表单工具套件
|
||||
- 基于 MUI v7 的 `Box`, `Stack`, `Paper` 等组件构建.
|
||||
- 页面特定的复杂样式应在 `config/pageTheme.ts` 中统一定义,以保持视觉一致性.
|
||||
|
||||
**表单识别 (Form Recognizer)**
|
||||
## AI 代理开发准则
|
||||
|
||||
- 位置: `entrypoints/popup/pages/FormRecognizerPage.tsx`
|
||||
- Hook: `entrypoints/popup/pages/hooks/useFormRecognizer.ts`
|
||||
- 功能: 智能识别页面表单指纹
|
||||
1. **类型安全**: 始终优先使用 TypeScript 接口和类型. 不要使用 `any`.
|
||||
2. **组件化**: 新功能应拆分为 `pages/` 中的页面组件和 `components/` 中的通用组件.
|
||||
3. **单元测试**: 每次修改逻辑或添加新功能后,必须在对应的 `__tests__` 目录下增加测试用例.
|
||||
4. **单一事实来源**: 功能的添加、修改或删除应首先从 `config/features.tsx` 开始.
|
||||
5. **跨浏览器兼容**: WXT 处理了大部分差异,但涉及原生 API (如 `chrome.cookies`) 时,请确保逻辑在 Firefox 和 Chrome 下均有效.
|
||||
6. **i18n**: 目前主要使用中文 UI,但在开发时请注意提取硬编码字符串,以便未来国际化.
|
||||
|
||||
**表单映射 (Form Mapping)**
|
||||
## 权限管理
|
||||
|
||||
- 位置: `entrypoints/popup/pages/FormMappingPage.tsx`
|
||||
- 工具: `utils/formMapping/` 目录
|
||||
- `scanner.ts` - 表单扫描器
|
||||
- `highlighter.ts` - 表单高亮器
|
||||
- `smartInjector.ts` - 智能注入器
|
||||
- `ui.ts` - UI 工具
|
||||
- 功能: 表单指纹识别与自定义映射规则配置
|
||||
|
||||
**表单填充 (Form Fill)**
|
||||
|
||||
- 位置: `entrypoints/popup/pages/FormFillPage.tsx`
|
||||
- 工具: `utils/dummyDataGenerator.ts` (基于 @faker-js/faker)
|
||||
- 功能: 根据表单指纹智能填充表单数据
|
||||
|
||||
#### 6. 仪表盘系统
|
||||
|
||||
- 位置: `entrypoints/popup/pages/DashboardPage.tsx`
|
||||
- 配置: `config/features.tsx`
|
||||
- 组件: `components/DashboardCard.tsx`, `components/ToolCard.tsx`
|
||||
- 功能: 统一工具入口,可自定义显示的工具卡片
|
||||
|
||||
#### 7. 多模式显示系统
|
||||
|
||||
- 支持三种显示模式:
|
||||
- **popup** - 扩展弹窗(点击图标显示)
|
||||
- **sidepanel** - 浏览器侧边栏
|
||||
- **detached** - 独立窗口模式
|
||||
- 路由配置: `config/features.tsx`
|
||||
- 路由容器: `components/RouterContainer.tsx`
|
||||
- Provider: `providers/RouterProvider.tsx`
|
||||
|
||||
#### 8. 通信系统
|
||||
|
||||
- 位置: `utils/messages.ts`
|
||||
- 机制: 使用 `@webext-core/messaging` 库实现
|
||||
- 内容脚本消息处理: `entrypoints/content/messageHandler.ts`
|
||||
- 通信通道: 后台脚本 ↔ 内容脚本 ↔ 弹窗/侧边栏
|
||||
|
||||
#### 9. 数据存储
|
||||
|
||||
- Chrome Storage API: `utils/chromeStorage.ts`
|
||||
- 存储状态 Hook: `utils/useStorageState.ts`
|
||||
- URL 偏好设置: `utils/useUrlPreferences.ts`
|
||||
- 类型定义: `types/storage.d.ts`
|
||||
|
||||
### 关键配置文件
|
||||
|
||||
#### wxt.config.ts
|
||||
|
||||
- 配置 WXT 框架参数
|
||||
- 启用 React 模块
|
||||
- 配置浏览器扩展权限(storage, unlimitedStorage, clipboardWrite, activeTab, scripting, tabs, cookies, sidePanel)
|
||||
- Vite 构建配置(使用 Terser 压缩,强制 ASCII 编码)
|
||||
- 配置侧边栏和选项页面
|
||||
|
||||
#### manifest 权限
|
||||
|
||||
```typescript
|
||||
permissions: [
|
||||
'storage', // 存储权限
|
||||
'unlimitedStorage', // 无限制存储
|
||||
'clipboardWrite', // 剪贴板写入
|
||||
'activeTab', // 当前标签页
|
||||
'scripting', // 脚本注入
|
||||
'tabs', // 标签页管理
|
||||
'cookies', // Cookies 管理
|
||||
'sidePanel', // 侧边栏
|
||||
],
|
||||
host_permissions:['<all_urls>'] // 访问所有网站
|
||||
```
|
||||
|
||||
#### CI/CD 配置
|
||||
|
||||
- `.github/workflows/ci.yml` - 持续集成工作流
|
||||
- `.github/workflows/release.yml` - 发布工作流
|
||||
|
||||
## 开发注意事项
|
||||
|
||||
### 扩展入口点
|
||||
|
||||
- **后台脚本**: `entrypoints/background.ts` - 处理扩展生命周期和后台任务
|
||||
- **内容脚本**: `entrypoints/content.ts` - 注入到网页中,处理 DOM 交互
|
||||
- **弹窗**: `entrypoints/popup/main.tsx` - 用户点击扩展图标时显示
|
||||
- **侧边栏**: `entrypoints/sidepanel/main.tsx` - 浏览器侧边栏界面
|
||||
- **选项页面**: `entrypoints/options/main.tsx` - 扩展设置页面
|
||||
|
||||
### 路由系统
|
||||
|
||||
- 使用自定义路由系统,支持多种显示模式
|
||||
- 路由配置在 `config/features.tsx`
|
||||
- 通过 `getEntryPointType()` 判断当前入口点类型
|
||||
- 支持页面可见性配置(`defaultVisible`)
|
||||
|
||||
### 浏览器兼容性
|
||||
|
||||
- 支持 Chrome 和 Firefox 浏览器
|
||||
- 使用 WXT 框架抽象浏览器差异
|
||||
- 使用 `@types/chrome` 和 `@types/webextension-polyfill` 提供类型支持
|
||||
|
||||
### 代码质量
|
||||
|
||||
- 使用 ESLint v9 进行代码检查(基于 typescript-eslint)
|
||||
- Prettier 进行代码格式化
|
||||
- Husky v9 用于 Git 钩子管理
|
||||
- Lint-staged 确保暂存文件符合规范
|
||||
- GitHub Actions CI/CD 自动化测试和构建
|
||||
|
||||
### 测试策略
|
||||
|
||||
- 组件测试: `components/__tests__/` 目录
|
||||
- 工具函数测试: `utils/__tests__/` 目录
|
||||
- 配置测试: `config/__tests__/` 目录
|
||||
- 使用 Vitest 作为测试框架
|
||||
- 使用 Testing Library 进行 React 组件测试
|
||||
所有新申请的浏览器权限必须同步更新至 `wxt.config.ts` 的 `manifest.permissions` 中.
|
||||
|
||||
Reference in New Issue
Block a user