Communitygithub.com

pharder56k/quote-generator-skill

室内設計報價系統:將飛書多維表/Excel 數據渲染為專業 PDF 報價單,支援封面、總價表、明細頁多頁輸出。MIT 授權。

quote-generator-skill とは?

此技能(skill)專為室內設計行業打造,能將工程量清單(來自飛書多維表或 Excel)自動轉換為專業、可列印的 PDF 報價單。它能產出包含封面、總價表(含增值稅、管理費)與明細頁的多頁文件。支援四種視覺模板(兩種配色 × 斑馬紋選項)以及兩種分類模式(按區域或按工程分類),皆由使用者透過對話選擇。在生成 PDF 前,技能會完整驗證數據完整性(檢查必填欄位、合價一致性與區域缺失等),並自動處理公司 Logo(從多維表附件或使用者上傳的圖片)。整個流程高度互動:由 AI 代理引導使用者完成環境檢查(Node.js、Playwright、lark-cli)、數據源確認、稅率與管理費設定、區域名稱英譯,最後將 PDF 輸出至飛書聊天或雲端文件。技能隨附詳細的 SKILL.md 文件,涵蓋逐步工作流程、錯誤處理與 Line 熱線常見問題,確保在 Claude Code、Cursor 與 Codex 等 AI 代理平台上無痛部署。

対応✓Claude Code~Codex CLI~Cursor
npx skills add pharder56k/quote-generator-skill

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

全案設計報價系統

本 skill 將工程量清單數據渲染為專業 PDF 報價單,支援封面、總價表、明細頁多頁輸出。

1. 何時使用本 Skill

觸發條件

以下場景應使用本 skill:

  • 用戶輸入 /報價 或 /quote — 生成 PDF 報價單
  • 用戶提到要將多維表或 Excel 中的報價數據轉為 PDF 報價單

以下場景不應使用本 skill:

  • 用戶只是在編輯多維表數據(應使用 lark-base skill)
  • 用戶只是在查看報價歷史(不需要重新生成)

前置依賴

  • lark-base skill — 讀取飛書多維表數據
  • lark-im skill — 發送 PDF 到飛書對話
  • lark-drive skill — 上傳 PDF 到飛書文件
  • xlsx skill — 解析 Excel 檔案(當用戶提供 Excel 時)
  • Node.js 執行環境 + Playwright(已安裝於專案目錄)

Step 0: 初次使用檢查

當用戶第一次使用 Skill,或執行命令時遇到依賴相關錯誤,Agent 應執行以下檢查流程。

1. 檢查 Node.js 環境

嘗試執行 node --version,要求 >= 18。如果失敗或版本過低:

2. 檢查 Playwright 瀏覽器

檢查專案目錄下 npx playwright install chromium 是否已完成。如果 render.js 執行時報 Executable doesn't exist 錯誤:

  • 在專案目錄下執行: npx playwright install chromium
  • 重試渲染

3. 檢查 lark-cli

嘗試執行 lark-cli --version。如果失敗(command not found):

  • 提示用戶安裝 lark-cli(飛書命令列工具)
  • 安裝後執行: lark-cli auth login

4. 檢查飛書登入狀態

嘗試執行 lark-cli base +table-list --base-token LfjJbLrTHacijesHmIjcDtSpnJf 測試登入狀態。如果返回認證錯誤:

  • 提示用戶執行: lark-cli auth login
  • 完成後重試

5. 提供飛書模板

用戶需要把專案模板複製到自己的飛書空間:

Excel 數據源處理

用戶提供 Excel 檔案時,不直接解析渲染。引導流程:

  1. 提示:推薦先匯入飛書多維表,欄位和順序更好對齊
  2. 引導用戶將 Excel 匯入飛書:
    • 開啟飛書 → 新建多維表 → 匯入 → 選擇 Excel 檔案
    • 或者直接複製模板多維表,將 Excel 數據貼上進去
  3. 用戶提供多維表連結後,繼續 /報價 流程

2. 工作流程

用戶觸發 → 環境檢查 → 確認數據源 → 讀取數據 → 數據驗證 → 確認 Logo → 確認稅率 → 確認模板 → 渲染 PDF → 發送飛書

