# 全市场目录接入看板（完成记录）

**日期**：2026-09-14
**授权**：用户明确允许修改（`dashboard.py` 与看板模板）

## 目标

把所有个股（5218 只）涵盖进看板，**分类归分类**——即完整呈现 + 分级，
但**不改变任何既有筛选逻辑**。

## 交付结果

看板新增「**全市场目录**」视图（侧边栏 + 移动端导航均可进入）：

```
市场总览 | 研究候选 657 | 因子观测 | 风险雷达 123 | 全市场目录 5218
```

| 验收项 | 结果 |
| --- | --- |
| 覆盖只数 | **5218 / 5218** |
| 侧边栏徽标 | `navMarketCount = 5218` |
| 默认每页 | 100 条，共 **53 页** |
| 分页信息 | `1–100 / 共 5218 只` |
| 无头浏览器实测 | ✅ 200 行模板 → 100 行渲染正确 |
| JS 语法 | ✅ `node --check` |
| 运行时错误 | ✅ 无（页面内无 `NaN`/`undefined`） |
| 公网分发 | ✅ HTTP 200，2.53 MB，含 `view-market` |

### 视图功能

- **搜索**：名称或代码
- **层级筛选**：下拉带各级数量（优先研究(21)、热点交集(48)、基本面精选(127)、观察(577)、仅入基础池(3370)、其他（数据不完整）(1075)）
- **行业筛选**：31 个一级行业
- **状态筛选**：已入研究候选 / 已入基础池 / 未入选池 / ST 或退市
- **排序**：层级优先 / 基本面总分 / 行业热度 / 总市值 / 20日均额 / 证券代码
- **每页**：50 / 100 / 200
- **点击行**：弹出个股快照；候选股复用原有抽屉，非候选股展示研究状态 + **未入选原因**

## 改动的文件

### 1. `deploy/build_full_market_catalog.py`（新增）

只读诊断脚本，**不属于项目流水线**。生成：

- `data/processed/full_market_catalog.csv`（带 BOM，Excel 可直接开）
- `data/processed/full_market_catalog.parquet`

输出 34 列，含 `catalog_tier`（分级）、`exclude_reasons`（未入选原因）、
以及全部评分与指标。**不修改任何既有判定逻辑**，只并列呈现。

### 2. `src/fundamental_mvp/dashboard.py`

- 新增读取 `full_market_catalog.csv`
- 新增 `fullMarket`（逐股精简字段）与 `fullMarketCounts` 写入 payload
- 目录文件缺失时**静默降级**（`fullMarket` 为空），不影响看板其余部分生成

### 3. `src/fundamental_mvp/assets/dashboard.html`

- 侧边栏：把原本占位的「股票池状态」按钮改为真正的「全市场目录」入口
- 新增 `<section class="view" id="view-market">`：工具栏 + 表格 + 分页
- 新增 CSS：`.market-pager`、`.reason-cell`、`.reason-none`
- 新增 JS：`marketState`、`qty()`、`marketMatches()`、`marketDrawer()`、
  `renderMarket()`、`populateMarketFilters()`、`clearMarketFilters()`
- `viewMeta` 增加 `market` 条目；`switchView` 切到 market 时重渲染
- 移动端导航增加「全市场」按钮

### 4. `deploy/daily_all.cmd`（新增）

组合启动器：先跑 `run_daily_update.cmd`，成功后重建目录，保证**目录与看板同源**。
带参数（如 `--check`）时只透传，不重建目录。

> **重要衔接**：日更会重新生成看板，而看板构建时要读目录 CSV。
> 若只跑 `run_daily_update.cmd`，目录会滞后于看板行情截面。
> **定时任务应指向 `deploy\daily_all.cmd`**，而不是 `run_daily_update.cmd`。

## 踩过的坑

写 `daily_all.cmd` 时用了中文注释。**cmd.exe 按 GBK 解析文件，UTF-8 的中文被拆坏**，
导致命令被截断、报 `'hell' is not recognized`。已改为纯 ASCII（0 个非 ASCII 字节）。

> 与之前的教训一致：`.cmd` / `.ps1` 必须纯 ASCII。
> `user.ini` 必须用 GBK（`Encoding.GetEncoding(936)`）读写。

## 副作用

`reports/dashboard/index.html` 由 **974 KB 增至 2,532 KB**（内嵌 5218 只目录数据）。
本地与隧道访问均正常，实测公网加载 HTTP 200。

若将来觉得 2.5 MB 偏大，可改为按需加载：
把 `full_market_catalog.csv` 放到 `reports/dashboard/` 下由前端 `fetch` 获取。
但要注意该目录是原子替换的，需要单独维护，当前方案更简单可靠。

## 未改变的部分（重要）

- `basic_pool_eligible`、`fundamental_eligible`、`candidate_tier` 的判定**一字未改**
- 候选池仍为 **657 只**，基础池仍为 **4027 只**
- `config/*.toml` 中的阈值（`min_avg_amount_20 = 50000000`、
  `minimum_fundamental_score = 65`）**未改动**

即：本次只是"把已排除的个股也展示出来并标注原因"，不是放宽门槛。
