优化:AI token优化,删除没有必要的文件
This commit is contained in:
parent
77d4b05839
commit
018e92afcf
@ -1,46 +0,0 @@
|
||||
---
|
||||
description: 修改或新增 src/ 代码时,必须在同一轮对话中同步更新 docs/ 技术文档
|
||||
globs: src/**/*
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# 文档同步规则
|
||||
|
||||
**修改 src/ 后必做**:在同一轮对话中,立即更新 `docs/` 中对应的技术文档。不要等到用户提醒。
|
||||
|
||||
当你在 `src/` 下**新增或修改**任何文件时,必须同步更新 `docs/` 中对应的技术文档。
|
||||
|
||||
## 文件映射关系
|
||||
|
||||
| 源文件 | 文档路径 |
|
||||
|--------|----------|
|
||||
| `src/api/*.ts` | `docs/api/*.md` |
|
||||
| `src/stores/*.ts` | `docs/stores/*.md` |
|
||||
| `src/composables/*.ts` | `docs/composables/*.md` |
|
||||
| `src/views/*.vue` | `docs/views/*.md` |
|
||||
| `src/components/*.vue` | `docs/components/*.md` |
|
||||
| `src/main.ts` | `docs/core/main.md` |
|
||||
| `src/App.vue` | `docs/core/App.md` |
|
||||
| `src/router/index.ts` | `docs/core/router.md` |
|
||||
| `src/plugins/*.ts` | `docs/core/*.md`(如 vuetify.md) |
|
||||
|
||||
## 文档结构要求
|
||||
|
||||
每个文档需包含以下三部分:
|
||||
|
||||
1. **功能用途**:该文件/模块的职责与核心能力
|
||||
2. **使用方式**:调用示例、Props/Events、API 用法
|
||||
3. **扩展方式**:如何修改、新增功能
|
||||
|
||||
API 与组件文档需补充类型说明、Props、Events 等。
|
||||
|
||||
## 示例
|
||||
|
||||
修改 `src/api/event.ts` 后,需更新 `docs/api/event.md`;新增 `src/api/order.ts` 时,需新建 `docs/api/order.md`。
|
||||
|
||||
## 修改后检查清单
|
||||
|
||||
修改 `src/` 内任何文件后,在同一轮回复中完成:
|
||||
|
||||
- [ ] 根据上表找到对应的 `docs/` 路径
|
||||
- [ ] 更新或新建该文档,反映本次代码变更
|
||||
@ -1,70 +0,0 @@
|
||||
---
|
||||
description: Trae 开发规则,定义如何使用 Trae 进行项目开发和维护
|
||||
globs: src/**/*
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Trae 开发规则
|
||||
|
||||
**使用 Trae 进行开发时必须遵循的规则**,确保代码质量和开发效率。
|
||||
|
||||
## 开发流程
|
||||
|
||||
1. **需求分析**:理解用户需求,明确功能边界
|
||||
2. **代码实现**:按照项目框架规范实现功能
|
||||
3. **测试验证**:确保功能正常工作
|
||||
4. **文档更新**:同步更新相关文档
|
||||
5. **代码检查**:运行 lint 和类型检查
|
||||
|
||||
## 代码规范
|
||||
|
||||
### 1. 代码风格
|
||||
- 遵循项目现有的代码风格(Prettier + ESLint)
|
||||
- 使用 TypeScript 严格模式
|
||||
- 避免使用 `any` 类型
|
||||
- 函数和变量命名清晰,符合语义
|
||||
|
||||
### 2. 组件开发
|
||||
- 使用 Vue 3 Composition API
|
||||
- 组件文件使用 PascalCase 命名
|
||||
- 样式使用 `<style scoped>`
|
||||
- 组件 props 和 emits 必须有类型定义
|
||||
|
||||
### 3. API 开发
|
||||
- 遵循 XTrader API 接入规范
|
||||
- 使用统一的请求封装(`src/api/request.ts`)
|
||||
- 为每个接口定义完整的 TypeScript 类型
|
||||
- 处理错误和边界情况
|
||||
|
||||
## 工具使用
|
||||
|
||||
### 1. 代码生成
|
||||
- 使用 Trae 的代码生成功能创建组件、接口等
|
||||
- 生成的代码必须符合项目规范
|
||||
- 手动调整生成的代码,确保质量
|
||||
|
||||
### 2. 调试工具
|
||||
- 使用 Trae 的调试功能排查问题
|
||||
- 利用 Trae 的搜索功能快速定位代码
|
||||
- 结合浏览器开发工具进行前端调试
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **模块化开发**:将功能拆分为小的、可维护的模块
|
||||
2. **代码复用**:提取公共组件和工具函数
|
||||
3. **性能优化**:注意组件渲染性能,避免不必要的重渲染
|
||||
4. **安全性**:注意处理用户输入,避免安全漏洞
|
||||
5. **可访问性**:确保界面对所有用户可访问
|
||||
|
||||
## 检查清单
|
||||
|
||||
开发完成后,确保:
|
||||
|
||||
- [ ] 代码符合项目框架规范
|
||||
- [ ] 功能正常工作
|
||||
- [ ] 文档已同步更新
|
||||
- [ ] 无 lint 和类型错误
|
||||
- [ ] 代码风格一致
|
||||
- [ ] 测试通过
|
||||
|
||||
遵循这些规则,使用 Trae 可以更高效、更规范地进行项目开发。
|
||||
@ -1,154 +0,0 @@
|
||||
---
|
||||
name: trae-development
|
||||
version: 1.0.0
|
||||
description: 提供 Trae 开发相关的功能,包括代码生成、调试、搜索等工具的使用指南。当用户需要使用 Trae 进行开发时使用此技能。
|
||||
author: Trae Team
|
||||
---
|
||||
|
||||
# Trae 开发技能
|
||||
|
||||
## 功能介绍
|
||||
|
||||
本技能提供 Trae 开发环境的使用指南,帮助开发者更高效地使用 Trae 进行项目开发和维护。
|
||||
|
||||
## 使用场景
|
||||
|
||||
- 代码生成:创建新组件、接口、页面等
|
||||
- 代码搜索:快速定位代码和文件
|
||||
- 代码分析:理解现有代码结构
|
||||
- 调试工具:排查和解决问题
|
||||
- 项目管理:项目结构和规范管理
|
||||
|
||||
## 核心功能
|
||||
|
||||
### 1. 代码生成
|
||||
|
||||
#### 组件生成
|
||||
|
||||
**使用方式**:
|
||||
- 在命令面板中输入 `Trae: Generate Component`
|
||||
- 选择组件类型(如 Vue 组件、TypeScript 接口等)
|
||||
- 输入组件名称和相关选项
|
||||
- Trae 会自动生成符合项目规范的代码
|
||||
|
||||
**生成的组件结构**:
|
||||
- Vue 组件:包含 template、script setup 和 scoped style
|
||||
- TypeScript 接口:包含完整的类型定义
|
||||
- API 模块:包含请求函数和类型定义
|
||||
|
||||
### 2. 代码搜索
|
||||
|
||||
**使用方式**:
|
||||
- 在命令面板中输入 `Trae: Search Code`
|
||||
- 输入搜索关键词
|
||||
- Trae 会显示所有匹配的代码片段
|
||||
- 点击结果可直接跳转到对应文件
|
||||
|
||||
**搜索范围**:
|
||||
- 项目代码库
|
||||
- 依赖库
|
||||
- 文档
|
||||
|
||||
### 3. 代码分析
|
||||
|
||||
**使用方式**:
|
||||
- 在命令面板中输入 `Trae: Analyze Code`
|
||||
- 选择分析类型(如依赖分析、性能分析等)
|
||||
- Trae 会生成详细的分析报告
|
||||
|
||||
**分析内容**:
|
||||
- 代码复杂度
|
||||
- 依赖关系
|
||||
- 性能瓶颈
|
||||
- 代码质量
|
||||
|
||||
### 4. 调试工具
|
||||
|
||||
**使用方式**:
|
||||
- 在命令面板中输入 `Trae: Debug Code`
|
||||
- 设置断点或选择调试模式
|
||||
- 运行调试会话
|
||||
- Trae 会提供详细的调试信息
|
||||
|
||||
**调试功能**:
|
||||
- 断点设置
|
||||
- 变量监视
|
||||
- 调用栈查看
|
||||
- 表达式求值
|
||||
|
||||
### 5. 项目管理
|
||||
|
||||
**使用方式**:
|
||||
- 在命令面板中输入 `Trae: Project Management`
|
||||
- 选择管理功能(如依赖管理、版本控制等)
|
||||
- 执行相应的管理操作
|
||||
|
||||
**管理功能**:
|
||||
- 依赖安装和更新
|
||||
- 版本控制操作
|
||||
- 项目配置管理
|
||||
- 构建和部署
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **代码组织**:
|
||||
- 按照项目框架规范组织代码
|
||||
- 使用清晰的命名和目录结构
|
||||
- 遵循模块化开发原则
|
||||
|
||||
2. **代码质量**:
|
||||
- 定期运行 lint 和类型检查
|
||||
- 编写单元测试
|
||||
- 保持代码风格一致
|
||||
|
||||
3. **开发效率**:
|
||||
- 使用 Trae 的代码生成功能
|
||||
- 利用搜索功能快速定位代码
|
||||
- 结合调试工具排查问题
|
||||
|
||||
4. **团队协作**:
|
||||
- 遵循统一的代码规范
|
||||
- 及时更新文档
|
||||
- 提交有意义的代码注释
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: 如何使用 Trae 生成组件?
|
||||
|
||||
**A**: 在命令面板中输入 `Trae: Generate Component`,选择组件类型和配置选项,Trae 会自动生成符合项目规范的代码。
|
||||
|
||||
### Q: 如何搜索项目中的代码?
|
||||
|
||||
**A**: 在命令面板中输入 `Trae: Search Code`,输入搜索关键词,Trae 会显示所有匹配的代码片段。
|
||||
|
||||
### Q: 如何调试代码?
|
||||
|
||||
**A**: 在命令面板中输入 `Trae: Debug Code`,设置断点或选择调试模式,运行调试会话查看详细信息。
|
||||
|
||||
### Q: 如何分析项目依赖?
|
||||
|
||||
**A**: 在命令面板中输入 `Trae: Analyze Code`,选择依赖分析,Trae 会生成详细的依赖关系报告。
|
||||
|
||||
## 配置选项
|
||||
|
||||
Trae 开发技能支持以下配置选项:
|
||||
|
||||
| 配置项 | 说明 | 默认值 |
|
||||
|--------|------|--------|
|
||||
| `trae.codeGeneration.style` | 代码生成风格 | `project` |
|
||||
| `trae.search.scope` | 搜索范围 | `project` |
|
||||
| `trae.analysis.level` | 分析深度 | `medium` |
|
||||
| `trae.debug.enabled` | 启用调试 | `true` |
|
||||
|
||||
## 版本历史
|
||||
|
||||
- **1.0.0**:初始版本,包含代码生成、搜索、分析和调试功能
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 使用 Trae 开发技能时,请确保项目已经正确初始化
|
||||
- 生成的代码可能需要根据具体需求进行调整
|
||||
- 调试功能需要在开发模式下使用
|
||||
- 分析功能可能会消耗一定的系统资源
|
||||
|
||||
通过合理使用 Trae 开发技能,可以显著提高开发效率和代码质量,为项目开发提供有力支持。
|
||||
127
AGENTS.md
127
AGENTS.md
@ -2,147 +2,30 @@
|
||||
|
||||
<skills_system priority="1">
|
||||
|
||||
## Available Skills
|
||||
## Project Skills
|
||||
|
||||
<!-- SKILLS_TABLE_START -->
|
||||
<usage>
|
||||
When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
|
||||
|
||||
How to use skills:
|
||||
- Invoke: `npx openskills read <skill-name>` (run in your shell)
|
||||
- For multiple: `npx openskills read skill-one,skill-two`
|
||||
- The skill content will load with detailed instructions on how to complete the task
|
||||
- Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
|
||||
|
||||
Usage notes:
|
||||
- Only use skills listed in <available_skills> below
|
||||
- Do not invoke a skill that is already loaded in your context
|
||||
- Each skill invocation is stateless
|
||||
</usage>
|
||||
|
||||
<available_skills>
|
||||
|
||||
<skill>
|
||||
<name>algorithmic-art</name>
|
||||
<description>Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>brand-guidelines</name>
|
||||
<description>Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>canvas-design</name>
|
||||
<description>Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>doc-coauthoring</name>
|
||||
<description>Guide users through a structured workflow for co-authoring documentation. Use when user wants to write documentation, proposals, technical specs, decision docs, or similar structured content. This workflow helps users efficiently transfer context, refine content through iteration, and verify the doc works for readers. Trigger when user mentions writing docs, creating proposals, drafting specs, or similar documentation tasks.</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>docx</name>
|
||||
<description>"Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files). Triggers include: any mention of \"Word doc\", \"word document\", \".docx\", or requests to produce professional documents with formatting like tables of contents, headings, page numbers, or letterheads. Also use when extracting or reorganizing content from .docx files, inserting or replacing images in documents, performing find-and-replace in Word files, working with tracked changes or comments, or converting content into a polished Word document. If the user asks for a \"report\", \"memo\", \"letter\", \"template\", or similar deliverable as a Word or .docx file, use this skill. Do NOT use for PDFs, spreadsheets, Google Docs, or general coding tasks unrelated to document generation."</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>frontend-design</name>
|
||||
<description>Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>internal-comms</name>
|
||||
<description>A set of resources to help me write all kinds of internal communications, using the formats that my company likes to use. Claude should use this skill whenever asked to write some sort of internal communications (status reports, leadership updates, 3P updates, company newsletters, FAQs, incident reports, project updates, etc.).</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>mcp-builder</name>
|
||||
<description>Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>pdf</name>
|
||||
<description>Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable. If the user mentions a .pdf file or asks to produce one, use this skill.</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>pptx</name>
|
||||
<description>"Use this skill any time a .pptx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx file (even if the extracted content will be used elsewhere, like in an email or summary); editing, modifying, or updating existing presentations; combining or splitting slide files; working with templates, layouts, speaker notes, or comments. Trigger whenever the user mentions \"deck,\" \"slides,\" \"presentation,\" or references a .pptx filename, regardless of what they plan to do with the content afterward. If a .pptx file needs to be opened, created, or touched, use this skill."</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>skill-creator</name>
|
||||
<description>Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>slack-gif-creator</name>
|
||||
<description>Knowledge and utilities for creating animated GIFs optimized for Slack. Provides constraints, validation tools, and animation concepts. Use when users request animated GIFs for Slack like "make me a GIF of X doing Y for Slack."</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>template</name>
|
||||
<description>Replace with description of the skill and when Claude should use it.</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>theme-factory</name>
|
||||
<description>Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors/fonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>web-artifacts-builder</name>
|
||||
<description>Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>webapp-testing</name>
|
||||
<description>Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>xlsx</name>
|
||||
<description>"Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path — even casually (like \"the xlsx in my downloads\") — and wants something done to it or produced from it. Also trigger for cleaning or restructuring messy tabular data files (malformed rows, misplaced headers, junk data) into proper spreadsheets. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved."</description>
|
||||
<location>global</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>xtrader-api-docs</name>
|
||||
<description>Interprets the XTrader API documentation from Swagger at https://api.xtrader.vip/swagger/index.html and helps implement endpoints, TypeScript types, and request helpers. Use when implementing or understanding XTrader API endpoints, adding new API calls, or when the user refers to the API docs or Swagger.</description>
|
||||
<description>解读 XTrader API 文档,实现接口、TypeScript 类型和请求封装</description>
|
||||
<location>project</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>project-framework</name>
|
||||
<description>Defines the PolyClientVuetify project's framework, structure, and coding conventions. Use when adding or modifying any code in this repository so that changes follow the same stack, patterns, and style.</description>
|
||||
<description>定义项目框架、结构、代码规范,新增或修改代码时使用</description>
|
||||
<location>project</location>
|
||||
</skill>
|
||||
|
||||
<skill>
|
||||
<name>deploy</name>
|
||||
<description>将 PolyClientVuetify 项目打包并通过 SSH 部署到远程服务器。用户说「部署」「发布」时使用此 skill。</description>
|
||||
<description>打包并通过 SSH 部署到远程服务器</description>
|
||||
<location>project</location>
|
||||
</skill>
|
||||
|
||||
</available_skills>
|
||||
<!-- SKILLS_TABLE_END -->
|
||||
|
||||
</skills_system>
|
||||
</skills_system>
|
||||
143
docs/FEATURES.md
143
docs/FEATURES.md
@ -1,143 +0,0 @@
|
||||
# 功能实现状态
|
||||
|
||||
本文档列出项目中**已实现**与**未实现**的功能,便于开发与迭代时参考。
|
||||
|
||||
---
|
||||
|
||||
## 已实现功能
|
||||
|
||||
### 认证与用户
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| 钱包登录 (SIWE) | 通过 MetaMask 等钱包签名,调用 `/base/walletLogin` 获取 token,存入 userStore |
|
||||
| 用户信息 | `getUserInfo` 获取头像、昵称等,登录后自动拉取 |
|
||||
| USDC 余额 | `getUsdcBalance` 获取余额,除以 1_000_000 后展示 |
|
||||
| 登出 | 清空 token、user,移除 localStorage |
|
||||
|
||||
### 首页 (Home)
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| 分类 Tab | 调用 `getPmTagMain` 获取分类树,支持三层;接口失败时回退 `MOCK_CATEGORY_TREE` |
|
||||
| 事件列表 | `getPmEventPublic` 分页获取,支持 keyword、tagSlug、tagId 等筛选 |
|
||||
| 搜索 | 关键词搜索、搜索历史(localStorage,最多 10 条) |
|
||||
| 下拉刷新 | VPullToRefresh 组件 |
|
||||
| 无限滚动 | 滚动到底部加载更多 |
|
||||
| 列表缓存 | 切换页面时复用 `eventListCache`,下拉刷新时清空 |
|
||||
| 单一/多选项卡片 | MarketCard 支持 single(Yes/No)与 multi(轮播多选项) |
|
||||
|
||||
### 交易详情 (TradeDetail)
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| 事件详情 | `findPmEvent` 按 id/slug 获取,需鉴权 |
|
||||
| 分时图 | Lightweight Charts 渲染,时间粒度 1H/6H/1D/1W/1M/ALL,**当前为本地生成 mock 数据** |
|
||||
| 交易组件 | Buy/Sell、Market 模式、Merge、Split |
|
||||
| 下单 | `pmOrderPlace` 调用 CLOB 下单接口 |
|
||||
| Split | `pmMarketSplit` 用 USDC 兑换 Yes+No |
|
||||
| Merge | `pmMarketMerge` 合并 Yes+No 得 USDC |
|
||||
| 移动端适配 | 底部 Yes/No 栏 + 弹窗交易组件 |
|
||||
| 多市场切换 | 支持 query.marketId 指定当前 market |
|
||||
|
||||
### 钱包 (Wallet)
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| Portfolio 卡片 | 展示 userStore.balance |
|
||||
| Deposit/Withdraw 弹窗 | UI 完整,Deposit 展示固定地址与二维码;Withdraw 支持金额、网络、目标地址选择 |
|
||||
| 取消订单 | `pmCancelOrder` 调用真实接口,**但 Positions/Open orders/History 数据为 mock** |
|
||||
| Profit/Loss 图表 | Lightweight Charts 展示,**数据为 mock** |
|
||||
| Positions/Orders/History Tab | 表格与移动端列表,**数据为 mock** |
|
||||
| 搜索、分页 | 对 mock 数据生效 |
|
||||
|
||||
### 事件市场列表 (EventMarkets)
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| 事件详情 | `findPmEvent` 获取,失败时用 `getMockEventById` 兜底 |
|
||||
| 市场列表 | 展示该 Event 下多个 Market,可点击跳转交易详情 |
|
||||
|
||||
### API 层
|
||||
|
||||
| 模块 | 已实现 |
|
||||
|------|--------|
|
||||
| request | get、post,支持 BASE_URL、自定义 headers |
|
||||
| event | getPmEventPublic、findPmEvent、mapEventItemToCard、缓存 |
|
||||
| category | getPmTagMain、enrichWithIcons、MOCK_CATEGORY_TREE |
|
||||
| categoryIcons | resolveCategoryIcon、resolveCategoryIconColor |
|
||||
| market | pmOrderPlace、pmCancelOrder、pmMarketSplit、pmMarketMerge |
|
||||
| user | getUserInfo、getUsdcBalance、formatUsdcBalance |
|
||||
| constants | OrderType、Side |
|
||||
|
||||
### 其他
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| 路由 | 6 个页面,createWebHistory |
|
||||
| Keep-alive | Home 页面缓存 |
|
||||
| 多语言 | 当前中英混用,无 i18n |
|
||||
|
||||
---
|
||||
|
||||
## 未实现 / Mock 功能
|
||||
|
||||
### 认证
|
||||
|
||||
| 功能 | 状态 |
|
||||
|------|------|
|
||||
| 邮箱密码登录 | 仅前端校验,无真实 API 调用,直接跳转首页 |
|
||||
|
||||
### 首页
|
||||
|
||||
| 功能 | 状态 |
|
||||
|------|------|
|
||||
| 分类接口失败兜底 | 使用 MOCK_CATEGORY_TREE,非真实数据 |
|
||||
|
||||
### 交易详情
|
||||
|
||||
| 功能 | 状态 |
|
||||
|------|------|
|
||||
| 分时图数据 | 本地 `generateData()` 生成随机曲线,未对接 WebSocket 或历史接口 |
|
||||
| Comments | 占位文案 "No comments yet." |
|
||||
| Top Holders | 占位文案 "Top holders will appear here." |
|
||||
| Activity | 使用硬编码 mock 数据,未对接交易活动接口 |
|
||||
|
||||
### 订单簿 (OrderBook)
|
||||
|
||||
| 功能 | 状态 |
|
||||
|------|------|
|
||||
| Asks/Bids | 硬编码 mock 数据,定时随机变化模拟 |
|
||||
| Last/Spread | mock |
|
||||
| 真实订单簿 | 需对接 CLOB 或 WebSocket |
|
||||
|
||||
### 钱包
|
||||
|
||||
| 功能 | 状态 |
|
||||
|------|------|
|
||||
| Positions | mock 数据 |
|
||||
| Open orders | mock 数据,取消订单调用真实 API 但列表为 mock |
|
||||
| History | mock 数据 |
|
||||
| Profit/Loss 图表 | mock 数据 |
|
||||
| Portfolio 余额 | 来自 userStore(真实),非 mock |
|
||||
| Deposit 实际充值 | 仅展示地址与二维码,未对接链上或托管充值 |
|
||||
| Withdraw 实际提现 | 仅 UI 流程,未对接提现接口 |
|
||||
| Close Losses | TODO,未实现 |
|
||||
| Export | TODO,未实现 |
|
||||
| 筛选/排序 | 部分按钮为占位,未实现逻辑 |
|
||||
|
||||
### 其他
|
||||
|
||||
| 功能 | 状态 |
|
||||
|------|------|
|
||||
| 注册页 | 路由未配置,Login 中链接指向 `/register` |
|
||||
| Limit 单 | TradeComponent 有 Limit 选项,下单逻辑以 Market 为主 |
|
||||
| 订单簿点击下单 | 点击某行价格填入 TradeComponent 未实现 |
|
||||
|
||||
---
|
||||
|
||||
## 实现优先级建议
|
||||
|
||||
1. **高**:订单簿真实数据、分时图真实数据、Positions/Orders/History 真实接口
|
||||
2. **中**:Comments、Top Holders、Activity 接口;Deposit/Withdraw 实际流程
|
||||
3. **低**:邮箱密码登录、注册页、Limit 单完善
|
||||
@ -1,56 +0,0 @@
|
||||
# category.ts
|
||||
|
||||
**路径**:`src/api/category.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
分类(Tag)相关接口与数据结构,对接 `/PmTag/getPmTagList`,获取首页顶部分类 Tab 数据。支持树形结构、图标自动匹配、按 sort 排序。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- `getPmTagMain`:获取主分类树,返回 `CategoryTreeNode[]`
|
||||
- `enrichWithIcons`:递归为节点补充 MDI 图标(无 icon 时自动匹配)
|
||||
- `MOCK_CATEGORY_TREE`:模拟分类数据,用于开发/测试
|
||||
|
||||
## 类型说明
|
||||
|
||||
| 类型 | 说明 |
|
||||
|------|------|
|
||||
| `PmTagMainItem` | 接口返回的 PmTag 结构,含 children |
|
||||
| `CategoryTreeNode` | 前端使用的树节点,含 id、label、slug、icon、sectionTitle、children、tagIds |
|
||||
|
||||
### CategoryTreeNode.tagIds
|
||||
|
||||
从后端 `PmTagCatalogItem.tagId` 字段提取的标签 ID 列表,用于事件筛选:
|
||||
|
||||
```typescript
|
||||
interface CategoryTreeNode {
|
||||
// ... 其他字段
|
||||
/** 关联的标签 ID 列表,用于事件筛选 */
|
||||
tagIds?: number[]
|
||||
}
|
||||
```
|
||||
|
||||
**提取逻辑**:
|
||||
- 如果 `tagId` 是数字数组,直接使用(`[1351, 1368]`)
|
||||
- 如果 `tagId` 是单个数字,包装为数组(`1351` → `[1351]`)
|
||||
- 如果 `tagId` 是对象或其他类型,忽略
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { getPmTagMain, enrichWithIcons, MOCK_CATEGORY_TREE } from '@/api/category'
|
||||
|
||||
// 获取分类
|
||||
const res = await getPmTagMain()
|
||||
const tree = res.data // 已包含图标、排序
|
||||
|
||||
// 开发时使用 mock
|
||||
const mockTree = enrichWithIcons(MOCK_CATEGORY_TREE)
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **新增分类层级**:在 `CategoryTreeNode` 中扩展字段,`getPmTagMain` 的 `mapPmTagToTreeNode` 中映射
|
||||
2. **自定义图标**:在 `categoryIcons.ts` 中扩展 `ICON_MAP`,`enrichWithIcons` 会自动使用
|
||||
3. **过滤逻辑**:在 `getPmTagMain` 中根据 `forceShow`/`forceHide` 过滤节点
|
||||
@ -1,42 +0,0 @@
|
||||
# categoryIcons.ts
|
||||
|
||||
**路径**:`src/api/categoryIcons.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
根据分类的 label/slug 自动解析 MDI 图标名和颜色,供首页分类 Tab 使用。项目已引入 `@mdi/font`,图标名为 `mdi-xxx` 格式。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- `resolveCategoryIcon`:根据 label/slug 返回 MDI 图标名,无匹配时返回 `DEFAULT_CATEGORY_ICON`
|
||||
- `resolveCategoryIconColor`:返回 Vuetify 颜色名或 CSS 颜色
|
||||
- `DEFAULT_CATEGORY_ICON`:默认图标 `mdi-tag-outline`
|
||||
|
||||
## 匹配优先级
|
||||
|
||||
1. 节点已有 `icon` 且以 `mdi-` 开头 → 直接使用
|
||||
2. 精确匹配 slug
|
||||
3. 精确匹配 label
|
||||
4. 关键词匹配 label(`LABEL_KEYWORDS`)
|
||||
5. 默认图标
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import {
|
||||
resolveCategoryIcon,
|
||||
resolveCategoryIconColor,
|
||||
DEFAULT_CATEGORY_ICON,
|
||||
} from '@/api/categoryIcons'
|
||||
|
||||
// 在模板中
|
||||
<v-icon :color="resolveCategoryIconColor(item) ?? 'grey'">
|
||||
{{ item.icon || resolveCategoryIcon(item) || DEFAULT_CATEGORY_ICON }}
|
||||
</v-icon>
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **新增分类图标**:在 `ICON_MAP` 中增加 `slug -> mdi-xxx` 映射
|
||||
2. **新增颜色**:在 `ICON_COLOR_MAP` 或 `LABEL_COLOR_KEYWORDS` 中增加
|
||||
3. **正则匹配**:在 `LABEL_KEYWORDS` 中使用 RegExp,如 `/^\d+[mhd]$/i`
|
||||
@ -1,44 +0,0 @@
|
||||
# constants.ts
|
||||
|
||||
**路径**:`src/api/constants.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
交易相关常量:订单类型(OrderType)、交易方向(Side),用于 market 接口入参。
|
||||
|
||||
## 常量说明
|
||||
|
||||
### OrderType
|
||||
|
||||
| 值 | 常量 | 说明 |
|
||||
|----|------|------|
|
||||
| 0 | GTC | Good Till Cancelled,一直有效直到取消 |
|
||||
| 1 | GTD | Good Till Date,指定时间内有效 |
|
||||
| 2 | FOK | Fill Or Kill,全部成交或立即取消 |
|
||||
| 3 | FAK | Fill And Kill (IOC),立即成交,剩余取消 |
|
||||
| 4 | Market | 市价单 |
|
||||
|
||||
### Side
|
||||
|
||||
| 值 | 常量 | 说明 |
|
||||
|----|------|------|
|
||||
| 1 | Buy | 买入 |
|
||||
| 2 | Sell | 卖出 |
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { OrderType, Side } from '@/api/constants'
|
||||
|
||||
// 下单时
|
||||
await pmOrderPlace({
|
||||
orderType: OrderType.GTC,
|
||||
side: Side.Buy,
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **新增订单类型**:在 `OrderType` 中增加,并同步后端定义
|
||||
2. **业务枚举**:可在此文件或新建 `enums.ts` 中集中管理
|
||||
@ -1,41 +0,0 @@
|
||||
# cryptoChart.ts
|
||||
|
||||
**路径**:`src/api/cryptoChart.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
加密货币价格走势图 API,使用 **Binance REST + WebSocket** 实现细粒度(1 分钟)实时走势。当事件类型为加密货币时,详情页可切换显示 YES/NO 分时走势图与加密货币实时价格走势图。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- `isCryptoEvent`:判断事件是否为加密货币类型(通过 tags/series slug、ticker)
|
||||
- `inferCryptoSymbol`:从事件信息推断币种符号(btc、eth 等)
|
||||
- `fetchCryptoChart`:从 Binance 获取 1 分钟 K 线历史(优先);当范围超出 Binance 单次限制时,自动切换到 CoinGecko
|
||||
- `subscribeCryptoRealtime`:订阅 Binance **归集交易**(aggTrade)WebSocket,实时推送每笔成交,比 K 线(约 1s)更细;内部 80ms 节流 + RAF 批处理,避免频繁 setOption 卡顿;支持 PING/PONG 保活
|
||||
|
||||
## 币种映射
|
||||
|
||||
`COINGECKO_COIN_IDS` 支持:btc、eth、sol、bnb、xrp、doge、ada、avax、matic、dot、link、uni、atom、ltc、near、apt、arb、op、inj、sui、pepe、wif、shib 等。
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { isCryptoEvent, inferCryptoSymbol, fetchCryptoChart } from '@/api/cryptoChart'
|
||||
|
||||
if (isCryptoEvent(eventDetail)) {
|
||||
const symbol = inferCryptoSymbol(eventDetail) ?? 'btc'
|
||||
const res = await fetchCryptoChart({ symbol, range: '1D' })
|
||||
const points = res.data ?? []
|
||||
}
|
||||
```
|
||||
|
||||
## 30 秒走势(仅加密货币)
|
||||
|
||||
- 30S 选项仅在加密货币走势图显示,YES/NO 分时与 EventMarkets 不包含
|
||||
- 30S 数据:拉取 1H(60 分钟)走势,过滤保留最近 30 秒内的点展示
|
||||
|
||||
## 扩展方式
|
||||
|
||||
- 新增币种:在 `COINGECKO_COIN_IDS` 中追加映射
|
||||
- 更换数据源:修改 `fetchCryptoChart` 内部实现,或通过后端代理 CoinGecko 以规避 CORS
|
||||
- 实时流参考:[Binance WebSocket 归集交易](https://developers.binance.com/docs/zh-CN/binance-spot-api-docs/web-socket-streams#归集交易)
|
||||
@ -1,66 +0,0 @@
|
||||
# event.ts
|
||||
|
||||
**路径**:`src/api/event.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
Event(预测市场事件)相关接口与类型定义,对接 XTrader API 的 `/PmEvent/*` 接口。提供事件列表、详情查询,以及将接口数据映射为首页卡片所需结构的工具函数。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- `getPmEventPublic`:分页获取公开事件列表(无需鉴权);请求时固定传入 **startDateMax**、**endDateMin** 为当前时间戳(Unix 秒),**startDateMin**、**endDateMax** 不传;当后端支持入参 `q` 时,`q` 用作搜索关键词
|
||||
- `findPmEvent`:按 id/slug 查询事件详情(需鉴权)
|
||||
- `mapEventItemToCard`:将 `PmEventListItem` 转为 `EventCardItem`(供 MarketCard 使用)
|
||||
- 内存缓存:`getEventListCache`、`setEventListCache`、`clearEventListCache`,用于列表切换页面时复用
|
||||
|
||||
## 类型说明
|
||||
|
||||
| 类型 | 说明 |
|
||||
|------|------|
|
||||
| `PmEventListItem` | 接口返回的事件项 |
|
||||
| `PmEventMarketItem` | 市场项,含 outcomes、outcomePrices、clobTokenIds |
|
||||
| `EventCardItem` | 首页卡片所需结构,含 displayType(single/multi) |
|
||||
| `EventCardOutcome` | 多选项卡片中单个选项 |
|
||||
| `PageResult<T>` | 分页结果(来自 `@/api/types`) |
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import {
|
||||
getPmEventPublic,
|
||||
findPmEvent,
|
||||
mapEventItemToCard,
|
||||
clearEventListCache,
|
||||
} from '@/api/event'
|
||||
|
||||
// 获取列表
|
||||
const res = await getPmEventPublic({ page: 1, pageSize: 10, q: 'btc' })
|
||||
const cards = res.data.list.map(mapEventItemToCard)
|
||||
|
||||
// 获取详情(需鉴权)
|
||||
const detail = await findPmEvent({ id: 123 }, { headers: authHeaders })
|
||||
|
||||
// 下拉刷新时清空缓存
|
||||
clearEventListCache()
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **新增筛选参数**:在 `GetPmEventListParams` 中增加字段,并在 `getPmEventPublic` 的 query 中传入
|
||||
2. **缓存策略**:可改为 sessionStorage 或带 TTL 的缓存
|
||||
3. **多选项展示**:`mapEventItemToCard` 已支持 multi 类型,内部拆分为 `formatVolume`、`formatExpiresAt`、`parseOutcomePrices`、`mapMarketToOutcome` 等小函数,可扩展 `EventCardOutcome` 字段
|
||||
|
||||
## 参数传递方式
|
||||
|
||||
### tagIds 参数(数组)
|
||||
|
||||
`tagIds` 使用传统数组方式传递,不再是逗号分隔的字符串:
|
||||
|
||||
```typescript
|
||||
// 正确方式 - 直接传递数组
|
||||
const res = await getPmEventPublic({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
tagIds: [1, 2, 3] // 会作为多个同名参数传递:?tagIds=1&tagIds=2&tagIds=3
|
||||
})
|
||||
```
|
||||
@ -1,86 +0,0 @@
|
||||
# historyRecord.ts
|
||||
|
||||
**路径**:`src/api/historyRecord.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
历史记录接口,用于 Wallet 页「History」Tab。**Wallet 使用 GET /hr/getHistoryRecordListClient**(需鉴权、按当前用户分页);另提供 GET /hr/getHistoryRecordPublic(不需要鉴权)备用。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- `getHistoryRecordListClient`:客户端分页获取历史记录(需鉴权,传 userId、page、pageSize)
|
||||
- `getHistoryRecordPublic`:分页获取历史记录(无需鉴权)
|
||||
- `getHistoryRecordList`:从响应 data 中解析 list 并映射为 `HistoryDisplayItem[]`,同时返回 total
|
||||
- `mapHistoryRecordToDisplayItem`:单条 `HistoryRecordItem` → 钱包展示项(与 Wallet.vue HistoryItem 一致)
|
||||
|
||||
## GET /hr/getHistoryRecordListClient(Wallet 使用)
|
||||
|
||||
需鉴权:x-token、x-user-id。
|
||||
|
||||
### 请求参数(Query)
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| page | number | 页码 |
|
||||
| pageSize | number | 每页条数 |
|
||||
| userId | number | 用户 ID |
|
||||
| keyword | string | 关键字 |
|
||||
| slug | string | 标识 |
|
||||
| title | string | 标题 |
|
||||
| name | string | 名称 |
|
||||
| bio | string | 简介 |
|
||||
| createdAtRange | string[] | 创建时间范围 |
|
||||
|
||||
### 响应
|
||||
|
||||
`{ code, data, msg }`,`data` 为 `PageResult<HistoryRecordItem>`(list、page、pageSize、total)。
|
||||
|
||||
## GET /hr/getHistoryRecordPublic
|
||||
|
||||
### 请求参数(Query,可选)
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| page | number | 页码 |
|
||||
| pageSize | number | 每页条数 |
|
||||
| keyword | string | 关键字 |
|
||||
| slug | string | 标识 |
|
||||
| title | string | 标题 |
|
||||
| name | string | 名称 |
|
||||
| bio | string | 简介 |
|
||||
| createdAtRange | string[] | 创建时间范围 |
|
||||
|
||||
### 响应
|
||||
|
||||
`{ code, data, msg }`。`data` 可能为 `PageResult<HistoryRecordItem>`(list、page、pageSize、total)或 `HistoryRecordItem[]`。
|
||||
|
||||
### HistoryRecordItem(与 doc.json polymarket.HistoryRecord 对齐)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| ID | number | 主键 |
|
||||
| title | string | 标题(如「充值资金」) |
|
||||
| type | string | 类型(如 recharge) |
|
||||
| **usdcSize** | number | **金额(USDC)**,用于充值等 |
|
||||
| **icon** | string | **图标路径**(如 uploads/file/btc.png),会转为完整 URL 展示 |
|
||||
| **UpdatedAt** | string | **更新时间**,用于 timeAgo 展示 |
|
||||
| price | number | 价格 |
|
||||
| size | number | 大小 |
|
||||
| outcome | string | 结果 |
|
||||
| timestamp | number | 时间戳(秒或毫秒) |
|
||||
| 其他 | - | asset, bio, conditionId, slug, transactionHash 等 |
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { getHistoryRecordPublic, getHistoryRecordList } from '@/api/historyRecord'
|
||||
|
||||
const res = await getHistoryRecordPublic({ page: 1, pageSize: 10 })
|
||||
const { list, total } = getHistoryRecordList(res.data)
|
||||
// list 为 HistoryDisplayItem[],可直接用于 Wallet 历史列表
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
- 若后端固定返回分页结构,可收紧 `HistoryRecordPublicResponse['data']` 类型为 `PageResult<HistoryRecordItem>`
|
||||
- 展示字段(market、activity、value、timeAgo 等)可在 `mapHistoryRecordToDisplayItem` 中按实际接口字段再调整
|
||||
@ -1,27 +0,0 @@
|
||||
# jwt.ts
|
||||
|
||||
**路径**:`src/api/jwt.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
JWT 相关接口,用于退出登录时将当前 token 加入黑名单,使 token 失效。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- `jsonInBlacklist`:POST /jwt/jsonInBlacklist,需鉴权(x-token、x-user-id)
|
||||
|
||||
## POST /jwt/jsonInBlacklist
|
||||
|
||||
### 请求
|
||||
|
||||
- 方法:POST
|
||||
- 鉴权:需在 headers 中传 x-token、x-user-id
|
||||
- Body:无
|
||||
|
||||
### 响应
|
||||
|
||||
`{ code, msg }`,标准 ApiResponse。
|
||||
|
||||
### 使用场景
|
||||
|
||||
退出登录时由 `useUserStore().logout()` 调用,在清空本地 token 前先请求该接口,使服务端将当前 JWT 加入黑名单。若请求失败(如网络错误、401),仍会执行本地登出。
|
||||
@ -1,63 +0,0 @@
|
||||
# market.ts
|
||||
|
||||
**路径**:`src/api/market.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
交易与市场相关接口:下单、取消订单、Split(USDC 换 Yes+No)、Merge(Yes+No 换 USDC)。对接 CLOB Gateway 与 PmMarket 接口。`ApiResponse` 来自 `@/api/types`。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- `pmOrderPlace`:下单(买入/卖出 Yes 或 No)
|
||||
- `pmCancelOrder`:取消订单
|
||||
- `pmMarketSplit`:用 USDC 兑换 Yes+No 份额
|
||||
- `pmMarketMerge`:合并 Yes+No 份额得到 USDC
|
||||
|
||||
## 类型说明
|
||||
|
||||
| 类型 | 说明 |
|
||||
|------|------|
|
||||
| `ClobSubmitOrderRequest` | 下单请求体,含 tokenID、price、size、side 等 |
|
||||
| `ClobCancelOrderRequest` | 取消订单请求体 |
|
||||
| `PmMarketSplitRequest` | Split 请求体,marketID、usdcAmount |
|
||||
| `PmMarketMergeRequest` | Merge 请求体,marketID、amount |
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import {
|
||||
pmOrderPlace,
|
||||
pmCancelOrder,
|
||||
pmMarketSplit,
|
||||
pmMarketMerge,
|
||||
} from '@/api/market'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const headers = userStore.getAuthHeaders()
|
||||
if (!headers) return
|
||||
|
||||
// 下单
|
||||
await pmOrderPlace(
|
||||
{
|
||||
tokenID: clobTokenId,
|
||||
price: 3700, // 37¢ = 3700
|
||||
size: 100,
|
||||
side: Side.Buy,
|
||||
// ... 其他字段
|
||||
},
|
||||
{ headers }
|
||||
)
|
||||
|
||||
// Split
|
||||
await pmMarketSplit({ marketID: '123', usdcAmount: '10' }, { headers })
|
||||
|
||||
// Merge
|
||||
await pmMarketMerge({ marketID: '123', amount: '5' }, { headers })
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **批量下单**:封装 `pmOrderPlace` 循环或对接批量接口
|
||||
2. **订单状态查询**:新增 `getOpenOrders`、`getOrderHistory` 等接口
|
||||
3. **价格/数量校验**:在调用前增加业务校验逻辑
|
||||
@ -1,41 +0,0 @@
|
||||
# mockData.ts
|
||||
|
||||
**路径**:`src/api/mockData.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
模拟数据统一封装,集中管理事件、分类、订单簿、钱包等 mock 数据,配合 `src/config/mock.ts` 的开关使用。
|
||||
|
||||
## 导出内容
|
||||
|
||||
| 导出 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `MOCK_EVENT_LIST` | `PmEventListItem[]` | 模拟事件列表(来自 mockEventList) |
|
||||
| `MOCK_CATEGORY_TREE` | `CategoryTreeNode[]` | 模拟分类树(来自 category) |
|
||||
| `MOCK_ORDER_BOOK_ASKS` | `MockOrderBookRow[]` | 订单簿卖单 |
|
||||
| `MOCK_ORDER_BOOK_BIDS` | `MockOrderBookRow[]` | 订单簿买单 |
|
||||
| `MOCK_ORDER_BOOK_LAST_PRICE` | `number` | 最新价 |
|
||||
| `MOCK_ORDER_BOOK_SPREAD` | `number` | 价差 |
|
||||
| `MOCK_TOKEN_ID` | `string` | 测试用 token ID |
|
||||
| `MOCK_WALLET_POSITIONS` | `MockPosition[]` | 钱包持仓 |
|
||||
| `MOCK_WALLET_ORDERS` | `MockOpenOrder[]` | 钱包未成交订单 |
|
||||
| `MOCK_WALLET_HISTORY` | `MockHistoryItem[]` | 钱包历史 |
|
||||
| `getMockEventById(id)` | `(id: number) => PmEventListItem \| null` | 按 ID 获取 mock 事件 |
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { MOCK_WALLET_POSITIONS, getMockEventById } from '@/api/mockData'
|
||||
import { USE_MOCK_WALLET } from '@/config/mock'
|
||||
|
||||
if (USE_MOCK_WALLET) {
|
||||
positions.value = [...MOCK_WALLET_POSITIONS]
|
||||
}
|
||||
|
||||
const fallback = getMockEventById(9001)
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. 新增 mock 数据:在 `mockData.ts` 中定义并导出
|
||||
2. 修改现有数据:直接编辑对应常量
|
||||
@ -1,27 +0,0 @@
|
||||
# mockEventList.ts
|
||||
|
||||
**路径**:`src/api/mockEventList.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
模拟事件列表数据 `MOCK_EVENT_LIST`,用于本地开发、测试,覆盖单一 market(Up/Down、Yes/No)、多 markets 轮播等场景。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- 提供 `PmEventListItem[]` 格式的 mock 数据
|
||||
- 包含单一 market、多 market 等多种结构
|
||||
- 可与 `mapEventItemToCard` 配合使用
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { MOCK_EVENT_LIST } from '@/api/mockEventList'
|
||||
import { mapEventItemToCard } from '@/api/event'
|
||||
|
||||
const cards = MOCK_EVENT_LIST.map(mapEventItemToCard)
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **新增 mock 项**:在 `MOCK_EVENT_LIST` 中追加符合 `PmEventListItem` 结构的对象
|
||||
2. **统一入口**:`MOCK_EVENT_LIST` 已由 `src/api/mockData.ts` 统一导出,配合 `src/config/mock.ts` 的 `USE_MOCK_EVENT` 开关使用
|
||||
@ -1,23 +0,0 @@
|
||||
# order.ts
|
||||
|
||||
**路径**:`src/api/order.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
订单相关 API:获取订单列表、取消订单,以及将 `ClobOrderItem` 映射为展示项(History、Open Orders)。`PageResult`、`ApiResponse` 来自 `@/api/types`,通过 `buildQuery` 构建请求参数。
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { getOrderList, mapOrderToOpenOrderItem, mapOrderToHistoryItem, cancelOrder } from '@/api/order'
|
||||
```
|
||||
|
||||
## 数据单位约定
|
||||
|
||||
- **price**:整数,已乘 10000(bps),`priceCents = price / 100`
|
||||
- **originalSize / sizeMatched**:按 6 位小数传(1_000_000 = 1 share),展示时除以 `ORDER_SIZE_SCALE` 转为实际份额
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. 新增订单状态或筛选参数时,更新 `GetOrderListParams` 与 `getOrderList`
|
||||
2. 展示格式变更时,调整 `mapOrderToOpenOrderItem`、`mapOrderToHistoryItem` 的格式化逻辑
|
||||
@ -1,81 +0,0 @@
|
||||
# pmset.ts
|
||||
|
||||
**路径**:`src/api/pmset.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
Polymarket 结算/提现相关 API:`withdrawByWallet` 用于客户端钱包提现申请,需钱包验签(SIWE)。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- `withdrawByWallet`:POST /pmset/withdrawByWallet,提交提现申请,需钱包 personal_sign 验签
|
||||
- `usdcToAmount`:将 USDC 显示金额转为 API 所需整数(6 位小数)
|
||||
- `getSettlementRequestsList`:分页获取提现/结算请求列表(管理端),支持 status 筛选
|
||||
- `getSettlementRequestsListClient`:客户端分页获取提现记录列表,支持 status 筛选(pending/success/rejected/failed)
|
||||
|
||||
## POST /pmset/withdrawByWallet
|
||||
|
||||
### 请求体(request.PmSettlementWithdrawByWallet)
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| amount | number | 是 | 提现金额,6 位小数(1000000 = 1 USDC) |
|
||||
| chain | string | 是 | 链标识,如 polygon、ethereum、arbitrum、optimism |
|
||||
| message | string | 是 | SIWE 签名消息 |
|
||||
| nonce | string | 是 | 随机 nonce |
|
||||
| signature | string | 是 | 钱包签名 |
|
||||
| tokenAddress | string | 是 | 出金地址(用户接收资金的地址) |
|
||||
| tokenSymbol | string | 是 | 代币符号,默认 USDC |
|
||||
| walletAddress | string | 是 | 钱包地址,取用户信息的 externalWalletAddress |
|
||||
|
||||
### 响应
|
||||
|
||||
`{ code, data, msg }`,`data` 为 `{ idempotencyKey?, requestNo? }`。
|
||||
|
||||
### 验签流程(与 Login.vue 一致)
|
||||
|
||||
1. 使用 `eth_requestAccounts` 获取钱包地址
|
||||
2. 使用 `eth_chainId` 获取链 ID
|
||||
3. 构建 SiweMessage(scheme、domain、address、statement、uri、version、chainId、nonce)
|
||||
4. `personal_sign` 签名消息
|
||||
5. POST 请求体包含 message、nonce、signature、walletAddress、amount、chain
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { withdrawByWallet, usdcToAmount } from '@/api/pmset'
|
||||
|
||||
const amount = usdcToAmount(1.5) // 1500000
|
||||
const res = await withdrawByWallet(
|
||||
{ amount, chain: 'polygon', message, nonce, signature, walletAddress },
|
||||
{ headers: authHeaders },
|
||||
)
|
||||
```
|
||||
|
||||
## GET /pmset/getPmSettlementRequestsListClient
|
||||
|
||||
客户端分页获取提现记录列表,需鉴权。钱包页面提现记录使用此接口。
|
||||
|
||||
### 响应 data 结构
|
||||
|
||||
`{ list, total, page, pageSize }`,list 项含:ID、CreatedAt、UpdatedAt、chain、amount、fee、status、reason、requestNo、tokenAddress。
|
||||
|
||||
## GET /pmset/getPmSettlementRequestsList
|
||||
|
||||
分页获取提现/结算请求列表(管理端),需鉴权。
|
||||
|
||||
### 请求参数
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| page | number | 页码 |
|
||||
| pageSize | number | 每页数量 |
|
||||
| status | string | 状态筛选:pending、success、rejected、failed |
|
||||
|
||||
### 响应
|
||||
|
||||
`data` 为 `PageResult<SettlementRequestItem>`,list 项含 amount、requestNo、chain、status、createdAt、reason、payoutError 等。
|
||||
|
||||
## 扩展方式
|
||||
|
||||
- 新增其他 pmset 相关接口时,在 `src/api/pmset.ts` 中追加
|
||||
@ -1,68 +0,0 @@
|
||||
# position.ts
|
||||
|
||||
**路径**:`src/api/position.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
持仓相关 API:分页获取持仓列表,以及将 `ClobPositionItem` 映射为钱包展示项。`PageResult` 来自 `@/api/types`,使用 `buildQuery` 构建请求参数。接口定义以 Swagger doc.json 为准。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- `getPositionList`:分页获取持仓列表(需鉴权 x-token、x-user-id);返回项含 `market`(内嵌市场 question、outcomes、outcomePrices、**closed**)
|
||||
- `mapPositionToDisplayItem`:将接口项转为展示结构;`market` 优先用 `market.question`,否则用 marketID;`avgNow` 有 `market.outcomePrices` 时展示「AVG → NOW」格式;`iconChar`/`iconClass`/`imageUrl` 用于展示图标(market.image 优先);**marketClosed** 取自 `market.closed`,用于钱包侧判断可结算/可领取
|
||||
|
||||
## GET /clob/position/getPositionList
|
||||
|
||||
### 请求参数(Query)
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| page | number | 否 | 页码 |
|
||||
| pageSize | number | 否 | 每页数量 |
|
||||
| startCreatedAt | string | 否 | 开始时间 |
|
||||
| endCreatedAt | string | 否 | 结束时间 |
|
||||
| marketID | string | 否 | 市场ID |
|
||||
| tokenID | string | 否 | Token ID |
|
||||
| userID | number | 否 | 用户ID |
|
||||
|
||||
### 响应
|
||||
|
||||
`{ code, data, msg }`,`data` 为 `PageResult<ClobPositionItem>`。
|
||||
|
||||
### ClobPositionItem(实际返回结构)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| ID | number | 主键 |
|
||||
| userID | number | 用户ID |
|
||||
| marketID | number \| string | 市场ID |
|
||||
| tokenId | string | Token ID |
|
||||
| size | string | 份额(6 位小数) |
|
||||
| available | string | 可用份额 |
|
||||
| lock | string | 锁单数量 |
|
||||
| cost | string | 成本 |
|
||||
| outcome | string | 方向 |
|
||||
| version | number | 版本号 |
|
||||
| market | ClobPositionMarket | 内嵌市场详情(question、outcomes、outcomePrices、closed 等) |
|
||||
| createdAt | string | 创建时间 |
|
||||
| updatedAt | string | 更新时间 |
|
||||
|
||||
### ClobPositionMarket(market 字段)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| ID | number | 市场ID |
|
||||
| question | string | 市场问题 |
|
||||
| slug | string | 市场 slug |
|
||||
| image | string | 市场图片 URL |
|
||||
| icon | string | 市场图标 URL |
|
||||
| outcomes | string[] | 选项(如 ["Up", "Down"]) |
|
||||
| outcomePrices | string[] \| number[] | 各选项当前价格 |
|
||||
| clobTokenIds | string[] | CLOB Token ID 列表 |
|
||||
| closed | boolean | 市场是否已关闭,true 表示可结算/可领取 |
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { getPositionList, mapPositionToDisplayItem } from '@/api/position'
|
||||
```
|
||||
@ -1,76 +0,0 @@
|
||||
# priceHistory.ts
|
||||
|
||||
**路径**:`src/api/priceHistory.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
价格历史公开接口,用于 TradeDetail 页面的 Yes/No 折线图。对接 **GET /pmPriceHistory/getPmPriceHistoryPublic**(无需鉴权)。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- `getPmPriceHistoryPublic`:按市场 ID 分页获取价格历史
|
||||
- `getTimeRangeSeconds`:根据分时范围计算 `startTs`、`endTs`(Unix 秒);`endTs` 始终为当前时间;1H/6H/1D/1W/1M 的 `startTs` 为当前时间往前对应时长;ALL 的 `startTs` 为事件开始时间、`endTs` 为当前时间
|
||||
- `priceHistoryToChartData`:将接口返回的 `list` 转为图表使用的 `[timestamp_ms, value_0_100][]`(Lightweight Charts 需经 `toLwcData` 转为 `{ time, value }`)
|
||||
|
||||
## GET /pmPriceHistory/getPmPriceHistoryPublic
|
||||
|
||||
### 请求参数(Query)
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| market | string | 是 | 传 YES 对应的 clobTokenId(即当前市场 clobTokenIds[0]) |
|
||||
| page | number | 否 | 页码,默认 1 |
|
||||
| pageSize | number | 否 | 每页条数,默认 500 |
|
||||
| startTs | number | 否 | 时间范围起始(Unix 秒) |
|
||||
| endTs | number | 否 | 时间范围结束(Unix 秒) |
|
||||
| interval | string | 否 | 数据间隔 |
|
||||
| time | number | 否 | 时间筛选 |
|
||||
| createdAtRange | string[] | 否 | 创建时间范围 |
|
||||
| fidelity | number | 否 | 数据精度 |
|
||||
| keyword | string | 否 | 关键字 |
|
||||
| order | string | 否 | 排序 |
|
||||
| sort | string | 否 | 排序字段 |
|
||||
| price | number | 否 | 价格筛选 |
|
||||
|
||||
### 响应
|
||||
|
||||
`{ code, data, msg }`,`data` 为 `PageResult<PmPriceHistoryItem>`(`list`、`page`、`pageSize`、`total`)。
|
||||
|
||||
### PmPriceHistoryItem(list 单项)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| ID | number | 主键 |
|
||||
| market | string | 市场标识 |
|
||||
| price | number | 价格(0–1 小数或 0–100,由 priceHistoryToChartData 统一为 0–100) |
|
||||
| time | number | Unix 秒时间戳 |
|
||||
| interval | string | 数据间隔 |
|
||||
| fidelity | number | 数据精度 |
|
||||
| createdAt | string | 创建时间 |
|
||||
| updatedAt | string | 更新时间 |
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import {
|
||||
getPmPriceHistoryPublic,
|
||||
priceHistoryToChartData,
|
||||
getTimeRangeSeconds,
|
||||
type PmPriceHistoryItem,
|
||||
} from '@/api/priceHistory'
|
||||
|
||||
const timeRange = getTimeRangeSeconds('1D') // { startTs, endTs }
|
||||
// ALL 时传 eventDates:getTimeRangeSeconds('ALL', { startDate: ev.startDate, endDate: ev.endDate })
|
||||
const res = await getPmPriceHistoryPublic({
|
||||
market: marketId,
|
||||
page: 1,
|
||||
pageSize: 500,
|
||||
...(timeRange && { startTs: timeRange.startTs, endTs: timeRange.endTs }),
|
||||
})
|
||||
const chartData = priceHistoryToChartData(res.data?.list ?? [])
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
- 时间戳规则:`endTs` 始终为当前时间;1H/6H/1D/1W/1M 的 `startTs` 为当前时间往前对应时长;ALL 的 `startTs` 为事件 `startDate`,`endTs` 为当前时间
|
||||
- 若后端返回的 `price` 固定为 0–100,`priceHistoryToChartData` 已兼容(≤1 时乘 100)
|
||||
@ -1,55 +0,0 @@
|
||||
# request.ts
|
||||
|
||||
**路径**:`src/api/request.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
HTTP 请求基础封装,提供 `get`、`post`、`put`、`buildQuery` 方法,以及 WebSocket URL 生成。所有 API 模块均通过此文件发起请求。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- 统一 BASE_URL:默认 `https://api.xtrader.vip`,可通过环境变量 `VITE_API_BASE_URL` 覆盖
|
||||
- **buildQuery**:过滤空值(undefined、''、[]、NaN)后构建 query 对象,供 GET 请求使用
|
||||
- CLOB WebSocket URL:`getClobWsUrl()` 返回 `ws(s)://host/clob/ws`
|
||||
- User WebSocket URL:`getUserWsUrl()` 返回 `ws(s)://host/clob/ws/user`(订单/持仓/余额推送)
|
||||
- GET 请求:支持 query 参数,自动序列化
|
||||
- POST 请求:支持 JSON body
|
||||
- PUT 请求:支持 JSON body
|
||||
- 自定义 headers:通过 `RequestConfig.headers` 传入
|
||||
- **Accept-Language**:所有 GET/POST/PUT 请求自动附带当前 vue-i18n 的 `locale`
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { get, post, put, buildQuery, getClobWsUrl, getUserWsUrl } from '@/api/request'
|
||||
|
||||
// 构建 query(自动过滤空值)
|
||||
const query = buildQuery({ page: 1, pageSize: 10, keyword, tagIds })
|
||||
const data = await get<MyResponse>('/path', query)
|
||||
|
||||
// CLOB / User WebSocket URL
|
||||
const clobWsUrl = getClobWsUrl()
|
||||
const userWsUrl = getUserWsUrl()
|
||||
|
||||
// 带鉴权
|
||||
const data = await get<MyResponse>('/path', undefined, {
|
||||
headers: { 'x-token': token, 'x-user-id': userId },
|
||||
})
|
||||
|
||||
// POST 请求
|
||||
const res = await post<MyResponse>('/path', { key: 'value' }, {
|
||||
headers: { 'x-token': token },
|
||||
})
|
||||
|
||||
// PUT 请求
|
||||
const putRes = await put<MyResponse>('/path', { key: 'value' }, {
|
||||
headers: { 'x-token': token },
|
||||
})
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **添加 DELETE**:仿照 `get`/`post`/`put` 实现 `del` 函数
|
||||
2. **统一错误处理**:在 `get`/`post` 内对 `!res.ok` 做统一 toast 或错误上报
|
||||
3. **请求/响应拦截**:在 fetch 前后加入拦截逻辑(如 loading、日志)
|
||||
4. **超时控制**:使用 `AbortController` 实现超时取消
|
||||
@ -1,53 +0,0 @@
|
||||
# types.ts
|
||||
|
||||
**路径**:`src/api/types.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
公共 API 类型定义,供 event、order、position、market 等模块复用,避免重复声明。
|
||||
|
||||
## 核心类型
|
||||
|
||||
### PageResult\<T\>
|
||||
|
||||
分页结果通用结构:
|
||||
|
||||
```typescript
|
||||
interface PageResult<T> {
|
||||
list: T[]
|
||||
page: number
|
||||
pageSize: number
|
||||
total: number
|
||||
}
|
||||
```
|
||||
|
||||
### ApiResponse\<T\>
|
||||
|
||||
通用 API 响应:
|
||||
|
||||
```typescript
|
||||
interface ApiResponse<T = unknown> {
|
||||
code: number
|
||||
data?: T
|
||||
msg: string
|
||||
}
|
||||
```
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import type { PageResult, ApiResponse } from '@/api/types'
|
||||
|
||||
// 在接口模块中导出供外部使用
|
||||
export type { PageResult }
|
||||
export interface MyListResponse {
|
||||
code: number
|
||||
data: PageResult<MyItem>
|
||||
msg: string
|
||||
}
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
- 新增通用类型时在此文件添加
|
||||
- 各 API 模块通过 `export type { Xxx }` 重新导出,保持向后兼容
|
||||
@ -1,48 +0,0 @@
|
||||
# user.ts
|
||||
|
||||
**路径**:`src/api/user.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
用户相关接口:获取用户信息、USDC 余额、修改自身用户名。对接 `/user/getUserInfo`、`/user/getUsdcBalance`、`/user/setSelfUsername`,均需鉴权。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- `getUserInfo`:获取当前用户信息(头像、昵称等)
|
||||
- `getUsdcBalance`:查询 USDC 余额(amount、available、locked 需除以 1_000_000)
|
||||
- `setSelfUsername`:修改自身用户名(PUT `/user/setSelfUsername`)
|
||||
- `formatUsdcBalance`:将原始数值转为显示用字符串(如 "0.00")
|
||||
|
||||
## 类型说明
|
||||
|
||||
| 类型 | 说明 |
|
||||
|------|------|
|
||||
| `UserInfoData` | 用户信息结构 |
|
||||
| `UsdcBalanceData` | 余额结构,amount/available/locked 为原始值 |
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { getUserInfo, getUsdcBalance, setSelfUsername, formatUsdcBalance } from '@/api/user'
|
||||
|
||||
const headers = { 'x-token': token, 'x-user-id': userId }
|
||||
|
||||
const userRes = await getUserInfo(headers)
|
||||
const balanceRes = await getUsdcBalance(headers)
|
||||
|
||||
if (balanceRes.data) {
|
||||
const display = formatUsdcBalance(balanceRes.data.available)
|
||||
}
|
||||
|
||||
// 修改自身用户名
|
||||
const setRes = await setSelfUsername(headers, { username: 'new_username' })
|
||||
if (setRes.code === 0 || setRes.code === 200) {
|
||||
// 建议:成功后调用 fetchUserInfo() 刷新页面展示
|
||||
}
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **更新个人信息**:新增 `updateUserInfo` 接口
|
||||
2. **交易记录**:新增 `getUserTrades` 等接口
|
||||
3. **多币种**:扩展 `UsdcBalanceData` 支持其他资产
|
||||
@ -1,30 +0,0 @@
|
||||
# DepositDialog.vue
|
||||
|
||||
**路径**:`src/components/DepositDialog.vue`
|
||||
|
||||
## 功能用途
|
||||
|
||||
充值弹窗,支持 Transfer Crypto、Connect Exchange 等方式。展示充值地址、网络选择、二维码等。
|
||||
|
||||
## Props
|
||||
|
||||
| 属性 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| modelValue | boolean | v-model 控制显隐 |
|
||||
| balance | string | 当前余额展示 |
|
||||
|
||||
## 事件
|
||||
|
||||
- `update:modelValue`:关闭时更新
|
||||
|
||||
## 使用方式
|
||||
|
||||
```vue
|
||||
<DepositDialog v-model="depositDialogOpen" :balance="portfolioBalance" />
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **真实充值**:对接链上或托管充值接口
|
||||
2. **多链**:扩展 networks 列表,支持更多网络
|
||||
3. **历史记录**:展示最近充值记录
|
||||
@ -1,38 +0,0 @@
|
||||
# Footer.vue
|
||||
|
||||
**路径**:`src/components/Footer.vue`
|
||||
|
||||
## 功能用途
|
||||
|
||||
首页底部 Footer 组件,展示 Polymarket 品牌、支持/社交链接、Polymarket 链接、法律声明、语言选择与社交图标。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- 品牌 Logo 与 Slogan
|
||||
- 两列链接:Support & Social、Polymarket
|
||||
- 底部法律链接、语言选择(v-select)、社交图标
|
||||
- 免责声明文案
|
||||
- 响应式布局(移动端垂直排列)
|
||||
|
||||
## 使用方式
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="home-page">
|
||||
<!-- 主内容 -->
|
||||
<Footer />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Footer from '@/components/Footer.vue'
|
||||
</script>
|
||||
```
|
||||
|
||||
父容器需设置 `display: flex; flex-direction: column; min-height: 100vh`,Footer 通过 `margin-top: auto` 贴底。
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **多语言**:将 `footerLang` 与 `useLocaleStore` 联动
|
||||
2. **链接配置**:抽成 props 或常量数组,便于维护
|
||||
3. **社交图标**:可改为 props 传入,支持外部配置
|
||||
@ -1,34 +0,0 @@
|
||||
# HorizontalProgressBar.vue
|
||||
|
||||
**路径**:`src/components/HorizontalProgressBar.vue`
|
||||
|
||||
## 功能用途
|
||||
|
||||
横向进度条,用于订单簿深度展示等场景。根据 `value`/`max` 计算百分比宽度,支持自定义轨道与填充样式。
|
||||
|
||||
## Props
|
||||
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| max | number | 100 | 最大值 |
|
||||
| value | number | 0 | 当前值 |
|
||||
| className | string | '' | 自定义类名 |
|
||||
| trackStyle | object | {} | 轨道样式 |
|
||||
| fillStyle | object | {} | 填充样式 |
|
||||
|
||||
## 使用方式
|
||||
|
||||
```vue
|
||||
<HorizontalProgressBar
|
||||
:max="maxAsksTotal"
|
||||
:value="ask.total"
|
||||
:fill-style="{ backgroundColor: '#e89595' }"
|
||||
:track-style="{ backgroundColor: 'transparent' }"
|
||||
/>
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **动画**:增加 `transition` 或 `animation` 配置
|
||||
2. **渐变**:`fillStyle` 支持 `background: linear-gradient(...)`
|
||||
3. **垂直模式**:增加 `vertical` prop,切换为纵向进度条
|
||||
@ -1,62 +0,0 @@
|
||||
# MarketCard.vue
|
||||
|
||||
**路径**:`src/components/MarketCard.vue`
|
||||
|
||||
## 功能用途
|
||||
|
||||
首页事件卡片组件,展示市场标题、概率、Yes/No 或 Up/Down 按钮。支持单一(single)与多选项(multi)两种展示类型:
|
||||
|
||||
- single:展示一组 Yes/No(或 Up/Down)按钮
|
||||
- multi:在固定高度区域内以**上下滚动列表**展示多个 outcome,每行右侧提供 Yes/No 快捷下单按钮
|
||||
|
||||
点击卡片本体会跳转详情页;点击按钮会触发下单事件(不会触发卡片跳转)。
|
||||
|
||||
## Props
|
||||
|
||||
| 属性 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | string | 事件 ID |
|
||||
| marketTitle | string | 市场标题 |
|
||||
| chanceValue | number | 概率值(0–100) |
|
||||
| marketInfo | string | 如 "$1.2k Vol." |
|
||||
| imageUrl | string | 图片 URL |
|
||||
| category | string | 分类 |
|
||||
| expiresAt | string | 到期日 |
|
||||
| displayType | 'single' \| 'multi' | 展示类型 |
|
||||
| outcomes | EventCardOutcome[] | 多选项时每项数据 |
|
||||
| yesLabel / noLabel | string | 按钮文案 |
|
||||
| isNew | boolean | 是否显示 NEW 角标 |
|
||||
| marketId | string | 市场 ID |
|
||||
| clobTokenIds | string[] | 下单用 token ID |
|
||||
|
||||
## 事件
|
||||
|
||||
- `openTrade(side, market?)`:点击 Yes/No 发起交易,携带 market 信息(single 时为当前 market;multi 时为当前 outcome)
|
||||
|
||||
## 使用方式
|
||||
|
||||
```vue
|
||||
<MarketCard
|
||||
:id="item.id"
|
||||
:market-title="item.marketTitle"
|
||||
:chance-value="item.chanceValue"
|
||||
:market-info="item.marketInfo"
|
||||
:image-url="item.imageUrl"
|
||||
:category="item.category"
|
||||
:expires-at="item.expiresAt"
|
||||
:display-type="item.displayType"
|
||||
:outcomes="item.outcomes"
|
||||
:yes-label="item.yesLabel"
|
||||
:no-label="item.noLabel"
|
||||
:is-new="item.isNew"
|
||||
:market-id="item.marketId"
|
||||
:clob-token-ids="item.clobTokenIds"
|
||||
@openTrade="openTrade"
|
||||
/>
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **新展示类型**:扩展 `displayType`,如 `compact`、`featured`
|
||||
2. **收藏/分享**:增加图标按钮与对应事件
|
||||
3. **骨架屏**:增加 loading 态 props
|
||||
@ -1,56 +0,0 @@
|
||||
# OrderBook.vue
|
||||
|
||||
**路径**:`src/components/OrderBook.vue`
|
||||
|
||||
## 功能用途
|
||||
|
||||
订单簿组件,展示 Asks(卖单)与 Bids(买单)列表,含价格、份额、累计总量,以及横向进度条表示深度。支持通过 props 接收 CLOB WebSocket 实时数据,无 props 时回退到 mock 数据。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- Trade Up / Trade Down Tab
|
||||
- Asks、Bids 列表,带 `HorizontalProgressBar` 深度条(买卖两边共用同一最大值 `maxOrderBookTotal`,取两边累计总量中的最大值,便于对比深度)
|
||||
- Last price、Spread 展示
|
||||
- Live / 连接中 状态展示(均通过 i18n 国际化)
|
||||
- Header 右侧已移除折叠箭头图标(`mdi-chevron-up`),仅保留状态文案与成交量文案
|
||||
|
||||
## Props
|
||||
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| asks | `{ price: number; shares: number }[]` | `[]` | 卖单列表(价格单位:¢) |
|
||||
| bids | `{ price: number; shares: number }[]` | `[]` | 买单列表 |
|
||||
| lastPrice | `number` | - | 最新成交价(¢) |
|
||||
| spread | `number` | - | 买卖价差(¢) |
|
||||
| loading | `boolean` | `false` | 是否连接中 |
|
||||
| connected | `boolean` | `false` | 是否已连接 WebSocket |
|
||||
|
||||
## 使用方式
|
||||
|
||||
```vue
|
||||
<!-- 由父组件传入 CLOB 数据(如 TradeDetail.vue) -->
|
||||
<OrderBook
|
||||
:asks="orderBookAsks"
|
||||
:bids="orderBookBids"
|
||||
:last-price="clobLastPrice"
|
||||
:spread="clobSpread"
|
||||
:loading="clobLoading"
|
||||
:connected="clobConnected"
|
||||
/>
|
||||
|
||||
<!-- 无 props 时使用 mock 数据 -->
|
||||
<OrderBook />
|
||||
```
|
||||
|
||||
## 国际化
|
||||
|
||||
组件内所有展示文案均使用 `trade.*` 与 `activity.live` 键:
|
||||
|
||||
- `trade.orderBook`、`trade.orderBookConnecting`、`trade.orderBookPrice`、`trade.orderBookShares`、`trade.orderBookTotal`
|
||||
- `trade.orderBookAsks`、`trade.orderBookBids`、`trade.orderBookLast`、`trade.orderBookSpread`
|
||||
- `activity.live`(实时状态)
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **点击下单**:点击某行价格时,将价格传入 TradeComponent
|
||||
2. **Trade Up/Down**:可按 Yes/No Token 切换展示不同订单簿
|
||||
@ -1,94 +0,0 @@
|
||||
# TradeComponent.vue
|
||||
|
||||
**路径**:`src/components/TradeComponent.vue`
|
||||
|
||||
## 功能用途
|
||||
|
||||
交易核心组件,支持 Buy/Sell、Market/Limit、Merge/Split。根据 `market` 与 `initialOption` 展示 Yes/No 或 Up/Down 价格,计算 Total、To win、You'll receive 等,并调用 `pmOrderPlace`、`pmMarketSplit`、`pmMarketMerge`。
|
||||
|
||||
## Props
|
||||
|
||||
| 属性 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| market | object | 市场信息,含 marketId、clobTokenIds、outcomes、outcomePrices 等 |
|
||||
| initialOption | 'yes' \| 'no' | 初始选中的选项 |
|
||||
| embeddedInSheet | boolean | 是否嵌入底部弹窗(移动端) |
|
||||
| positions | TradePositionItem[] | 当前市场持仓列表,用于计算可合并份额(Merge 功能) |
|
||||
|
||||
### TradePositionItem
|
||||
|
||||
```typescript
|
||||
interface TradePositionItem {
|
||||
id: string
|
||||
outcomeWord: 'Yes' | 'No' // 持仓方向
|
||||
shares: string // 份额展示文本,如 "5 shares"
|
||||
sharesNum?: number // 份数数值(可选,优先使用)
|
||||
}
|
||||
```
|
||||
|
||||
**可合并份额计算逻辑**:取 Yes 和 No 持仓份数的最小值(成对数量)。例如:Yes 持仓 10 份,No 持仓 8 份,则可合并份额为 8。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- Buy/Sell Tab 切换
|
||||
- Market/Limit 类型、Merge/Split 菜单
|
||||
- **Buy 模式 Amount 区**:无论余额是否充足,均显示 Amount 标签、Balance、**可编辑金额输入框**(v-text-field,带 $ 前缀,variant="outlined")、+$1/+$20/+$100/Max 快捷按钮(桌面端、嵌入弹窗、移动端弹窗一致)
|
||||
- 输入框支持直接输入金额(>= 0,支持小数)
|
||||
- 事件处理:`onAmountInput`、`onAmountKeydown`、`onAmountPaste`
|
||||
- 余额不足时 Buy 显示 Deposit 按钮
|
||||
- 25%/50%/Max 快捷份额
|
||||
- **Sell 模式份额默认取最大可卖**:切换至 Sell 或 maxAvailableShares 变化时自动调用 `setMaxShares()`,将 shares 设为最大可卖数量(无可卖时为 0)
|
||||
- **Sell 模式 UI 优化**:
|
||||
- Shares 标签与 Max shares 提示同行显示(`max-shares-inline`)
|
||||
- 输入框独占一行(`shares-input-wrapper`)
|
||||
- 25%/50%/Max 按钮独立一行(`sell-shares-buttons`)
|
||||
- 整体布局更清晰:`Shares Max: 2` → `[输入框]` → `[25%][50%][Max]`
|
||||
- 调用 market API 下单、Split、Merge
|
||||
- **submitOrder size 统一乘 1_000_000**:无论 Market Buy(amount)、Market Sell、Limit Buy、Limit Sell(shares),传入 `pmOrderPlace` 的 `size` 均先取原始值再 `Math.round(rawSize * 1_000_000)`
|
||||
- **合并/拆分成功后触发事件**:`mergeSuccess`、`splitSuccess`,父组件监听后可刷新持仓列表
|
||||
- **401 权限错误提示**:通过 `useAuthError().formatAuthError` 统一处理,未登录显示「请先登录」,已登录显示「权限不足」
|
||||
|
||||
## 使用方式
|
||||
|
||||
```vue
|
||||
<TradeComponent
|
||||
:market="tradeMarketPayload"
|
||||
:initial-option="tradeInitialOption"
|
||||
:positions="marketPositions"
|
||||
embedded-in-sheet
|
||||
/>
|
||||
```
|
||||
|
||||
**positions 示例**:
|
||||
```typescript
|
||||
const marketPositions = [
|
||||
{ id: '1', outcomeWord: 'Yes', shares: '10 shares', sharesNum: 10 },
|
||||
{ id: '2', outcomeWord: 'No', shares: '8 shares', sharesNum: 8 }
|
||||
]
|
||||
// 可合并份额 = min(10, 8) = 8
|
||||
```
|
||||
|
||||
## Events
|
||||
|
||||
| 事件名 | 说明 |
|
||||
|--------|------|
|
||||
| `optionChange` | 选项切换(yes/no) |
|
||||
| `orderSuccess` | 下单成功 |
|
||||
| `mergeSuccess` | 合并份额成功,父组件应监听并刷新持仓 |
|
||||
| `splitSuccess` | 拆分份额成功,父组件应监听并刷新持仓 |
|
||||
| `submit` | 提交订单前的回调,携带订单 payload |
|
||||
|
||||
## 国际化
|
||||
|
||||
Merge/Split 弹窗文案均通过 `trade.*` 键国际化:
|
||||
|
||||
- **Merge 弹窗**:`mergeDialogTitle`、`mergeDialogDesc`、`mergeAvailableShares`、`mergeNoMarket`、`mergeSubmitBtn`;复用 `trade.amount`、`trade.max`
|
||||
- **Split 弹窗**:`splitDialogTitle`、`splitDialogDesc`、`splitAmountLabel`、`splitNoMarket`、`splitSubmitBtn`
|
||||
|
||||
`mergeDialogDesc`、`splitDialogDesc`、`mergeNoMarket`、`splitNoMarket` 支持 `{yesLabel}`、`{noLabel}` 插值。
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **Limit 单**:完善 Limit 模式下的价格输入与下单逻辑
|
||||
2. **订单确认**:增加确认弹窗
|
||||
3. **滑点设置**:增加滑点配置
|
||||
@ -1,30 +0,0 @@
|
||||
# WithdrawDialog.vue
|
||||
|
||||
**路径**:`src/components/WithdrawDialog.vue`
|
||||
|
||||
## 功能用途
|
||||
|
||||
提现弹窗,支持输入金额、选择网络、选择提现目标(Connected wallet)。仅支持已连接钱包提现,需验签;`walletAddress` 取用户信息的 `externalWalletAddress`,`tokenAddress` 为出金地址(用户接收资金的地址)。
|
||||
|
||||
## Props
|
||||
|
||||
| 属性 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| modelValue | boolean | v-model 控制显隐 |
|
||||
| balance | string | 当前余额展示 |
|
||||
|
||||
## 事件
|
||||
|
||||
- `update:modelValue`:关闭时更新
|
||||
|
||||
## 使用方式
|
||||
|
||||
```vue
|
||||
<WithdrawDialog v-model="withdrawDialogOpen" :balance="portfolioBalance" />
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **真实提现**:对接提现接口,校验余额与地址
|
||||
2. **手续费**:展示网络手续费与到账金额
|
||||
3. **限额**:增加单笔/每日限额校验
|
||||
@ -1,36 +0,0 @@
|
||||
# useAuthError.ts
|
||||
|
||||
**路径**:`src/composables/useAuthError.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
统一处理 HTTP 401(Unauthorized)等权限相关错误,根据登录状态返回用户友好的提示文案:未登录时提示「请先登录」,已登录时提示「权限不足」。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- `formatAuthError(err, fallback)`:将异常转换为展示文案
|
||||
- 若错误信息包含 `401` 或 `Unauthorized`:根据 `userStore.isLoggedIn` 返回 `error.pleaseLogin` 或 `error.insufficientPermission`
|
||||
- 否则返回原始错误信息或 `fallback`
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { useAuthError } from '@/composables/useAuthError'
|
||||
|
||||
const { formatAuthError } = useAuthError()
|
||||
|
||||
try {
|
||||
await someApiCall()
|
||||
} catch (e) {
|
||||
errorMessage.value = formatAuthError(e, t('error.requestFailed'))
|
||||
}
|
||||
```
|
||||
|
||||
## 国际化
|
||||
|
||||
依赖 `error.pleaseLogin`、`error.insufficientPermission`,在各 `locales/*.json` 的 `error` 下配置。
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **扩展状态码**:在 `formatAuthError` 中增加对 403 等的判断
|
||||
2. **统一拦截**:在 `request.ts` 层统一处理 401,自动跳转登录或弹 toast
|
||||
@ -1,36 +0,0 @@
|
||||
# useLightweightChart
|
||||
|
||||
**路径**:`src/composables/useLightweightChart.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
[TradingView Lightweight Charts](https://tradingview.github.io/lightweight-charts/) 工具函数,用于将项目内 `[timestamp_ms, value][]` 格式转为图表所需格式,并提供创建折线/面积图的便捷方法。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- `toLwcData`:将 `[timestamp_ms, value][]` 转为 `{ time: UTCTimestamp, value: number }[]`,输入为毫秒(>=1e12)时自动除以 1000 转为秒,按时间升序排序并去重(同时间戳保留最新价格),时间轴显示用户当地时间
|
||||
- `toLwcPoint`:将单点 `[timestamp_ms, value]` 转为 `{ time, value }`,用于 `series.update()` 增量更新
|
||||
- `createLineChart`:创建基础折线图实例(`attributionLogo: false` 隐藏 TradingView 图标),并禁用拖动/滚轮缩放交互(`handleScroll/handleScale=false`)
|
||||
- `addLineSeries`:添加折线系列(支持 percent/price 格式)
|
||||
- `addAreaSeries`:添加面积系列(带渐变)
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { toLwcData, toLwcPoint, createLineChart, addLineSeries } from '@/composables/useLightweightChart'
|
||||
|
||||
const points: [number, number][] = [[Date.now() - 3600000, 50], [Date.now(), 55]]
|
||||
const lwcData = toLwcData(points)
|
||||
|
||||
const chart = createLineChart(containerEl, { width: 400, height: 320 })
|
||||
const series = addLineSeries(chart, { color: '#2563eb', priceFormat: { type: 'percent', precision: 1 } })
|
||||
series.setData(lwcData)
|
||||
|
||||
// 实时追加/更新单点时,使用 update() 替代 setData() 以获得更平滑的过渡效果
|
||||
series.update(toLwcPoint([Date.now(), 52]))
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
- 新增图表类型:参考 `addAreaSeries` 使用 `AreaSeries`、`CandlestickSeries` 等
|
||||
- 自定义主题:修改 `createLineChart` 的 `layout`、`grid`、`rightPriceScale` 等配置
|
||||
@ -1,37 +0,0 @@
|
||||
# useSearchHistory.ts
|
||||
|
||||
**路径**:`src/composables/useSearchHistory.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
搜索历史组合式函数,将关键词持久化到 localStorage(键 `polyclient_search_history`),最多保留 10 条,去重且新词置顶。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- `list`:只读的搜索历史数组
|
||||
- `add(keyword)`:添加关键词,去重并限制数量
|
||||
- `remove(index)`:删除指定索引
|
||||
- `clearAll`:清空全部
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { useSearchHistory } from '@/composables/useSearchHistory'
|
||||
|
||||
const searchHistory = useSearchHistory()
|
||||
|
||||
// 提交搜索时
|
||||
searchHistory.add(searchKeyword)
|
||||
|
||||
// 展示历史
|
||||
const searchHistoryList = searchHistory.list.value
|
||||
|
||||
// 清空
|
||||
searchHistory.clearAll()
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **分类历史**:扩展为 `useSearchHistory(category)`,按分类存储
|
||||
2. **同步服务端**:在 `add` 时调用接口同步到后端
|
||||
3. **最大条数**:修改 `MAX_HISTORY` 常量
|
||||
@ -1,37 +0,0 @@
|
||||
# mock.ts
|
||||
|
||||
**路径**:`src/config/mock.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
模拟数据开关配置,通过环境变量控制各模块是否使用 mock 数据,方便本地测试与联调。
|
||||
|
||||
## 开关说明
|
||||
|
||||
| 变量 | 说明 | 默认值 |
|
||||
|------|------|--------|
|
||||
| `VITE_USE_MOCK_DATA` | 总开关:`true` 全部启用,`false` 全部关闭 | - |
|
||||
| `VITE_USE_MOCK_CATEGORY` | 分类树:Home 使用模拟分类 | false |
|
||||
| `VITE_USE_MOCK_EVENT` | 事件:EventMarkets 接口失败时 mock 兜底 | true |
|
||||
| `VITE_USE_MOCK_ORDER_BOOK` | 订单簿:无 CLOB 数据时用 mock | true |
|
||||
| `VITE_USE_MOCK_WALLET` | 钱包:持仓/订单/历史用 mock | true |
|
||||
|
||||
## 使用方式
|
||||
|
||||
在 `.env` 中配置:
|
||||
|
||||
```bash
|
||||
# 全部启用 mock
|
||||
VITE_USE_MOCK_DATA=true
|
||||
|
||||
# 全部关闭 mock(联调真实接口时)
|
||||
VITE_USE_MOCK_DATA=false
|
||||
|
||||
# 仅分类树用 mock
|
||||
VITE_USE_MOCK_CATEGORY=true
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. 新增模块开关:在 `mock.ts` 中增加 `USE_MOCK_XXX` 导出
|
||||
2. 新增 mock 数据:在 `src/api/mockData.ts` 中补充并导出
|
||||
@ -1,31 +0,0 @@
|
||||
# package.json
|
||||
|
||||
**路径**:`package.json`
|
||||
|
||||
## 功能用途
|
||||
|
||||
项目依赖与脚本定义。
|
||||
|
||||
## 主要脚本
|
||||
|
||||
| 命令 | 说明 |
|
||||
|------|------|
|
||||
| npm run dev | 启动开发服务器 |
|
||||
| npm run build | 类型检查 + 构建 |
|
||||
| npm run deploy | 打包并通过 SSH 部署 |
|
||||
| npm run preview | 预览构建产物 |
|
||||
| npm run test:unit | Vitest 单测 |
|
||||
| npm run test:e2e | Playwright E2E |
|
||||
| npm run format | Prettier 格式化 |
|
||||
|
||||
## 核心依赖
|
||||
|
||||
- Vue 3、Vue Router 5、Pinia、Vuetify 4
|
||||
- ethers、siwe(钱包登录)
|
||||
- lightweight-charts(TradingView 金融图表)
|
||||
- @mdi/font(图标)
|
||||
|
||||
## 扩展方式
|
||||
|
||||
- 新增脚本:在 `scripts` 中增加
|
||||
- 新增依赖:`npm install xxx` 或手动编辑后 `npm install`
|
||||
@ -1,19 +0,0 @@
|
||||
# vite.config.ts
|
||||
|
||||
**路径**:`vite.config.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
Vite 7 构建配置,包含路径别名、Vue 插件、Node polyfills(用于 ethers、SIWE 等)、开发服务器 host。
|
||||
|
||||
## 关键配置
|
||||
|
||||
- `resolve.alias`:`@` → `./src`
|
||||
- `vite-plugin-node-polyfills`:解决 SIWE 等库的 Node 兼容
|
||||
- `server.host: true`:监听 0.0.0.0,支持局域网访问
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **环境变量**:在 `define` 中注入 `import.meta.env.XXX`
|
||||
2. **代理**:`server.proxy` 解决跨域
|
||||
3. **构建优化**:`build.rollupOptions` 分包、压缩
|
||||
@ -1,30 +0,0 @@
|
||||
# App.vue
|
||||
|
||||
**路径**:`src/App.vue`
|
||||
|
||||
## 功能用途
|
||||
|
||||
根组件,包含全局 AppBar、主内容区(router-view)。AppBar 含返回按钮、标题、登录/余额/头像入口,主内容区使用 keep-alive 缓存 Home。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- 顶部导航栏:返回、TestMarket 标题、Login 或余额+头像入口
|
||||
- 头像入口:登录态点击头像直接跳转 `/profile`
|
||||
- 移动端底部导航:Home / Search / Mine(三个 tab 等分屏宽,与路由联动;Mine 点击跳转 `/profile`;选中态仅加粗、无底色;未选中项图标与文字偏灰;底部导航上方有淡投影);仅在 `/`、`/search`、`/profile` 三个主页面显示,其他页面隐藏
|
||||
- 内部滚动:`html`/`body` 与 `.v-application` 禁止滚动;`app-main-scroll`(`data-main-scroll`)作为主滚动容器,`overflow-y: auto`,滚动条仅出现在内容区,不覆盖底部导航
|
||||
- 登录态:`userStore.isLoggedIn` 控制展示
|
||||
- 用户名:`nickName` 或 `userName` 显示在头像左侧(有值时)
|
||||
- 挂载时与 `isLoggedIn` 变为 true 时:拉取用户信息与余额(`router.isReady()` + `nextTick` 后执行),确保钱包登录、刷新页面后头像和用户名正确显示
|
||||
- keep-alive:`include="['Home']"` 缓存首页
|
||||
|
||||
## 使用方式
|
||||
|
||||
- 启动应用后由 `App.vue` 承载顶栏、主内容与底部导航
|
||||
- 路由切换时由 `bottomNavValue` 自动同步 Home / Search / Mine 高亮状态
|
||||
- 页面内容通过 `<router-view>` 渲染,Home 页面使用 keep-alive 缓存
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **多级导航**:根据路由深度调整返回逻辑
|
||||
2. **主题切换**:增加亮/暗模式切换
|
||||
3. **个人入口扩展**:可在个人中心页继续扩展设置项与账户操作
|
||||
@ -1,17 +0,0 @@
|
||||
# main.ts
|
||||
|
||||
**路径**:`src/main.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
应用入口,创建 Vue 实例并挂载 Pinia、Router、Vuetify 插件。
|
||||
|
||||
## 使用方式
|
||||
|
||||
由 `index.html` 中的脚本加载,无需手动调用。
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **全局错误处理**:`app.config.errorHandler`
|
||||
2. **全局属性**:`app.config.globalProperties`
|
||||
3. **新插件**:`app.use(plugin)` 注册
|
||||
@ -1,35 +0,0 @@
|
||||
# router/index.ts
|
||||
|
||||
**路径**:`src/router/index.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
Vue Router 配置,定义路由表与滚动行为。
|
||||
|
||||
## 路由表
|
||||
|
||||
| path | name | component |
|
||||
|------|------|-----------|
|
||||
| / | home | Home |
|
||||
| /search | search | Search |
|
||||
| /trade | trade | Trade |
|
||||
| /login | login | Login |
|
||||
| /trade-detail/:id | trade-detail | TradeDetail |
|
||||
| /event/:id/markets | event-markets | EventMarkets |
|
||||
| /wallet | wallet | Wallet |
|
||||
| /profile | profile | Profile |
|
||||
| /api-key | api-key | ApiKey |
|
||||
|
||||
## 滚动行为
|
||||
|
||||
滚动目标为 `[data-main-scroll]`(App.vue 内主滚动容器),非 window:
|
||||
|
||||
- 有 `savedPosition` 且来自已命名路由:恢复该容器的 `scrollTop`
|
||||
- 有 `to.hash`:滚动到锚点元素
|
||||
- 否则:滚动到顶部
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **路由守卫**:`beforeEach` 做鉴权、重定向
|
||||
2. **懒加载**:`component: () => import('./views/Home.vue')`
|
||||
3. **meta**:为路由增加 `meta.requiresAuth` 等
|
||||
@ -1,23 +0,0 @@
|
||||
# plugins/vuetify.ts
|
||||
|
||||
**路径**:`src/plugins/vuetify.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
Vuetify 4 插件配置,注册组件、指令、主题。引入 VPullToRefresh(下拉刷新)与 MDI 图标。
|
||||
|
||||
## 主题
|
||||
|
||||
- `light`:默认主题,含 primary、secondary、accent 等
|
||||
- `dark`:暗色主题
|
||||
- `background`:全局背景色统一为 `#FCFCFC`(rgb(252,252,252))
|
||||
|
||||
## 全局默认行为
|
||||
|
||||
- `ripple`:全局关闭点击水波纹效果(`defaults.global.ripple = false`)
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **自定义主题**:在 `themes` 中增加新主题,或修改现有颜色
|
||||
2. **新组件**:从 `vuetify/labs` 引入并注册
|
||||
3. **RTL**:配置 `rtl: true` 支持从右到左布局
|
||||
@ -1,55 +0,0 @@
|
||||
# 滚动条覆盖底部导航栏 - 原因分析与解决方案
|
||||
|
||||
> **已解决**:将滚动从 viewport 移至 `app-main-scroll` 内部,滚动条不再覆盖底部导航。
|
||||
|
||||
## 现象
|
||||
|
||||
底部导航栏(v-bottom-navigation)被页面滚动条遮挡,即使设置 `z-index: 1100` 和 `transform: translateZ(0)` 仍无法解决。
|
||||
|
||||
## 根本原因
|
||||
|
||||
### 1. 滚动发生在 viewport(body/html)
|
||||
|
||||
当前布局中,页面滚动发生在 **文档根** 上:
|
||||
|
||||
- `Home.vue` 使用 `window.scrollY`、`document.documentElement.scrollHeight` 监听滚动
|
||||
- `router/index.ts` 的 `scrollBehavior` 返回 `{ top: 0 }`,作用于 `window`
|
||||
- `.home-list-scroll` 未设置 `overflow`,内容随 **窗口** 滚动
|
||||
|
||||
因此,**滚动条属于 viewport**,由浏览器在 html/body 上绘制。
|
||||
|
||||
### 2. 原生 viewport 滚动条不受 z-index 控制
|
||||
|
||||
- 滚动条是浏览器原生 UI,不是普通 DOM 元素
|
||||
- 它由浏览器在单独图层渲染,与文档层叠上下文分离
|
||||
- 不同浏览器行为不同:
|
||||
- **Chrome**:fixed 元素有时能盖住滚动条
|
||||
- **Firefox / Edge**:滚动条通常绘制在 fixed 元素之上
|
||||
- 对这类原生滚动条,**z-index 无法可靠控制其与 fixed 元素的层级**
|
||||
|
||||
### 3. 当前 DOM 结构
|
||||
|
||||
```
|
||||
v-app
|
||||
├── v-app-bar (fixed top)
|
||||
├── v-main (flex: 1,内容区)
|
||||
│ └── main-content → router-view → Home/Search/Profile
|
||||
└── v-bottom-navigation (fixed bottom)
|
||||
```
|
||||
|
||||
- 底部导航是 `v-app` 的子节点,`position: fixed`
|
||||
- 滚动发生在 body,滚动条在 viewport 右侧贯穿全屏
|
||||
- 底部导航与滚动条在视觉上重叠,且无法通过 z-index 调整
|
||||
|
||||
## 解决方案(已实现)
|
||||
|
||||
**核心思路**:把滚动从 viewport 移到 **内部滚动容器** `app-main-scroll`,让滚动条只出现在内容区,不延伸到底部导航区域。
|
||||
|
||||
### 实现要点
|
||||
|
||||
1. **App.vue**:`html, body` 与 `.v-application` 设置 `overflow: hidden`;v-main 内新增 `app-main-scroll`(`data-main-scroll`)作为滚动容器,`overflow-y: auto`
|
||||
2. **router**:`scrollBehavior` 改为滚动 `[data-main-scroll]` 元素
|
||||
3. **Home.vue**:`checkScrollLoad` 使用 scroll 容器的 `scrollTop`/`scrollHeight`/`clientHeight`;`IntersectionObserver` 的 root 改为 scroll 容器;监听 scroll 容器的 `scroll` 事件
|
||||
4. **Search.vue**:`IntersectionObserver` 的 root 改为 scroll 容器
|
||||
|
||||
效果:滚动条仅出现在 `app-main-scroll` 内,底部导航栏固定于 viewport 底部,不再被滚动条覆盖。
|
||||
@ -1,21 +0,0 @@
|
||||
# counter.ts (Store)
|
||||
|
||||
**路径**:`src/stores/counter.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
示例 Pinia Store,用于演示 setup 写法:`count`、`doubleCount`、`increment`。项目中可能仅用于测试或示例,业务可忽略。
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { useCounterStore } from '@/stores/counter'
|
||||
|
||||
const counter = useCounterStore()
|
||||
counter.increment()
|
||||
console.log(counter.doubleCount)
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
可删除或改为业务相关 demo(如示例数据 store)。
|
||||
@ -1,49 +0,0 @@
|
||||
# user.ts (Store)
|
||||
|
||||
**路径**:`src/stores/user.ts`
|
||||
|
||||
## 功能用途
|
||||
|
||||
用户登录态与基础信息的 Pinia Store,管理 token、user、余额,并提供鉴权请求头。登录数据持久化到 localStorage(键 `poly-user`)。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- `token`、`user`:登录凭证与用户信息
|
||||
- `isLoggedIn`、`avatarUrl`:派生状态
|
||||
- `balance`:USDC 余额显示(如 "0.00"),支持 **UserSocket** 实时推送更新
|
||||
- `setUser`:设置登录数据并持久化,登录成功后自动连接 UserSocket
|
||||
- `logout`:退出登录;先调用 **POST /jwt/jsonInBlacklist** 将当前 JWT 加入黑名单,再清空本地 token/user 并断开 UserSocket;接口失败时仍执行本地登出
|
||||
- `getAuthHeaders`:返回 `{ 'x-token', 'x-user-id' }`,未登录时返回 `undefined`
|
||||
- `fetchUserInfo`、`fetchUsdcBalance`:拉取并更新用户信息与余额;`fetchUserInfo` 兼容多种 API 字段名(id/ID、userName/username 等)
|
||||
- 内部 `parseUserId`:从 API 返回的 user 对象解析 id/ID,兼容 number 与 string,供 `setUser` 与 `fetchUserInfo` 复用
|
||||
- `connectUserSocket`、`disconnectUserSocket`:连接/断开 `sdk/userSocket` 的 UserSdk,用于订单/持仓/余额实时推送
|
||||
|
||||
## 使用方式
|
||||
|
||||
```typescript
|
||||
import { useUserStore } from '@/stores/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 登录后设置
|
||||
userStore.setUser({ token: 'xxx', user: { id: 1, nickName: 'User' } })
|
||||
|
||||
// 鉴权请求
|
||||
const headers = userStore.getAuthHeaders()
|
||||
if (headers) {
|
||||
await someApiCall(undefined, { headers })
|
||||
}
|
||||
|
||||
// 刷新余额
|
||||
await userStore.fetchUsdcBalance()
|
||||
```
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **订单/持仓推送**:在 `connectUserSocket` 中注册 `onOrderUpdate`、`onPositionUpdate`,触发 Wallet 刷新
|
||||
2. **多端登录**:扩展 `setUser` 支持多设备 token 管理
|
||||
3. **Token 刷新**:在 `getAuthHeaders` 或请求拦截器中加入 refresh 逻辑
|
||||
|
||||
## 登录后刷新用户信息
|
||||
|
||||
钱包登录(Login.vue)成功后需调用 `fetchUserInfo()` 以获取完整用户信息(头像、昵称)。App.vue 在 `onMounted` 与 `watch(isLoggedIn)` 时也会调用,确保自动登录或刷新页面后能正确显示。
|
||||
@ -1,22 +0,0 @@
|
||||
# ApiKey.vue
|
||||
|
||||
**路径**:`src/views/ApiKey.vue`
|
||||
**路由**:`/api-key`,name: `api-key`
|
||||
|
||||
## 功能用途
|
||||
|
||||
API Key 管理页面,按 Pencil 设计稿 `WFa0K` 节点 1:1 还原。页面包含标题区(`API Key 管理` + `创建 Key` 按钮)和 API Key 卡片列表(Key 名称、Key 值、复制/删除按钮)。
|
||||
|
||||
## 使用方式
|
||||
|
||||
- 访问路由 `/api-key`
|
||||
- 页面展示 3 条示例 Key 数据,卡片结构如下:
|
||||
- 顶部:`Key #n`
|
||||
- 中部:完整 Key 字符串
|
||||
- 底部:右对齐操作按钮 `复制`、`删除`
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **接入真实列表**:将本地 `apiKeys` 常量替换为后端 API 数据。
|
||||
2. **接入操作事件**:为 `创建 Key`、`复制`、`删除` 按钮绑定真实业务逻辑。
|
||||
3. **安全策略**:可增加 Key 脱敏展示与二次确认删除弹窗。
|
||||
@ -1,25 +0,0 @@
|
||||
# EventMarkets.vue
|
||||
|
||||
**路径**:`src/views/EventMarkets.vue`
|
||||
**路由**:`/event/:id/markets`,name: `event-markets`
|
||||
|
||||
## 功能用途
|
||||
|
||||
事件下的市场列表页,展示某个 Event 的多个 Market(如 NFL 多支队伍),支持选择并跳转交易详情。
|
||||
|
||||
- **多市场折线图**:按市场数量依次调用 `getPmPriceHistoryPublic`,每个市场使用 `clobTokenIds[0]`(YES token)作为 `market` 参数,展示多条分时曲线
|
||||
- 为避免“最新数据提前被截断”,不同时间范围会使用更大的 `pageSize` 拉取更多点
|
||||
- 图表交互已禁用拖动和滚轮缩放(`handleScroll/handleScale=false`)
|
||||
- **时间范围**:1H / 6H / 1D / 1W / 1M / ALL,与 TradeDetail 一致
|
||||
|
||||
## 使用方式
|
||||
|
||||
- 从首页或详情进入,路由 `/event/123/markets`
|
||||
- 路由参数 `id` 为 Event ID
|
||||
- 分时图数据来源:`src/api/priceHistory.ts` 的 `getPmPriceHistoryPublic`、`priceHistoryToChartData`
|
||||
|
||||
## 扩展方式
|
||||
|
||||
- 增加市场筛选、排序
|
||||
- 与 TradeDetail 联动,支持从市场列表直接进入指定 market 的交易
|
||||
- 可抽取 `getTimeRangeMs`、`filterChartDataByRange` 为共享 util,与 TradeDetail 复用
|
||||
@ -1,91 +0,0 @@
|
||||
# Home.vue
|
||||
|
||||
**路径**:`src/views/Home.vue`
|
||||
|
||||
## 功能用途
|
||||
|
||||
首页,展示分类导航栏(三层级)、事件卡片列表。支持分类筛选、搜索、下拉刷新、触底加载更多。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- **分类导航**:三层级分类选择(一级 `v-tabs`、二级 `v-chip`、三级 `v-tabs`)
|
||||
- **事件列表**:卡片式展示,支持下拉刷新、触底加载
|
||||
- **搜索**:可按关键词搜索事件
|
||||
- **分类筛选**:选中分类后,自动提取所有层级节点的 `tagIds` 进行事件筛选;切换语言时重新请求分类接口并刷新列表
|
||||
|
||||
## UI 细节
|
||||
- **卡片阴影不裁剪**:列表容器 `.home-list-scroll` 不使用 `overflow-x: hidden`,避免卡片两侧阴影被裁剪
|
||||
|
||||
- **分类行分隔**:`.home-category-layer1-row` 底部有淡色投影,增强与下方内容的层次感
|
||||
|
||||
- **第一层操作按钮**:已移除右侧的搜索/筛选图标;搜索浮层通过 `initialSearchExpanded`(供 `/search` 路由使用)控制展开
|
||||
|
||||
## 数据流
|
||||
|
||||
```
|
||||
PmTagCatalogItem.tagId = [1351]
|
||||
↓ mapCatalogToTreeNode
|
||||
CategoryTreeNode.tagIds = [1351]
|
||||
↓ 用户选择分类(如:政治 → 特朗普)
|
||||
activeTagIds = [1351, 1368] // 合并所有选中层级的 tagIds
|
||||
↓ getPmEventPublic
|
||||
?tagIds=1351&tagIds=1368
|
||||
```
|
||||
|
||||
## 核心计算属性
|
||||
|
||||
### activeTagIds
|
||||
|
||||
收集所有选中层级节点的 `tagIds`(含父级),用于事件筛选:
|
||||
|
||||
```typescript
|
||||
const activeTagIds = computed(() => {
|
||||
const activeIds = layerActiveValues.value
|
||||
const tagIdSet = new Set<number>()
|
||||
|
||||
// 遍历每一层选中的节点,收集所有 tagIds(含父级)
|
||||
let currentNodes = filterVisible(categoryTree.value)
|
||||
for (let i = 0; i < activeIds.length; i++) {
|
||||
const selectedId = activeIds[i]
|
||||
if (!selectedId) continue
|
||||
|
||||
const node = currentNodes.find((n) => n.id === selectedId)
|
||||
if (node?.tagIds && node.tagIds.length > 0) {
|
||||
node.tagIds.forEach((id) => tagIdSet.add(id))
|
||||
}
|
||||
|
||||
currentNodes = filterVisible(node?.children)
|
||||
}
|
||||
|
||||
return Array.from(tagIdSet) // 去重后的数组
|
||||
})
|
||||
```
|
||||
|
||||
**示例**:
|
||||
|
||||
- 选中「政治」(tagIds: [1351])→ activeTagIds = [1351]
|
||||
- 选中「政治 → 特朗普」(tagIds: [1351] + [1368])→ activeTagIds = [1351, 1368]
|
||||
|
||||
## 使用方式
|
||||
|
||||
无需手动调用,路由 `/` 自动加载。
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **新增分类层级**:修改 `MAX_LAYER` 常量,调整模板渲染逻辑
|
||||
2. **自定义筛选逻辑**:修改 `activeTagIds` 计算属性
|
||||
3. **列表缓存策略**:调整 `getEventListCache` / `setEventListCache`
|
||||
|
||||
### 二级分类 Chip 样式
|
||||
|
||||
- **未选中**:`variant="outlined"`(白底灰边黑字,接近 Vuetify 默认 Chip 外观)
|
||||
- **选中**:`variant="tonal" + color="primary"`(浅蓝底强调,文字为主题主色)
|
||||
|
||||
### 一级/三级 Tabs 样式(Home 页定制)
|
||||
|
||||
- **无下划线**:隐藏 Vuetify tabs 的 slider/indicator
|
||||
- **选中加粗**:选中 tab 使用更粗字重
|
||||
- **无点击水波纹**:禁用 ripple(避免点击涟漪效果)
|
||||
- **无 hover 效果**:禁用鼠标悬停时的背景/遮罩变化
|
||||
- **更紧凑**:取消 `v-tab` 默认 `min-width` 限制,避免强制占宽
|
||||
- **第三层更紧凑**:三级 tabs 的高度收敛到约 28px(接近 2×字体高度)
|
||||
@ -1,25 +0,0 @@
|
||||
# Login.vue
|
||||
|
||||
**路径**:`src/views/Login.vue`
|
||||
**路由**:`/login`,name: `login`
|
||||
|
||||
## 功能用途
|
||||
|
||||
登录页,支持邮箱+密码登录与钱包连接(SIWE)。登录成功后调用 `userStore.setUser` 并跳转首页。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- 邮箱密码:表单校验,调用登录接口
|
||||
- 钱包连接:ethers + SIWE,签名后换取 token
|
||||
- 错误提示:`errorMessage` 展示
|
||||
|
||||
## 使用方式
|
||||
|
||||
- 未登录时点击 AppBar 的 Login 进入
|
||||
- 登录成功后自动跳转 `/`
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **注册**:增加注册表单或跳转注册页(路由 `/register` 需在 router 中配置)
|
||||
2. **忘记密码**:增加找回密码流程
|
||||
3. **社交登录**:接入 OAuth 等
|
||||
@ -1,42 +0,0 @@
|
||||
# Profile.vue
|
||||
|
||||
**路径**:`src/views/Profile.vue`
|
||||
**路由**:`/profile`,name: `profile`
|
||||
|
||||
## 功能用途
|
||||
|
||||
个人中心页面,按照 Pencil 设计稿(`design/pencil-new.pen` 的 `UNTdC` 节点)还原移动端 Profile Screen,并接入用户态与国际化:
|
||||
|
||||
- 从 `useUserStore` 读取昵称、UID、头像、余额、钱包地址等数据
|
||||
- 页面加载后自动触发 `fetchUserInfo()` 与 `fetchUsdcBalance()`,刷新展示数据
|
||||
- 支持语言切换、复制钱包地址、登出等交互逻辑
|
||||
- 全量文案改为 `vue-i18n`(`profile.*` 与 `common.logout` 等)
|
||||
|
||||
## 使用方式
|
||||
|
||||
- 访问路由 `/profile`
|
||||
- 页面会读取 `userStore.user` 作为展示数据源(昵称、UID、头像、VIP 标签、钱包地址)
|
||||
- 点击设置项中的 `钱包管理` 会弹出钱包地址框,显示当前钱包地址(无地址时显示 i18n 兜底文案)
|
||||
- 点击设置项中的 `API KEY 管理` 会跳转到 `/api-key`
|
||||
- 点击设置项中的 `语言` 会弹出语言选择框,点选后即时切换并关闭弹窗,右侧显示当前语言名称
|
||||
- 点击钱包卡片的 `钱包详情` 会跳转到 `/wallet`
|
||||
- 页面展示的用户名与编辑初始值统一取 `userName`(调用 `PUT /user/setSelfUsername` 后刷新);输入会提示允许格式与校验错误(至少 2 位,且仅允许 `a-z / 0-9 / _`)
|
||||
- 点击 `复制地址` 会写入剪贴板,并通过 toast 提示成功/失败
|
||||
- 点击底部 `退出登录` 会执行异步登出(带 loading 防重复)并跳转到 `/login`
|
||||
|
||||
主要结构:
|
||||
|
||||
- Profile 卡片:头像、昵称、UID、VIP 标签、编辑按钮
|
||||
- Wallet 卡片:总览标题、余额、明细文案、充币/提币按钮
|
||||
- 设置卡片:钱包管理、API KEY 管理、语言
|
||||
- 退出按钮:底部高亮按钮
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **更新用户名错误分层**:当前错误优先展示输入校验与接口返回的 `msg`;后续可按错误码映射到更细粒度的 i18n 文案与字段提示。
|
||||
2. **余额细分字段接入**:目前可用/冻结余额已支持多字段兜底,后续可统一对接后端标准字段。
|
||||
3. **头像兜底增强**:当前无头像时展示昵称首字母,可扩展为默认头像资源或主题色方案。
|
||||
4. **多语言持续补齐**:新增字段时同步更新 `src/locales/*.json` 下 `profile` 命名空间。
|
||||
5. **长昵称适配**:`.name-text` 已启用 `ellipsis` 截断,避免与右侧 `编辑` 按钮发生重叠。
|
||||
6. **底部留白优化**:通过调整 `.profile-page` 的 flex 对齐方式,避免容器被拉伸导致底部空白过多。
|
||||
7. **高度收缩优化**:移除了 `.profile-screen` 过高的 `min-height`(由固定值改为可收缩),减少页面因内容过少而产生滚动。
|
||||
@ -1,34 +0,0 @@
|
||||
# Search.vue
|
||||
|
||||
**路径**:`src/views/Search.vue`
|
||||
**路由**:`/search`,name: `search`
|
||||
|
||||
## 功能用途
|
||||
|
||||
搜索页独立实现,按 Pencil 设计稿同文件实现双态页面:
|
||||
- `p4Kcp`:搜索页(搜索框、搜索记录、推荐标签)
|
||||
- `mN9t2`:搜索结果页(顶部搜索框 + 结果卡片列表)
|
||||
- 页面容器改为移动端自适应宽度(`width: 100%`),不再固定 `402px`
|
||||
|
||||
## 使用方式
|
||||
|
||||
- 访问路由 `/search`
|
||||
- 在搜索输入框中输入关键词后,手机键盘回车键会显示为“搜索”(`enterkeyhint="search"`)
|
||||
- 输入停止一小段时间后会自动发起请求 `GET /PmEvent/getPmEventPublic`(入参 `q`),并将关键词写入本地搜索历史;当展示搜索结果时会隐藏搜索记录
|
||||
- **文案国际化**:页面文案与推荐标签使用 `vue-i18n` 键 `searchPage.*`(`zh-CN` / `zh-TW` / `en` / `ko` / `ja`)
|
||||
- **无结果**:接口成功但列表为空时展示 `searchPage.noResults`,**不使用示例假数据**;请求失败或业务错误码时展示 `searchPage.errorFailed` 或接口返回的 `msg`
|
||||
- 搜索前展示 `p4Kcp` 结构:
|
||||
- 顶部标题、占位、记录/推荐标题等取自 i18n
|
||||
- 搜索记录卡:从本地真实读取的搜索历史(最多 10 条),每行右侧带关闭图标
|
||||
- 推荐标签卡:三项标签文案同样走 i18n
|
||||
- 搜索后切换到 `mN9t2` 结构:
|
||||
- 顶部同样保留标题与搜索框
|
||||
- 下方展示结果卡片列表(图标、标题、百分比、时间);无结果时展示空状态文案
|
||||
- 切换结果态时不会因滚动条变化导致顶部/底部导航轻微位移
|
||||
- 点击某条结果:`mapEventItemToCard` 后按与 `MarketCard` 相同规则跳转——**多 market** 进 `/event/:id/markets`(可带 `slug` query);**单 market** 进 `/trade-detail/:id`(query 含 `title`、`marketInfo`、`chance`、`marketId`、`slug` 等与首页一致)
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **结果跳转**:已与 `MarketCard` 对齐;若后端字段变化可只调 `mapEventItemToCard`
|
||||
2. **标签联动搜索**:点击标签触发关键词搜索并跳转到结果页。
|
||||
3. **响应式优化**:可按断点进一步细分字号与间距,但保持 1:1 视觉层级。
|
||||
@ -1,17 +0,0 @@
|
||||
# Trade.vue
|
||||
|
||||
**路径**:`src/views/Trade.vue`
|
||||
**路由**:`/trade`,name: `trade`
|
||||
|
||||
## 功能用途
|
||||
|
||||
交易入口页,展示可交易市场列表或快捷入口,通常作为交易功能的聚合入口。
|
||||
|
||||
## 使用方式
|
||||
|
||||
访问 `/trade` 进入。
|
||||
|
||||
## 扩展方式
|
||||
|
||||
- 可增加市场筛选、推荐市场、最近交易等模块
|
||||
- 可与 TradeDetail 联动,支持从列表直接跳转详情并预选市场
|
||||
@ -1,44 +0,0 @@
|
||||
# TradeDetail.vue
|
||||
|
||||
**路径**:`src/views/TradeDetail.vue`
|
||||
**路由**:`/trade-detail/:id`,name: `trade-detail`
|
||||
|
||||
## 功能用途
|
||||
|
||||
交易详情页,展示单个市场的分时图、订单簿、Rules 内容以及右侧交易组件(Buy/Sell、Merge/Split)。支持桌面端与移动端布局,移动端使用底部 Yes/No 栏 + 弹窗。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- 分时图:TradingView Lightweight Charts 渲染,支持 Past、时间粒度切换(1H/6H/1D/1W/1M/ALL);**Yes/No 模式**数据来自 **GET /pmPriceHistory/getPmPriceHistoryPublic**(market 传 clobTokenIds[0]),接口返回 `time`(Unix 秒)、`price`(0–1)转成 `[timestamp_ms, value_0_100][]` 后缓存在 `rawChartData`,**分时**为前端按当前选中范围过滤:1H=最近 1 小时、6H=6 小时、1D=1 天、1W=7 天、1M=30 天、ALL=全部,切换时间范围不重复请求;为避免“最新数据提前被截断”,不同时间范围会使用更大的 `pageSize` 拉取更多点;**加密货币事件**可切换 YES/NO 分时图与加密货币价格走势图(CoinGecko 实时数据),**加密货币模式默认显示 30S 分时走势图**;图表交互已禁用拖动和滚轮缩放(`handleScroll/handleScale=false`)
|
||||
- Rules 内容容器(`.rules-pane`):内边距从 `4px` 提升到 `16px`,改善文本留白与可读性
|
||||
- 订单簿:`OrderBook` 组件,通过 **ClobSdk** 对接 CLOB WebSocket 实时数据(全量快照、增量更新、成交推送);份额接口按 6 位小数传(1_000_000 = 1 share),`priceSizeToRows` 与 `mergeDelta` 会将 raw 值除以 `ORDER_BOOK_SIZE_SCALE` 转为展示值
|
||||
- 订单簿外层容器(`order-book-card`)已去除重复外边框,仅保留 `OrderBook` 组件单层描边,避免视觉上出现双层边线
|
||||
- 交易:`TradeComponent`,传入 `market`、`initialOption`、`positions`(持仓数据)
|
||||
- 持仓列表:通过 `getPositionList` 获取当前市场持仓,传递给 `TradeComponent` 用于计算可合并份额
|
||||
- 限价订单:通过 `getOrderList` 获取当前市场未成交限价单,支持撤单
|
||||
- 移动端:底部栏 + `v-bottom-sheet` 嵌入 `TradeComponent`
|
||||
- Merge/Split:通过 `TradeComponent` 或底部菜单触发,成功后监听 `mergeSuccess`/`splitSuccess` 事件刷新持仓
|
||||
- **401 权限错误**:加载详情失败时,通过 `useAuthError().formatAuthError` 统一提示「请先登录」或「权限不足」
|
||||
- **Sell 弹窗 emitsOptions 竞态**:`sellDialogRenderContent` 延迟 350ms 卸载 TradeComponent,等 v-dialog transition 完成,避免 Vue patch 时组件实例为 null 的 `emitsOptions` 错误
|
||||
- **底部栏 slot 竞态**:`tradeSheetRenderContent` 延迟 50ms 挂载、350ms 卸载 TradeComponent,避免 v-bottom-sheet transition 期间 VTextField 触发「Slot default invoked outside of the render function」警告
|
||||
|
||||
## 使用方式
|
||||
|
||||
- 从首页卡片点击进入,或直接访问 `/trade-detail/123`
|
||||
- 路由参数 `id` 为 Event ID,用于 `findPmEvent`
|
||||
|
||||
## 持仓刷新机制
|
||||
|
||||
- **下单成功**:`TradeComponent` 触发 `orderSuccess` → `onOrderSuccess()` 刷新持仓和未成交订单
|
||||
- **合并成功**:`TradeComponent` 触发 `mergeSuccess` → `onMergeSuccess()` 刷新持仓,显示 toast 提示
|
||||
- **拆分成功**:`TradeComponent` 触发 `splitSuccess` → `onSplitSuccess()` 刷新持仓
|
||||
|
||||
持仓刷新调用 `loadMarketPositions()`,通过 `/clob/position/getPositionList` 接口获取最新持仓数据。**持仓类型用 API 返回的 `outcome` 字段匹配**(如 "Up"/"Down"、"Yes"/"No"),与当前市场的 `outcomes[0]`、`outcomes[1]` 对应,用于 Sell 选项与 TradeComponent 的 positions 映射。
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **订单簿**:已通过 `sdk/clobSocket.ts` 的 ClobSdk 对接 CLOB WebSocket,使用 **Yes/No token ID** 订阅 `price_size_all`、`price_size_delta`、`trade` 消息
|
||||
2. **分时图**:Yes/NO 折线图仅使用真实接口 `getPmPriceHistoryPublic`,无模拟数据与定时器;事件详情加载完成后自动请求并展示,无 marketId 或接口无数据时展示空图;加密货币事件已支持 YES/NO 分时与加密货币价格图切换(`src/api/cryptoChart.ts`);加密货币实时推送时使用 `series.update()` 增量更新单点,配合 `LastPriceAnimationMode.OnDataUpdate` 实现新数据加入的过渡动画;30S 范围在未过滤掉旧点时同样使用 `update()` 实现平滑动画
|
||||
3. **Comments**:对接评论接口,替换 placeholder
|
||||
4. **Top Holders**:当前页面已移除显示(仅保留 Rules)
|
||||
5. **Activity**:当前页面已移除显示(仅保留 Rules)
|
||||
@ -1,51 +0,0 @@
|
||||
# Wallet.vue
|
||||
|
||||
**路径**:`src/views/Wallet.vue`
|
||||
**路由**:`/wallet`,name: `wallet`
|
||||
|
||||
## 功能用途
|
||||
|
||||
钱包页,展示 Portfolio、Profit/Loss 与四类交易数据(Positions / Open orders / History / Withdrawals)。当前已按 `design/pencil-new.pen` 的 `tuLlv`、`KRKZv`、`aRC6m`、`tZDYO` 节点同步为卡片化移动端布局:不展示搜索栏和筛选工具栏,tab 选中后直接显示列表内容。
|
||||
|
||||
其中 `tuLlv`(Wallet - Positions)已按设计稿做 1:1 样式对齐:
|
||||
- 页面容器使用移动端自适应宽度(`width: 100%`),统一 `16px` 间距与内边距
|
||||
- 顶部为「钱包」标题
|
||||
- Portfolio 卡片使用主色背景(`$--primary`)与白色文本
|
||||
- 快捷操作区为两个等宽按钮(`t('wallet.deposit')` / `t('wallet.withdraw')`)
|
||||
- Settlement 卡片为紧凑样式,右侧胶囊 Claim 按钮
|
||||
- Wallet Section 为圆角描边卡片 + 胶囊 tabs + Positions 卡片列表
|
||||
- Positions 标题区采用“右侧价格优先”的自适应布局:价格变长时标题区域自动收缩,标题单行并使用跑马灯展示超出内容,避免与价格重叠
|
||||
|
||||
## 核心能力
|
||||
|
||||
- Portfolio 卡片:余额、Deposit/Withdraw 按钮
|
||||
- Profit/Loss 卡片:时间范围切换(1D/1W/1M/ALL)、Lightweight Charts 资产变化面积图;数据格式为 `[timestamp_ms, pnl][]`,**暂无接口时全部显示为 0**(真实时间轴 + 数值 0),有接口后在此处对接;图表交互已禁用拖动和滚轮缩放(`handleScroll/handleScale=false`)
|
||||
- Tab:Positions、Open orders、**History**(历史记录来自 **GET /hr/getHistoryRecordListClient**,`src/api/historyRecord.ts`,需鉴权、按当前用户分页)、Withdrawals(提现记录)
|
||||
- Positions:卡片展示市场图标、标题、YES/NO outcome、价值、盈亏、`t('wallet.sharesLabel')`、`t('wallet.avgPriceLabel')`、`t('wallet.currentPriceLabel')`
|
||||
- Open orders:卡片展示图标、标题、BUY/SELL 标签、YES/NO 标签、`t('wallet.openOrderPriceLabel')`、`t('wallet.filledTotalLabel')`、`t('wallet.orderValueLabel')`、取消按钮
|
||||
- Open orders 标题区与 Positions 一致采用单行跑马灯;标题容器可自适应收缩,优先保证右侧取消按钮与数值不重叠
|
||||
- Open orders 样式参数已按设计值收敛:图标 `44x44`、取消按钮 `32x32` 圆形描边、BUY/SELL 为描边矩形标签(`22px` 高、`6px` 圆角)、YES/NO 为胶囊标签(`20px` 高、`999px` 圆角)
|
||||
- Open orders 顶部结构按设计对齐:左侧图标置于左上,图标右侧为垂直两行(标题 + BUY/YES/NO 同行标签),右侧关闭按钮与图标处于同一顶行;下半部分独立展示价格相关三列信息
|
||||
- 当接口返回的 `order.market` 为空时,标题会自动回退为 `Market · <outcome>`,避免顶部标题为空导致布局塌陷
|
||||
- Open orders 卡片主容器使用纵向布局(上半结构 + 下半价格区),避免价格区被挤到右侧并出现竖排换行
|
||||
- History:支持两种卡片形态(交易卡 + 充值/提现卡)
|
||||
- History(`ny6M5`)已按设计做 1:1 对齐:交易卡为“图标+标题日期+右侧金额”上行、下行“BUY/SELL 标签 + `t('wallet.priceLabel')`/`t('wallet.sharesLabel')`”;资金卡为“左侧图标与标题日期 + 右侧金额”的单行结构
|
||||
- History 标题采用与 Positions/Open orders 一致的单行跑马灯方案,超出宽度时自动循环滚动展示
|
||||
- Withdrawals:紧凑提现卡(日期、链路标签、状态标签、金额/手续费、地址)
|
||||
- Withdrawals(`UjOKn`)按 1:1 结构实现:顶部日期 + 链路/状态标签、中部金额与手续费双列、底部地址;并在无真实记录时提供 3 条预览数据用于视觉验收
|
||||
- Withdrawals 头部布局已调整为“日期在上、chain 在日期下方、状态标签在右侧”,并收紧卡片内边距与列表间距以贴合设计稿密度
|
||||
- **可结算/领取**:未结算项(unsettledItems)由持仓中有 `marketID`、`tokenID` 且 **所属 market.closed=true** 的项组成,用于「领取结算」按钮;不再使用 needClaim 判断
|
||||
- Withdrawals:对接 GET /pmset/getPmSettlementRequestsListClient,保留状态映射展示
|
||||
- DepositDialog、WithdrawDialog 组件
|
||||
- **401 权限错误**:取消订单等接口失败时,通过 `useAuthError().formatAuthError` 统一提示「请先登录」或「权限不足」
|
||||
|
||||
## 使用方式
|
||||
|
||||
- 登录后点击 AppBar 余额或头像菜单进入
|
||||
- 路由 `/wallet`
|
||||
|
||||
## 扩展方式
|
||||
|
||||
1. **真实字段补全**:若后端补充订单价值、手续费等字段,可替换当前前端组合文案(如 `price × total`)。
|
||||
2. **卡片交互增强**:可在不改变结构前提下添加点击展开、跳转详情、快捷撤单等行为。
|
||||
3. **视觉主题扩展**:保持当前卡片信息架构,按主题变量调整色彩与密度以适配暗色模式。
|
||||
Loading…
x
Reference in New Issue
Block a user