Step 1: 確認數據源

用戶需提供以下之一:

  1. 飛書多維表連結 — 如 https://xxx.feishu.cn/base/XXX
  2. Excel 檔案 — 本地檔案路徑或透過對話上傳

如果用戶未提供,詢問用戶選擇數據源。

Step 2: 讀取數據

飛書多維表數據源

  1. 從用戶提供的連結中提取 base-token(URL 中 /base/ 後的部分)
  2. 列出表:lark-cli base +table-list --base-token <token>
  3. 找到 專案資訊 和 報價明細 兩張表的 table_id
  4. 讀取專案資訊:lark-cli base +record-list --base-token <token> --table-id <專案資訊table_id> --format json
  5. 先查檢視:lark-cli base +view-list --base-token <token> --table-id <報價明細table_id>,取預設 grid 檢視(如「全部項目」)的 view_id
  6. 讀取報價明細(必須帶 --view-id,否則返回順序與用戶在飛書介面拖拽後的順序不一致):lark-cli base +record-list --base-token <token> --table-id <報價明細table_id> --view-id <檢視ID> --format json --limit 200
  7. 從專案資訊中提取:專案名稱、工程編號、編製日期、編製人員、聯絡信箱、公司Logo、稅率、管理費
  8. 從報價明細中提取:區域、工程分類、項目名稱、項目特徵、單位、數量、綜合單價、合價、備註(序號無需讀取,渲染時自動生成)

Excel 數據源

使用 xlsx skill 解析 Excel,提取相同結構的數據。Excel 可能有多 sheet,需找到包含報價明細的 sheet(通常有「序號」、「工程分類」、「綜合單價」等列頭)。

Step 3: 數據驗證

在渲染 PDF 之前,Agent 必須對讀取到的數據進行驗證。不要直接跳過。

驗證清單(逐項執行):

3.1 專案資訊完整性

檢查 專案名稱、工程編號、編製日期 三個欄位:

  • 任一為空 → 告知用戶具體缺少哪個欄位,請用戶在飛書多維表的「專案資訊」表中補充
  • 全部通過 → 繼續

3.2 報價明細條目數

檢查 items 陣列:

  • 為 0 或不存在 → 「報價明細中沒有數據,請在飛書多維表的「報價明細」表中添加條目後重試」
  • 有數據 → 繼續

3.3 逐條欄位檢查

對每條記錄檢查必填欄位(工程分類、項目名稱、單位、數量、綜合單價),彙總報告:

數據驗證結果:
- 總條目: 104
- 區域缺失: 3 (第 6、9、20 條)
- 工程分類缺失: 2 (第 5、18 條)
- 項目名稱缺失: 0
- 單位缺失: 1 (第 12 條)
- 數量缺失: 0
- 綜合單價缺失: 3 (第 5、7、22 條)
- 工程分類不在標準列表中: 0

3.4 缺失欄位的處理

  • 缺失條目 ≤ 總條目的 20%:告知用戶具體哪些條目有問題,詢問「是否跳過這些條目繼續生成?」
  • 缺失條目 > 20%:要求用戶修正數據後重試,不繼續渲染
  • 用戶確認跳過 → 過濾掉問題條目,用有效數據繼續

3.7 區域缺失檢查(僅按區域分類時)

當用戶選擇按區域分類(Step 5.6 選擇「按區域」)時,額外檢查每條記錄的 區域 欄位:

區域缺失: X (第 X 條)
  • 缺失條目 ≤ 總條目的 20%:告知用戶具體哪些條目缺區域,詢問「是否將這些條目歸入『其他』繼續生成?」
  • 缺失條目 > 20%:要求用戶補充區域後重試
  • 用戶確認 → 缺失區域的條目歸入「其他」分組(與 Step 3.4 跳過邏輯互斥,用戶二選一:跳過 or 歸入其他)

3.5 合價自動修正

