# 区块链验真功能 - 页面改动说明

## 1. 文档信息

| 属性 | 值 |
|------|-----|
| 文档名称 | 区块链验真功能 - 页面改动说明 |
| 所属模块 | 全知平台 / 风控模块 / 区块链 |
| 文档版本 | v1.0 |
| 编写日期 | 2026-07-08 |
| 对应PRD | 区块链验真功能-PRD.md |

---

## 2. 改动概述

本次改动将现有虚拟验真状态升级为真实验真能力，在规则详情页和疑点链上详情弹窗中新增验真功能。

### 2.1 改动范围

| 页面 | 改动类型 | 说明 |
|------|----------|------|
| `规则详情.html` | 修改 | 区块链信息Tab新增验真按钮和验真时间 |
| `风险规则-我的规则.html` | 修改 | 链上详情弹窗新增验真按钮和验真时间 |
| `风险规则-公共规则库.html` | 修改 | 链上详情弹窗新增验真按钮和验真时间 |
| `疑点派发-疑点详情.html` | 修改 | 链上详情弹窗新增验真按钮和验真时间 |
| `疑点处置-疑点详情.html` | 修改 | 链上详情弹窗新增验真按钮和验真时间 |

### 2.2 不改动的内容

| 页面 | 说明 |
|------|------|
| `风险规则-我的规则.html` | 列表页不新增验真状态列 |
| `风险规则-公共规则库.html` | 列表页不新增验真状态列 |

---

## 3. 规则详情页改动说明

**对应页面**：`规则详情.html`

### 3.1 改动位置

规则详情页 → 区块链信息Tab → 存证汇总区域

### 3.2 改动内容

#### 新增字段

| 字段 | 位置 | 说明 |
|------|------|------|
| 验真时间 | 验真状态下方 | 展示最近一次验真时间，格式：YYYY-MM-DD HH:mm:ss |
| 验真按钮 | 验真状态右侧 | 点击触发验真操作 |

#### 改动前后对比

**改动前：**
```
┌─────────────────────────────────────────────────────┐
│ 上链状态：已上链                                      │
│ 唯一访问码：CZ20260210180000013                      │
│ 上链节点：节点A                                       │
│ 链上记录数量：5 条                                    │
│                                                      │
│ 验真状态：验真通过                                    │
└─────────────────────────────────────────────────────┘
```

**改动后：**
```
┌─────────────────────────────────────────────────────┐
│ 上链状态：已上链                                      │
│ 唯一访问码：CZ20260210180000013                      │
│ 上链节点：节点A                                       │
│ 链上记录数量：5 条                                    │
│                                                      │
│ 验真状态                                             │
│ ┌─────────────┐              ┌─────────┐           │
│ │ ✅ 验真通过  │              │  验真   │           │
│ │ (浅色背景)   │              │(实色背景)│           │
│ └─────────────┘              └─────────┘           │
│                                                     │
│ 上次验真时间：2026-07-08 14:30:00                    │
└─────────────────────────────────────────────────────┘
```

### 3.3 验真状态展示

| 状态 | 展示形式 | 按钮状态 |
|------|----------|----------|
| 未验真 | 灰色标签 `- 未验真` | 可点击 |
| 验真中 | 蓝色标签 `⏳ 验真中...` | 禁用（按钮文字保持"验真"） |
| 验真通过 | 绿色标签 `✅ 验真通过` | 可点击（重新验真） |
| 验真失败 | 红色标签 `❌ 验真失败` | 可点击（重新验真） |
| 验真异常 | 橙色标签 `⚠️ 验真异常` | 可点击（重新验真） |
| 暂不可验真 | 灰色标签 `暂不可验真` | 不显示按钮 |

**说明：**
- 验真状态标签为展示型，使用浅色背景+深色文字，无边框
- 验真按钮为操作型，使用实色背景
- 验真状态和验真按钮在同一行，间距24px
- 验真时间放在验真状态下方，小字灰色
- 验真中时，验真按钮保持"验真"文字，通过禁用状态（置灰）防止重复点击

### 3.4 验真按钮权限

| 用户角色 | 是否显示验真按钮 |
|----------|------------------|
| 管理员 | ✅ 显示 |
| 审计员 | ✅ 显示 |
| 规则创建人 | ✅ 显示 |
| 其他用户 | ❌ 不显示 |

### 3.5 交互规则

