原型設計技能

👤 contsun 📦 v1.0.2 ⭐ 4.4 ⬇️ 2.7K 下載
🎨 設計多媒體 免費

📖 技能介紹


name: prototype-design description: | 通用頁面原型設計技能。基於 58種設計風格(預設Figma 風格) UI 的複雜業務系統 HTML 原型開發, 包括標準頁面結構、統計卡片、篩選條件、資料表格、彈窗設計。 適用場景:(1) 建立新的管理頁面原型 (2) 對照業務文件實現功能模組 (3) 設計彈窗和詳情頁 (4) 構建帶看板和列表檢視的頁面。 樣式選擇:內建58+設計系統,直接引用 references/design-systems/ 目錄。 使用時指定 DESIGN_SYSTEM=<名稱> 即可應用對應設計風格。 origin: openclaw last_updated: 2026-04-14 changelog: - 2026-04-14: 初始版本,從 WMS 專案經驗中沉澱 - 2026-04-14: 新增長對話上下文管理章節 - 2026-04-14: 新增 WMS 專案實戰經驗(10條核心教訓)


原型設計技能

When to Use(何時使用)

  • 使用者要求建立新的管理頁面原型
  • 需要實現業務文件中的功能模組
  • 需要設計彈窗、詳情頁
  • 需要構建帶看板或列表檢視的頁面
  • 涉及 HTML/CSS/JS 前端程式碼的原型開發

How to Use(如何使用)

1. 專案初始化

mkdir -p project/{pages,styles,scripts}
cd project

2. 設計系統選擇

內建設計系統(references/design-systems/): - 預設:figma-DESIGN.md - 管理後臺:linear-DESIGN.md - 簡約專業:vercel-DESIGN.md

原型設計技能

通用頁面原型開發指南,支援58+設計系統風格。

專案結構

project/
├── index.html          # 單頁應用入口
├── pages/              # 頁面模組
│   ├── dashboard.html
│   ├── staff.html
│   └── ...
├── styles/
│   └── main.css        # 全域性樣式
└── scripts/
    └── main.js        # 全域性指令碼

設計系統選擇

重要:設計系統檔案位於 references/design-systems/ 目錄。

使用步驟

  1. 確定設計風格:根據專案需求選擇設計系統
  2. 管理後臺常用:Figma、Linear、Notion、Vercel
  3. 電商/消費:Airbnb、Spotify、Stripe
  4. 企業級:IBM、Salesforce

  5. 讀取對應 DESIGN.md bash cat references/design-systems/figma-DESIGN.md

  6. 應用設計規範

  7. Color Palette → CSS變數
  8. Typography → 字型規範
  9. Component Stylings → 元件樣式

常用設計系統快速參考

風格 設計系統 特點
預設 figma-DESIGN.md 多彩色、現代
管理後臺 linear-DESIGN.md 紫色主題、精緻
簡約專業 vercel-DESIGN.md 黑白精準、極簡
溫暖風格 notion-DESIGN.md 暖色極簡
企業級 stripe-DESIGN.md 紫色漸變、高階感

標準頁面結構

<div id="page-xxx" class="page">
  <!-- 1. Header -->
  <header class="header">
    <div class="header-left">
      <h2>頁面標題</h2>
      <div class="breadcrumb"><span>首頁</span><span>/</span><span>當前路徑</span></div>
    </div>
    <div class="header-right">
      <button class="btn btn-outline btn-sm">匯出</button>
      <button class="btn btn-primary btn-sm" onclick="openAddModal()">新增</button>
    </div>
  </header>

  <!-- 2. 統計卡片 -->
  <div class="stats-grid" style="grid-template-columns:repeat(4,1fr);">
    <div class="stat-card">
      <div class="stat-card-title">標題</div>
      <div class="stat-card-value">數值</div>
      <div class="stat-card-change">描述</div>
    </div>
  </div>

  <!-- 3. 篩選條件 -->
  <div class="table-filters">
    <div class="filter-group">
      <span class="filter-label">欄位名</span>
      <input type="text" class="filter-input" placeholder="提示...">
    </div>
  </div>

  <!-- 4. 資料表格 -->
  <table>
    <thead><tr><th>欄位1</th><th>欄位2</th><th>操作</th></tr></thead>
    <tbody>
      <tr>
        <td>資料</td>
        <td><span class="tag tag-success">狀態</span></td>
        <td><button class="btn btn-sm btn-outline">詳情</button></td>
      </tr>
    </tbody>
  </table>
</div>

彈窗設計規範

標準彈窗模板

<!-- 遮罩 + 居中彈窗 -->
<div id="modal-xxx" style="
  display:none;
  position:fixed;
  top:0;left:0;right:0;bottom:0;
  background:rgba(0,0,0,0.6);
  z-index:1000;
  align-items:center;
  justify-content:center;