對每條記錄檢查 合價 是否等於 數量 × 綜合單價:

  • 偏差 < 1 元 → 不做處理
  • 偏差 ≥ 1 元或為空 → 自動計算 合價 = 數量 × 綜合單價,值寫入渲染數據
  • 修正條目超過 10% → 提示用戶「已自動修正 X 條合價數據」,建議用戶檢查多維表公式

3.6 工程分類標準列表

以下為 13 類標準分類:

措施項目、拆除工程、砌築工程、混凝土及鋼筋混凝土工程、
金屬結構工程、防水工程、保溫隔熱工程、樓地面裝飾工程、
牆柱面裝飾與隔斷工程、天棚工程、油漆塗料工程、
其他裝飾工程、安裝工程

不在列表中的分類仍可渲染,但告知用戶「分類 'XXX' 不在標準列表中」。

Step 4: Logo 處理

必須執行,不可跳過。 無論數據源是多維表還是 Excel,都必須檢查並處理 Logo。

  1. 從多維表讀取:檢查專案資訊表中的 公司Logo 附件欄位
    • 如有附件,使用 media API 下載(drive +download 不支援多維表附件):
      lark-cli api GET /open-apis/drive/v1/medias/{file_token}/download --output ./logo.png
      
    • 將圖片轉為 base64 data URI,傳入渲染數據的 logo_url 欄位
  2. 從 Excel 讀取:檢查 Excel 中是否有 logo 圖片(通常嵌入在 sheet 中或作為附件)
    • 如有,提取並轉為 data URI
  3. Logo 缺失時(必須詢問用戶):
    • 如果多維表或 Excel 中沒有找到 Logo 圖片,必須向用戶詢問:
      • 「未在數據源中找到公司 Logo,請問如何處理?」
      • 選項 A:上傳 Logo 圖片
      • 選項 B:提供 Logo 圖片 URL
      • 選項 C:不使用 Logo(PDF 中顯示預設「R M」文字標識)
    • 不要預設跳過這一步,即使讀者說「直接生成」也要確認 Logo 處理方式

Step 5: 確認稅率與管理費

優先使用多維表專案資訊中的 稅率、管理費 欄位值。如果多維表中沒有該欄位,則詢問用戶。

費率規則(稅率與管理費通用):

  • 值 > 1 → 視為百分比整數,自動 ÷100(如 3 → 3%、10 → 10%)
  • 值 ≤ 1 → 視為小數直接使用(如 0.03 → 3%、0.1 → 10%)
  • 空值:稅率預設 3%,管理費預設 0(不收取)

計算順序:

合計 = Σ 各條目合價
管理費 = 合計 × 管理費率
增值稅 = (合計 + 管理費) × 稅率
總計 = 合計 + 管理費 + 增值稅

管理費 > 0 時總價表顯示「管理費」行;管理費 = 0 時不顯示(相容舊數據)。

Step 5.5: 確認模板風格

必須詢問,不可跳過。 即使之前使用過某個模板,也要每次都確認。

詢問用戶選擇模板:

請選擇報價單模板風格:
1. Swiss IKB(預設)— 藍底滿版封面 + 雙語分類標題
2. Swiss IKB Zebra — 同上 + 內容明細行斑馬紋(白/淺藍交替)
3. B&W — 白底封面 + 淺灰強調,適合黑白列印
4. B&W Zebra — 同上 + 內容明細行斑馬紋(白/淺灰交替)

如果用戶回覆中包含明確的模板名稱或編號,直接使用對應模板:

  • swiss-ikb — Swiss IKB(預設)
  • swiss-ikb-zebra — Swiss IKB Zebra
  • bw — B&W 黑白列印版
  • bw-zebra — B&W Zebra 黑白列印斑馬紋版

開發中(暫不對外提供): Editorial / Editorial B&W / Card / Card B&W 四個模板程式碼已存在,待用戶後續修改完善後啟用。如用戶主動要求使用這些模板,可執行 node scripts/render.js --template editorial 等命令,但優先推薦上述 4 個已上線模板。

Step 5.6: 確認分類方式

必須詢問,不可跳過。 每次渲染前都要確認,不要預設使用上次的選項。

詢問用戶選擇分類方式:

