Metadata-Version: 2.4
Name: django-admin-dashboards
Version: 0.1.0
Summary: Customizable data dashboards for Django Admin with KPI cards, charts, tables, and filters
Author-email: rRR0VrFP <rrr0vrfp@qq.com>
Maintainer-email: rRR0VrFP <rrr0vrfp@qq.com>
License: MIT
Project-URL: Homepage, https://django-admin-dashboards.readthedocs.io
Project-URL: Repository, https://gitee.com/rRR0VrFP/django-admin-dashboards
Keywords: django,admin,dashboard,analytics,charts,kpi
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Django
Classifier: Framework :: Django :: 5.2
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Django>=5.2
Requires-Dist: django-static-remixicon>=0.1.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-django>=4.5.0; extra == "dev"
Requires-Dist: black>=22.0.0; extra == "dev"
Requires-Dist: flake8>=5.0.0; extra == "dev"
Provides-Extra: docs
Requires-Dist: mkdocs~=1.6.1; extra == "docs"
Requires-Dist: mkdocs-material~=9.7.6; extra == "docs"
Requires-Dist: mkdocs-material-extensions~=1.3.1; extra == "docs"
Requires-Dist: mkdocstrings-python~=2.0.3; extra == "docs"
Dynamic: license-file

# Django Admin Dashboards