">
  <!-- 內容框 -->
  <div style="
    background:white;
    border-radius:16px;
    width:560px;
    max-width:90vw;
    max-height:85vh;
    overflow:hidden;
    box-shadow:0 25px 80px rgba(0,0,0,0.35);
  ">
    <!-- 標題欄 -->
    <div style="
      padding:20px 24px;
      border-bottom:1px solid #E5E7EB;
      display:flex;
      align-items:center;
      justify-content:space-between;
      background:#F9FAFB;
    ">
      <h3 style="margin:0;font-size:18px;font-weight:600;color:#111827;">彈窗標題</h3>
      <button onclick="closeModal()" style="
        border:none;
        background:none;
        font-size:24px;
        color:#6B7280;
        cursor:pointer;
        padding:4px;
        line-height:1;
      ">×</button>
    </div>
    <!-- 內容區 -->
    <div style="
      padding:24px;
      overflow-y:auto;
      max-height:calc(85vh - 140px);
    ">
      <!-- 表單項示例 -->
      <div style="display:grid;grid-template-columns:1fr 1fr;gap:20px;">
        <div>
          <label style="display:block;font-size:14px;font-weight:500;margin-bottom:8px;color:#374151;">
            欄位名 <span style="color:#EF4444;">*</span>
          </label>
          <select style="
            width:100%;
            padding:10px 12px;
            border:1px solid #E5E7EB;
            border-radius:8px;
            font-size:14px;
            background:white;
          ">
            <option value="">請選擇</option>
            <option>選項1</option>
            <option>選項2</option>
          </select>
        </div>
        <div>
          <label style="display:block;font-size:14px;font-weight:500;margin-bottom:8px;color:#374151;">欄位名</label>
          <input type="text" placeholder="請輸入" style="
            width:100%;
            padding:10px 12px;
            border:1px solid #E5E7EB;
            border-radius:8px;
            font-size:14px;
            box-sizing:border-box;
          ">
        </div>
      </div>
      <div style="margin-top:16px;">
        <label style="display:block;font-size:14px;font-weight:500;margin-bottom:8px;color:#374151;">備註</label>
        <textarea rows="3" placeholder="請輸入備註" style="
          width:100%;
          padding:10px 12px;
          border:1px solid #E5E7EB;
          border-radius:8px;
          font-size:14px;
          resize:none;
          box-sizing:border-box;
        "></textarea>
      </div>
    </div>
    <!-- 底部按鈕 -->
    <div style="
      padding:16px 24px;
      border-top:1px solid #E5E7EB;
      display:flex;
      justify-content:flex-end;
      gap:12px;
      background:#F9FAFB;
    ">
      <button onclick="closeModal()" style="
        padding:10px 20px;
        border:1px solid #E5E7EB;
        background:white;
        border-radius:8px;
        font-size:14px;
        font-weight:500;
        color:#374151;
        cursor:pointer;
      ">取消</button>
      <button onclick="saveData()" style="
        padding:10px 20px;
        border:none;
        background:#4F46E5;
        color:white;
        border-radius:8px;
        font-size:14px;
        font-weight:500;
        cursor:pointer;
      ">儲存</button>
    </div>
  </div>
</div>

彈窗樣式要點(必記)

元素 樣式屬性 正確值 常見錯誤
外層遮罩 position fixed absolute 會滾動
遮罩背景 background rgba(0,0,0,0.6) 0.5 太淡,0.7 太濃
遮罩定位 top/left/right/bottom 0(全屏覆蓋) 忘記設定任一邊
彈窗容器 display flex 父級用 flex 居中
居中方式 align-items + justify-content center + center 缺少任一屬性
內容框圓角 border-radius 16px 12px 不夠現代
內容框寬度 width 560px90vw 固定 px 在小螢幕不友好
內容框高度 max-height 85vh 80vh 可能顯示不全
陰影 box-shadow 0 25px 80px rgba(0,0,0,0.35) 太淡看不出層次

表單項樣式要點

元素 樣式屬性 正確值
輸入框/下拉框 padding 10px 12px
輸入框/下拉框 border-radius 8px
輸入框/下拉框 border 1px solid #E5E7EB
輸入框/下拉框 font-size 14px
textarea resize none
textarea box-sizing border-box
必填標記 color #EF4444 (紅色)

⚠️ 常見錯誤

  1. 不要使用 CSS 類名:如 class="modal"class="btn btn-primary" - 這些類通常沒有定義樣式或樣式被覆蓋
  2. 必須使用內聯樣式:彈窗元件應完全使用內聯樣式,避免外部 CSS 干擾
  3. 遮罩層必須有 z-index:1000:確保在最上層
  4. 內容框不能用 overflow:hidden:內容超出需要滾動,必須用 overflow-y:auto

看板檢視

<div style="display:grid;grid-template-columns:repeat(5,1fr);gap:16px;">
  <!-- 列 -->
  <div style="background:#F9FAFB;border-radius:12px;padding:16px;">
    <div style="display:flex;justify-content:space-between;padding-bottom:12px;border-bottom:1px solid #E5E7EB;">
      <span>待開始</span>
      <span style="background:#FEE2E2;color:#DC2626;padding:2px 8px;border-radius:10px;font-size:12px;">5</span>
    </div>
    <div style="background:white;border-radius:8px;padding:12px;margin-top:12px;cursor:pointer;" onclick="showDetail()">
      <div style="font-weight:500;">單號</div>
      <div style="font-size:12px;color:#6B7280;">描述</div>
    </div>
  </div>
</div>

Tab 切換

<div class="tabs" style="margin-bottom:24px;">
  <button class="tab active" onclick="switchTab('tab1')" style="background:#EEF2FF;color:#4F46E5;">Tab1</button>
  <button class="tab" onclick="switchTab('tab2')" style="background:#F3F4F6;color:#6B7280;">Tab2</button>
</div>

⚠️ 重要:保持 index.html 同步

問題現象:更新 pages/xxx.html 後,直接開啟 index.html 檢視不會看到變化。

原因index.html 是單頁應用入口,包含所有頁面的內嵌副本。pages/ 目錄的修改不會自動同步。

🔴 彈窗必須放在頁面 div 內部

常見錯誤:彈窗 HTML 放在 </div> (頁面關閉標籤) 之後

<!-- ❌ 錯誤:彈窗在頁面 div 外部 -->
<div id="page-xxx" class="page">
  ...頁面內容...