請選擇報價單分類方式:
1. 按區域(玄關、客廳、主臥……)— 總價表按區域彙總,明細表在序號後增加工程分類列
2. 按工程分類(措施項目、拆除工程……)— 傳統方式,明細表不含工程分類列

用戶回覆明確編號或名稱後使用對應模式:

  • area — 按區域分類,渲染命令加 --group-by area
  • category — 按工程分類(預設),不傳或加 --group-by category

注意:選擇「按區域」時,需確保報價明細表的 區域 欄位已填寫(Step 3.7 會檢查)。若數據尚未填寫區域,建議優先使用「按工程分類」。

Step 5.7: 區域英文翻譯(僅按區域分類時)

區域名每個項目不同,每次渲染前必須動態翻譯,禁止套用寫死的映射。

  1. 從報價明細中收集本次出現的全部區域名(去重)
  2. Agent 將區域名逐條翻譯為英文(設計行業慣用翻譯,如 玄關→Foyer、客廳→Living Room、陽光房→Sunroom)
  3. 將翻譯結果作為 region_names 物件寫入渲染數據 JSON:
{
  "region_names": {
    "玄關": "Foyer",
    "陽光房": "Sunroom"
  }
}
  1. 渲染時 render.js 優先使用 region_names 中的翻譯(未提供的區域名會回退到內建常見區域映射,再兜底顯示 AREA)
  2. 渲染完成後在彙報中列出本次區域翻譯對照表,用戶可糾正,下次報價重新翻譯

Step 6: 渲染 PDF

在專案目錄下執行:

node scripts/render.js --input <data.json> --template <模板名> --vat-rate <稅率> --group-by <area|category> --output ./output/<專案名稱>_<工程編號>.pdf
  • --group-by area — 按區域分類(大分類=區域,明細含工程分類列)
  • --group-by category 或不傳 — 按工程分類(原有行為)

渲染數據 JSON 格式:

{
  "專案名稱": "xxx",
  "工程編號": "xxx",
  "編製日期": "xxx",
  "編製人員": "xxx",
  "聯絡信箱": "xxx",
  "logo_url": "data:image/png;base64,...",
  "稅率": 0.08,
  "管理費": 0.1,
  "items": [
    {
      "區域": "玄關",
      "工程分類": "措施項目",
      "項目名稱": "腳手架",
      "項目特徵": "室內腳手架",
      "單位": "項",
      "數量": 1,
      "綜合單價": 3200,
      "合價": 3200
    }
  ]
}

序號自動生成規則:序號 欄位無需在數據中提供(飛書多維表可不建該列)。渲染時按 分組序號.組內序號 自動生成:按區域分類時 01 區域 → 1.1、1.2、…,02 區域 → 2.1、2.2、…;按工程分類時 措施項目 → 1.x、拆除工程 → 2.x…安裝工程 → 13.x。組內順序 = 飛書記記錄順序(多維表中可拖拽記錄排序)。

稅率與管理費(詳見 Step 5):

  • 稅率 / 管理費 值 > 1 視為百分比整數(3 → 3%),≤ 1 視為小數(0.08 → 8%)
  • 管理費 = 合計 × 管理費率;增值稅 = (合計 + 管理費) × 稅率;總計 = 合計 + 管理費 + 增值稅
  • 管理費未提供或為 0 → 不收取,總價表不顯示管理費行
  • 若未提供 --vat-rate 參數,render.js 優先讀取數據中的 稅率 欄位

Step 7: 儲存與發送

PDF 渲染完成後,必須詢問用戶選擇儲存方式:

PDF 已生成:<專案名稱>_<工程編號>_<模板名>.pdf(XX 條,¥XXX 含稅)

請問如何儲存?
1. 發送到目前聊天視窗
2. 儲存到飛書雲文件,推送文件連結
3. 兩者都要

根據用戶選擇執行:

選項 1 — 發送到聊天視窗

lark-cli im +messages-send --type media --file <pdf路徑>

選項 2 — 儲存到飛書雲文件

lark-cli drive +upload --file <pdf路徑> --title "<專案名稱>_<工程編號>"

獲取上傳後的文件連結,回覆用戶:

