feat: 优化界面并补充网格成交分析
This commit is contained in:
200
docs/superpowers/plans/2026-07-09-gui-visual-refresh.md
Normal file
200
docs/superpowers/plans/2026-07-09-gui-visual-refresh.md
Normal file
@@ -0,0 +1,200 @@
|
||||
# GUI Visual Refresh Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Refresh the PySide6 main window into a clean light desktop-tool style and apply A-share profit/loss colors to all PnL-like fields.
|
||||
|
||||
**Architecture:** Keep the existing `MainWindow` layout and data flow. Add focused UI helpers in `main_window.py` for theme setup, table setup, and PnL styling, then cover them with lightweight offscreen GUI tests.
|
||||
|
||||
**Tech Stack:** Python 3.11+, PySide6, pytest.
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
- Modify `src/grid_trading/ui/main_window.py`: apply QSS theme, assign object names, centralize table setup, and style PnL labels/items.
|
||||
- Modify `tests/test_ui.py`: add offscreen GUI tests for theme markers and profit/loss item styling.
|
||||
- No domain, service, storage, or database changes.
|
||||
|
||||
### Task 1: Add Failing GUI Tests
|
||||
|
||||
**Files:**
|
||||
- Test: `tests/test_ui.py`
|
||||
|
||||
- [ ] **Step 1: Write failing tests for theme markers and PnL colors**
|
||||
|
||||
```python
|
||||
def test_main_window_applies_light_theme(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("QT_QPA_PLATFORM", "offscreen")
|
||||
|
||||
from PySide6.QtWidgets import QApplication
|
||||
from grid_trading.services.trading_service import TradingService
|
||||
from grid_trading.ui.main_window import MainWindow
|
||||
|
||||
app = QApplication.instance() or QApplication([])
|
||||
service = TradingService(tmp_path / "grid.db")
|
||||
window = MainWindow(service)
|
||||
|
||||
assert window.centralWidget().objectName() == "appRoot"
|
||||
assert window.holdings_table.alternatingRowColors()
|
||||
assert "QMainWindow" in window.styleSheet()
|
||||
|
||||
window.close()
|
||||
service.close()
|
||||
app.processEvents()
|
||||
```
|
||||
|
||||
```python
|
||||
def test_profit_and_loss_cells_use_a_share_colors(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("QT_QPA_PLATFORM", "offscreen")
|
||||
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from PySide6.QtGui import QColor
|
||||
from PySide6.QtWidgets import QApplication
|
||||
from grid_trading.domain.models import PositionSummary
|
||||
from grid_trading.services.trading_service import TradingService
|
||||
from grid_trading.ui.main_window import MainWindow
|
||||
|
||||
app = QApplication.instance() or QApplication([])
|
||||
service = TradingService(tmp_path / "grid.db")
|
||||
window = MainWindow(service)
|
||||
window._positions = [
|
||||
PositionSummary(
|
||||
instrument_id=1,
|
||||
code="510300",
|
||||
name="沪深300ETF",
|
||||
total_quantity=100,
|
||||
available_quantity=100,
|
||||
base_quantity=0,
|
||||
grid_quantity=100,
|
||||
remaining_cost=Decimal("1000"),
|
||||
average_cost=Decimal("10"),
|
||||
position_breakeven_price=Decimal("10"),
|
||||
account_breakeven_price=Decimal("10"),
|
||||
realized_pnl=Decimal("12.34"),
|
||||
grid_profit=Decimal("-5.67"),
|
||||
current_price=Decimal("10.50"),
|
||||
market_value=Decimal("1050"),
|
||||
floating_pnl=Decimal("50"),
|
||||
last_quote_at=datetime(2026, 7, 9, 10, 0, 0),
|
||||
)
|
||||
]
|
||||
|
||||
window._fill_holdings_table()
|
||||
|
||||
profit_item = window.holdings_table.item(0, 10)
|
||||
loss_item = window.holdings_table.item(0, 11)
|
||||
assert profit_item.foreground().color() == QColor("#c62828")
|
||||
assert profit_item.font().bold()
|
||||
assert loss_item.foreground().color() == QColor("#2e7d32")
|
||||
assert loss_item.font().bold()
|
||||
|
||||
window.close()
|
||||
service.close()
|
||||
app.processEvents()
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the tests and verify they fail**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
pytest tests/test_ui.py::test_main_window_applies_light_theme tests/test_ui.py::test_profit_and_loss_cells_use_a_share_colors -q
|
||||
```
|
||||
|
||||
Expected: both new tests fail because object names, theme QSS, alternating row setup, and PnL item colors do not exist yet.
|
||||
|
||||
### Task 2: Add Light Theme and Shared Table Setup
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/grid_trading/ui/main_window.py`
|
||||
|
||||
- [ ] **Step 1: Add imports and theme constants**
|
||||
|
||||
Add `Decimal`, `QBrush`, `QColor`, `QFont`, and `QAbstractItemView` imports needed by the helpers.
|
||||
|
||||
- [ ] **Step 2: Apply theme in `_build_ui`**
|
||||
|
||||
Set `root.setObjectName("appRoot")`, call `self._apply_light_theme()`, and set object names on the navigation, summary card frames, toolbar buttons, tab widget, and tables.
|
||||
|
||||
- [ ] **Step 3: Add `_apply_light_theme` and `_configure_table`**
|
||||
|
||||
Create helpers that set the QSS theme once and apply consistent table settings: alternating rows, row selection, no editing, visible grid, row height, and header resize behavior.
|
||||
|
||||
- [ ] **Step 4: Run theme test**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
pytest tests/test_ui.py::test_main_window_applies_light_theme -q
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
### Task 3: Add PnL Styling Helpers
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/grid_trading/ui/main_window.py`
|
||||
|
||||
- [ ] **Step 1: Add `_style_pnl_item`, `_style_pnl_label`, and `_make_item`**
|
||||
|
||||
Use the raw `Decimal | None` value, not the formatted string, to decide color and font weight:
|
||||
|
||||
- `value > 0`: foreground `#c62828`, bold.
|
||||
- `value < 0`: foreground `#2e7d32`, bold.
|
||||
- otherwise: default foreground, non-bold.
|
||||
|
||||
- [ ] **Step 2: Use helpers in summary and tables**
|
||||
|
||||
Apply the helpers to summary floating PnL and these table columns:
|
||||
|
||||
- holdings: columns 10, 11, 12.
|
||||
- grid levels: column 6.
|
||||
- open grid lots: column 5.
|
||||
- grid matches: column 7.
|
||||
|
||||
- [ ] **Step 3: Run PnL style test**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
pytest tests/test_ui.py::test_profit_and_loss_cells_use_a_share_colors -q
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
### Task 4: Full Verification
|
||||
|
||||
**Files:**
|
||||
- No additional changes expected.
|
||||
|
||||
- [ ] **Step 1: Run UI test module**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
pytest tests/test_ui.py -q
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 2: Run full test suite**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
pytest -q
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 3: Review diff**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git diff -- src/grid_trading/ui/main_window.py tests/test_ui.py docs/superpowers/specs/2026-07-09-gui-visual-refresh-design.md docs/superpowers/plans/2026-07-09-gui-visual-refresh.md
|
||||
```
|
||||
|
||||
Expected: diff only contains the UI theme, PnL styling, tests, and docs for this task.
|
||||
@@ -0,0 +1,53 @@
|
||||
# GUI 页面美化与盈亏着色设计
|
||||
|
||||
日期:2026-07-09
|
||||
|
||||
## 目标
|
||||
|
||||
把现有 PySide6 桌面 GUI 调整为清爽浅色桌面工具风格,并统一处理盈亏、利润字段的视觉反馈:亏损显示绿色加粗,盈利显示红色加粗,零值和空值保持中性显示。
|
||||
|
||||
本次只改视觉表现和表格单元格样式,不改变业务计算、数据结构、行情刷新、成交录入或持仓选择逻辑。
|
||||
|
||||
## 视觉方向
|
||||
|
||||
采用轻量主题化方案:
|
||||
|
||||
- 保留当前左侧导航、顶部摘要、工具栏、持仓表和底部详情 tab 的布局结构。
|
||||
- 主窗口使用浅灰背景,内容区使用白色和浅边框分区,减少默认 Qt 控件的粗糙感。
|
||||
- 侧边栏使用白底、蓝色选中态和更紧凑的列表项。
|
||||
- 摘要卡片使用白底、浅边框、圆角和更清晰的标题/数值层级。
|
||||
- 操作按钮使用蓝色主按钮样式,禁用态降低对比。
|
||||
- 表格使用白底、浅灰表头、斑马纹、整行选中和统一网格线颜色。
|
||||
- Tab 使用浅色选项卡,当前 tab 用蓝色强调。
|
||||
|
||||
## 盈亏字段
|
||||
|
||||
需要应用盈亏样式的字段:
|
||||
|
||||
- 汇总卡:浮动盈亏。
|
||||
- 持仓表:已实现盈亏、网格利润、浮动盈亏。
|
||||
- 网格档位表:预计单轮毛利润。
|
||||
- 待卖网格表:预计毛利润。
|
||||
- 配对明细表:毛利润。
|
||||
|
||||
样式规则:
|
||||
|
||||
- 大于 0:红色、加粗。
|
||||
- 小于 0:绿色、加粗。
|
||||
- 等于 0、空值或无法解析:默认文字色和普通字重。
|
||||
|
||||
颜色按 A 股常见习惯处理,红色代表盈利,绿色代表亏损。
|
||||
|
||||
## 实现方式
|
||||
|
||||
- 在 `MainWindow` 中新增一个全局样式应用方法,用 QSS 统一主窗口、按钮、列表、表格、tab 和摘要卡片样式。
|
||||
- 给摘要卡片和关键控件设置 objectName,让 QSS 精准命中,避免影响弹窗内部布局。
|
||||
- 新增表格初始化 helper,复用表头、选择、斑马纹、行高和滚动行为设置。
|
||||
- 新增数值单元格 helper,根据 Decimal 原始值给 `QTableWidgetItem` 设置前景色和加粗字体。
|
||||
- 刷新汇总卡时对浮动盈亏标签应用同样的盈亏样式。
|
||||
|
||||
## 测试策略
|
||||
|
||||
- 增加 GUI 烟测,验证主窗口应用了浅色主题相关 objectName 或样式入口。
|
||||
- 增加单元格样式测试,直接填充带盈利和亏损的持仓数据,验证盈利字段为红色加粗、亏损字段为绿色加粗。
|
||||
- 保留现有窗口构造、tab、刷新线程测试。
|
||||
Reference in New Issue
Block a user