![Python 版本](https://img.shields.io/badge/python-3.8%2B-blue)
![Django 版本](https://img.shields.io/badge/django-5.2%2B-green)
![许可证](https://img.shields.io/badge/license-MIT-blue)
![文档](https://img.shields.io/badge/docs-readthedocs.io-blue)
![Gitee 仓库](https://img.shields.io/badge/gitee-仓库-orange)
![Vibe Coding: opencode+deepseek-reasoner](https://img.shields.io/badge/Vibe%20Coding-opencode+deepseek--reasoner-green)

**Django Admin Dashboards** 是一个强大的 Django 应用程序，它将默认的 Django Admin 界面转换为完全可定制的数据看板系统。用包含卡片、图表、表格和过滤器的数据看板替换静态的管理页面。

- **代码仓库**: [https://gitee.com/rRR0VrFP/django-admin-dashboards/](https://gitee.com/rRR0VrFP/django-admin-dashboards/)
- **使用文档**: [https://django-admin-dashboards.readthedocs.io/](https://django-admin-dashboards.readthedocs.io/)
- **PyPI发布**: [https://pypi.org/project/django-admin-dashboards/](https://pypi.org/project/django-admin-dashboards/)

*本项目使用AI辅助编程工具（opencode + deepseek-reasoner）自动生成和维护*

## ✨ 主要特性

- **交互式数据看板布局**：响应式网格布局（12列系统）支持灵活的行配置
- **多种组件类型**：
  - `Cards`（支持图标和单值/多值显示）
  - `Charts`（折线图、柱状图、饼图等）使用 Chart.js
  - `Data Tables` 支持排序和分页
  - `Filter Components` 用于数据过滤
- **深色模式支持**：完全兼容 Django Admin 的深色模式
- **全屏模式**：专用的全屏查看体验，支持 URL 参数控制
- **可定制导航**：与 `django-admin-global-sidebar` 集成
- **多语言支持**：内置中文翻译，可扩展支持其他语言
- **灵活配置**：通过 URL 参数控制深色模式、全屏模式和布局选项

## 🎯 示例数据看板

项目包含完整的示例数据看板 (`ExampleDashboard`)，展示所有组件类型：

- **4个卡片组件**：2个静态数据卡片，2个动态数据卡片
- **7种图表类型**：折线图、柱状图、饼图、环形图、雷达图、堆叠图、横向柱状图
- **1个表格组件**：显示最近销售记录
- **过滤器组件**：产品分类、日期范围、状态（单选/多选）、数值范围、文本搜索、金额过滤

运行示例：

```bash
# 生成示例数据
python manage.py generate_example_data --clear

# 启动开发服务器
python manage.py runserver
```

访问 `http://127.0.0.1:8000/admin/` 查看示例数据看板。

## 📦 安装

```bash
pip install django-admin-dashboards
```

或从源代码安装：

```bash
git clone https://gitee.com/rRR0VrFP/django-admin-dashboards.git
cd django-admin-dashboards
pip install -e .
```

## 🚀 快速开始

1. **在 Django 设置中添加 INSTALLED_APPS**：

```python
INSTALLED_APPS = [
    "django_admin_dashboards",  # 必须在 django.contrib.admin 之前
    "django_static_remixicon",  # 图标必需
    "django.contrib.admin",
    # ... 其他应用
]
```

2. **在 settings.py 中配置数据看板映射**：

```python
DJANGO_ADMIN_DASHBOARDS = {
    "admin:index": "django_admin_dashboards.contrib.auth.dashboard.AuthAppDashboard",
    "admin:app_list": {
        "auth": "django_admin_dashboards.contrib.auth.dashboard.AuthAppDashboard",
    },
}
```

3. **运行迁移并收集静态文件**：

```bash
python manage.py migrate
python manage.py collectstatic
```

4. **在 `/admin/` 访问您的数据看板**

## ⚙️ 配置

### 数据看板设置

配置不同管理视图使用的数据看板：

```python
DJANGO_ADMIN_DASHBOARDS = {
    # 管理首页
    "admin:index": "path.to.YourDashboardClass",
    
    # 应用列表页面（特定应用）
    "admin:app_list": {
        "auth": "django_admin_dashboards.contrib.auth.dashboard.AuthAppDashboard",
        "app_label": "path.to.AppSpecificDashboard",
    },
    
}
```

### 导航菜单配置

与 `django-admin-global-sidebar` 集成以增强导航：

```python
DJANGO_ADMIN_GLOBAL_SIDEBAR_MENUS = [
    {
        "title": "首页",  # Home
        "url": "/admin/",
        "icon": "fas fa-home",
    },
    {
        "title": "系统管理",  # System Management
        "icon": "fas fa-cog",
        "children": [
            {
                "title": "用户管理",  # User Management
                "url": "/admin/auth/user/",
                "icon": "fas fa-users",
            },
            # ... 更多菜单项
        ],
    },
]
```

## 📊 创建自定义数据看板

### 基本数据看板示例

通过扩展 `Dashboard` 基类创建自定义数据看板：

```python
# myapp/dashboards.py
from django_admin_dashboards.base import Dashboard, CardComponent, ChartComponent, Layout, TableComponent
from django.utils.translation import gettext_lazy as _
from django.db.models import Count
from datetime import datetime, timedelta
from django.utils import timezone

class MyCustomDashboard(Dashboard):
    title = _("My Dashboard")
    show_dashboard_title = True
    show_admin_title = False
    hide_others_in_fullscreen = True  # Enable fullscreen hide feature

    def get_layout(self):
        layout = Layout(columns=12)
        
        # 添加卡片
        layout.add_row([
            (CardComponent(
                title="Total Users",
                value=150,
                change="+12%",
                trend="up",
                color="primary",
                icon_class="ri-user-line"
            ), 4),
            (CardComponent(
                title="Active Sessions",
                value=42,
                change="-3%",
                trend="down",
                color="success",
                icon_class="ri-user-heart-line"
            ), 4),
            (CardComponent(
                title="Revenue",
                value="$12,450",
                change="+24%",
                trend="up",
                color="warning",
                icon_class="ri-money-dollar-circle-line"
            ), 4),
        ], height="auto")
        
        # Add chart
        layout.add_row([
            (ChartComponent(
                title="User Registration Trends",
                chart_type="line",
                data={
                    "labels": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
                    "datasets": [{
                        "label": "New Users",
                        "data": [65, 59, 80, 81, 56, 55],
                        "borderColor": "rgb(75, 192, 192)",
                    }]
                },
                options={
                    "responsive": True,
                    "plugins": {"legend": {"position": "top"}},
                }
            ), 12)
        ], height="400px")
        
        # Add table
        layout.add_row([
            (TableComponent(
                title="Recent Activity",
                columns=["User", "Action", "Date", "Status"],
                data=[
                    ["john_doe", "Login", "2024-01-15", "Success"],
                    ["jane_smith", "Profile Update", "2024-01-14", "Success"],
                    ["bob_johnson", "Password Reset", "2024-01-13", "Pending"],
                ]
            ), 12)
        ], height="auto")
        
        return layout
    
    def get_kpi_cards(self):
        """重写此方法以提供动态的指标数据"""
        from django.contrib.auth.models import User
        from django.db.models import Q
        
        total_users = User.objects.count()
        active_users = User.objects.filter(is_active=True).count()
        recent_users = User.objects.filter(
            date_joined__gte=timezone.now() - timedelta(days=30)
        ).count()
        
        return [
            CardComponent(
                title="User Status",
                values=[active_users, total_users - active_users, total_users],
                value_labels=["Active", "Inactive", "Total"],
                color="primary",
                icon_class="ri-user-2-line"
            ),
            # ... more cards
        ]
```

### 多值卡片

在单个卡片中显示多个值：

```python
CardComponent(
    title="User Status",
    values=[85, 15, 100],  # Active, Inactive, Total
    value_labels=["Active", "Inactive", "Total"],
    color="primary",
    icon_class="ri-user-2-line"
)
```

## 🧩 组件参考

### CardComponent

显示指标数据，支持趋势指示器和图标。

```python
CardComponent(
    title="Card Title",
    value=42,  # Main value (optional if using values)
    change="+12%",  # Percentage change
    trend="up",  # "up", "down", or "neutral"
    color="primary",  # "primary", "success", "warning", "danger", "info", "secondary"
    icon_class="ri-bar-chart-2-line",  # remixicon class
    
    # Multi-value display (alternative to single value)
    values=[10, 20, 30],
    value_labels=["Label1", "Label2", "Label3"],
)
```

**可用颜色**: `primary`, `success`, `warning`, `danger`, `info`, `secondary`

### ChartComponent

使用 Chart.js 的交互式图表。

```python
ChartComponent(
    title="Chart Title",
    chart_type="line",  # "line", "bar", "pie", "doughnut", "radar", "polarArea"
    data={
        "labels": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
        "datasets": [
            {
                "label": "Dataset 1",
                "data": [65, 59, 80, 81, 56, 55],
                "borderColor": "rgb(75, 192, 192)",
                "backgroundColor": "rgba(75, 192, 192, 0.1)",
                "fill": True,
            }
        ]
    },
    options={
        "responsive": True,
        "maintainAspectRatio": False,
        "plugins": {
            "legend": {"position": "top"},
        },
        "scales": {
            "y": {"beginAtZero": True}
        }
    },
    height=400,  # Height in pixels
)
```

### TableComponent

用于显示表格数据的表格组件。

```python
TableComponent(
    title="Table Title",
    columns=["Column 1", "Column 2", "Column 3"],  # Column headers
    data=[  # Row data
        ["Row 1 Col 1", "Row 1 Col 2", "Row 1 Col 3"],
        ["Row 2 Col 1", "Row 2 Col 2", "Row 2 Col 3"],
        ["Row 3 Col 1", "Row 3 Col 2", "Row 3 Col 3"],
    ],
)
```

### FilterComponent

用于数据看板数据的交互式过滤器，提供现代化触发按钮+下拉面板界面，支持 Select2 搜索和多选功能。

```python
FilterComponent(
    title="Filters",
    filters=[
        {
            "name": "date_range",
            "label": "Date Range",
            "type": "date_range",
            "options": [
                {"value": "today", "label": "Today"},
                {"value": "yesterday", "label": "Yesterday"},
                {"value": "last_7_days", "label": "Last 7 Days"},
                {"value": "last_30_days", "label": "Last 30 Days"},
                {"value": "custom", "label": "Custom Range"},
            ],
            "default": "last_30_days",
        },
        {
            "name": "status",
            "label": "Status",
            "type": "multi_select",  # 支持多选
            "options": [
                {"value": "active", "label": "Active"},
                {"value": "pending", "label": "Pending"},
                {"value": "completed", "label": "Completed"},
                {"value": "cancelled", "label": "Cancelled"},
            ],
            "default": ["active", "pending"],  # 多选默认值可以是数组
        },
        {
            "name": "price_range",
            "label": "Price Range",
            "type": "number_range",  # 数值范围（最小值和最大值）
            "default_min": 0,
            "default_max": 1000,
        },
        {
            "name": "category",
            "label": "Category",
            "type": "select",  # 单选下拉框，支持 Select2 搜索
            "options": [
                {"value": "all", "label": "All Categories"},
                {"value": "electronics", "label": "Electronics"},
                {"value": "clothing", "label": "Clothing"},
                {"value": "books", "label": "Books"},
            ],
            "default": "all",
        },
        {
            "name": "search",
            "label": "Search",
            "type": "text",  # 文本搜索
            "placeholder": "Enter keywords...",
        },
    ],
)
```

## 🛠️ 过滤器管理器

Django Admin Dashboards 提供 `FiltersManager` 抽象基类，用于简化业务过滤器的定义和共享。通过使用过滤器管理器，您可以在多个数据看板和数据源之间共享过滤器配置和过滤逻辑，避免代码重复。

### FiltersManager 基类

`FiltersManager` 是一个抽象基类，提供以下核心功能：

- **统一的过滤器配置管理**：通过 `get_filters_config()` 方法定义过滤器配置
- **过滤器应用逻辑**：通过 `apply_filters()` 方法将过滤器应用到查询集
- **便捷的过滤器创建方法**：提供 `create_select_filter()`、`create_multi_select_filter()` 等静态方法
- **与 `FilterHelper` 集成**：自动处理请求参数和过滤器状态

```python
from django_admin_dashboards.base import FiltersManager

class MyFiltersManager(FiltersManager):
    """自定义过滤器管理器"""
    
    @classmethod
    def get_filters_config(cls):
        """返回过滤器配置列表"""
        return [
            cls.create_select_filter(
                name="category",
                label="产品分类",
                options=[
                    {"value": "all", "label": "全部分类"},
                    {"value": "electronics", "label": "电子产品"},
                    {"value": "clothing", "label": "服装服饰"},
                ],
                default="all",
            ),
            cls.create_date_range_filter(
                name="date_range",
                label="日期范围",
                default="last_30_days",
            ),
        ]
    
    def apply_filters(self, queryset, filter_helper=None):
        """将过滤器应用到查询集"""
        if filter_helper is None:
            filter_helper = self.get_filter_helper()
        
        if filter_helper is None:
            return queryset
        
        # 应用分类过滤
        category = filter_helper.get_value("category", "all")
        if category != "all":
            queryset = queryset.filter(category=category)
        
        # 应用日期范围过滤
        start_date, end_date = filter_helper.get_date_range("date_range")
        if start_date and end_date:
            queryset = queryset.filter(
                created_at__gte=start_date,
                created_at__lte=end_date
            )
        
        return queryset
```

### 在 Dashboard 中集成过滤器管理器

在自定义数据看板中，通过设置 `filters_manager_class` 属性来集成过滤器管理器：

```python
from django_admin_dashboards.base import Dashboard
from .filters import MyFiltersManager

class MyDashboard(Dashboard):
    title = "我的数据看板"
    filters_manager_class = MyFiltersManager  # 集成过滤器管理器
    
    def get_layout(self):
        # 布局定义...
        pass
    
    def get_context_data(self, request):
        context = super().get_context_data(request)
        # 可以通过 self.get_filters_manager(request) 获取过滤器管理器实例
        filters_manager = self.get_filters_manager(request)
        if filters_manager:
            # 使用过滤器管理器...
            pass
        return context
```

### 在 DataSource 中集成过滤器管理器

数据源也可以通过 `filters_manager_class` 属性集成过滤器管理器，实现过滤器配置和逻辑的共享：

```python
from django_admin_dashboards.base import SecurityCheckedDataSource

@DataSource.register
class MyDataSource(SecurityCheckedDataSource):
    source_id = "my_data_source"
    description = "我的数据源"
    permission_required = "app.view_model"
    filters_manager_class = MyFiltersManager  # 集成过滤器管理器
    
    def _fetch_data(self, request):
        # 获取过滤器管理器实例
        filters_manager = self.get_filters_manager(request)
        
        # 获取基础查询集
        queryset = MyModel.objects.all()
        
        # 应用过滤器
        if filters_manager:
            queryset = filters_manager.apply_filters(queryset)
        
        # 处理数据并返回
        return queryset.count()
```

### 示例：ExampleFiltersManager

示例应用提供了一个完整的 `ExampleFiltersManager` 实现，位于 `django_admin_dashboards_example/example_filters.py`：

- **共享过滤器配置**：为销售和产品模型定义统一的过滤器
- **模型特定的过滤逻辑**：提供 `apply_sales_filters()` 和 `apply_products_filters()` 方法
- **显示名称映射**：内置分类和状态的中文显示映射

通过使用 `ExampleFiltersManager`，示例数据看板 (`ExampleDashboard`) 和销售数据源 (`RecentSalesDataSource`) 可以共享相同的过滤器配置和逻辑，避免代码重复。

## 🔌 数据源系统

Django Admin Dashboards 提供安全的数据源系统，用于异步数据加载。所有数据源都必须预定义并注册，确保安全性。

### SecurityCheckedDataSource 基类

```python
from django_admin_dashboards.base import SecurityCheckedDataSource

@DataSource.register
class MyDataSource(SecurityCheckedDataSource):
    source_id = "my_data_source"
    description = "我的数据源描述"
    permission_required = "app.view_model"
    
    def _fetch_data(self, request):
        # 实现数据获取逻辑
        return {"data": "example"}
```

### 组件数据源支持

组件可以通过 `data_source` 参数使用数据源：

```python
# 卡片组件使用数据源
CardComponent(
    title="用户统计",
    data_source=UserCountDataSource(count_active_only=True)
)

# 图表组件使用数据源 - 需要实际数据
ChartComponent(
    title="用户活动趋势",
    chart_type="line",
    # 图表数据源需要返回图表.js兼容的数据结构
    # 这里只是示例，实际需要实现返回图表数据的数据源
    data_source=None  # 替换为实际的图表数据源
)

# 表格组件使用数据源
TableComponent(
    title="用户角色分布",
    columns=["角色", "数量"],
    # 使用 UserRoleDistributionDataSource，但需要适配表格格式
    # 实际使用中需要实现返回表格数据的数据源
    data_source=None  # 替换为实际的表格数据源
)

# 更多实际示例
CardComponent(
    title="最近活跃用户",
    data_source=RecentUserActivityDataSource(days=7, active_only=True)
)

CardComponent(
    title="权限统计",
    data_source=PermissionCountDataSource()
)
```

### 安全要求
1. **预定义与注册**：所有数据源必须预定义并注册
2. **权限检查**：数据源实现中必须包含权限检查
3. **唯一标识符**：每个数据源必须有唯一的 `source_id`
4. **安全反序列化**：使用 `DataSource.create_from_json()` 确保安全

### 内置示例
示例数据源位于 `django_admin_dashboards_example/example_data_sources.py`：

| 数据源类 | 描述 | 所需权限 |
|----------|------|----------|
| `UserCountDataSource` | 用户计数统计（支持按启用状态过滤） | `auth.view_user` |
| `GroupCountDataSource` | 用户组计数统计 | `auth.view_group` |
| `LogEntryCountDataSource` | 管理员日志条目计数（支持按时间过滤） | `admin.view_logentry` |
| `ContentTypeCountDataSource` | 内容类型总数统计 | `contenttypes.view_contenttype` |
| `PermissionCountDataSource` | 权限总数统计（支持按内容类型过滤） | `auth.view_permission` |
| `RecentUserActivityDataSource` | 最近活跃用户统计（支持按天数过滤） | `auth.view_user` |
| `UserRoleDistributionDataSource` | 用户角色分布统计（超级用户、员工、普通用户） | `auth.view_user` |

## 🎛️ 数据看板配置选项

### 类属性

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `title` | string | `None` | 数据看板标题，显示在页眉中 |
| `show_dashboard_title` | bool | `True` | 显示/隐藏数据看板标题 |
| `show_admin_title` | bool | `False` | 显示/隐藏默认的 Django admin 标题 |
| `hide_others_in_fullscreen` | bool | `False` | 启用功能：在全屏模式下隐藏周围元素 |
| `force_hide_others` | bool | `False` | 启用功能：始终隐藏周围元素 |
| `template_name` | string | `"admin/dashboard.html"` | 用于数据看板渲染的自定义模板 |

### URL 参数控制

数据看板行为可以通过 URL 参数控制：

| Parameter | Values | Description |
|-----------|--------|-------------|
| `_dark_mode_on` | `true`, `false`, `auto` | 控制深色模式：`true`=强制深色，`false`=强制浅色，`auto`=跟随 Django admin 设置 |
| `_hide_others_in_fullscreen` | `true`, `false` | 在全屏模式下隐藏周围元素（需要数据看板支持此功能） |
| `_force_hide_others` | `true`, `false` | 始终隐藏周围元素，无论是否全屏模式 |

**示例URL：**
- `/admin/?_dark_mode_on=true` - 强制深色模式
- `/admin/?_dark_mode_on=false` - 强制浅色模式  
- `/admin/?_dark_mode_on=auto` - 跟随 Django admin 主题
- `/admin/?_hide_others_in_fullscreen=true` - 全屏模式下隐藏周围元素
- `/admin/?_force_hide_others=true` - 始终隐藏周围元素

## 🌙 深色模式支持

数据看板完全支持 Django Admin 的深色模式系统，并提供基于 URL 的额外控制：

- **自动检测**：跟随 Django Admin 的主题设置
- **URL 覆盖**：使用 `?_dark_mode_on=true/false/auto` 进行覆盖
- **CSS 兼容性**：所有组件都有深色模式样式
- **主题保留**：在 `auto` 模式下，深色模式切换按钮仍然有效

## 🖥️ 全屏模式

数据看板可以在全屏模式下查看，有两种控制选项：

### 1. 全屏模式下隐藏
数据看板元素仅在浏览器全屏模式下隐藏周围的 admin UI。
要求：在数据看板类中设置 `hide_others_in_fullscreen = True` + URL 参数 `?_hide_others_in_fullscreen=true`。

### 2. 强制隐藏其他元素
始终隐藏周围元素，无论是否全屏模式。
要求：在数据看板类中设置 `force_hide_others = True` + URL 参数 `?_force_hide_others=true`。



## 🔧 开发

### 运行测试

```bash
python manage.py test django_admin_dashboards_example
```

### 构建分发包

```bash
# Install build tools
pip install build twine

# Build package
python -m build

# Upload to PyPI (requires credentials)
python -m twine upload dist/*
```

### 添加翻译

1. 提取可翻译字符串：
   ```bash
   django-admin makemessages -l zh_Hans
   ```

2. 编辑翻译文件：`locale/zh_Hans/LC_MESSAGES/django.po`

3. 编译翻译：
   ```bash
   django-admin compilemessages
   ```

## 📄 许可证

MIT 许可证 - 详情请见 [LICENSE](LICENSE) 文件。

## 📝 版本历史

### v0.1.0 (2026-04-04)
- 初始版本
- 数据看板系统，包含卡片、图表、表格和过滤器
- 支持深色模式，可通过 URL 参数控制
- 全屏模式，支持隐藏选项
- 响应式网格布局系统
- 内置 AuthAppDashboard 示例

## 🤝 贡献指南

欢迎贡献！请随时提交 Pull Request。

1. Fork 仓库
2. 创建功能分支（`git checkout -b feature/amazing-feature`）
3. 提交更改（`git commit -m 'Add amazing feature'`）
4. 推送到分支（`git push origin feature/amazing-feature`）
5. 打开 Pull Request

## 📧 支持

如有问题、疑问或功能请求，请在 Gitee 仓库中提交 issue。

您也可以通过 rrr0vrfp@qq.com 联系维护者。

---

**Django Admin Dashboards** - 将您的 Django Admin 转变为强大的分析数据看板！
