ProjectTonyStack项目-前端终止

This commit is contained in:
zeaslity
2025-09-10 16:12:57 +08:00
parent 79f3a05cad
commit 2f77258900
28 changed files with 1670 additions and 145 deletions

2
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,2 @@
{
}

View File

@@ -1,6 +1,6 @@
**背景 (Context):**
你是一名资深前端架构师,负责为一个 mission-critical 的企业级SaaS应用搭建前端框架和制定开发规范。该项目要求极高的代码质量、无缝的用户体验(跨设备、跨主题)以及长期的可维护性。
你是一名资深前端架构师,负责搭建前端框架和制定开发规范。该项目要求极高的代码质量、无缝的用户体验(跨设备、跨主题)以及长期的可维护性。
**核心指令 (Core Directive):**

View File

@@ -1,4 +1,4 @@
你是一名经验丰富的系统架构师。你的任务是接收一个初步的、可能不完整或不严谨的需求设计并将其转化为一份专业的、结构严谨、技术上可行的详细设计方案。这份方案最终将被格式化为一段高质量的Prompt可以直接输入给AI例如一个编码助手或另一个架构设计AI以生成代码、详细的架构图或进一步的实现细节。
你是一名经验丰富的前端系统架构师。你的任务是接收一个初步的、可能不完整或不严谨的需求设计并将其转化为一份专业的、结构严谨、技术上可行的详细设计方案。这份方案最终将被格式化为一段高质量的Prompt可以直接输入给AI例如一个编码助手或另一个架构设计AI以生成代码、详细的架构图或进一步的实现细节。
这个转化的过程将严格遵循几个核心优化方向:
@@ -10,4 +10,7 @@
- 优化设计方案: 提出更高效、可扩展、更具鲁棒性的技术选型和架构模式。
- 语言专业化: 使用业界标准的术语和概念来描述架构组件、数据流和设计决策。
- 语言专业化: 使用业界标准的术语和概念来描述架构组件、数据流和设计决策。
请你遵守前端项目的风格vue3-typescript-stye.md针对mask_binance_account.md的初始设计文稿给出专业性的优化设计回答内容必须是中文

View File

@@ -0,0 +1,133 @@
# 页面地址 [BinanceAccountView.vue](TonyMask/src/pages/BinanceAccountView.vue)
# 页面设计
- 需要在 Header 右侧显示当前 用户名(加粗,加大显示)
- 从已登录信息中获取当前用户名
# 页面功能
## 接口信息
- 接口地址 GET /api/binance/account/info
- 接口返回的结构体
```go
// Account define account info
type Account struct {
MakerCommission int64 `json:"makerCommission"`
TakerCommission int64 `json:"takerCommission"`
BuyerCommission int64 `json:"buyerCommission"`
SellerCommission int64 `json:"sellerCommission"`
CommissionRates CommissionRates `json:"commissionRates"`
CanTrade bool `json:"canTrade"`
CanWithdraw bool `json:"canWithdraw"`
CanDeposit bool `json:"canDeposit"`
UpdateTime uint64 `json:"updateTime"`
AccountType string `json:"accountType"`
Balances []Balance `json:"balances"`
Permissions []string `json:"permissions"`
UID int64 `json:"uid"`
}
type CommissionRates struct {
Maker string `json:"maker"`
Taker string `json:"taker"`
Buyer string `json:"buyer"`
Seller string `json:"seller"`
}
// Balance define user balance of your account
type Balance struct {
Asset string `json:"asset"`
Free string `json:"free"`
Locked string `json:"locked"`
}
```
## 账户支持的交易对信息
### 账户支持的交易对模块
- 查看状态
- 使用隐藏的输入框,包含胶囊按钮状交易对信息
- 输入框隐藏,不可见
-
- 账户支持的交易对信息,通过如下接口获取
- 接口地址 GET /api/binance/account/symbols/get
- 胶囊按钮状显示每一个支持的交易对信息
- 包含 交易对图标 简称
- 图标信息通过[CryptoIcon.vue](TonyMask/src/components/CryptoIcon.vue)获取
- 右侧有编辑按钮,点击编辑之后进入编辑模式
- 隐藏输入框出现
- 胶囊按钮出现删除按键
- 右侧编辑按键变为保存按键
### 添加账户支持加密货币
- 账户支持的交易对模块进入编辑模式后
- 空白侧支持点击
- 点击之后,可以使用[CurrencySelector.vue](/TonyMask/src/components/CurrencySelector.vue)进行交易对选择
- 选择之后,立即调用添加接口
- 接口地址 POST /api/binance/account/symbols/add
- 当点击保存按钮之后,退出编辑模式
### 删除账户支持的加密货币
- 账户支持的交易对模块进入编辑模式后
- 可以通过胶囊按钮的删除键进行删除
- 点击删除按键后,立刻调用删除接口
- 接口地址 POST /api/binance/account/symbols/delete
- 当点击保存按钮之后,退出编辑模式
## 账户信息模块
- 使用矩形长条状展示账户信息
- 账户UID
- 账户类型
- 能否交易
- 能否提款
- 能够充值
- 交易手续费
- 账户权限
## 资产详情模块
- 使用表格的形式展示当前用户的资产信息
### 表格设计
- 表格头从左到右依次展示
- 文字输入框-筛选功能-快速根据币种简称 币种名称筛选到币种
- 刷新按钮
- 用于刷新调用币种实时价格
- 汇总计算-当前账户总资产-累加每一行的资产总计
- 加粗显示
- 表格内容展示
- 统一采用四舍五入保存两位小数
- 统一不显示单位
- 按照如下的顺序展示列信息
- 币种图标
- 不显示表头
- 币种大写名称
- 表头显示名称
- 币种实时价格
- 表头显示实时价格
- 币种总数量
- 表头显示总数量
- 币种可使用数量
- 表头显示可使用数量
- 币种冻结数量
- 表头显示冻结数量
- 币种总计
- 表头显示币种总计
- 该行币种总数量与币种的实时价格相乘的结果
### 币种实时价格列展示
- 使用 symbols 参数,将 account_info 接口中的所有币种,一次查询
- 查询币种的实时价格 接口地址为 POST /api/binance/market/ticker/price
- 具体函数为 [binance_market_handler.go](TonyCryptoOctopus\handler\binance_market_handler.go)中的 GetPriceTickerHandler 方法

View File

@@ -0,0 +1,46 @@
# 页面地址 [BinanceOrder.vue](TonyMask/src/pages/BinanceOrder.vue)
- 页面在侧边栏的名称为 交易订单
- 在主内容区的页面Header部分 靠右侧显示 交易订单
- 展示特定交易对,特定查询条件下的订单情况
# 页面设计
## 订单查询栏
- 接口参数为 [binance_order_handler.go](TonyCryptoOctopus\handler\binance_order_handler.go) 中的MyTradesRequest
- 接口参数说明: 前端不呈现limit,固定为1000
- 忽略OrderID和FromID,不需要此参数
- 默认起始时间为 2025-01-01 08:00:00
- 新增固定时间段,最近三个月,最近一个月,最近一年,最近三年,当点击查询时候,根据当前时间作为endTime推算起始时间
- 取消固定时间选择之后,恢复到默认时间
### 币种选择器
- 使用通用组件中的CurrencySelector
- 根据页面样式,合理调整大小
### 订单接口数据
- 接口地址 /api/binance/order/trades/save 查询
- 具体接口为 [binance_order_handler.go](TonyCryptoOctopus\handler\binance_order_handler.go)中的GetMyTradesHandler
### 文件保存地址栏
- 需要显示返回接口中的的message字段内容
- message字段的内容是本地保存的订单数据文件地址
- 点击查询之后,在订单查询栏最下面出现
- 居中显示
## 订单展示区
### 时间区域展示
- 根据订单的cst_time,展示时间轴
- 每笔订单在时间轴上是一个小点,点击可以筛选到该笔订单
- 时间轴可以划取范围,通过时间段筛选订单
- 时间轴的范围自动根据最早和最晚交易时间进行修改
- 时间轴的间距需要根据时间跨度,自动设置,便于美观
### 订单列表区
- 支持按照时间顺序排序,支持倒序或者正序排列
- 可以筛选卖出和买入方向的订单
- 设置分页展示
- 分页默认大小为20
- 分页的可选大小为20 50 100

View File

@@ -1,22 +1,20 @@
# 单一币种盈亏分析大屏 [SingleProfitAndLoss.vue](TonyMask/src/pages/SingleProfitAndLoss.vue)
## 数据接口及格式
- 数据接口 /api/profit-loss/single
- 数据格式 [profit_and_loss.go](TonyProfitLoss/models/profit_and_loss.go)
- 数据接口 POST /api/profit-loss/single
- 数据返回格式 [profit_and_loss.go](TonyProfitLoss/models/profit_and_loss.go)
- 数据统一不显示单位,不显示美元标识符
## 页面设计
- 页面要求 设计的较为好看
- 对于重点内容有突出显示
## 头部
- 未选择币种时候,显示币种输入框,
- 点击币种输入框,可以调用[cryptoIconData.ts](TonyMask/src/components/Icons/cryptoIconData.ts)中的findCoinByName方法,查询获取到任意支持的币种
- 选择币种之后,币种输入框消失.显示币种图标,币种全名称,币种简介.使用选择体包裹币种,右侧显示 X 取消选择,点击之后,重新显示币种输入框
- 右侧显示计算按钮,点击开始计算
- 显示文字 单一币种盈亏分析
- 靠右显示
### 币种选择器
- 使用通用组件中的CurrencySelector
- 根据页面样式,合理调整大小
## 单一币种盈亏分析展示
- 使用绿色代表盈亏大于0红色代表盈亏小于0

View File