已儲存到飛書雲文件:<專案名稱>_<工程編號>_<模板名>.pdf
文件連結: https://xxx.feishu.cn/drive/xxx

選項 3 — 兩者都要

先執行選項 2(上傳),再執行選項 1(發送檔案 + 連結)。

清理暫存檔案

發送/儲存完成後,刪除渲染過程中產生的暫存 JSON 檔案和 Logo 下載檔案(如有)。

3. 專案結構

quote-generator-skill/
├── package.json                # 專案配置
├── setup.sh                     # 一鍵安裝腳本
├── SKILL.md                     # Skill 定義
├── scripts/
│   ├── render.js               # HTML → PDF 渲染引擎
│   ├── demo.js                 # 開箱即用演示
│   └── generate-large-test.js  # 大型測試數據生成器
├── references/
│   ├── templates/
│   │   ├── content.html        # Handlebars PDF 模板(內容頁)
│   │   ├── cover-screen.html   # Swiss IKB 封面獨立模板
│   │   ├── cover-bw.html       # B&W 黑白列印封面模板
│   │   ├── swiss-ikb.json      # Swiss IKB 配置
│   │   ├── swiss-ikb-zebra.json # Swiss IKB Zebra 配置
│   │   ├── bw.json             # B&W 黑白列印配置
│   │   └── bw-zebra.json       # B&W Zebra 配置
│   ├── helpers.js              # Handlebars 自訂 helper
│   └── bitable-config.json     # 多維表欄位配置
├── docs/plans/                 # 設計文件
├── output/                     # 生成的 PDF 輸出目錄
└── README.md

4. 模板說明

PDF 模板包含三種頁面:

  1. 封面 — 工程名稱、編號、日期、編製人員、logo(右上角)
  2. 總價表 — 按工程分類彙總金額 + 合計/增值稅/總計
  3. 明細頁 — 每頁約 8 行數據,含分類標題、明細行、小計行、頁碼

5. 注意事項

  • 多維表中的 合價 是公式欄位(=數量×綜合單價),讀取時已計算好
  • 序號 無需在飛書中維護:渲染時自動生成(分組序號.組內序號,組內按記錄順序)。若要調整明細順序,在飛書多維表中拖拽記錄排序即可
  • 工程分類 是單選欄位,13 個選項對應 13 類工程
  • 區域 是自由文字欄位(建議在飛書中改為單選:玄關、客廳、餐廳、廚房、主臥、次臥、衛生間、陽台、書房、衣帽間、走廊、全屋等),僅按區域分類時使用,可為空
  • 區域模式的分組標題顯示中英對照(如 Living Room 客廳)。區域名每個項目不同,Agent 每次渲染前按 Step 5.7 動態翻譯並寫入 region_names;內建常見區域映射僅作兜底,未命中時顯示 AREA
  • 單位 是單選欄位,支援自訂擴展
  • Logo 支援圖片(推薦)和文字兩種形式
  • 增值稅稅率每次由用戶指定,不固定
  • 輸出 PDF 為 A4 尺寸,適合列印

6. 常見問題處理

錯誤現象原因Agent 處理方式
command not found: lark-clilark-cli 未安裝提示安裝 lark-cli,參考 Step 0.3
lark-cli 返回認證錯誤未登入或 token 過期提示執行 lark-cli auth login
Executable doesn't existPlaywright Chromium 未安裝執行 npx playwright install chromium
渲染 PDF 為空或格式混亂數據 JSON 格式不正確檢查 專案名稱、工程編號 非空,items 至少 1 條
明細序號與手動填的不一樣序號已改為自動生成正常現象:序號按分組自動重編(如 01 全屋 → 1.1、1.2…)。調整順序請在飛書拖拽記錄
字型異常極少發生(字型已內建為 WOFF2,不依賴外部 CDN)檢查專案 references/fonts/ 目錄下字型檔案是否完整
Logo 下載失敗多維表附件 API 權限問題確認用戶已授權,或選擇「不使用 Logo」
base-token 無法從 URL 提取用戶提供的不是多維表連結提示用戶提供飛書多維表連結(URL 中應包含 /base/)

関連スキル