1. **点击验真按钮**
   - 前端检查上链状态：
     - 未上链 → 提示"该记录尚未上链，无法验真"
     - 上链中 → 提示"记录上链中，请稍后再试"
     - 已上链/上链异常 → 执行验真
   - 调用验真接口（异步）
   - 立即更新状态为"验真中"（蓝色标签）
   - 按钮禁用，显示"验真中..."
   - 启动轮询机制

2. **轮询查询结果**
   - 每3秒查询一次验真结果
   - 查询到结果后（状态非verifying）→ 停止轮询，更新状态
   - 超时（3分钟/60次）→ 更新为"验真异常"

3. **验真中状态展示**
   ```
   验真状态
   ┌─────────────┐              ┌─────────┐
   │ ⏳ 验真中... │              │  验真   │
   │ (浅色背景)   │              │ (置灰)  │
   └─────────────┘              └─────────┘
   上次验真时间：尚未进行验真
   ```

4. **验真完成状态展示**
   ```
   验真状态
   ┌─────────────┐              ┌─────────┐
   │ ✅ 验真通过  │              │  验真   │
   │ (浅色背景)   │              │(实色背景)│
   └─────────────┘              └─────────┘
   上次验真时间：2026-07-08 14:30:00
   ```

### 3.6 样式规范

#### 验真状态标签样式

| 状态 | 文字 | 背景色 | 文字色 | 边框色 | 图标 |
|------|------|--------|--------|--------|------|
| 验真中 | 验真中... | `#ecf5ff` | `#409eff` | 无 | ⏳ |
| 验真通过 | 验真通过 | `#f0f9eb` | `#67c23a` | 无 | ✅ |
| 验真失败 | 验真失败 | `#fef0f0` | `#f56c6c` | 无 | ❌ |
| 验真异常 | 验真异常 | `#fdf6ec` | `#e6a23c` | 无 | ⚠️ |
| 未验真 | 未验真 | `#f4f4f5` | `#909399` | 无 | - |

**说明：**
- 验真状态标签为展示型，使用浅色背景+深色文字，无边框
- 验真按钮为操作型，使用实色背景或强调边框
- 验真状态和验真按钮在同一行，间距24px

#### 验真按钮样式

```css
.btn-verify {
    background: var(--color-primary);
    color: #fff;
    border: none;
    padding: 4px 12px;
    border-radius: var(--radius-sm);
    font-size: var(--font-xs);
    cursor: pointer;
    transition: all 0.2s;
}

.btn-verify:hover {
    background: var(--color-primary-dark);
}

.btn-verify:disabled {
    color: var(--text-secondary);
    background: var(--bg-hover);
    cursor: not-allowed;
}
```

#### 验真时间样式

```css
.verify-time {
    margin-top: 6px;
    font-size: var(--font-xs);
    color: var(--text-secondary);
}
```

---

## 4. 疑点派发详情页改动说明

**对应页面**：`疑点派发-疑点详情.html`

### 4.1 改动位置

疑点派发详情页 → 链上详情弹窗 → 校验信息区域

### 4.2 改动内容

#### 新增字段

| 字段 | 位置 | 说明 |
|------|------|------|
| 验真时间 | 验真状态下方 | 展示最近一次验真时间 |
| 验真按钮 | 弹窗底部操作栏 | 点击触发验真操作 |

#### 改动前后对比

**改动前：**
```
┌─────────────────────────────────────────────────────┐
│ 校验信息                                              │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 验真状态                                          │ │
│ │ <span class="chain-status chain-success">验真通过</span> │
│ └─────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────┤
│                              [关闭] 按钮              │
└─────────────────────────────────────────────────────┘
```

**改动后：**
```
┌─────────────────────────────────────────────────────┐
│ 校验信息                                              │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 验真状态                                          │ │
│ │ ┌─────────────┐              ┌─────────┐       │ │
│ │ │ ✅ 验真通过  │              │  验真   │       │ │
│ │ │ (浅色背景)   │              │(实色背景)│       │ │
│ │ └─────────────┘              └─────────┘       │ │
│ │                                                  │ │
│ │ 上次验真时间：2026-07-08 14:30:00                │ │
│ └─────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────┤
│                                        [关闭] 按钮   │
└─────────────────────────────────────────────────────┘
```

### 4.3 验真状态展示

与规则详情页一致，使用相同的样式规范。

### 4.4 验真按钮权限

| 用户角色 | 是否显示验真按钮 |
|----------|------------------|
| 管理员 | ✅ 显示 |
| 审计员 | ✅ 显示 |
| 场景创建人 | ✅ 显示 |
| 场景协作人 | ✅ 显示 |
| 疑点处置人 | ✅ 显示 |
| 疑点审核人 | ✅ 显示 |
| 其他用户 | ❌ 不显示 |