</div>
<!-- 彈窗在這是錯誤的 -->
<div id="modal-xxx" style="display:none...">彈窗內容</div>

<!-- ✅ 正確:彈窗必須在頁面 div 內部 -->
<div id="page-xxx" class="page">
  ...頁面內容...
  <!-- 彈窗放在這裡 -->
  <div id="modal-xxx" style="display:none...">彈窗內容</div>
</div>

🔴 Tab 切換函式必須使用頁面級作用域

常見錯誤:使用全域性選擇器 .tabs .tab 會影響所有頁面

// ❌ 錯誤:會選擇頁面上所有的 tab
const tabs = document.querySelectorAll('.tabs .tab');

// ✅ 正確:使用頁面級作用域
const tabs = document.querySelectorAll('#page-xxx .tabs > .tab');

Tab 切換函式模板

function switchXxxTab(tabName) {
  // 1. 隱藏所有 tab 內容
  document.querySelectorAll('.xxx-tab').forEach(t => t.style.display = 'none');

  // 2. 顯示選中的 tab 內容
  document.getElementById('xxx-' + tabName).style.display = 'block';

  // 3. 更新 tab 按鈕狀態(使用頁面級作用域)
  const tabs = document.querySelectorAll('#page-xxx .tabs > .tab');
  tabs.forEach((t, i) => {
    if (i === /* 當前tab索引 */) {
      t.style.background = '#EEF2FF';
      t.style.color = '#4F46E5';
    } else {
      t.style.background = '#F3F4F6';
      t.style.color = '#6B7280';
    }
  });
}

✅ 同步指令碼

解決方案:每次建立/更新 pages/ 目錄的頁面後,必須執行以下同步指令碼:

cd project
python3 << 'PYEOF'
import os
import re

# 1. 讀取當前index.html
with open('index.html', 'r', encoding='utf-8') as f:
    content = f.read()

# 2. 獲取pages/目錄下所有html檔案(按檔名排序)
pages_dir = 'pages'
page_files = sorted([f for f in os.listdir(pages_dir) if f.endswith('.html')])

# 3. 對每個頁面檔案,提取 <div id="page-xxx" 內容
for page_file in page_files:
    with open(os.path.join(pages_dir, page_file), 'r', encoding='utf-8') as f:
        page_content = f.read()

    # 提取 page-xxx 塊的完整內容
    match = re.search(r'(<div id="(page-\w+)"[^>]*class="page"[^>]*>.*?<script>\s*function \w+Open\w+Modal)', page_content, re.DOTALL)
    if not match:
        match = re.search(r'(<div id="(page-\w+)"[^>]*class="page"[^>]*>.*?)(<!--\s+<div id="page-)', page_content, re.DOTALL)

    if match:
        page_id = match.group(2)
        page_block = match.group(1).strip()

        # 在index.html中查詢並替換對應的page塊
        # 匹配模式:<div id="page-xxx" class="page">...</div> 或 <div id="page-xxx" class="page">...<div id="page-yyy"
        pattern = rf'(<div id="{re.escape(page_id)}"[^>]*class="page"[^>]*>)(.*?)((?=<div id="page-)|(?=<script>\s*$)|(?=</main>)|(?=</body>))'

        existing = re.search(pattern, content, re.DOTALL)
        if existing:
            content = content[:existing.start()] + page_block + content[existing.end():]
            print(f'✓ Updated: {page_id}')
        else:
            print(f'⚠ Not found in index: {page_id}')
    else:
        print(f'⚠ No page block found in: {page_file}')

# 4. 寫回index.html
with open('index.html', 'w', encoding='utf-8') as f:
    f.write(content)

print('\n✅ Sync complete!')
PYEOF

重要提示: - ❌ 不要跳過同步步驟 - ❌ 不要只更新 pages/ 目錄就以為完成了 - ✅ 每次修改後都要運行同步指令碼,再驗證 index.html


元件命名規範

元件 類名
頁面容器 .page
頁頭 .header
內容區 .content
統計卡片 .stat-card
表格卡片 .table-card
按鈕-主要 .btn .btn-primary
按鈕-次要 .btn .btn-outline
標籤 .tag
狀態 .status
分頁 .pagination

重建 index.html

cd project
python3 << 'PYEOF'
page_order = ['dashboard', 'page1', 'page2', ...]
pages = [open(f'pages/{p}.html').read() for p in page_order]
html = f'''<!DOCTYPE html>
<html>
<head>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700" rel="stylesheet">
  <link rel="stylesheet" href="styles/main.css">
</head>
<body>
  <div class="layout">
    <aside class="sidebar">...</aside>
    <main class="main">
      {chr(10).join(pages)}
    </main>
  </div>
  <script src="scripts/main.js"></script>
</body>
</html>'''
open('index.html','w').write(html)
PYEOF

常見問題速查表

問題 症狀 解決方案
彈窗打不開 xxx is not defined 檢查 main.js 引用位置和函式定義
Tab 選中態錯亂 所有 Tab 同時選中 用頁面級作用域選擇器
Hash URL 不工作 頁面 display:none 新增 hashchange 監聽
表格侵入側邊欄 橫向滾動時佈局亂 用 Ant Design 固定表頭表格
核取方塊丟失 資料行沒有 checkbox 手動新增每個資料行的核取方塊
同步後功能失效 彈窗/按鈕不工作 檢查 script 標籤格式和 div 平衡

長對話上下文管理(重要)

問題背景

當對話持續較長時,上下文視窗會逐漸積累歷史訊息,可能導致: - 模型響應變慢 - token 超出限制 - 早期上下文被遺忘