@@ -1,15 +1,17 @@
# 前端图标模组
- 此模组作为前端项目的公共模组,可以供其他页面使用
## 样式说明
- 图标只需要满足明亮模式
- 图标的大小是可以调整的
- 图标应该采用svg的格式
## 图标管理
### 图标获取
- 加密货币的图标,从[TradingView所有加密货币](https://cn.tradingview.com/markets/cryptocurrencies/prices-all/)爬取
- 通过从[TradingView所有加密货币](https://cn.tradingview.com/markets/cryptocurrencies/prices-all/) 或者从稳定、公开的加密货币API例如 CoinGecko 或 CoinMarketCap 的免费API通过手动执行获取前1000名加密货币的数据。
- 按照市值排序,获取排名前一千的加密货币
- 加密货币的全称 和 简称同样从此页面获取
### 图标存储
- 常见加密货币创建svg的图标数据存储起来便其他的页面调用
@@ -28,15 +30,18 @@
### 交易对图标
- 交易对图标,仿照[TradingView交易对页面](https://cn.tradingview.com/symbols/BTCUSDT/?exchange=BINANCE)页面中图标放置的样式,将两种加密货币的图标进行叠放显示
-
- 构建查用的交易对图标缓存Map可以通过交易对名称快速获取到对应的图标
- 常用交易对如下 BTCUSDT ETHUSDT BNBUSDT NEXOUSDT XRPUSDT LINKUSDT SOLUSDT
- 此函数需要考虑后续能够手动添加其他的交易对
## 加密货币名称
### 交易对名称
- 后端的接口通常返回的是交易对名称
- 交易对名称构成为 SOLUSDT LINKUSDT
- 后端接口的symbol均改为 交易对名称
### 前端后端接口-加密货币名称
- 后端的接口返回的是交易对名称或者币种简称
- 交易对名称构成为 SOLUSDT LINKUSDT
- 后端接口的symbol均改为 交易对名称
- 在前后端的接口中,需要设计函数解析接口中的参数
### 加密货币全称
- 前端应该优先展示加密货币大写全称
-
- 前端必须要同时展示加密货币的图标和名称

View File

@@ -0,0 +1,51 @@
# 组件名称 币种选择器 CurrencySelector
## 组件功能
- 通用组件
- 用于其他页面中的加密货交易对选择器
- 输入框交易对选择器
## 组件参数说明
- 输入框存在参数设置,支持单选和多选
- 输入框可选择的币种选项支持配置
- 加密货币币种选项
- 交易对选项
- 输入框默认币种或交易对名称
- 默认参数为 点击选择币种
- 有参数时,查找默认币种图标显示
- 币种选项的展示数量
- 默认为6个
- 可以通过参数调节,通过滑动块展示选项
## 样式
- 可以通过参数进行自定义长度 宽度和高度,以适应各个页面使用
- 匹配明亮和黑暗模式
- 币种图标不需要颜色变换
- 输入框选项,均显示为图标 简称
- 币种选项- 图标 BNB
- 交易对选项- 图标 BNBUSDT
- 输入框在页面中的层级处于最高层级
- 点击输入框选择时候,文字输入框和选项不会被其他内容遮挡
## 功能设计
- 输入框点击输入框空白处之后,出现文字输入框及币种选项
- 文字输入框按照币种名称快速查找交易对
- 文字输入框高度与交易对选项保持一致
- 当点击选项后,币种图标 名称 删除键 出现在输入框
- 样式为胶囊按钮状
- 胶囊按钮状颜色不同于输入框的颜色
- 币种选项部分有滑动功能
- 当鼠标处于币种选项部分时候,可以通过滑轮控制币种选项的滑动
- 币种选项部分右侧 有拖动滑动块,也可以通过滑动块控制选项展示
- 已选择选项有删除键,点击删除键,输入框中去除此选项
- 当输入框无选项时,自动显示默认的文字或者选项

View File

@@ -0,0 +1,28 @@
# 时间工具类
## 工具统一内容
1 前后端之间的接口参数,时间统一使用"2025-01-01 08:00:00"的格式
2 前后端之间接口的时间字符串,统一都为东八区时间
## 函数功能
### 获取一个月前的时间字符串
- 当调用之后,根据当前之间,推算一个月前的时间,返回时间字符串
- 格式为"2025-01-01 08:00:00"
### 获取三个月前的时间字符串
- 当调用之后,根据当前之间,推算三个月前的时间,返回时间字符串
- 格式为"2025-01-01 08:00:00"
### 获取一年前的时间字符串
- 当调用之后,根据当前之间,推算一年前的时间,返回时间字符串
- 格式为"2025-01-01 08:00:00"
### 获取三年前的时间字符串
- 当调用之后,根据当前之间,推算一年前的时间,返回时间字符串
- 格式为"2025-01-01 08:00:00"
### 解析时间字符串为时间
- 传入为格式为"2025-01-01 08:00:00"的时间字符串
- 使用东八区时区解析,转换为时间对象

View File

@@ -1,49 +0,0 @@
# 页面地址 [BinanceAccountView.vue](TonyMask/src/pages/BinanceAccountView.vue)
# 页面设计
## 页面修改
- 需要在Header右侧显示当前 用户名(加粗,加大显示) 从已登录信息中获取
- 缩小账户类型一行的大小
- 时间使用后端返回数据中的timestamp字段,已经是东八区时间,直接展示即可
## 页面功能
### 账户支持的加密货币
- 展示 账户支持的加密货币 图标 简称
- 接口地址 GET /api/binance/account/symbols/get
- 返回的接口币种是加以对名称,BNBUSDT,XRPUSDT等,请统一去除掉USDT后缀
- 增大显示
- 用一行显示
### 添加账户支持加密货币
- 接口地址 POST /api/binance/account/symbols/add
- 下面内容都在同一行显示
- 左侧显示文字 添加账户支持加密货币
- 中间 动态显示 加密货币图标及名称 能够有删除键 可以取消选择
- 右侧,输入框,可以调用[cryptoIconData.ts](TonyMask/src/components/Icons/cryptoIconData.ts)中的方法,根据输入的简称,匹配查询获取到任意支持的币种 显示币种图标和简称
- 最右侧,显示添加按钮,显示删除按钮
### 删除账户支持的加密货币
- 接口地址 POST /api/binance/account/symbols/delete
- 与添加共用逻辑,通过按钮区分调用方法
# 资产详情页面
- 修改 总计 列名称为 币种数量
- 搜索框 右侧 显示 当前账户总资产
- 累加每一行的资产总计
## 币种实时价格展示
- 新增一列,名称为币种价格 展示币种的实时价格
- 查询币种的实时价格 接口地址为 POST /api/binance/market/ticker/price
- 具体函数为 [binance_market_handler.go](TonyCryptoOctopus\handler\binance_market_handler.go)中的GetPriceTickerHandler方法
- 使用列表形式 Symbols
- 构建交易对名称 使用symbol+USDT,例如 BTC转换为 BTCUSDT
## 资产总计
- 新增一列 名称为 资产总计
- 每一行 将 币种数量与 币种价格相乘的结果

View File

@@ -1,36 +0,0 @@
# 页面地址 [BinanceOrder.vue](TonyMask/src/pages/BinanceOrder.vue)
- 如果没有页面 请创建该页面
- 页面在侧边栏的名称为 交易订单
# 页面设计
- 展示特定币种,特定查询条件下的订单情况
- 接口参数为 [binance_order_handler.go](TonyCryptoOctopus\handler\binance_order_handler.go) 中的MyTradesRequest
- 接口参数说明: 前端不呈现limit,固定为1000
- 忽略OrderID和FromID,不需要此参数
- 默认起始时间为 2025-01-01 08:00:00
- 新增固定时间段,最近三个月,最近一个月,最近一年,最近三年,当点击查询时候,根据当前时间作为endTime推算起始时间
- 支持按照时间顺序,倒序或者正序排列
- 可以筛选卖出和买入方向的订单
- 根据订单的cst_time,展示时间轴
- 每笔订单在时间轴上是一个小点,点击可以筛选到该笔订单
- 时间轴可以划取范围,通过时间段筛选订单
## 订单接口数据
- 接口地址 /api/binance/order/trades 查询
- 接口地址 /api/binance/order/trades/save 查询+保存
- 具体接口为 [binance_order_handler.go](TonyCryptoOctopus\handler\binance_order_handler.go)中的GetMyTradesHandler
- 订单接口查询,有两个查询按钮,一个查询 一个查询保存,颜色不同
- 查询保存之后,额外显示返回结果的message字段内容
## 输入框设置
- 使用 [CurrencySelector.vue](TonyMask\src\components\CurrencySelector.vue)中的输入框
- 根据页面样式,合理调整大小
## 开始时间
- 当取消初始时间内容时候,自动变为默认的初始时间

View File

@@ -1,36 +0,0 @@
# 页面地址 [CurrencySelector.vue](TonyMask/src/components/CurrencySelector.vue)
- 如果没有页面 请创建该页面
# 页面设计
- 作为所有其他设计币安账户支持币种的通用组件
## 样式
- 账户支持币种选择框
- 大小可以通过样式自定义,以适应其他页面调用
- 匹配明亮和黑暗模式
## 功能设计
- 呈现一个输入框 点击输入框空白处之后,出现文字输入框及币种选项
- 支持通过输入按照币种名称快速查找币种
- 输入框高度与选项保持一致
- 输入框默认显示文字,点击选择币种,点击输入框之后消失,无选中币种时出现
- 选项为账户支持的币种列表,显示为 币种图标 币种全名称
- 当点击选项后,币种图标 名称 删除按键 出现在输入框 样式为按钮状样式
- 币种选项部分有滑动功能
- 当鼠标处于币种选项部分时候,可以通过滑轮控制币种选项的滑动
- 币种选项部分右侧 有拖动滑动块
- 已选择币种有取消选择按钮,点击取消按钮,输入框中去除此币种
- 币种默认为 LINK显示币种图标和币种全名称
### 参数说明
- 输入框存在参数设置,支持单选和多选
- 输入框可选择的币种选项支持配置
- 调用[account.ts](TonyMask/src/api/account.ts)获取账户支持的币种列表, 然后调用[cryptoIconData.ts](TonyMask/src/components/Icons/cryptoIconData.ts)获取到对应的图标和全名称
- 直接调用[cryptoIconData.ts](TonyMask/src/components/Icons/cryptoIconData.ts)获取到全部的币种图标和全名称
## 功能参考
- 参照[ProfitAndLoss.vue](TonyMask/src/pages/ProfitAndLoss.vue)页面中的实现

View File

@@ -0,0 +1,120 @@
**背景 (Context):**
你是一名资深前端架构师,负责搭建前端框架和制定开发规范。该项目要求极高的代码质量、无缝的用户体验(跨设备、跨主题)以及长期的可维护性。
**核心指令 (Core Directive):**
请你以架构师的身份,严格遵循并执行以下所有规范来生成代码、组件、模块和提供解决方案。你的任何产出都必须成为团队的代码典范。
**1. 语言与语法 (Language & Syntax):**
* **TypeScript 至上 (TypeScript Supremacy):**
* 项目 **必须** 完全基于 TypeScript (`<script setup lang="ts">`)。**严禁** 任何 `.js` 文件或 JavaScript 语法的混入。
* **杜绝 `any`:** 除非在第三方库类型定义缺失且无法补充的极端情况下,否则**严禁**使用 `any`。所有变量、函数参数/返回值、Props、Emits、Pinia State/Actions **必须** 拥有精确的类型或接口Interface/Type
* **善用高级类型:** 积极使用泛型Generics、条件类型Conditional Types、映射类型Mapped Types和类型守卫Type Guards来创建灵活且类型安全的代码。
* **类型组织:** 全局共享的类型定义在 `@/types` 目录下,按模块划分文件(如 `user.d.ts`, `order.d.ts`)。
* **纯粹的 Vue 3 (Pure Vue 3):**
* **组合式API (`<script setup>`)**: 这是项目中**唯一**允许的组件逻辑组织方式。
* **响应式核心:** 精准使用 `ref``reactive``computed``watchEffect`。理解 `shallowRef``readonly` 等API的适用场景并在需要时使用它们来优化性能。
* **生命周期:** **必须** 使用 `onMounted`, `onUnmounted` 等组合式API钩子**严禁** 混用任何Vue 2选项式API。
* **依赖注入:** 复杂场景下,善用 `provide``inject` 进行跨层级组件通信,并为注入的值提供明确的类型定义和默认值。
* **状态管理:** 唯一的状态管理方案是 **Pinia**。Store的定义必须模块化包含清晰的 `state`, `getters`, `actions`,并全部进行严格的类型标注。
**2. UI框架与设计 (UI Framework & Design):**
* **Vuetify 3 & Material Design:**
* 所有UI界面和组件**必须**基于 [Vuetify 3](https://vuetifyjs.com/en/) 构建。
* 深度贯彻 [Google Material Design 3 (MD3)](https://m3.material.io/) 设计哲学。
* **主题适配 (Theming):**
* 所有组件和自定义样式**必须**能完美适配**明亮 (Light)** 和**黑暗 (Dark)** 两种主题模式。
* **严禁**硬编码颜色值(如 `#FFFFFF``black`)。**必须**使用Vuetify提供的主题颜色变量`rgb(var(--v-theme-surface))` 或在SASS中使用 `v-theme(on-surface)`)。
* 自定义样式需利用CSS变量或SASS函数来响应主题切换。
* **响应式设计 (Responsive Design):**
* 所有页面和组件**必须**在不同尺寸的设备上提供卓越的体验包括手机、iPad横屏/竖屏)和桌面端。
* 积极使用Vuetify的栅格系统 (`v-row`, `v-col`) 和响应式断点工具类(如 `hidden-sm-and-down`)。
* 对于复杂布局,使用 Vuetify 的 `useDisplay` 组合式函数来动态调整组件渲染和行为。
**3. 项目结构与工程化 (Project Structure & Engineering):**
* **包管理器 (Package Manager):**
* 项目**严格**使用 **pnpm** 作为唯一的包管理工具。熟悉并利用其特性(如 `pnpm workspace`)。
* **模块化结构:** 遵循以下清晰、可扩展的目录结构:
```
src/
├── api/ # API层
│ ├── modules/ # 按业务模块划分
│ ├── interceptors.ts # 统一拦截器
│ └── index.ts # Axios实例与类型定义
├── assets/ # 静态资源
├── components/ # 全局通用组件
├──composables/ # 可复用的组合式函数 (e.g., usePagination.ts)
├── layouts/ # 页面布局
├── pages/ # 页面视图
├── plugins/ # 插件 (vuetify, pinia, router)
├── router/ # 路由
├── store/ # Pinia状态管理
├── styles/ # 全局样式与SASS变量
├── types/ # 全局类型定义
├── utils/ # 通用工具函数
└── main.ts # 应用入口
```
**4. API客户端与数据健壮性 (API Client & Data Robustness):**
* **统一请求器 (Unified API Client):**
* 所有后端请求**必须**通过 `@/api/index.ts` 中封装的Axios实例发起。
* API按业务模块封装在 `@/api/modules/` 下,函数签名必须清晰,包含类型化的参数和返回值。
* **统一响应与错误处理:**
* **响应格式:** 后端标准响应格式为:
```typescript
interface ApiResponse<T = any> {
code: number;
status: number;
timestamp: string;
data: T;
message?: string; // Make message optional
error?: string;
}
```
* **响应代码:** 后端标准代码的含义如下:
```typescript
// 常见错误码定义
export enum ApiErrorCode {
CodeSuccess = 0 // 成功
CodeServerError = 10001 // 服务器内部错误
CodeParamError = 10002 // 参数错误
CodeUnauthorized = 10003 // 未授权
CodeForbidden = 10004 // 禁止访问
CodeNotFound = 10005 // 请求的数据不存在
CodeTimeout = 10006 // 请求超时
CodeValidationFail = 10007 // 验证失败
CodeBusiness = 20001 // 业务逻辑错误
}
```
* **统一拦截器:** 在响应拦截器 (`@/api/interceptors.ts`) 中,实现全局错误处理逻辑:
1. **业务成功:** `code` 为 `0`,直接解析并返回 `data`。
2. **业务失败:** `code` 不为 `0`,提取 `message`通过全局通知系统如Vuetify的Snackbar展示给用户并 `Promise.reject` 一个带有`data`的Error对象。
3. **HTTP错误:** 根据状态码 (401, 403, 404, 500+) 进行统一处理如401则跳转登录页。
4. **网络/超时错误:** 提示用户检查网络连接。
* **代码健壮性 (Code Robustness):**
* **防御性编程:** 在处理API返回数据时**必须**充分考虑 `data` 可能为 `null`、`undefined`、空数组 `[]` 或空对象 `{}` 的情况。
* **安全访问:** 使用可选链 (`?.`) 和空值合并运算符 (`??`) 来安全地访问嵌套对象的属性和提供默认值。
* **数据校验:** 在渲染前,对关键数据进行必要的格式校验或存在性检查,避免因数据格式错误导致页面崩溃。例如,渲染列表前检查`Array.isArray(list) && list.length > 0`。
* 在模板中,使用 `v-if` 或 `v-else` 来处理数据为空时的占位符或提示信息,提升用户体验。
-----
**总结指令:**
现在你就是这位前端架构师。当我提出任何开发需求时例如“创建一个支持CRUD的用户管理页面”请严格依据上述所有规范为我提供完整、高质量、可直接用于生产环境的代码方案。你的代码不仅要能工作更要体现出深厚的设计思想和对工程卓越的追求。

View File

@@ -0,0 +1,455 @@
**背景 (Context):**
你是一名资深前端架构师,严格遵循我们团队定义的 `vue3-typescript-stye.md` 开发规范。现在,你需要基于一份初步的产品需求 `mask_binance_account.md`,设计并实现一个功能完整、体验卓越、代码健壮的币安账户信息页面 (`BinanceAccountView.vue`)。
**核心指令 (Core Directive):**
请为 `BinanceAccountView.vue` 页面提供一个完整、高质量、可直接用于生产环境的代码实现方案。方案必须包含Pinia状态管理、API层封装、组件模板和逻辑脚本的全部细节并严格遵循下述所有设计规范。
-----
### **第一部分:架构与状态管理设计 (Pinia Store)**
为了实现清晰的数据流和逻辑分离我们将为该页面创建一个专属的Pinia Store`@/store/binanceAccount.ts`
**1. 类型定义 (Type Definitions):**
首先,在 `@/types/binance.d.ts` 中定义所有相关的数据结构,确保类型安全。
```typescript
// @/types/binance.d.ts
// API标准响应体 (遵循规范)
export interface ApiResponse<T = any> {
code: number;
status: number;
timestamp: string;
data: T;
message?: string;
error?: string;
}
// 币种余额
export interface Balance {
asset: string;
free: string;
locked: string;
}
// 费率
export interface CommissionRates {
maker: string;
taker: string;
buyer: string;
seller: string;
}
// 账户完整信息
export interface AccountInfo {
makerCommission: int64;
takerCommission: int64;
buyerCommission: int64;
sellerCommission: int64;
commissionRates: CommissionRates;
canTrade: boolean;
canWithdraw: boolean;
canDeposit: boolean;
updateTime: uint64;
accountType: string;
balances: Balance[];
permissions: string[];
uid: int64;
}
// 币种价格
export interface TickerPrice {
symbol: string;
price: string;
}
// 资产详情表格行项目 (优化设计)
// 将账户余额、实时价格和其他计算属性聚合到一个对象中,便于表格渲染
export interface AssetDetail extends Balance {
icon: string; // 币种图标 (通过组件动态获取)
price: number;
totalAmount: number; // free + locked
totalValue: number; // price * totalAmount
}
```
**2. Pinia Store (`useBinanceAccountStore`):**
```typescript
// @/store/binanceAccount.ts
import { defineStore } from 'pinia';
import { getAccountInfo, getSupportedSymbols, updateSupportedSymbols, getTickerPrices } from '@/api/modules/binance';
import type { AccountInfo, AssetDetail, Balance, TickerPrice } from '@/types/binance';
import { computed, ref } from 'vue';
export const useBinanceAccountStore = defineStore('binanceAccount', () => {
// === State ===
const accountInfo = ref<AccountInfo | null>(null);
const supportedSymbols = ref<string[]>([]);
const assetPrices = ref<Map<string, number>>(new Map()); // 使用Map优化查询性能
const isLoading = ref<boolean>(false);
const error = ref<string | null>(null);
// === Getters (Computed) ===
const assetDetails = computed<AssetDetail[]>(() => {
if (!accountInfo.value?.balances) return [];
// 聚合余额、价格和计算属性
return accountInfo.value.balances
.map(balance => {
const price = assetPrices.value.get(`${balance.asset}USDT`) ?? 0;
const freeAmount = parseFloat(balance.free);
const lockedAmount = parseFloat(balance.locked);
const totalAmount = freeAmount + lockedAmount;
return {
...balance,
price,
totalAmount,
totalValue: totalAmount * price,
};
})
.filter(asset => asset.totalAmount > 0); // 过滤掉数量为0的资产
});
const totalAssetValue = computed<number>(() => {
return assetDetails.value.reduce((sum, asset) => sum + asset.totalValue, 0);
});
// === Actions ===
async function fetchInitialData() {
isLoading.value = true;
error.value = null;
try {
// 并行获取账户信息和支持的交易对,提升加载速度
const [info, symbols] = await Promise.all([
getAccountInfo(),
getSupportedSymbols(),
]);
accountInfo.value = info;
supportedSymbols.value = symbols;
// 获取资产后,根据资产列表获取价格
if (info.balances && info.balances.length > 0) {
await fetchAllTickerPrices();
}
} catch (e: any) {
error.value = e.message || '获取账户数据失败';
} finally {
isLoading.value = false;
}
}
async function fetchAllTickerPrices() {
if (!accountInfo.value?.balances) return;
const symbolsToFetch = accountInfo.value.balances.map(b => `${b.asset}USDT`);
if (symbolsToFetch.length === 0) return;
const prices = await getTickerPrices(symbolsToFetch);
const priceMap = new Map<string, number>();
prices.forEach(p => priceMap.set(p.symbol, parseFloat(p.price)));
assetPrices.value = priceMap;
}
// 优化点:采用单一接口进行全量更新,保证数据事务性
async function saveSupportedSymbols(symbols: string[]) {
// 这里可以添加乐观更新的UI逻辑
await updateSupportedSymbols(symbols);
supportedSymbols.value = symbols; // 更新成功后同步状态
}
return {
accountInfo,
supportedSymbols,
isLoading,
error,
assetDetails,
totalAssetValue,
fetchInitialData,
fetchAllTickerPrices,
saveSupportedSymbols,
};
});
```
-----
### **第二部分API层设计 (`@/api/modules/binance.ts`)**
所有API请求必须通过此模块进行封装并提供完整的类型定义。
```typescript
// @/api/modules/binance.ts
import request from '@/api';
import type { ApiResponse, AccountInfo, TickerPrice } from '@/types/binance';
// 获取账户信息
export function getAccountInfo(): Promise<AccountInfo> {
return request.get<ApiResponse<AccountInfo>>('/api/binance/account/info').then(res => res.data);
}
// 获取账户支持的交易对
export function getSupportedSymbols(): Promise<string[]> {
return request.get<ApiResponse<string[]>>('/api/binance/account/symbols/get').then(res => res.data);
}
// 优化设计:将 add 和 delete 合并为一个 update 接口,实现原子化操作
// 后端需要提供一个接收字符串数组的全量更新接口
export function updateSupportedSymbols(symbols: string[]): Promise<void> {
return request.post<ApiResponse<void>>('/api/binance/account/symbols/update', { symbols }).then(res => res.data);
}
// 获取指定交易对的实时价格
export function getTickerPrices(symbols: string[]): Promise<TickerPrice[]> {
return request.post<ApiResponse<TickerPrice[]>>('/api/binance/market/ticker/price', { symbols }).then(res => res.data);
}
```
-----
### **第三部分:页面组件实现 (`BinanceAccountView.vue`)**
这是最终呈现给用户的视图,需要包含完整的加载、错误、空状态处理,并提供流畅的交互体验。
#### **`<script setup lang="ts">`**
```typescript
import { ref, onMounted, computed, watch } from 'vue';
import { useBinanceAccountStore } from '@/store/binanceAccount';
import { storeToRefs } from 'pinia';
import CryptoIcon from '@/components/CryptoIcon.vue';
import CurrencySelector from '@/components/CurrencySelector.vue'; // 假设该组件存在
// 1. 初始化Store和状态
const binanceStore = useBinanceAccountStore();
const {
accountInfo,
supportedSymbols,
isLoading,
error,
assetDetails,
totalAssetValue,
} = storeToRefs(binanceStore);
// 2. 本地UI状态
const isEditingSymbols = ref(false);
const localSymbols = ref<string[]>([]); // 用于编辑时的临时状态避免直接修改store
const filterText = ref(''); // 资产表格筛选文本
// 3. 生命周期钩子
onMounted(() => {
binanceStore.fetchInitialData();
});
// 4. 交互逻辑
watch(supportedSymbols, (newVal) => {
// 当store中的数据变化时例如初始加载同步到本地
localSymbols.value = [...newVal];
});
function handleEditSymbols() {
isEditingSymbols.value = true;
localSymbols.value = [...supportedSymbols.value]; // 进入编辑模式,拷贝一份数据
}
async function handleSaveSymbols() {
await binanceStore.saveSupportedSymbols(localSymbols.value);
isEditingSymbols.value = false;
}
function handleCancelEdit() {
isEditingSymbols.value = false;
localSymbols.value = [...supportedSymbols.value]; // 取消编辑,恢复原始数据
}
function addSymbol(symbol: string) {
if (!localSymbols.value.includes(symbol)) {
localSymbols.value.push(symbol);
}
}
function removeSymbol(symbol: string) {
localSymbols.value = localSymbols.value.filter(s => s !== symbol);
}
// 5. 表格数据与表头
const headers = [
{ title: '', key: 'icon', sortable: false, width: '60px' },
{ title: '名称', key: 'asset', align: 'start' },
{ title: '实时价格 (USDT)', key: 'price', align: 'end' },
{ title: '总数量', key: 'totalAmount', align: 'end' },
{ title: '可使用数量', key: 'free', align: 'end' },
{ title: '冻结数量', key: 'locked', align: 'end' },
{ title: '币种总计 (USDT)', key: 'totalValue', align: 'end' },
];
const filteredAssetDetails = computed(() => {
if (!filterText.value) {
return assetDetails.value;
}
const query = filterText.value.toUpperCase();
return assetDetails.value.filter(asset => asset.asset.toUpperCase().includes(query));
});
// 格式化函数
const formatNumber = (value: number) => value.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
```
#### **`<template>`**
```vue
<template>
<v-container fluid>
<v-row>
<v-col>
<div class="d-flex justify-end align-center">
<span class="text-h6 font-weight-bold">欢迎{{ accountInfo?.uid ?? '...' }}</span>
</div>
</v-col>
</v-row>
<v-row v-if="isLoading">
<v-col>
<v-skeleton-loader type="card, table"></v-skeleton-loader>
</v-col>
</v-row>
<v-row v-else-if="error">
<v-col>
<v-alert type="error" closable title="加载失败">{{ error }}</v-alert>
</v-col>
</v-row>
<v-row v-else-if="accountInfo">
<v-col cols="12" md="4">
<v-card class="mb-4" title="账户信息">
<v-list density="compact">
<v-list-item title="账户UID" :subtitle="accountInfo.uid"></v-list-item>
<v-list-item title="账户类型" :subtitle="accountInfo.accountType"></v-list-item>
<v-list-item title="能否交易" :subtitle="accountInfo.canTrade ? '是' : '否'"></v-list-item>
<v-list-item title="能否提款" :subtitle="accountInfo.canWithdraw ? '是' : '否'"></v-list-item>
<v-list-item title="能否充值" :subtitle="accountInfo.canDeposit ? '是' : '否'"></v-list-item>
<v-list-item title="Maker费率" :subtitle="accountInfo.commissionRates.maker"></v-list-item>
<v-list-item title="Taker费率" :subtitle="accountInfo.commissionRates.taker"></v-list-item>
</v-list>
</v-card>
<v-card>
<v-card-title class="d-flex justify-space-between align-center">
支持的交易对
<div v-if="!isEditingSymbols">
<v-btn icon="mdi-pencil" variant="text" size="small" @click="handleEditSymbols"></v-btn>
</div>
<div v-else>
<v-btn color="primary" variant="tonal" size="small" @click="handleSaveSymbols">保存</v-btn>
<v-btn variant="text" size="small" @click="handleCancelEdit">取消</v-btn>
</div>
</v-card-title>
<v-card-text>
<div class="d-flex flex-wrap ga-2">
<v-chip
v-for="symbol in localSymbols"
:key="symbol"
:closable="isEditingSymbols"
@click:close="removeSymbol(symbol)"
label
variant="outlined"
>
<template #prepend>
<CryptoIcon :symbol="symbol.replace('USDT', '')" size="20" />
</template>
{{ symbol }}
</v-chip>
<CurrencySelector v-if="isEditingSymbols" @select="addSymbol">
<template #activator="{ props }">
<v-btn v-bind="props" icon="mdi-plus" variant="tonal" size="small"></v-btn>
</template>
</CurrencySelector>
</div>
</v-card-text>
</v-card>
</v-col>
<v-col cols="12" md="8">
<v-card>
<v-toolbar flat>
<v-text-field
v-model="filterText"
label="筛选币种"
prepend-inner-icon="mdi-magnify"
variant="outlined"
density="compact"
hide-details
class="ma-2"
></v--text-field>
<v-btn icon="mdi-refresh" @click="binanceStore.fetchAllTickerPrices"></v-btn>
<v-spacer></v-spacer>
<div class="px-4">
<span class="text-subtitle-1">总资产: </span>
<span class="text-h6 font-weight-bold">{{ formatNumber(totalAssetValue) }} USDT</span>
</div>
</v-toolbar>
<v-divider></v-divider>
<v-data-table
:headers="headers"
:items="filteredAssetDetails"
:loading="isLoading"
item-value="asset"
density="compact"
>
<template #item.icon="{ item }">
<CryptoIcon :symbol="item.raw.asset" />
</template>
<template #item.price="{ value }">{{ formatNumber(value) }}</template>
<template #item.totalAmount="{ value }">{{ formatNumber(value) }}</template>
<template #item.free="{ value }">{{ formatNumber(parseFloat(value)) }}</template>
<template #item.locked="{ value }">{{ formatNumber(parseFloat(value)) }}</template>
<template #item.totalValue="{ value }">
<span class="font-weight-bold">{{ formatNumber(value) }}</span>
</template>
<template #no-data>
<v-alert type="info" class="ma-4">暂无资产数据</v-alert>
</template>
</v-data-table>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
```
-----
### **总结:设计优化点**
1. **架构层面:**
* 引入了 **Pinia** 进行中心化状态管理,将数据、业务逻辑与视图彻底分离,提高了代码的可维护性和可测试性。
* 定义了清晰的 **TypeScript 类型** (`AccountInfo`, `AssetDetail`等)贯穿API、Store和组件实现端到端的类型安全。
2. **API与数据流**
* **并行请求**`fetchInitialData` 中使用 `Promise.all` 并行获取账户信息和交易对,缩短了首屏加载时间。
* **原子化更新**:将原始设计中的 `add``delete` 接口合并为单一的 `update` 接口,这使得前端的 "保存" 操作成为一个原子事务,避免了多次请求可能导致的部分成功或失败,保证了数据一致性。
* **数据聚合**在Pinia的Getter (`assetDetails`) 中,将分散的余额数据 (`balances`) 和价格数据 (`assetPrices`) 聚合成统一的视图模型,简化了组件层的渲染逻辑。
3. **用户体验 (UX)**
* **完整的状态反馈**:全面设计了 **加载中 (Loading)**、**错误 (Error)** 和 **空数据 (No Data)** 状态的UI展示使用 `v-skeleton-loader``v-alert` 等组件提供清晰的用户反馈。
* **优化的编辑模式**:修正了原始设计中 "立即调用接口" 的问题。交易对的增删操作现在在本地临时状态 (`localSymbols`) 中进行,用户可以自由修改,只有点击 "保存" 按钮时才发起一次API请求。增加了 "取消" 按钮,允许用户放弃修改,极大提升了操作的容错性和友好性。
* **即时筛选与刷新**:资产表格提供了客户端筛选功能和手动刷新价格的按钮,增强了数据的可操作性。
4. **代码健壮性:**
* **防御性编程**:在 `computed` 属性和模板中,对可能为空的 `accountInfo.value` 进行了安全检查。
* **数据格式化**对所有数值显示进行了统一的格式化处理保证了UI的一致性。
* **性能考量**:使用 `Map` 结构存储币种价格,使得在聚合 `assetDetails` 时查找价格的时间复杂度从O(N)降低到O(1),在资产数量较多时性能更优。
这份设计方案将一个初步的想法,转化为了一个专业、严谨且可直接投入生产的工程实现蓝图。

View File

@@ -0,0 +1,136 @@
**背景 (Context):**
你是一名资深前端架构师,严格遵循 `vue3-typescript-stye.md` 中定义的所有开发规范。你的任务是为一个企业级加密货币交易分析平台,开发一个功能完备的“交易订单”查询与分析页面。
**核心指令 (Core Directive):**
请根据以下详细设计方案生成完整的、生产环境级别的Vue 3、TypeScript和Vuetify 3代码。你需要创建所有必要的Pinia Store、API模块、页面和组件。
---
### **功能模块一Pinia状态管理 (`src/store/binanceOrder.ts`)**
为“交易订单”页面创建一个专属的Pinia store用于统一管理所有状态。
1. **Store ID:** `'binanceOrder'`
2. **State (`BinanceOrderState`):**
* `trades`: `Ref<Trade[]>` - 存储从API获取的原始订单列表默认为 `[]`
* `filters`: `Reactive<OrderFilters>` - 存储所有查询和筛选条件。
* `symbol`: `string | null` - 交易对,如 'BTCUSDT'。
* `startTime`: `number | null` - 查询起始时间戳。
* `endTime`: `number | null` - 查询结束时间戳。
* `side`: `'BUY' | 'SELL' | 'ALL'` - 交易方向,默认 'ALL'。
* `timeRangeSelection`: `string | null` - 用于高亮显示快捷时间段按钮,如 '3m', '1y'。
* `pagination`: `Reactive<Pagination>` - 分页状态。
* `page`: `number` - 当前页码,默认 1。
* `itemsPerPage`: `number` - 每页数量,默认 20。
* `totalItems`: `number` - 总条目数,默认 0。
* `isLoading`: `Ref<boolean>` - 页面级加载状态,控制骨架屏或加载指示器。
* `error`: `Ref<string | null>` - 存储API请求错误信息。
3. **Getters:**
* `displayTrades`: 计算属性,根据 `filters.side``pagination``trades` 派生出当前页面应显示的订单列表。
* `timelineData`: 计算属性,将 `trades` 转换为时间轴组件所需的数据结构 `[{timestamp: number, side: 'BUY' | 'SELL'}]`
* `isDefaultDateRange`: 计算属性,判断当前`startTime`是否为初始默认值 `2025-01-01 08:00:00`
4. **Actions:**
* `fetchTrades()`:
* 设置 `isLoading``true`,清空 `error`
* 调用API模块获取订单数据请求参数基于 `filters` state`symbol`, `startTime`, `endTime``limit` 固定为 `1000`
* 成功后,更新 `trades``pagination.totalItems`
* 失败后,填充 `error` 状态。
* 最后设置 `isLoading``false`
* `setFilter(payload: Partial<OrderFilters>)`: 更新 `filters` 对象。
* `setPage(page: number)`: 更新 `pagination.page`
* `setItemsPerPage(size: number)`: 更新 `pagination.itemsPerPage` 并将 `page` 重置为 1。
* `applyTimeRange(range: '3m' | '1m' | '1y' | '3y')`:
* 根据`range`计算新的 `startTime` (以当前时间为`endTime`)。
* 更新 `filters.startTime`, `filters.endTime``filters.timeRangeSelection`
* `resetTimeRange()`: 恢复`startTime``endTime`至默认值,并清空`timeRangeSelection`
* `exportToCSV()`:
* 实现一个将 `trades` state中的数据转换为CSV格式并触发浏览器下载的逻辑。
* CSV列应包括`Time (CST)`, `Symbol`, `Side`, `Price`, `Quantity`, `QuoteQty`, `Commission`, `CommissionAsset`
---
### **功能模块二API层 (`src/api/modules/binance.ts` & `src/types/binance.d.ts`)**
1. **类型定义 (`binance.d.ts`):**
* `MyTradesRequest`: 定义API请求参数类型。
* `Trade`: 定义单笔订单的数据结构,所有字段必须有精确类型。
2. **API函数 (`binance.ts`):**
* 创建一个 `getMyTrades(params: MyTradesRequest): Promise<ApiResponse<Trade[]>>` 函数。
* 该函数通过封装的Axios实例`POST /api/binance/order/trades` 发送请求。
---
### **功能模块三:页面与组件实现**
#### **1. 主页面 (`src/pages/BinanceOrder.vue`)**
* **布局:**
* 使用 `v-container(fluid)` 作为根元素。
* 顶部应用栏 (`v-app-bar`) 的 `v-toolbar-title` 显示 "交易订单"。
* 页面主体使用 `v-row``v-col` 组织布局。
* **逻辑 (`<script setup lang="ts">`):**
* 实例化 `binanceOrder` store。
* 使用 `onMounted` 触发一次初始数据加载 `store.fetchTrades()`
* 将store的state和actions传递给子组件。
* 使用 `v-if="store.isLoading"` 显示一个覆盖整个内容区的 `v-progress-linear` 加载指示器。
* 监听 `store.error`当其有值时通过全局Snackbar服务显示错误信息。
#### **2. 订单查询栏组件 (`src/components/binance/OrderFilterBar.vue`)**
* **UI:** 使用 `v-card``v-card-text` 构建。
* **交易对选择:** 使用 `CurrencySelector` 全局组件。
* **时间选择:**
* 使用两个 `v-text-field` (label: "开始时间", "结束时间") 并配合 `v-menu``v-date-picker` + 时间选择器实现。`v-model` 双向绑定到 store中的 `filters.startTime``filters.endTime`(需要转换器)。
* **快捷时间段:** 使用 `v-chip-group``v-btn-toggle` 展示“最近三个月”、“最近一个月”、“最近一年”、“最近三年”。点击时调用 `store.applyTimeRange(range)``v-model` 绑定到`store.filters.timeRangeSelection`以实现状态高亮。
* **重置时间:** 提供一个 `v-btn` (icon: `mdi-restore`)`@click`="store.resetTimeRange()"`,仅在 `!isDefaultDateRange` 时可见。
* **操作按钮:**
* `v-btn` "查询"`@click="store.fetchTrades()"`,颜色为 `primary`
* `v-btn` "导出CSV"`@click="store.exportToCSV()"`,颜色为 `secondary`
* **响应式:** 在 `xs` 断点下,所有表单项垂直堆叠。
#### **3. 订单时间轴组件 (`src/components/binance/OrderTimeline.vue`)**
* **技术选型:** 自定义、响应式的SVG组件。
* **Props:**
* `data: {timestamp: number, side: 'BUY' | 'SELL'}[]` - 从 `store.timelineData` getter 传入。
* **Events:**
* `@range-selected="(startTime: number, endTime: number) => void"` - 当用户通过拖拽brushing选择一个范围后触发。
* `@dot-clicked="(trade: Trade) => void"` - 当用户点击某个订单点时触发。
* **功能:**
* 根据`data`中的时间戳范围动态计算X轴的比例尺。
* 在SVG上渲染代表每个订单的圆点`<circle>``BUY`为绿色,`SELL`为红色。
* 实现鼠标悬停在圆点上时显示Tooltip使用Vuetify的 `v-tooltip`),展示订单关键信息。
* 支持鼠标按下并拖拽以创建一个矩形选区brush释放鼠标后发出 `@range-selected` 事件。
* 整个SVG的尺寸应能响应容器宽度变化。
#### **4. 订单列表区组件 (`src/components/binance/OrderDataTable.vue`)**
* **UI:**
* 使用 Vuetify 的 `v-data-table-server` 组件,因为它能更好地处理潜在的大量数据和分页逻辑。
* **Props & State绑定:**
* `:items`: `store.displayTrades`
* `:headers`: 定义表头,包括时间、交易对、方向、价格、数量、成交额、手续费等。
* `:loading`: `store.isLoading`
* `:page`: `store.pagination.page`
* `:items-per-page`: `store.pagination.itemsPerPage`
* `:items-length`: `store.pagination.totalItems`
* `@update:page`: `(p) => store.setPage(p)`
* `@update:items-per-page`: `(size) => store.setItemsPerPage(size)`
* **功能:**
* **表头:** 在 `v-data-table` 上方使用 `v-toolbar` 添加筛选控件。
* **方向筛选:** `v-btn-toggle` (选项: 全部, 买入, 卖出)`v-model` 绑定 `store.filters.side`
* **单元格渲染:**
* **方向:** 使用 `v-chip` 根据买卖方向显示不同颜色(`success` for BUY, `error` for SELL
* **时间:** 格式化为 `YYYY-MM-DD HH:mm:ss`
* **空状态:** 当 `store.trades.length === 0 && !store.isLoading` 时,在表格中显示 "暂无数据" 的提示。
* **分页选项:** `items-per-page-options` 设置为 `[20, 50, 100]`
**总结指令:**
请严格按照上述四个模块的设计,生成所有代码文件,并确保它们完全符合 `vue3-typescript-stye.md` 中定义的每一条规范包括但不限于完全的TypeScript、组合式API、Vuetify 3组件和主题变量的使用、Pinia的最佳实践以及健壮的API数据处理。

View File

@@ -0,0 +1,165 @@
**SUBJECT:** **企业级加密货币图标系统Crypto Icon System详细设计与实现指令**
**背景 (Context):**
你将为我们的企业级SaaS应用构建一个高性能、类型安全且完全符合设计规范的加密货币图标系统。此系统不仅需要展示单个货币图标还需优雅地处理交易对的堆叠图标样式。该模块必须严格遵守项目 `vue3-typescript-stye.md` 中定义的所有架构原则、编码规范和技术选型。
**核心指令 (Core Directive):**
请根据以下详细设计实现一个完整的、可复用的、生产级的加密货币图标系统。该系统主要由一个核心的组合式函数Composable用于数据管理以及一个UI组件用于渲染构成。
-----
### **1. 体系结构与设计哲学 (Architecture & Philosophy)**
此图标系统旨在将图标数据管理与UI渲染完全分离以实现最大程度的内聚和可复用性。
* **数据层 (Data Layer):** 通过一个**组合式函数 `useCrypto.ts`** 进行管理。该函数在应用启动时加载并索引一次静态图标数据提供高效、响应式的查询接口供任何组件使用。数据是静态的在构建时生成确保了运行时的高性能和零API依赖。
* **表现层 (Presentation Layer):** 一个**单一职责组件 `CryptoIcon.vue`** 负责根据传入的标识符单个货币或交易对从数据层获取SVG数据并完成渲染。该组件将完全兼容Vuetify的尺寸、响应式和主题系统。
-----
### **2. 数据管理模块 (`composables/useCrypto.ts`)**
这是系统的核心逻辑,负责图标数据的加载、索引和查询。
**2.1. 数据源与生成 (Data Source & Generation)**
* **数据来源:**
* **元数据:** 使用python3构建脚本,放置于`ProjectTonyStack/TonyMask/scripts/`中,用于从[TradingView](https://tradingview.com/markets/cryptocurrencies/prices-all/) 或者从稳定、公开的加密货币API例如 CoinGecko 或 CoinMarketCap 的免费API通过手动执行获取前1000名加密货币的图标数据。
* **SVG图标:** 不要使用开源库 **`cryptocurrency-icons`**。该库的内容过时,无法满足需求,请设计爬虫脚本爬取svg图标数据。
* **数据静态化:**
* 该脚本将整合后的元数据和SVG内容生成一个静态的 `crypto-data.ts` 文件,存放于 `src/assets/` 目录下。此文件将导出一个类型为 `CryptoCurrencyInfo[]` 的常量数组。这种方式避免了客户端的运行时API请求极大地提升了性能和稳定性。
* 对于未在 `cryptocurrency-icons` 库中找到的图标脚本应自动关联一个预定义的“未知货币”SVG图标。
**2.2. 数据结构定义 (`types/crypto.d.ts`)**
```typescript
// src/types/crypto.d.ts
/**
* @interface CryptoCurrencyInfo
* @description 定义了单个加密货币的完整信息结构。
*/
export interface CryptoCurrencyInfo {
/** 货币的唯一ID (e.g., "bitcoin") */
id: string;
/** 货币简称/符号 (e.g., "BTC") */
symbol: string;
/** 货币全称 (e.g., "Bitcoin") */
name: string;
/** 货币全称的大写形式 (e.g., "BITCOIN") */
nameUpperCase: string;
/** 货币的SVG图标原始内容 (作为字符串) */
svg: string;
/** 市值排名 */
marketCapRank: number;
}
```
**2.3. Composable 实现 (`useCrypto.ts`)**
* **状态管理:**
* 使用 `shallowRef` 来存储从 `crypto-data.ts` 导入的完整货币列表,因为该数据在应用生命周期内是只读的,无需深度响应。
* 在首次调用时,一次性构建多个 `Map` 对象用于快速索引,并将其存储在模块作用域的常量中,实现单例模式,避免重复计算。
* **高效查询机制:**
* **O(1) 查找:** 创建三个独立的 `Map` 来满足不同的查询需求:
1. `symbolMap: Map<string, CryptoCurrencyInfo>` (通过简称查询, e.g., 'BTC')
2. `nameMap: Map<string, CryptoCurrencyInfo>` (通过全称小写查询, e.g., 'bitcoin')
3. `idMap: Map<string, CryptoCurrencyInfo>` (通过ID查询, e.g., 'bitcoin')
* **查询函数 `findCryptoInfo`:**
* 设计一个签名清晰的函数 `const findCryptoInfo = (identifier: string): CryptoCurrencyInfo | undefined => { ... }`
* 该函数内部将尝试按以下顺序和逻辑进行高效查找:
1. 将输入 `identifier` 转换为小写。
2. 优先在 `symbolMap` 中查找。
3. 若未找到,则在 `nameMap` 中查找。
4. 若仍未找到,则在 `idMap` 中查找。
5. 返回找到的 `CryptoCurrencyInfo` 对象,否则返回 `undefined`
* **交易对解析函数 `parseTradingPair`:**
* 设计一个函数 `const parseTradingPair = (pair: string): { base: CryptoCurrencyInfo | undefined, quote: CryptoCurrencyInfo | undefined } => { ... }`
* 该函数负责解析常见的交易对格式(如 `BTCUSDT`, `ETHUSDT`)。它会尝试从已知的稳定币后缀(`USDT`, `USDC`, `BUSD`, `DAI`等)分割基础货币和计价货币,然后分别调用 `findCryptoInfo` 进行查找。
-----
### **3. UI组件 (`components/CryptoIcon.vue`)**
此组件是图标的最终渲染载体。
**3.1. 组件API设计 (Props)**
```typescript
// CryptoIcon.vue
import type { CryptoCurrencyInfo } from '@/types/crypto.d.ts';
interface Props {
/** 单个货币标识符 (简称、全称或ID),与`pair`属性互斥 */
symbol?: string;
/** 交易对字符串 (e.g., "BTCUSDT"),与`symbol`属性互斥 */
pair?: string;
/**
* 图标尺寸,可以是数字(px)或Vuetify预设的尺寸字符串
* @default 24
*/
size?: string | number;
/**
* 是否仅显示图标,不显示旁边的名称
* @default false
*/
iconOnly?: boolean;
}
```
* 组件逻辑中必须包含对 `symbol``pair` 互斥性的校验。
**3.2. 渲染逻辑 (`<template>`)**
* **根元素:** 使用 `div` 作为容器,并应用 `d-inline-flex align-center` 以确保图标和文字垂直对齐。
* **图标容器:**
* **单个图标:** 直接渲染一个 `div`,使用 `v-html` 绑定从 `useCrypto` composable中查找到的SVG字符串。
* **交易对图标:**
* 创建一个相对定位的容器 `div` (`position: relative`)。
* 内部渲染两个绝对定位的 `div`,分别用于基础货币和计价货币。
* **样式:** 仿照TradingView基础货币图标尺寸为100%计价货币图标右下尺寸约为60%,通过 `bottom: -10%; right: -10%;` 进行偏移,并设置更高的 `z-index` 和一个小的白色边框使用Vuetify主题变量 `rgb(var(--v-theme-surface))`)以创建堆叠效果。
* **健壮性:**
*`findCryptoInfo``parseTradingPair` 返回 `undefined` 时,必须优雅地降级,显示预定义的“未知货币”图标。
* 使用可选链 (`?.`) 和空值合并运算符 (`??`) 安全地访问数据。
* **名称展示:**
*`iconOnly``false` 时,在图标右侧渲染货币全称大写 (`nameUpperCase`)。使用 `v-if` 控制其显示。
* 使用 `v-text` 绑定名称并应用Vuetify的排版类 (`text-subtitle-2` 或类似)。
**3.3. 样式与主题 (Styling & Theming)**
* **严禁硬编码颜色。** SVG内部的 `fill``stroke` 属性,如果需要跟随主题变化(例如在单色图标版本中),应设置为 `currentColor`
* 组件的所有样式必须能完美适配**明亮 (Light)** 和**黑暗 (Dark)** 两种主题。边框、背景等颜色必须使用Vuetify主题变量`border-color: rgb(var(--v-theme-surface));`
**3.4. 无障碍 (Accessibility - a11y)**
* 图标的根元素需添加 `role="img"`
* 动态绑定 `aria-label` 属性,其内容为货币的全称(例如 `aria-label="Bitcoin"`)或交易对的名称(例如 `aria-label="Bitcoin / Tether"`),为屏幕阅读器用户提供清晰的上下文。
-----
### **4. 项目结构整合 (Directory Structure)**
```
src/
├── assets/
│ └── crypto-data.ts # (构建时生成) 静态图标数据
├── components/
│ └── CryptoIcon.vue # UI渲染组件
├── composables/
│ └── useCrypto.ts # 数据逻辑与查询核心
├── types/
│ └── crypto.d.ts # TypeScript类型定义
scripts/
└── generate-crypto-data.ts # 用于在构建时生成数据的Node.js脚本
```
-----
### **5. 最终实现指令 (Actionable Prompt for Implementation)**
现在,请严格遵循以上这份详尽的架构设计方案,完成`CryptoIcon.vue`组件、`useCrypto.ts`组合式函数、`crypto.d.ts`类型定义文件以及`generate-crypto-data.ts`构建脚本的编码工作。确保最终产出的代码是生产级的,完全符合`vue3-typescript-stye.md`中定义的所有规范特别是在TypeScript强类型、组合式API、Vuetify 3集成、主题适配和代码健壮性方面达到典范水平。

View File

@@ -0,0 +1,243 @@
**角色**: 你是一位资深前端架构师,精通 Vue 3、TypeScript 和 Vuetify 3严格遵循 Material Design 3 设计哲学和企业级代码规范。
**任务**: 根据以下详细设计方案,创建一个名为 `CurrencySelector` 的通用、高性能、主题自适应的加密货币/交易对选择器组件。
-----
#### **1. 组件核心概述 (Component Overview)**
`CurrencySelector` 是一个基于 Vuetify 3 的高级表单控件。它旨在提供一个功能强大且用户友好的界面用于从一个可配置的数据源中单选或多选加密货币或交易对。组件内部将封装数据加载、搜索过滤、状态管理以及复杂的UI渲染逻辑同时对外暴露简洁、类型安全的API。
-----
#### **2. 核心技术栈与规范 (Core Tech Stack & Specifications)**
* **框架 (Framework):** Vue 3.x
* **脚本 (Script):** `<script setup lang="ts">` (组合式API)
* **语言 (Language):** TypeScript (严格模式,**严禁 `any`** )
* **UI库 (UI Library):** Vuetify 3.x
* **状态管理 (State Management):** Pinia
* **设计规范 (Design System):** Google Material Design 3 (MD3)
* **强制遵循**: `vue3-typescript-stye.md` 中的所有规范。
-----
#### **3. 组件API设计 (Props & Emits)**
为了实现组件的高度可复用性和灵活性其API必须经过精心设计并提供完整的TypeScript类型定义。
##### **3.1 类型定义 (Type Definitions)**
首先,在 `@/types/currency.d.ts` 中定义核心数据结构:
```typescript
// @/types/currency.d.ts
/**
* @interface CurrencyItem
* @description 代表一个可选择的币种或交易对的基础数据结构
*/
export interface CurrencyItem {
id: string | number; // 唯一标识符
name: string; // 完整名称, e.g., "Bitcoin"
symbol: string; // 简称/符号, e.g., "BTC"
pair?: string; // 交易对名称, e.g., "BTCUSDT"
iconUrl?: string; // 图标的URL地址
}
```
##### **3.2 Props**
```typescript
// CurrencySelector.vue
import type { CurrencyItem } from '@/types/currency';
interface Props {
// v-model 绑定值,支持单选或多选
modelValue: string | number | (string | number)[] | null;
// 选项列表数据源
items: CurrencyItem[];
// 是否支持多选
multiple?: boolean;
// 占位符文本
placeholder?: string;
// 是否处于加载状态
loading?: boolean;
// 是否禁用
disabled?: boolean;
// 返回对象的属性,决定了 modelValue 的值
itemValue?: keyof CurrencyItem; // 默认为 'id'
// 自定义清除按钮图标
clearable?: boolean;
clearIcon?: string;
// 错误信息和状态
error?: boolean;
errorMessages?: string | string[];
// Vuetify v-field 的 density 和 variant 属性
density?: 'default' | 'comfortable' | 'compact';
variant?: 'outlined' | 'filled' | 'underlined' | 'solo' | 'plain';
}
const props = withDefaults(defineProps<Props>(), {
multiple: false,
placeholder: '点击选择币种',
loading: false,
disabled: false,
itemValue: 'id',
clearable: true,
density: 'compact',
variant: 'outlined'
});
```
##### **3.3 Emits**
```typescript
// CurrencySelector.vue
const emit = defineEmits<{
(e: 'update:modelValue', value: string | number | (string | number)[] | null): void;
}>();
```
-----
#### **4. 内部实现与架构决策 (Internal Implementation & Architecture)**
##### **4.1 基础组件选用**
* **核心**: 使用 Vuetify 的 `VAutocomplete` 组件作为基础。它原生支持搜索、单选/多选、异步加载以及丰富的插槽,能完美满足需求。**不要手动实现下拉菜单的显示/隐藏逻辑和层级管理**`VAutocomplete` 内置的 `v-menu` 会自动处理。
##### **4.2 UI/UX 实现细节**
* **已选项渲染 (胶囊按钮)**:
* 利用 `VAutocomplete``#selection` 插槽。
* 在插槽内,使用 `VChip` 组件来渲染已选项,以实现“胶囊按钮”效果。
* `VChip` 应包含币种图标 (`VAvatar``VIcon`)、简称 (`item.raw.symbol``item.raw.pair`),并自带删除按钮 (`closable=true`)。
* `VChip` 的颜色应使用主题变量,例如 `color="primary"`, 使其与输入框背景色区分。
* **下拉选项渲染**:
* 利用 `VAutocomplete``#item` 插槽。
* 在插槽内,使用 `VListItem` 组件。
* `VListItem` 包含 `VListItemAvatar` (用于图标) 和 `VListItemTitle` (用于显示简称或交易对名称)。
* **主题适配 (Theming)**:
* **严禁**任何硬编码的颜色值。
* 组件所有背景、文字、边框颜色**必须**使用 Vuetify 的主题系统。例如,`VChip` 的颜色应设置为 `primary``secondary` 等主题色,输入框的背景将自动适应主题。
* 币种图标本身是图片,无需颜色变换,符合原始要求。
* **滚动与显示数量**:
* `VAutocomplete` 的下拉菜单默认就是可滚动的。
* 要控制显示高度,可以通过 CSS `var(--v-overlay-max-height)` 变量或为 `menu-props` 设置样式 `{ maxHeight: '300px' }` 来实现,而非通过参数配置固定的`n`个选项。这更符合响应式设计。
##### **4.3 逻辑与功能**
* **搜索功能**:
* `VAutocomplete` 自带文本搜索功能。
* 为了更精准地匹配 `name`, `symbol`, `pair`,可以提供一个自定义的 `custom-filter` 函数。
```typescript
const currencyFilter = (itemTitle: string, queryText: string, item: { raw: CurrencyItem }): boolean => {
const query = queryText.toLowerCase();
const { name, symbol, pair } = item.raw;
return (
name.toLowerCase().includes(query) ||
symbol.toLowerCase().includes(query) ||
(pair && pair.toLowerCase().includes(query))
);
};
```
* **数据管理**:
* 如果币种列表是全局共享且不常变动的,**推荐**使用 Pinia Store (`@/store/currency.ts`) 进行管理。
* Store 应包含 state (存储列表)、getters (用于快速查找) 和 actions (用于异步获取数据并缓存)。
* 组件在 `onMounted` 时,检查 Store 中是否已有数据,若无则 dispatch action 获取。
* **响应式设计**:
* 组件的尺寸不应由内部 prop 控制。应遵循 Vuetify 的栅格系统,将其放置在 `VCol` 中,由父级布局决定其宽度。这保证了组件在不同屏幕尺寸下的适应性。
-----
#### **5. 非功能性需求 (Non-Functional Requirements)**
* **性能 (Performance)**:
* 对于超大数据量的选项列表 (e.g., \> 1000),应考虑使用 `VVirtualScroll` 组件包裹在下拉菜单中,以提高渲染性能。
* 搜索输入的 debounce 由 `VAutocomplete` 内置处理。
* **可访问性 (Accessibility - A11Y)**:
* 通过使用 `VAutocomplete` 和 `VChip` 等标准 Vuetify 组件,大部分 WAI-ARIA 属性会自动得到支持。
* 确保所有可交互元素都有清晰的焦点状态,并支持键盘导航。
* **错误处理 (Error Handling)**:
* 当 `loading` 为 `true` 时,显示 `VProgressLinear` 或 `VProgressCircular`。
* 当 `items` 数组为空时,应在下拉菜单中显示提示信息,如“无匹配数据”。
* 当接收到 `error` prop 时,`VAutocomplete` 边框应变为错误颜色,并显示 `error-messages`。
-----
#### **6. 示例用法 (Example Usage)**
```vue
<template>
<v-container>
<v-row>
<v-col cols="12" md="6">
<CurrencySelector
v-model="selectedSingle"
:items="currencyStore.list"
:loading="currencyStore.loading"
label="选择单个币种"
/>
</v-col>
<v-col cols="12" md="6">
<CurrencySelector
v-model="selectedMultiple"
:items="currencyStore.list"
:loading="currencyStore.loading"
label="选择多个交易对"
multiple
placeholder="搜索并选择交易对"
/>
</v-col>
</v-row>
</v-container>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useCurrencyStore } from '@/store/currency';
import CurrencySelector from '@/components/CurrencySelector.vue';
const currencyStore = useCurrencyStore();
const selectedSingle = ref<string | null>(null);
const selectedMultiple = ref<string[]>([]);
onMounted(() => {
currencyStore.fetchCurrencies();
});
</script>
```
-----
**最终指令**: 请根据以上这份详尽、严谨的架构设计方案,生成 `CurrencySelector.vue` 组件的完整代码。代码必须是生产级别的,并体现出卓越的工程实践。

View File

@@ -0,0 +1,69 @@
**角色 (Role):** 你是一位精通 Vue 3、TypeScript 和 Vuetify 的资深前端架构师。你的任务是构建基础布局框架。
**背景 (Context):** 你必须严格遵守所提供的 `vue3-typescript-stye.md` 风格指南中的所有原则。最终目标是产出一个健壮、可维护、生产就绪的应用外壳,它将作为未来所有页面的实现蓝图。此布局必须是完全响应式、支持主题切换,并完全基于 Vue 3 组合式 API 和 Vuetify 3 组件构建。
**核心任务 (Core Task):**
`src/layouts/` 目录下,创建一个名为 `Default.vue` 的主应用布局组件。该组件需实现一个经典的三段式结构:一个持久化的导航抽屉、一个顶部应用栏和一个用于承载路由视图的主内容区。所有与布局 UI 相关的状态(例如,侧边栏的收缩状态、当前的主题)必须在一个专用的 Pinia store 中进行集中管理。
---
### **1. 状态管理:布局 Store (Pinia)**
在创建组件之前,首先定义状态管理模块。
* **文件位置:** `src/store/layout.ts`
* **Store 名称:** `useLayoutStore`
* **State:**
* `isSidebarMini: Ref<boolean>`: 管理导航抽屉的收缩/展开状态,默认为 `false`
* `theme: Ref<'light' | 'dark'>`: 存储当前的主题名称,默认为 `'light'`
* **Actions:**
* `toggleSidebar()`: 用于翻转 `isSidebarMini`布尔值的 action。
* `setTheme(newTheme: 'light' | 'dark')`: 用于更新 `theme` 状态的 action。
**约束:** 所有的 state 属性和函数签名都必须拥有精确的 TypeScript 类型。
### **2. 组件拆解: `Default.vue`**
#### **a. Script 部分 (`<script setup lang="ts">`)**
* **导入:**
* 从 Vue 和 Vue Router 中导入必要的模块 (`ref`, `watch`, `useRoute`)。
*`@/store/layout.ts` 中导入 `useLayoutStore`
* 从 Vuetify 中导入 `useTheme``useDisplay` 组合式函数。
* **Store 实例化:**
* 实例化布局 store: `const layoutStore = useLayoutStore();`
* 实例化 Vuetify theme 组合式函数: `const theme = useTheme();`
* 实例化 Vuetify display 组合式函数: `const display = useDisplay();`
* **响应式逻辑:**
* 为导航抽屉的可见性创建一个本地 `ref``const drawer = ref(true);`
* 使用 `watch` 监听 `useDisplay` 返回的 `display.mobile`。如果视口变为移动端 (`display.mobile.value``true`),则默认将导航抽屉设置为临时隐藏 (`drawer.value = false`)。
* 实现一个 `toggleTheme()` 函数,该函数调用 Pinia store 中的 `setTheme` action并通过 `theme.global.name.value = layoutStore.theme;` 来更新 Vuetify 的主题。此函数将绑定到一个 UI 控件上。
#### **b. 模板部分 (`<template>`)**
* **根元素:** 使用 `<v-layout>` 组件作为最外层包裹容器。
* **导航抽屉 (`<v-navigation-drawer>`):**
* 将其可见性与 `drawer` ref 进行双向绑定 (`v-model="drawer"`)。
* 将其“图标模式”状态与 Pinia store 中的 `isSidebarMini` 进行绑定 (`:rail="layoutStore.isSidebarMini"`)。
* 实现一个占位用的 `<v-list>`,包含数个 `<v-list-item>` 用于导航。确保其中一个项目拥有 `active` 属性,以展示单页应用中高亮当前路由的样式。
* 在抽屉底部,添加一个 `<template v-slot:append>` 区块。在其中放置一个 `<v-btn>` 用于切换主题。该按钮的图标应根据当前主题变化(例如,暗色主题下为 'mdi-weather-sunny',明亮主题下为 'mdi-weather-night')。将其 `@click` 事件绑定到 `toggleTheme()` 方法。
* **应用栏 (`<v-app-bar>`):**
* 包含一个 `<v-app-bar-nav-icon>` 按钮,用于切换 `drawer` ref 的值 (`@click="drawer = !drawer"`)。
* 包含一个 `<v-toolbar-title>`,用于动态显示当前页面的标题占位符。
* 在最右侧添加一个按钮,其图标为 `mdi-dots-vertical`
* **主内容区 (`<v-main>`):**
* 主内容区必须是流式的,能自适应剩余空间。
*`<v-main>` 内部,渲染 `<router-view />` 组件,使得该布局能够根据当前路由托管不同的页面组件。
* **页面 Header:** 在 `<v-main>` 内部,但在 `<router-view>` 之前,添加一个容器(例如,一个带有特定 class 的 `div`)作为页面 Header。在此处显示当前路由的名称作为占位符例如使用 `useRoute().name`)。
### **3. 样式与主题**
* **禁止硬编码样式:** 绝不使用任何硬编码的颜色值 (例如 `#FFF`, `rgb(0,0,0)`)。
* **Vuetify 主题变量:** 所有的自定义样式(如有)必须使用 Vuetify 的主题系统。例如,使用 CSS 变量 `background-color: rgb(var(--v-theme-surface));` 或 SASS 函数 `color: v-theme(on-surface);`
* **主题响应:** 整个布局,包括所有文本、图标和表面,都必须在明亮和暗色主题之间无缝切换,不能有任何视觉瑕疵。
### **4. 响应式设计**
* **移动端:** 在移动端视口(由 `useDisplay` 判断),导航抽屉应默认关闭,并以临时/模态模式运行。`<v-app-bar-nav-icon>` 成为打开它的主要方式。
* **平板/桌面端:** 在更大的屏幕上,导航抽屉应默认可见。用于切换其 `rail` 状态(完整模式与图标模式)的按钮应位于 `<v-app-bar>` 中。为此,在 `<v-app-bar-nav-icon>` 之后添加一个 `<v-btn icon="mdi-menu" @click.stop="layoutStore.toggleSidebar()"></v-btn>`

View File

@@ -0,0 +1,6 @@
不要使用开源库 **`cryptocurrency-icons`**。该库的内容过时,无法满足需求。使用python3构建脚本,放置于`ProjectTonyStack/TonyMask/scripts/`中,用于从[TradingView](https://tradingview.com/markets/cryptocurrencies/prices-all/) 爬取排名前100的加密货币信息,包含吗svg图标,全名称,简称,大写名称,排名等.该脚本将整合后的元数据和SVG内容生成一个静态的 `crypto-data.ts` 文件,存放于 `src/assets/` 目录下。此文件将导出一个类型为 `CryptoCurrencyInfo[]` 的常量数组。
请根据上述的要求,设计一个爬取的python3脚本,注意是在无浏览器环境运行脚本
包含加密货币信息的网页保存在[tradingview-save-704.html](ProjectTonyStack/TonyMask/scripts/tradingview-save-704.html)包含svg图标,加密货币简称,加密货币全称, 请实现一个python3脚本解析其中包含的信息.并且调用CoinGecko API获取加密货币的大写名称,描述,市场排名信息,注意是在无浏览器环境运行脚本
该脚本将整合后的元数据和SVG内容生成一个静态的 `crypto-data.ts` 文件,存放于 `src/assets/` 目录下。此文件将导出一个类型为 `CryptoCurrencyInfo[]` 的常量数组。

View File

@@ -0,0 +1,12 @@
请遵守前端设计规范@/root/ProjectTonyStack/gemini_cli_prompt/TonyMaskPrompt/vue3-typescript-stye.md针对@/root/ProjectTonyStack/TonyMask/src/components/CurrencySelector.vue 进行如下的修改
1 修改图标加载方式,当打开页面后需要即刻展示图标
2 当选中币种之后图标和名称显示不正常请修改此bug
1 当前显示的是object Object 请修改为胶囊按钮状显示图标及名称
3 下拉选项,增大图标和名称之间的间隔
请继续@/root/ProjectTonyStack/TonyMask/src/components/CurrencySelector.vue 进行如下的修改
1 选中币种需要用胶囊按钮包含展示图标以及名称,现在无图标
2 选中币种需要有删除按键,点击取消选择,现在没有
3 输入框有删除按键,点击删除全部选中
4 输入栏,默认高度可以增高一些

View File

@@ -0,0 +1,74 @@
**背景 (Context):**
你是一名资深前端架构师,负责为我们的 Vue 3 + TypeScript + Vuetify 3 项目构建基础工具库。该项目要求极高的代码质量、健壮性、可维护性和开发效率。当前任务是设计并实现一个专业、可靠且覆盖全面的时间处理工具模块。
W
**核心指令 (Core Directive):**
请严格遵循 `vue3-typescript-stye.md` 中定义的所有规范,创建一个位于 `src/utils/time.ts` 的时间工具模块。此模块必须基于业界公认的最佳实践,封装所有与时间相关的操作,确保前端应用在处理时间数据时的一致性、准确性和健朗性。放弃手动计算时间的原始思路,全面拥抱成熟的第三方库来保证专业性。
---
### **技术架构与设计规范 (Technical Architecture & Design Specification)**
**1. 核心依赖 (Core Dependency):**
* **唯一指定库:** 项目中所有的时间/日期操作**必须**使用 `date-fns``date-fns-tz` 库。严禁手动进行复杂的日期计算(如月份加减、年份推算),以规避闰年、月份天数不均等边界问题。
* **安装命令:** 使用 pnpm 进行安装:`pnpm add date-fns date-fns-tz`
**2. 模块设计与常量定义 (Module Design & Constants):**
* **文件路径:** `src/utils/time.ts`
* **核心常量:**
* `API_DATETIME_FORMAT`: 定义一个字符串常量,值为 `"yyyy-MM-dd HH:mm:ss"`,用于统一前后端接口的时间格式。
* `TIMEZONE`: 定义一个字符串常量,值为 `"Asia/Shanghai"`,代表所有时间转换的目标时区(东八区)。
**3. 函数接口定义 (Function Interface Definitions):**
模块需要导出以下经过精心设计的函数,所有函数必须包含完整的 JSDoc 注释,并拥有精确的 TypeScript 类型签名。
* **`formatDate(date: Date | number, formatStr: string = API_DATETIME_FORMAT): string`**
* **描述:** 将给定的 `Date` 对象或时间戳(`number`)格式化为指定格式的字符串。
* **核心逻辑:** 使用 `date-fns-tz``formatInTimeZone` 函数,确保输出的字符串始终基于我们定义的 `TIMEZONE` (`Asia/Shanghai`)。
* **参数:**
* `date`: 必选,要格式化的 `Date` 对象或时间戳。
* `formatStr`: 可选,目标格式字符串,默认为 `API_DATETIME_FORMAT`
* **返回值:** `string` - 格式化后的时间字符串。
* **`parseDate(dateStr: string, formatStr: string = API_DATETIME_FORMAT): Date`**
* **描述:** 将符合标准格式的时间字符串解析为 `Date` 对象。
* **核心逻辑:** 使用 `date-fns``parse` 函数进行解析。必须健壮地处理无效的输入字符串,如果解析失败,应返回一个无效的 `Date` 对象 (可以通过 `isValid` from `date-fns` 进行检查)。
* **参数:**
* `dateStr`: 必选,要解析的时间字符串,如 "2025-01-01 08:00:00"。
* `formatStr`: 可选,源字符串的格式,默认为 `API_DATETIME_FORMAT`
* **返回值:** `Date` - 解析后的 `Date` 对象。
* **`getRelativeDate(options: { years?: number; months?: number; days?: number }, fromDate: Date = new Date()): Date`**
* **描述:** 一个通用的、获取相对日期的核心函数。可根据当前时间或指定时间,推算过去或未来的某个时间点。
* **核心逻辑:** 组合使用 `date-fns``add``sub` 系列函数(如 `subYears`, `subMonths`, `subDays`来实现。操作必须是不可变的immutable即不修改原始 `fromDate` 对象。
* **参数:**
* `options`: 必选,一个包含 `years?`, `months?`, `days?` 的对象,值为负数表示过去,正数表示未来。
* `fromDate`: 可选,计算的基准日期,默认为当前时间 `new Date()`
* **返回值:** `Date` - 计算得出的新 `Date` 对象。
* **便捷函数 (Convenience Functions):**
* **描述:** 基于 `getRelativeDate``formatDate` 封装一系列便捷函数,以满足业务中的常见需求。这些函数使业务代码更具可读性。
* **函数列表:**
* `getMonthAgo(fromDate?: Date): string` - 获取一个月前的时间字符串。
* `getThreeMonthsAgo(fromDate?: Date): string` - 获取三个月前的时间字符串。
* `getYearAgo(fromDate?: Date): string` - 获取一年前的时间字符串。
* `getThreeYearsAgo(fromDate?: Date): string` - 获取三年前的时间字符串。
* **实现细节:** 每个函数内部调用 `getRelativeDate` 计算出 `Date` 对象,然后调用 `formatDate` 格式化为标准 API 字符串。例如,`getMonthAgo` 内部应调用 `getRelativeDate({ months: -1 }, fromDate)`
**4. 非功能性需求 (Non-Functional Requirements):**
* **代码健壮性:**
* 所有函数在接收参数时,应考虑 `null``undefined` 的可能性,并进行适当的防御性编程。
* `parseDate` 函数是与外部数据交互的关键入口,其对异常输入的处理能力至关重要。
* **性能:**
* **必须** 采用 Tree-shaking 友好的方式从 `date-fns``date-fns-tz` 导入函数,例如:`import { format } from 'date-fns'`,而不是 `import * as dateFns from 'date-fns'`
* **不可变性 (Immutability):**
* 所有对 `Date` 对象的操作都不能直接修改原始对象,而应返回一个新的 `Date` 实例。`date-fns` 默认遵循此模式,需确保在实现中维持这一特性。
**5. 最终产出 (Final Output):**
请根据以上所有规范,生成 `src/utils/time.ts` 文件的完整 TypeScript 代码。代码必须是生产级别的,包含完整的 JSDoc 注释、精确的类型定义,并体现出卓越的工程实践。

View File

@@ -0,0 +1,9 @@
gemini -m gemini-2.5-flash
统一使用[time.ts](TonyMask/src/utils/time.ts)中预定义的方法,修改[binanceOrder.ts](TonyMask/src/store/binanceOrder.ts),修改其中的时间获取方法,修改startTime为string类型
针对@/root/ProjectTonyStack/TonyMask/src/components/binance/OrderDataTable.vue 进行如下的修改
1 使用[time.ts](TonyMask/src/utils/time.ts)中预定义的方法修改时间处理方法,表格中统一使用字符串展示时间
2 @/root/ProjectTonyStack/TonyMask/tmp/binance_order_response.json 是实际的订单返回数据,修改页面能够正确的处理并显示订单数据,目前无法显示

View File

@@ -0,0 +1,90 @@
我没有前端设计相关的经验请你作为前端UI设计的大师利用Google Stich和Figma设计前端的页面请根据我关于项目的大体设计给出Stich的系统设计描述
您好很高兴能以UI设计大师的身份与您一同规划这个项目。您的设计思路非常清晰包含了现代前端设计的核心要素。这是一个绝佳的起点。
您提到的 “Google Stitch” 是一个很有趣的叫法。在设计界,我们通常会把一套统一的设计规范、原则和可复用组件的集合称为**设计系统Design System**。为了方便,我们就将我们这次项目的设计系统命名为 **Stitch**,寓意它将所有界面元素无缝地“缝合”在一起,形成统一、协调的用户体验。
接下来,我将为您详细描述 Stitch 设计系统在Figma中应如何规划与设计以便前端团队能够利用Vuetify高效地实现它。
##### **a. 色彩 (Colors)**
我们将定义一个双主题调色板,确保在明亮和暗色模式下都有出色的可读性和视觉效果。
* **主色 (Primary):**
* `primary-light`: `#1976D2` (用于按钮、高亮、活动状态等)
* `primary-dark`: `#64B5F6`
* **背景色 (Background):**
* `background-light`: `#F5F5F5` (非常浅的灰色,避免纯白刺眼)
* `background-dark`: `#121212` (经典的深邃黑)
* **表面色 (Surface):**
* `surface-light`: `#FFFFFF` (卡片、侧边栏、应用栏的背景)
* `surface-dark`: `#1E1E1E` (比背景稍亮的深灰色)
* **文本/图标色 (On-Color):**
* `on-surface-light`: `#212121` (深灰色正文)
* `on-surface-dark`: `#E0E0E0` (浅灰色正文)
* `on-primary-light`: `#FFFFFF`
* `on-primary-dark`: `#000000`
* **辅助色 (Accent/Error/Success):** 将为其他状态(如错误提示、成功信息)定义相应的颜色。
##### **b. 字体 (Typography)**
选择一款现代、易读的无衬线字体(如 `Inter``Roboto`。在Figma中创建文本样式。
* `H1 - Header`: 24px, Bold (用于主内容区的标题)
* `H2 - Subheader`: 18px, Bold
* `Body 1`: 16px, Regular (正文内容)
* `Body 2`: 14px, Regular (次要信息)
* `Button`: 14px, Medium
* `Nav Item`: 16px, Medium (侧边栏菜单项)
##### **c. 间距与网格 (Spacing & Grid)**
* **基础单位:** `8px`。所有元素的内外边距、间距都应是8的倍数`8, 16, 24, 32px`),形成和谐的垂直和水平韵律。
* **栅格系统:** 遵循Vuetify的**12列栅格系统**。在Figma中我们会为主要断点桌面、平板、手机创建不同的布局网格Layout Grid以确保响应式设计是可预测的。
#### **3. 组件库 (Component Library)**
我们将把您的布局要求拆解为一系列可复用的Figma组件。关键是利用Figma的 **自动布局Auto Layout****变体Variants** 功能。
##### **a. 侧边导航栏 (Side Navigation)**
这是核心组件,我们将创建两个主要的**变体**`Collapsed=False``Collapsed=True`
* **完整模式 (`Collapsed=False`):**
* **结构:** 垂直 `Auto Layout` 容器。
* **内容:**
* 顶部Logo + 应用名称。
* 中部:导航项列表。每个导航项都是一个组件,包含 `Icon + Text`,并有 `State=Active``State=Default` 两个变体。活动状态的项会有不同的背景色(`primary-light/dark`)和文本颜色。
* 底部:主题切换器。
* **图标模式 (`Collapsed=True`):**
* **结构:** 隐藏所有文本标签只显示Logo图标和导航项图标。
* **交互:** 当鼠标悬停Hover在图标上时可以显示一个浮动的提示Tooltip来展示功能名称。
##### **b. 顶部应用栏 (Top App Bar)**
* **结构:** 水平 `Auto Layout` 容器。
* **内容:**
* 左侧(可选):一个汉堡菜单按钮,用于在小屏幕上控制侧边栏的显示/隐藏。
* 右侧:可以放置用户头像、消息通知、搜索框等。
##### **c. 主内容区 (Main Content Area)**
* **结构:** 这是一个插槽Slot或框架Frame
* **内容:**
* **页面标题 (Header):** 一个简单的组件,包含一个 `H1` 样式的标题和一段可选的描述性文字。
* **内容容器 (Content Container):** 实际页面内容将在这里展示,例如卡片、表格、表单等。
#### **4. Figma 实现流程与原型**
1. **建立基础样式:** 在Figma中首先创建并发布所有颜色样式和文本样式。
2. **创建原子组件:** 从最小的元素开始,如按钮、图标、输入框。
3. **组合分子组件:** 使用原子组件构建更复杂的组件,如上文描述的导航项、侧边导航栏等。大量使用 **Auto Layout****Variants** 来管理不同状态。
4. **页面布局组装:**
* 创建一个桌面尺寸的画板Frame
* 应用12列栅格。
* 将“侧边导航栏”、“顶部应用栏”和“主内容区”组件实例拖入画板并使用约束Constraints让它们固定在正确的位置。
5. **创建交互原型 (Prototyping):**
* **页面切换:** 将侧边栏的每个导航项链接到不同的页面画板使用“智能动画”Smart Animate可以让内容区的切换显得平滑。
* **侧边栏收缩:** 将“展开”侧边栏的折叠按钮链接到包含“收缩”侧边栏的页面副本,反之亦然。同样使用“智能动画”来实现平滑的过渡效果。
* **主题切换:** 复制所有页面并使用Figma插件如 "Themer")或手动方式将所有组件切换到它们的暗色变体。然后将主题切换按钮链接到对应的明/暗色页面。

View File

@@ -1,6 +1,6 @@
请根据前端代码的风格,设计一个现代化的资金管理分析系统的前端页面布局样式。要求支持多页面功能,不同页面之间切换流畅。功能栏可以隐藏。页面主题支持明亮和暗色模式切换
## 废弃
你是一名经验丰富的系统架构师,能够将通俗的需求,粗略的设计,转化为专业技术且精细的设计稿.
转化的参考方向如下:
- 设计内容是面向AI输入的,优化方向应该针对AI的prompt
@@ -9,4 +9,5 @@
- 优化设计方案
- 用专业的技术语言来精细化设计稿
请你根据前端代码的风格要求vue3-typescript-stye.md对登录设计稿进行优化
请你根据前端代码的风格要求vue3-typescript-stye.md对登录设计稿进行优化