### 4.5 交互规则

1. **打开弹窗时**
   - 从数据库读取验真状态和验真时间
   - 如果验真状态为"verifying"，启动轮询

2. **点击验真按钮**
   - 前端检查上链状态
   - 调用验真接口
   - 更新弹窗内验真状态为"验真中"
   - 按钮禁用
   - 启动轮询

3. **轮询查询结果**
   - 每3秒查询一次
   - 查询到结果后更新弹窗内状态
   - 超时后更新为"验真异常"

4. **关闭弹窗时**
   - 停止轮询

---

## 5. 疑点处置详情页改动说明

**对应页面**：`疑点处置-疑点详情.html`

### 5.1 改动内容

与疑点派发详情页完全一致，参见第4章。

---

## 6. 接口对接说明

### 6.1 发起验真接口

```
POST /core/blockchain/verify
```

#### 请求参数

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `dataType` | String | 是 | 数据类型：RULE / DOUBT |
| `dataId` | String | 是 | 数据ID |

#### 响应示例

```json
{
  "code": 200,
  "data": {
    "taskId": "VERIFY_20260708143000001",
    "dataType": "RULE",
    "dataId": "GZ177019905698527",
    "message": "验真任务已提交，请稍后查询结果"
  }
}
```

### 6.2 查询验真结果接口

```
GET /core/blockchain/verify/result
```

#### 请求参数

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `dataType` | String | 是 | 数据类型：RULE / DOUBT |
| `dataId` | String | 是 | 数据ID |

#### 响应示例

```json
{
  "code": 200,
  "data": {
    "verifyStatus": "verified_pass",
    "verifyTime": "2026-07-08 14:30:05",
    "message": "数据与链上记录一致"
  }
}
```

### 6.3 状态值映射

| 后端状态值 | 前端展示 | 说明 |
|------------|----------|------|
| `not_verified` | 未验真 | 初始状态 |
| `verifying` | 验真中 | 需要轮询 |
| `verified_pass` | 验真通过 | 最终状态 |
| `verified_fail` | 验真失败 | 最终状态 |
| `verified_error` | 验真异常 | 最终状态 |

---

## 7. Mock数据说明

### 7.1 规则验真数据

在 `规则详情.html` 中，`chainLifecycleMap` 已包含 `verifyStatus` 字段，需要扩展为支持验真时间和验真按钮状态。

#### 扩展数据结构

```javascript
const chainLifecycleMap = {
    'GZ177019905698527': {
        status: '已上链',
        evidenceNo: 'RULE-CHAIN-20260204-001',
        chainNode: '规则上线',
        verifyStatus: 'verified_pass',  // 状态值
        verifyTime: '2026-07-08 14:30:00',  // 新增
        // ... 其他字段
    }
};
```

### 7.2 疑点验真数据

在 `疑点派发-疑点详情.html` 和 `疑点处置-疑点详情.html` 中，`doubtChainData` 需要扩展验真字段。

#### 扩展数据结构

```javascript
const doubtChainData = {
    'YD20250101001': {
        status: '上链异常',
        exceptionReason: '链上节点连接超时，请稍后重试',
        verifyStatus: 'verified_error',  // 新增
        verifyTime: '2026-07-08 10:00:00',  // 新增
        chain: [...]
    }
};
```

---

## 8. 前端实现要点

### 8.1 轮询机制实现

```javascript
let verifyPollingTimer = null;
let verifyPollingCount = 0;
const MAX_POLLING_COUNT = 60;  // 最多轮询60次
const POLLING_INTERVAL = 3000;  // 每3秒轮询一次

function startVerifyPolling(dataType, dataId) {
    // 停止之前的轮询
    stopVerifyPolling();
    
    verifyPollingCount = 0;
    verifyPollingTimer = setInterval(() => {
        verifyPollingCount++;
        
        // 超时处理
        if (verifyPollingCount >= MAX_POLLING_COUNT) {
            stopVerifyPolling();
            updateVerifyStatus('verified_error', null, '验真超时');
            return;
        }
        
        // 查询验真结果
        queryVerifyResult(dataType, dataId);
    }, POLLING_INTERVAL);
}

function stopVerifyPolling() {
    if (verifyPollingTimer) {
        clearInterval(verifyPollingTimer);
        verifyPollingTimer = null;
    }
}

function queryVerifyResult(dataType, dataId) {
    // 调用查询接口
    fetch(`/core/blockchain/verify/result?dataType=${dataType}&dataId=${dataId}`)
        .then(res => res.json())
        .then(data => {
            if (data.code === 200 && data.data.verifyStatus !== 'verifying') {
                stopVerifyPolling();
                updateVerifyStatus(data.data.verifyStatus, data.data.verifyTime);
            }
        });
}
```