解決方案:自動壓縮 + 分階段提交

1. 自動 Compaction(對話壓縮)

OpenClaw 會自動對長對話進行 compaction(壓縮): - 將對話歷史壓縮成一個 summary 摘要 - 保留關鍵的專案進展、決策、待辦事項 - 釋放大量 token 空間

觸發時機:通常在上下文累積到一定量時自動進行,無需手動干預

2. Compaction 後的處理流程

當收到 compaction 後的新對話時,立即執行以下步驟:

1️⃣ 讀取 summary 摘要,理解當前專案狀態
       ↓
2️⃣ 檢查 memory/YYYY-MM-DD.md 檔案
       ↓
3️⃣ 將新進展追加到 memory 檔案
       ↓
4️⃣ 繼續工作,保持檔案平衡

3. 分階段提交策略(小步提交)

原則:每個功能完成後立即提交,避免大量變更堆積

# ✅ 好的做法:功能完成即提交
git add -A && git commit -m "feat: 新增使用者管理彈窗"

# ❌ 不好的做法:多個功能一起提交
git add -A && git commit -m "feat: 多項最佳化"

好處: - 如果出問題,容易回溯 - 減少每次提交的檔案變更量 - Compaction 後的 summary 更簡潔

4. 保持檔案平衡

每次 HTML 修改後檢查 div 平衡:

# 檢查 div 平衡
python3 -c "
with open('index.html', 'r') as f:
    c = f.read()
print(f'opens={c.count(\"<div\")}, closes={c.count(\"</div>\")}, diff={c.count(\"<div\")-c.count(\"</div>\")}')
"

# ✅ 正確輸出:opens=xxx, closes=xxx, diff=0
# ❌ 錯誤輸出:opens=xxx, closes=xxx, diff=≠0

如果 diff 不為 0,立即修復: - 缺少 </div>:在合適位置新增 - 多餘 </div>:刪除多餘的部分

5. 定期同步到 memory 檔案

每次 compaction 後或重要里程碑時,將進展寫入 memory/YYYY-MM-DD.md

## 14:30 狀態更新

### 功能名稱 - 完善/修復

**新增內容**:
- 具體修改1
- 具體修改2

**提交記錄**:`abc1234` feat: 描述

**檔案**:`/path/to/file.html`

6. 長對話工作流

使用者提出需求
       ↓
理解現有程式碼結構(檢視 summary + 檔案)
       ↓
用 Python 指令碼做精確文本替換
       ↓
修改完檢查 div 平衡
       ↓
提交程式碼(每個功能單獨提交)
       ↓
截圖驗證(如需要)
       ↓
回覆使用者
       ↓
(Compaction 自動觸發時)
       ↓
讀取 summary,追加進展到 memory 檔案

為什麼單頁 HTML 不受上下文限制影響

WMS 原型是單頁 HTML(index.html),3700+ divs: - 不是日誌檔案:不會無限增長 - 每次修改同一個檔案:不是追加模式 - Compaction 只壓縮對話歷史:不影響 HTML 檔案本身

關鍵心態

"我是 AI,每次醒來都是新的開始。但檔案裡的內容是我的記憶。"

  • 上下文超限是 對話歷史 被壓縮,不是檔案內容丟失
  • HTML 檔案本身不受影響
  • 只要保持檔案平衡和定期 commit,就能穩定工作

相關資源

  • 內建設計系統references/design-systems/ 目錄包含58+設計系統完整規範
  • 包含:Figma、Linear、Stripe、Vercel、Notion 等
  • 欄位規範field-norms.md - 各模組標準欄位定義

修改工作流(重要)

標準修改流程

每次對任何頁面進行修改,必須遵循以下步驟:

1️⃣ 修改 pages/xxx.html
       ↓
2️⃣ 運行同步指令碼 → 更新 index.html
       ↓
3️⃣ 本地測試 → 驗證功能正常
       ↓
4️⃣ 提交程式碼 → git add + commit

🔴 第一步:修改 pages/xxx.html

pages/ 目錄的對應頁面檔案中進行修改: - 彈窗 HTML 必須放在 <div id="page-xxx" class="page"> 內部 - 指令碼函式放在頁面的 <script> 塊中

🔴 第二步:同步到 index.html

必須運行同步指令碼

cd your-project-directory
python3 << 'PYEOF'
import os
import re

with open('index.html', 'r', encoding='utf-8') as f:
    content = f.read()

pages_dir = 'pages'
page_files = sorted([f for f in os.listdir(pages_dir) if f.endswith('.html')])

for page_file in page_files:
    with open(os.path.join(pages_dir, page_file), 'r', encoding='utf-8') as f:
        page_content = f.read()

    match = re.search(r'(<div id="(page-\w+)"[^>]*class="page"[^>]*>.*?)(?=<div id="page-|\s*<script>|\s*</main>)', page_content, re.DOTALL)
    if not match:
        print(f'⚠ Skip: {page_file}')
        continue

    page_id = match.group(2)
    page_block = match.group(1).strip()

    # 驗證 div 平衡
    opens = page_block.count('<div')
    closes = page_block.count('</div>')
    if opens != closes:
        print(f'❌ Div imbalance in {page_id}: opens={opens}, closes={closes}')
        continue

    pattern = rf'(<div id="{re.escape(page_id)}"[^>]*class="page"[^>]*>)(.*?)(?=<div id="page-|\s*</main>)'
    existing = re.search(pattern, content, re.DOTALL)

    if existing:
        content = content[:existing.start()] + page_block + content[existing.end():]
        print(f'✓ Synced: {page_id}')
    else:
        print(f'⚠ Not found in index: {page_id}')

opens_all = content.count('<div')
closes_all = content.count('</div>')
print(f'\nDiv balance: opens={opens_all}, closes={closes_all}, diff={opens_all-closes_all}')

with open('index.html', 'w', encoding='utf-8') as f:
    f.write(content)

print('✅ Sync complete!')
PYEOF

重要檢查: - 同步後必須驗證 index.html 的 div 平衡(opens == closes) - 如果不平衡,查詢問題所在

🔴 第三步:本地測試

啟動本地伺服器(如果未執行):

cd your-project-directory
npx http-server -p 8080 &

測試步驟

# 1. 開啟瀏覽器到首頁
agent-browser goto http://localhost:8080

# 2. 導航到目標頁面(使用 URL hash)
agent-browser goto http://localhost:8080/#page-name

# 3. 測試彈窗
agent-browser eval "openAddModal()"  # 開啟彈窗
agent-browser screenshot test-modal.png  # 截圖驗證
agent-browser eval "closeModal()"  # 關閉彈窗

# 4. 關閉瀏覽器
agent-browser close

測試檢查清單: - [ ] 頁面正常載入 - [ ] 彈窗能開啟 - [ ] 彈窗內容正確 - [ ] 彈窗能關閉 - [ ] Tab 切換正常(如有) - [ ] 按鈕點選有效

🔴 第四步:提交程式碼

cd your-project-directory
git add -A
git commit -m "fix: 描述修改內容"

📝 經驗沉澱(2026-04-13)

問題1:彈窗函式無法呼叫(Uncaught ReferenceError)

症狀openAddModal is not defined 等錯誤

根本原因: 1. main.js 引用被同步指令碼刪除 2. 同步指令碼移動了 <script src="main.js"></script> 位置

解決方案

// 確保 main.js 在 </main> 之後引入
</main>
<script src="scripts/main.js"></script>
</body>

問題2:所有 Tab 選中態不顯示

症狀:切換 Tab 時按鈕背景色不變化,全部選中態顯示錯誤

根本原因:Tab 切換函式使用全域性選擇器 .tabs .tab 會選中所有頁面的 tab

解決方案:使用頁面級作用域

// ❌ 錯誤:會選擇所有頁面的 tab
document.querySelectorAll('.tabs .tab')

// ✅ 正確:只選當前頁面的 tab
document.querySelectorAll('#page-xxx .tabs > .tab')

問題3:直接訪問 hash URL 時頁面不顯示

症狀http://localhost:8080/#delivery_return 直接訪問時頁面 display:none

想要更強大的技能外掛,就來小蔥技能站7w4.net看看吧。

根本原因:沒有 hashchange 監聽,導航只用 click 事件

解決方案:在 main.js 新增 hash 路由監聽

// Hash 路由監聽 - 支援直接訪問 #page
window.addEventListener('hashchange', () => {
  const hash = window.location.hash.replace('#', '');
  if (hash) {
    const navItem = document.querySelector(`[data-page="${hash}"]`);
    if (navItem) {
      navItem.click();
    }
  }
});

// 頁面載入時檢查 hash
if (window.location.hash) {
  setTimeout(() => {
    const hash = window.location.hash.replace('#', '');
    const navItem = document.querySelector(`[data-page="${hash}"]`);
    if (navItem) {
      navItem.click();
    }
  }, 100);
}

問題4:表格橫向滾動侵入左側選單

症狀:表格內容多時,整個頁面寬度被撐開,侵入左側選單欄

根本原因: 1. 表格使用 width:100% + min-width:1400px 矛盾 2. 容器沒有正確設定 overflow:hidden

解決方案:使用 Ant Design 風格的固定表頭表格

問題5:固定表頭表格實現(Ant Design 風格)

核心原理: 1. 表頭和表體分離 - 用兩個獨立的 <table> 2. 表頭固定 - overflow:hidden,表頭不滾動 3. 表體滾動 - overflow:auto;max-height:440px 4. 固定列用 position:sticky - left:0 / right:0 5. 固定表格佈局 - table-layout:fixed + colgroup 定義列寬

程式碼模板

<!-- 外層容器 -->
<div class="ant-table-wrapper" style="display:flex;flex-direction:column;overflow:hidden;height:500px;">

  <!-- 表頭 - 固定不滾動 -->
  <div class="ant-table-header" style="overflow:hidden;border-bottom:2px solid #E5E7EB;flex-shrink:0;">
    <table style="table-layout:fixed;width:1800px;border-collapse:collapse;font-size:14px;">
      <colgroup>
        <col style="width:48px;"><!-- 核取方塊 -->
        <col style="width:180px;"><!-- 單號 -->
        <col style="width:100px;"><!-- 其他列... -->
        <!-- ... -->
      </colgroup>
      <thead><tr>
        <th style="position:sticky;left:0;background:#F9FAFB;z-index:4;"><input type="checkbox"></th>
        <th style="position:sticky;left:48px;background:#F9FAFB;z-index:3;">單號</th>
        <th>欄位1</th>
        <th>欄位2</th>
        <!-- ... -->
        <th style="position:sticky;right:0;background:#F9FAFB;z-index:3;">操作</th>
      </tr></thead>
    </table>
  </div>

  <!-- 表體 - 獨立滾動 -->
  <div class="ant-table-body" style="overflow:auto;max-height:440px;">
    <table style="table-layout:fixed;width:1800px;border-collapse:collapse;font-size:14px;">
      <colgroup>
        <!-- 與表頭相同的列寬定義 -->
      </colgroup>
      <tbody>
        <tr>
          <td style="position:sticky;left:0;background:white;z-index:2;"><input type="checkbox"></td>
          <td style="position:sticky;left:48px;background:white;z-index:2;">單號值</td>
          <td>欄位1值</td>
          <!-- ... -->
          <td style="position:sticky;right:0;background:white;z-index:2;"><button>操作</button></td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