### 8.2 页面离开时停止轮询

```javascript
// 页面离开时停止轮询
window.addEventListener('beforeunload', stopVerifyPolling);

// Tab切换时停止轮询
document.addEventListener('visibilitychange', () => {
    if (document.hidden) {
        stopVerifyPolling();
    }
});
```

### 8.3 验真状态更新函数

```javascript
function updateVerifyStatus(status, time, errorMsg) {
    const statusMap = {
        'not_verified': { text: '未验真', cls: 'chain-unpublished', icon: '-' },
        'verifying': { text: '验真中...', cls: 'chain-processing', icon: '🔄' },
        'verified_pass': { text: '验真通过', cls: 'chain-success', icon: '✅' },
        'verified_fail': { text: '验真失败', cls: 'chain-failed', icon: '❌' },
        'verified_error': { text: '验真异常', cls: 'chain-failed', icon: '⚠️' }
    };
    
    const config = statusMap[status] || statusMap['not_verified'];
    
    // 更新状态标签
    const statusEl = document.getElementById('verifyStatus');
    if (statusEl) {
        statusEl.innerHTML = `<span class="chain-status ${config.cls}">${config.icon} ${config.text}</span>`;
        if (status === 'verifying') {
            statusEl.querySelector('.chain-status').classList.add('verifying');
        }
    }
    
    // 更新验真时间
    const timeEl = document.getElementById('verifyTime');
    if (timeEl) {
        timeEl.textContent = time || '-';
    }
    
    // 更新按钮状态
    const btnEl = document.getElementById('btnVerify');
    if (btnEl) {
        if (status === 'verifying') {
            btnEl.disabled = true;
            btnEl.textContent = '验真中...';
        } else {
            btnEl.disabled = false;
            btnEl.textContent = '验真';
        }
    }
}
```

---

## 9. 验收标准

### 9.1 规则详情页

- [ ] 区块链信息Tab展示验真状态、验真时间、验真按钮
- [ ] 已上链/上链异常的规则显示验真按钮
- [ ] 未上链/上链中的规则不显示验真按钮
- [ ] 点击验真按钮后，状态立即更新为"验真中"
- [ ] 验真中状态下，按钮禁用，显示"验真中..."
- [ ] 验真完成后更新验真状态和验真时间
- [ ] 无验真权限的用户不显示验真按钮

### 9.2 疑点派发详情页

- [ ] 链上详情弹窗展示验真状态、验真时间、验真按钮
- [ ] 已上链/上链异常的疑点显示验真按钮
- [ ] 未上链/上链中的疑点不显示验真按钮
- [ ] 点击验真按钮后，状态立即更新为"验真中"
- [ ] 验真完成后更新验真状态和验真时间
- [ ] 关闭弹窗时停止轮询
- [ ] 无验真权限的用户不显示验真按钮

### 9.3 疑点处置详情页

- [ ] 链上详情弹窗展示验真状态、验真时间、验真按钮
- [ ] 与疑点派发详情页交互一致

---

## 10. 与PRD的差异说明

| 差异点 | PRD描述 | 实际实现 | 原因 |
|--------|---------|----------|------|
| 列表页验真状态列 | 新增验真状态列 | 不新增 | 用户决策：保持列表简洁 |
| 列表页验真按钮 | 行操作新增验真按钮 | 不新增 | 用户决策：验真入口在详情页 |
| 验真结果可见性 | 未明确 | 所有人可见 | 用户决策：透明度优先 |

---

## 11. 后续待完善功能

以下功能在本期暂不实现，记录为后续待完善项：

1. **验真与数据变更的时序冲突**
   - 验真中修改数据的处理
   - 验真后修改数据的状态重置

2. **验真失败的业务处理流程**
   - 验真失败后的通知机制
   - 验真失败对业务流程的影响

3. **验真频率和并发控制**
   - 同一记录的并发验真处理
   - 验真频率限制

4. **验真结果通知机制**
   - 验真完成后的通知推送

5. **列表页验真状态筛选**
   - 按验真状态筛选规则/疑点

---

## 12. 一句话总结

本次改动在规则详情页区块链信息Tab和疑点链上详情弹窗中新增验真功能，支持异步验真和轮询机制，验真结果对所有用户可见，验真操作记录到审计日志。