關鍵樣式: | 元素 | 樣式 | 說明 | |------|------|------| | 表頭 wrapper | overflow:hidden;flex-shrink:0 | 不滾動 | | 表體 wrapper | overflow:auto;max-height:440px | 垂直滾動 | | 表頭表格 | table-layout:fixed;width:固定值 | 固定列寬 | | 固定列 th/td | position:sticky;left:0;z-index:2 | 左側固定 | | 右側固定列 | position:sticky;right:0 | 右側固定 | | 固定列背景 | background:#F9FAFB (表頭) / background:white (表體) | 避免透明 |

問題6:篩選條件缺少查詢/重置按鈕

解決方案

<div class="table-filters">
  <!-- 其他篩選欄位... -->
  <div class="filter-group" style="display:flex;gap:8px;">
    <button class="btn btn-outline btn-sm" onclick="resetXxxFilters()">重置</button>
    <button class="btn btn-primary btn-sm" onclick="searchXxx()">查詢</button>
  </div>
</div>

對應 JS 函式

function resetXxxFilters() {
  document.querySelectorAll('#page-xxx .filter-select').forEach(s => s.selectedIndex = 0);
  document.querySelectorAll('#page-xxx .filter-input').forEach(i => i.value = '');
}

function searchXxx() {
  alert('查詢功能 - 實際專案中會呼叫API過濾資料');
}

問題7:列表資料缺少核取方塊

解決方案:每行資料第一個 td 新增核取方塊

<tr>
  <td style="position:sticky;left:0;z-index:1;background:white;">
    <input type="checkbox">
  </td>
  <td style="position:sticky;left:48px;z-index:1;background:white;">
    <span style="font-family:monospace;font-weight:500;">FC-2026-0410-001</span>
  </td>
  <!-- 其他欄位... -->
</tr>

問題8:script 標籤格式導致同步失敗

症狀:同步後彈窗函式丟失

原因</script> 後面沒有正確換行,導致被當作 HTML 標籤解析

解決方案

<!-- ❌ 錯誤 -->
<script>function foo(){}</script><div>

<!-- ✅ 正確 -->
<script>
function foo(){}
</script>
<div>

常見問題速查表

問題 症狀 解決方案
彈窗打不開 xxx is not defined 檢查 main.js 引用位置和函式定義
Tab 選中態錯亂 所有 Tab 同時選中 用頁面級作用域選擇器
Hash URL 不工作 頁面 display:none 新增 hashchange 監聽
表格侵入側邊欄 橫向滾動時佈局亂 用 Ant Design 固定表頭表格
核取方塊丟失 資料行沒有 checkbox 手動新增每個資料行的核取方塊
同步後功能失效 彈窗/按鈕不工作 檢查 script 標籤格式和 div 平衡

📝 WMS 專案實戰經驗(2026-04-14)

經驗1:彈窗 HTML 必須在頁面 div 內部

問題現象:"新增組織"按鈕點選無反應,彈窗無法開啟

排查過程: 1. 檢查按鈕 onclick 處理函式 → 存在 2. 檢查 JavaScript 函式 → 存在 3. 檢查彈窗 HTML 位置 → 發現彈窗放在了頁面 div 外部

根本原因

<!-- ❌ 錯誤:彈窗在頁面 div 外部 -->
<div id="page-system_org" class="page">
  ...頁面內容...
</div>
<!-- 彈窗在這裡,頁面關閉後的位置 -->
<div id="modal-add-org" style="display:none...">...</div>

<!-- ✅ 正確:彈窗必須在頁面 div 內部 -->
<div id="page-system_org" class="page">
  ...頁面內容...
  <!-- 彈窗必須放在這裡 -->
  <div id="modal-add-org" style="display:none...">...</div>
</div>

教訓:彈窗 HTML 放在 </div> (頁面關閉標籤) 之後導致彈窗不顯示。必須在頁面 div 內部。


經驗2:JavaScript 語法錯誤會導致整個指令碼塊失效

問題現象:修復彈窗位置後,按鈕仍然無法點選

排查過程: 1. 使用 prototype-design 技能的除錯方法 2. 檢查 div 平衡 → 發現頁面 div 缺少閉合標籤 3. 修復 div 後檢查指令碼塊 → 發現多餘的 }

根本原因submitNewException() 函式後有一個多餘的閉合括號 },導致 JavaScript 語法錯誤,整個指令碼塊無法執行

// ❌ 錯誤:函式後有多餘的 }
function submitNewException() {
  // ...表單提交邏輯
}
//}  <-- 多餘的括號導致語法錯誤

// ✅ 正確:括號匹配
function submitNewException() {
  // ...表單提交邏輯
}

教訓:修改 HTML 時要確保 div 平衡;修改 JS 時要確保括號匹配。使用 Python 指令碼做精確替換比手動編輯更安全。


經驗3:按鈕必須手動繫結 onclick

問題現象:新增彈窗後,彈窗中的按鈕點選無反應

根本原因:新增的彈窗按鈕沒有 onclick 屬性

解決方案:每個按鈕都要顯式繫結 onclick

<!-- ❌ 錯誤:按鈕沒有 onclick -->
<button class="btn btn-primary">確定</button>

<!-- ✅ 正確:顯式繫結 onclick -->
<button onclick="submitAddOrg()" class="btn btn-primary">確定</button>

教訓:複製彈窗模板時,別忘了修改按鈕的 onclick 屬性。


經驗4:按鈕樣式統一使用 CSS 類

問題現象:各頁面按鈕樣式不統一,有內聯樣式如 style="padding:10px 24px;"

解決方案:統一使用 CSS 類

<!-- ✅ 主按鈕:黑色背景,膠囊形狀 -->
<button class="btn btn-primary btn-sm">新增</button>

<!-- ✅ 次按鈕:白色背景,灰色邊框 -->
<button class="btn btn-outline btn-sm">取消</button>

按鈕樣式規範: | 元素 | 類名 | 樣式 | |------|------|------| | 主按鈕 | .btn .btn-primary | 黑色背景 #111827,膠囊形 | | 次按鈕 | .btn .btn-outline | 白色背景,#E5E7EB 邊框 | | 按鈕尺寸 | .btn-sm | padding: 6px 12px; font-size: 12px | | 膠囊形狀 | border-radius: 50px | 用於主、次按鈕 |


經驗5:Python 指令碼精確替換避免手動錯誤

問題現象:手動編輯 HTML 時容易出現 div 不平衡、括號遺漏等問題

解決方案:使用 Python 指令碼做精確文本替換

with open('index.html', 'r') as f:
    content = f.read()

# 替換前先備份
# ...

# 精確替換一段 HTML
old_text = '''<button class="btn btn-primary btn-sm">
              新增模組
            </button>'''

new_text = '''<button class="btn btn-primary btn-sm" onclick="openAddModuleModal()">
              新增模組
            </button>'''

content = content.replace(old_text, new_text)

with open('index.html', 'w') as f:
    f.write(content)

# 驗證 div 平衡
print(f'opens={content.count("<div")}, closes={content.count("</div>")}, diff={content.count("<div")-content.count("</div>")}')

教訓:用 Python 指令碼做精確替換,比手動編輯更可靠,尤其是涉及多行 HTML 時。


經驗6:系統管理模組彈窗欄位設計

新增模組彈窗欄位: | 欄位 | 型別 | 說明 | |------|------|------| | 模組編碼 | text | 必填,如 SYS_010 | | 模組名稱 | text | 必填 | | 上級模組 | select | 無(頂級模組)/系統管理/基礎檔案... | | 模組分類 | select | 系統管理/基礎檔案/作業配置... | | 選單層級 | select | 一級/二級/三級選單 | | 選單圖示 | text | emoji 格式 | | 路由路徑 | text | 如 /system/module | | 排序 | number | 數字越小越靠前 | | 狀態 | select | 啟用/停用 | | 備註 | textarea | 可選 |

新增組織彈窗欄位: | 欄位 | 型別 | 說明 | |------|------|------| | 組織編碼 | text | 必填,如 ORG_010 | | 組織名稱 | text | 必填 | | 上級組織 | select | 母公司/北京倉/上海倉... | | 組織型別 | select | 公司/倉庫/部門/作業組 | | 負責人 | text | 可選 | | 聯絡電話 | tel | 可選 | | 所在地區 | text | 如 北京市/朝陽區 | | 狀態 | select | 啟用/停用 | | 組織地址 | textarea | 可選 |

新增使用者彈窗欄位: | 欄位 | 型別 | 說明 | |------|------|------| | 使用者名稱 | text | 必填 | | 登入密碼 | password | 必填,6位以上 | | 姓名 | text | 必填 | | 手機號 | tel | 必填 | | 郵箱 | email | 可選 | | 所屬組織 | select | 必填,北京倉-收貨組/上海倉... | | 使用者角色 | select | 超級管理員/倉庫管理員/作業員... | | 崗位 | text | 可選 | | 入職日期 | date | 可選 | | 狀態 | select | 正常/停用/待稽核 |


經驗7:資料統計報表頁面豐富度提升

質量與異常報表增強: - 異常趨勢圖(近7天柱狀圖) - 異常型別分佈(貨損42%/配送延誤28%等) - 閉環率分析(96.8%閉環率、2.5h平均處理時長)

對賬準確率監察增強: - KPI 從 4 個擴充套件到 6 個 - 新增已核銷/核對中指標

作業報表增強: - 新增時效達標率分析(揀貨98.5%/上架97.8%等)

庫存報表增強: - 新增滯銷庫存預警(30天以上) - 新增安全庫存預警


經驗8:複合條件定位按鈕

問題現象:頁面有多個相似按鈕(如"新增"),用 document.querySelector 定位困難

解決方案:使用複合條件或更精確的選擇器

// ❌ 困難:頁面有多個 btn-primary
document.querySelector('.btn.btn-primary')

// ✅ 更好:使用 onclick 屬性定位
document.querySelector('button[onclick="openAddModuleModal()"]')

// ✅ 更好:在頁面內部查詢
document.querySelector('#page-system_module button[onclick="openAddModuleModal()"]')

經驗9:修改後立即驗證

原則:每次修改後立即驗證,不要積累多個問題

驗證清單

# 1. 檢查 div 平衡
python3 -c "with open('index.html') as f: c=f.read(); print(f'opens={c.count(\"<div\")}, closes={c.count(\"</div>\")}, diff={c.count(\"<div\")-c.count(\"</div>\")}')"

# 2. 截圖驗證
agent-browser goto http://localhost:8080/#page-name
agent-browser eval "openAddModal()"
agent-browser screenshot test-modal.png
agent-browser close

# 3. 提交程式碼
git add -A && git commit -m "feat: 描述"

經驗10:單頁 HTML 專案的好處

為什麼 WMS 原型用單頁 HTML 沒有問題: 1. Compaction 只壓縮對話歷史:不影響 HTML 檔案本身 2. 不是日誌檔案:不會無限增長 3. 每次修改同一個檔案:不是追加模式 4. 3700+ divs 仍然高效:檔案體積適中,渲染快

什麼時候該拆分成多檔案: - 單個檔案超過 2MB - 需要多人協作(git merge 衝突) - 模組之間完全獨立

🤖 AI 評測

這個技能質量不錯,它提供了58種設計風格可選,直接參考就能用,不用從零設計。頁面模板、彈窗、表格這些常用元件都有現成規範,複製改改就能用。還總結了真實專案踩過的坑,比如彈窗位置放錯、表格樣式衝突等問題都有解決方案。不過文件有些地方寫重複了,看起來不夠精簡。總體來說是一款實用且經驗豐富的原型設計技能,適合快速開發管理後臺頁面。

📊 多維度評分

適應性4.1
規範性4.3
有效性4.7
可靠性4
可信度4.9

📁 包含檔案 (63 個)

📄 README.md 2.3 KB
📄 SKILL.md 36.5 KB
📄 _meta.json 135 B
📄 references/design-systems/airbnb-DESIGN.md 13.7 KB
📄 references/design-systems/airtable-DESIGN.md 3.5 KB
📄 references/design-systems/apple-DESIGN.md 19.9 KB
📄 references/design-systems/bmw-DESIGN.md 9.6 KB
📄 references/design-systems/claude-DESIGN.md 19.8 KB
📄 references/design-systems/clay-DESIGN.md 16.9 KB
📄 references/design-systems/clickhouse-DESIGN.md 15 KB
📄 references/design-systems/cohere-DESIGN.md 14.4 KB
📄 references/design-systems/coinbase-DESIGN.md 4.9 KB
📄 references/design-systems/composio-DESIGN.md 20.4 KB
📄 references/design-systems/cursor-DESIGN.md 18.6 KB
📄 references/design-systems/elevenlabs-DESIGN.md 14.8 KB
📄 references/design-systems/expo-DESIGN.md 18.2 KB
📄 references/design-systems/ferrari-DESIGN.md 24.9 KB
📄 references/design-systems/figma-DESIGN.md 11.3 KB
📄 references/design-systems/framer-DESIGN.md 17.2 KB
📄 references/design-systems/hashicorp-DESIGN.md 15.3 KB
📄 references/design-systems/ibm-DESIGN.md 19.1 KB
📄 references/design-systems/intercom-DESIGN.md 6.3 KB
📄 references/design-systems/kraken-DESIGN.md 4.3 KB
📄 references/design-systems/lamborghini-DESIGN.md 20.6 KB
📄 references/design-systems/linear-DESIGN.md 21.9 KB
📄 references/design-systems/linear.app-DESIGN.md 16.2 KB
📄 references/design-systems/lovable-DESIGN.md 17 KB
📄 references/design-systems/minimax-DESIGN.md 14 KB
📄 references/design-systems/mintlify-DESIGN.md 17 KB
📄 references/design-systems/miro-DESIGN.md 4.7 KB
📄 references/design-systems/mistral.ai-DESIGN.md 15.3 KB
📄 references/design-systems/mongodb-DESIGN.md 14.7 KB
📄 references/design-systems/notion-DESIGN.md 17.9 KB
📄 references/design-systems/nvidia-DESIGN.md 16.7 KB
📄 references/design-systems/ollama-DESIGN.md 15.2 KB
📄 references/design-systems/opencode.ai-DESIGN.md 15.2 KB
📄 references/design-systems/pinterest-DESIGN.md 11.6 KB
📄 references/design-systems/posthog-DESIGN.md 18.1 KB
📄 references/design-systems/raycast-DESIGN.md 18.1 KB
📄 references/design-systems/renault-DESIGN.md 23.7 KB
📄 references/design-systems/replicate-DESIGN.md 13.8 KB
📄 references/design-systems/resend-DESIGN.md 18 KB
📄 references/design-systems/revolut-DESIGN.md 8.4 KB
📄 references/design-systems/runwayml-DESIGN.md 14 KB
📄 references/design-systems/sanity-DESIGN.md 20.7 KB
📄 references/design-systems/sentry-DESIGN.md 14.4 KB
📄 references/design-systems/spacex-DESIGN.md 11.1 KB
📄 references/design-systems/spotify-DESIGN.md 12.7 KB
📄 references/design-systems/stripe-DESIGN.md 17.4 KB
📄 references/design-systems/supabase-DESIGN.md 14.5 KB
📄 references/design-systems/superhuman-DESIGN.md 18.5 KB
📄 references/design-systems/tesla-DESIGN.md 21.7 KB
📄 references/design-systems/together.ai-DESIGN.md 14 KB
📄 references/design-systems/uber-DESIGN.md 18.2 KB
📄 references/design-systems/vercel-DESIGN.md 19 KB
📄 references/design-systems/voltagent-DESIGN.md 25.7 KB
📄 references/design-systems/warp-DESIGN.md 16.3 KB
📄 references/design-systems/webflow-DESIGN.md 4 KB
📄 references/design-systems/wise-DESIGN.md 8.3 KB
📄 references/design-systems/x.ai-DESIGN.md 15.9 KB
📄 references/design-systems/zapier-DESIGN.md 18.3 KB
📄 references/field-norms.md 8.2 KB
📄 references/page-template.html 13 KB