Communitygithub.com

pharder56k/quote-generator-skill

Sistema de Geração de Orçamentos para Design de Interiores: Converte dados de tabelas online (Feishu) ou Excel em PDFs profissionais. MIT.

O que é quote-generator-skill?

Esta skill permite que agentes de IA (como Claude Code, Cursor, Codex) gerem orçamentos de design de interiores em formato PDF profissional a partir de dados provenientes de tabelas do Feishu (Bitable / 飞书多维表) ou arquivos Excel. Ela automatiza todo o fluxo de trabalho: desde a leitura e validação dos dados (projeto, itens, taxas), processamento do logo, seleção de modelo de template (Swiss IKB, B&W, etc.), até a renderização de um PDF com capa, tabela de preços e página de detalhes. A skill é útil para designers e empreiteiros que precisam criar orçamentos padronizados de forma rápida, eliminando erros manuais de cálculo e formatação. Ela depende de ferramentas como `lark-cli` para acessar o Feishu, Node.js + Playwright para renderizar o PDF, e oferece opções de classificação dos itens por área ou por categoria de obra. O agente orienta o usuário em cada etapa, desde a configuração inicial até o envio do PDF final no chat ou salvamento no drive do Feishu.

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

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Sistema de Orçamento para Projetos Completo (全案设计报价系统)

Esta skill renderiza dados de lista de quantidades em orçamentos PDF profissionais, com suporte a capa, tabela de preços total e páginas de detalhes de múltiplas páginas.

1. Quando usar esta Skill

Condições de disparo

As seguintes situações devem usar esta skill:

  • Usuário digita /quote — Gerar orçamento PDF
  • Usuário menciona que quer converter dados de orçamento de uma tabela online (Feishu) ou Excel para PDF

As seguintes situações não devem usar esta skill:

  • Usuário está apenas editando dados na tabela online (deve usar a skill lark-base)
  • Usuário está apenas visualizando histórico de orçamentos (não precisa regenerar)

Dependências prévias

  • Skill lark-base — Ler dados da tabela online do Feishu
  • Skill lark-im — Enviar PDF para o chat do Feishu
  • Skill lark-drive — Fazer upload do PDF para o drive do Feishu
  • Skill xlsx — Analisar arquivos Excel (quando o usuário fornece Excel)
  • Ambiente Node.js + Playwright (já instalados no diretório do projeto)

Etapa 0: Verificação de primeiro uso

Quando o usuário usa a Skill pela primeira vez ou encontra erros relacionados a dependências ao executar comandos, o Agente deve executar o seguinte processo de verificação.

1. Verificar ambiente Node.js

Tente executar node --version, exigido >= 18. Se falhar ou a versão for muito baixa:

  • Peça ao usuário para instalar Node.js (>= 18): https://nodejs.org
  • Sugira usar nvm para gerenciar versões

2. Verificar navegador Playwright

Verifique se npx playwright install chromium foi concluído no diretório do projeto. Se o render.js reportar erro Executable doesn't exist:

  • Execute no diretório do projeto: npx playwright install chromium
  • Tente renderizar novamente

3. Verificar lark-cli

Tente executar lark-cli --version. Se falhar (command not found):

  • Peça ao usuário para instalar o lark-cli (ferramenta de linha de comando do Feishu)
  • Após instalar, execute: lark-cli auth login

4. Verificar status de login do Feishu

Tente executar lark-cli base +table-list --base-token LfjJbLrTHacijesHmIjcDtSpnJf para testar o status de login. Se retornar erro de autenticação:

  • Peça ao usuário para executar: lark-cli auth login
  • Tente novamente

5. Fornecer modelo do Feishu

O usuário precisa copiar o modelo do projeto para seu próprio espaço do Feishu:

Processamento de dados de origem Excel

Quando o usuário fornece um arquivo Excel, não analise e renderize diretamente. Fluxo de orientação:

  1. Sugira: Recomenda-se primeiro importar para a tabela online do Feishu, os campos e a ordem ficam mais alinhados
  2. Guie o usuário para importar o Excel para o Feishu:
    • Abra o Feishu → Nova tabela online → Importar → Selecionar arquivo Excel
    • Ou copie diretamente a tabela modelo e cole os dados do Excel nela
  3. Após o usuário fornecer o link da tabela online, continue com o fluxo /quote

2. Fluxo de trabalho

Usuário dispara → Verificação de ambiente → Confirmar fonte de dados → Ler dados → Validar dados → Confirmar Logo → Confirmar taxa → Confirmar template → Renderizar PDF → Enviar para Feishu

Etapa 1: Confirmar fonte de dados

O usuário deve fornecer um dos seguintes:

  1. Link da tabela online do Feishu — Ex: https://xxx.feishu.cn/base/XXX
  2. Arquivo Excel — Caminho de arquivo local ou enviado pelo chat

Se o usuário não fornecer, pergunte qual fonte de dados ele prefere.

Etapa 2: Ler dados

Fonte de dados: Tabela online do Feishu

  1. Extraia o base-token do link fornecido pelo usuário (a parte após /base/ na URL)
  2. Liste as tabelas: lark-cli base +table-list --base-token <token>
  3. Encontre os table_id das duas tabelas: Informações do Projeto e Detalhes do Orçamento
  4. Leia as informações do projeto: lark-cli base +record-list --base-token <token> --table-id <table_id_Informações_do_Projeto> --format json
  5. Primeiro, consulte as visualizações: lark-cli base +view-list --base-token <token> --table-id <table_id_Detalhes_do_Orçamento>, pegue o view_id da visualização grid padrão (ex: "Todos os Itens")
  6. Leia os detalhes do orçamento (deve usar --view-id, caso contrário a ordem retornada pode não corresponder à ordem arrastada pelo usuário na interface do Feishu): lark-cli base +record-list --base-token <token> --table-id <table_id_Detalhes_do_Orçamento> --view-id <ID_da_visualização> --format json --limit 200
  7. Extraia das informações do projeto: Nome do Projeto, Número do Projeto, Data de Elaboração, Elaborador, Email de Contato, Logo da Empresa, Taxa de Imposto, Taxa de Administração
  8. Extraia dos detalhes do orçamento: Área, Categoria da Obra, Nome do Item, Características do Item, Unidade, Quantidade, Preço Unitário, Valor Total, Observações (Número de sequência não precisa ser lido, é gerado automaticamente na renderização)

Fonte de dados: Excel

Use a skill xlsx para analisar o Excel e extrair dados com a mesma estrutura. O Excel pode ter várias planilhas, é necessário encontrar a planilha que contém os detalhes do orçamento (geralmente com cabeçalhos como "Nº", "Categoria da Obra", "Preço Unitário", etc.).

Etapa 3: Validação de dados

Antes de renderizar o PDF, o Agente deve validar os dados lidos. Não pule esta etapa.

Lista de verificação (executar item por item):

3.1 Integridade das informações do projeto

Verifique os três campos: Nome do Projeto, Número do Projeto, Data de Elaboração:

  • Qualquer um vazio → Informe ao usuário qual campo está faltando e peça para complementar na tabela "Informações do Projeto" do Feishu
  • Todos preenchidos → Continue

3.2 Número de itens no orçamento

Verifique o array items:

  • Se for 0 ou não existir → "Não há dados nos detalhes do orçamento. Adicione itens na tabela 'Detalhes do Orçamento' do Feishu e tente novamente."
  • Se houver dados → Continue

3.3 Verificação campo a campo

Para cada registro, verifique os campos obrigatórios (Categoria da Obra, Nome do Item, Unidade, Quantidade, Preço Unitário) e gere um relatório resumido:

Resultado da validação:
- Total de itens: 104
- Área ausente: 3 (itens 6, 9, 20)
- Categoria da Obra ausente: 2 (itens 5, 18)
- Nome do Item ausente: 0
- Unidade ausente: 1 (item 12)
- Quantidade ausente: 0
- Preço Unitário ausente: 3 (itens 5, 7, 22)
- Categoria da Obra fora da lista padrão: 0

3.4 Tratamento de campos ausentes

  • Itens com falha ≤ 20% do total: Informe ao usuário quais itens específicos estão com problema e pergunte "Deseja pular esses itens e continuar a geração?"
  • Itens com falha > 20%: Peça ao usuário para corrigir os dados e tente novamente, não continue com a renderização
  • Usuário confirma pular → Filtre os itens problemáticos e continue com os dados válidos

3.7 Verificação de área ausente (apenas ao classificar por área)

Quando o usuário escolhe classificar por área (Etapa 5.6, opção "Por Área"), verifique adicionalmente o campo Área de cada registro:

Área ausente: X (item X)
  • Itens com falha ≤ 20% do total: Informe ao usuário quais itens estão sem área e pergunte "Deseja agrupar esses itens em 'Outros' e continuar?"
  • Itens com falha > 20%: Peça ao usuário para complementar a área e tente novamente
  • Usuário confirma → Itens sem área são agrupados em "Outros" (mutuamente excludente com a lógica de pular da Etapa 3.4: o usuário escolhe entre pular ou agrupar em Outros)

3.5 Correção automática do valor total

Para cada registro, verifique se o Valor Total é igual a Quantidade × Preço Unitário:

  • Diferença < 1 yuan → Não faça nada
  • Diferença ≥ 1 yuan ou vazio → Calcule automaticamente Valor Total = Quantidade × Preço Unitário e escreva o valor nos dados de renderização
  • Itens corrigidos > 10% → Aviso: "X itens com valor total corrigido automaticamente. Sugira verificar a fórmula na tabela online do Feishu."

3.6 Lista padrão de categorias de obra

Abaixo estão as 13 categorias padrão:

Medidas do Projeto, Demolição, Alvenaria, Concreto e Concreto Armado,
Estrutura Metálica, Impermeabilização, Isolamento Térmico, Revestimento de Pisos,
Revestimento de Paredes e Divisórias, Forro, Pintura e Revestimentos,
Outros Acabamentos, Instalações

Categorias que não estão na lista ainda podem ser renderizadas, mas informe ao usuário "A categoria 'XXX' não está na lista padrão."

Etapa 4: Processamento do Logo

Deve ser executado, não pode ser pulado. Independentemente da fonte de dados (tabela online ou Excel), o Logo deve ser verificado e processado.

  1. Ler da tabela online: Verifique o campo de anexo Logo da Empresa na tabela de Informações do Projeto
    • Se houver anexo, use a API media para baixar (drive +download não suporta anexos de tabela online):
      lark-cli api GET /open-apis/drive/v1/medias/{file_token}/download --output ./logo.png
      
    • Converta a imagem para data URI base64 e passe para o campo logo_url nos dados de renderização
  2. Ler do Excel: Verifique se há imagem do logo no Excel (geralmente incorporada na planilha ou como anexo)
    • Se houver, extraia e converta para data URI
  3. Logo ausente (deve perguntar ao usuário):
    • Se não encontrar a imagem do logo na fonte de dados, deve perguntar ao usuário:
      • "Não encontrei o Logo da empresa na fonte de dados. Como proceder?"
      • Opção A: Enviar imagem do logo
      • Opção B: Fornecer URL da imagem do logo
      • Opção C: Não usar logo (o PDF exibirá a marca "R M" padrão)
    • Não pule esta etapa por padrão, mesmo que o usuário diga "gerar direto", confirme como lidar com o logo

Etapa 5: Confirmar taxa de imposto e taxa de administração

Priorize o uso dos valores dos campos Taxa de Imposto e Taxa de Administração nas informações do projeto da tabela online do Feishu. Se a tabela online não tiver esses campos, pergunte ao usuário.

Regras de taxas (comum para taxa de imposto e taxa de administração):

  • Valor > 1 → Tratar como porcentagem inteira, dividir automaticamente por 100 (ex: 3 → 3%, 10 → 10%)
  • Valor ≤ 1 → Tratar como decimal diretamente (ex: 0.03 → 3%, 0.1 → 10%)
  • Valor vazio: Taxa de imposto padrão 3%, Taxa de administração padrão 0 (não cobrada)

Ordem de cálculo:

Subtotal = Σ Valor Total de cada item
Taxa de Administração = Subtotal × Taxa de Administração
Imposto = (Subtotal + Taxa de Administração) × Taxa de Imposto
Total Geral = Subtotal + Taxa de Administração + Imposto

Quando a Taxa de Administração > 0, a tabela de preços exibe a linha "Taxa de Administração"; quando = 0, não exibe (compatível com dados antigos).

Etapa 5.5: Confirmar estilo do template

Deve perguntar, não pode pular. Mesmo que um template tenha sido usado anteriormente, confirme a cada vez.

Pergunte ao usuário para escolher o template:

Escolha o estilo do template para o orçamento:
1. Swiss IKB (padrão) — Capa azul com fundo cheio + títulos de categoria bilíngues
2. Swiss IKB Zebra — Como acima + linhas de detalhes com listras zebradas (branco/azul claro alternados)
3. B&W — Capa branca + ênfase cinza claro, ideal para impressão P&B
4. B&W Zebra — Como acima + linhas de detalhes com listras zebradas (branco/cinza claro alternados)

Se a resposta do usuário contiver um nome ou número de template claro, use o template correspondente:

  • swiss-ikb — Swiss IKB (padrão)
  • swiss-ikb-zebra — Swiss IKB Zebra
  • bw — B&W versão impressão P&B
  • bw-zebra — B&W Zebra versão impressão P&B com listras zebradas

Em desenvolvimento (não disponível externamente por enquanto): Os códigos dos quatro templates Editorial / Editorial B&W / Card / Card B&W já existem, aguardando modificações futuras do usuário para ativação. Se o usuário solicitar explicitamente o uso desses templates, pode-se executar comandos como node scripts/render.js --template editorial, mas recomende prioritariamente os 4 templates acima já lançados.

Etapa 5.6: Confirmar método de classificação

Deve perguntar, não pode pular. Confirme antes de cada renderização, não use a opção anterior por padrão.

Pergunte ao usuário para escolher o método de classificação:

Escolha o método de classificação do orçamento:
1. Por Área (Entrada, Sala de Estar, Quarto Principal...) — Tabela de preços agrupa por área; na tabela de detalhes, adiciona coluna de Categoria da Obra após o número de sequência
2. Por Categoria de Obra (Medidas do Projeto, Demolição...) — Método tradicional; tabela de detalhes não inclui coluna de Categoria da Obra

Após o usuário responder com o número ou nome claro, use o modo correspondente:

  • area — Classificar por área, comando de renderização adiciona --group-by area
  • category — Classificar por categoria de obra (padrão), não passar ou adicionar --group-by category

Nota: Ao escolher "Por Área", certifique-se de que o campo Área na tabela de detalhes do orçamento está preenchido (a Etapa 3.7 verificará). Se os dados ainda não tiverem área preenchida, recomende usar "Por Categoria de Obra" primeiro.

Etapa 5.7: Tradução de nomes de áreas para inglês (apenas ao classificar por área)

Os nomes de áreas variam de projeto para projeto. A tradução deve ser feita dinamicamente antes de cada renderização, proibido usar mapeamento fixo.

  1. Colete todos os nomes de áreas que aparecem nos detalhes do orçamento (sem duplicatas)
  2. O Agente traduz cada nome de área para o inglês (tradução usual na indústria de design, ex: 玄关→Foyer, 客厅→Living Room, 阳光房→Sunroom)
  3. Escreva o resultado da tradução como objeto region_names no JSON dos dados de renderização:
{
  "region_names": {
    "玄关": "Foyer",
    "阳光房": "Sunroom"
  }
}
  1. Durante a renderização, o render.js prioriza as traduções em region_names (nomes de área não fornecidos retrocedem para o mapeamento interno de áreas comuns e, por último, exibem "AREA")
  2. Após a renderização, liste a tabela de tradução de áreas usada. O usuário pode corrigir; na próxima cotação, a tradução será refeita.

Etapa 6: Renderizar PDF

Execute no diretório do projeto:

node scripts/render.js --input <data.json> --template <nome_do_template> --vat-rate <taxa_de_imposto> --group-by <area|category> --output ./output/<Nome_do_Projeto>_<Número_do_Projeto>.pdf
  • --group-by area — Classificar por área (grande classificação = área; detalhes incluem coluna de Categoria da Obra)
  • --group-by category ou não passar — Classificar por categoria de obra (comportamento original)

Formato JSON dos dados de renderização:

{
  "项目名称": "xxx",
  "工程编号": "xxx",
  "编制日期": "xxx",
  "编制人员": "xxx",
  "联系邮箱": "xxx",
  "logo_url": "data:image/png;base64,...",
  "税率": 0.08,
  "管理费": 0.1,
  "items": [
    {
      "区域": "玄关",
      "工程分类": "措施项目",
      "项目名称": "脚手架",
      "项目特征": "室内脚手架",
      "单位": "项",
      "数量": 1,
      "综合单价": 3200,
      "合价": 3200
    }
  ]
}

Regra de geração automática de número de sequência: O campo 序号 não precisa ser fornecido nos dados (pode não ter esta coluna na tabela online do Feishu). Na renderização, é gerado automaticamente no formato Nº do grupo.Nº dentro do grupo: Ao classificar por área, Área 01 → 1.1, 1.2, …, Área 02 → 2.1, 2.2, …; Ao classificar por categoria de obra, Medidas do Projeto → 1.x, Demolição → 2.x… Instalações → 13.x. A ordem dentro do grupo = ordem dos registros no Feishu (pode ser arrastada na tabela online).

Taxa de imposto e taxa de administração (veja Etapa 5):

  • Valor de 税率 / 管理费 > 1 tratado como porcentagem inteira (3 → 3%), ≤ 1 tratado como decimal (0.08 → 8%)
  • Taxa de Administração = Subtotal × Taxa de Administração; Imposto = (Subtotal + Taxa de Administração) × Taxa de Imposto; Total Geral = Subtotal + Taxa de Administração + Imposto
  • Se a Taxa de Administração não for fornecida ou for 0 → não cobrada, a tabela de preços não exibe a linha de Taxa de Administração
  • Se o parâmetro --vat-rate não for fornecido, o render.js lê prioritariamente o campo 税率 dos dados

Etapa 7: Salvar e enviar

Após a renderização do PDF, deve perguntar ao usuário como deseja salvar:

PDF gerado: <Nome_do_Projeto>_<Número_do_Projeto>_<nome_do_template>.pdf (XX itens, ¥XXX com impostos)

Como deseja salvar?
1. Enviar para a janela de chat atual
2. Salvar no drive do Feishu e enviar o link
3. Ambos

Execute de acordo com a escolha do usuário:

Opção 1 — Enviar para a janela de chat

lark-cli im +messages-send --type media --file <caminho_do_pdf>

Opção 2 — Salvar no drive do Feishu

lark-cli drive +upload --file <caminho_do_pdf> --title "<Nome_do_Projeto>_<Número_do_Projeto>"

Obtenha o link do arquivo após o upload e responda:

Salvo no drive do Feishu: <Nome_do_Projeto>_<Número_do_Projeto>_<nome_do_template>.pdf
Link: https://xxx.feishu.cn/drive/xxx

Opção 3 — Ambos

Primeiro execute a Opção 2 (upload), depois a Opção 1 (enviar arquivo + link).

Limpeza de arquivos temporários

Após enviar/salvar, remova os arquivos JSON temporários e o arquivo de download do Logo (se houver) gerados durante a renderização.

3. Estrutura do projeto

quote-generator-skill/
├── package.json                # Configuração do projeto
├── setup.sh                     # Script de instalação com um clique
├── SKILL.md                     # Definição da Skill
├── scripts/
│   ├── render.js               # Motor de renderização HTML → PDF
│   ├── demo.js                 # Demonstração pronta para uso
│   └── generate-large-test.js  # Gerador de dados de teste em grande escala
├── references/
│   ├── templates/
│   │   ├── content.html        # Template Handlebars para PDF (página de conteúdo)
│   │   ├── cover-screen.html   # Template de capa independente para Swiss IKB
│   │   ├── cover-bw.html       # Template de capa independente para B&W
│   │   ├── swiss-ikb.json      # Configuração Swiss IKB
│   │   ├── swiss-ikb-zebra.json # Configuração Swiss IKB Zebra
│   │   ├── bw.json             # Configuração B&W
│   │   └── bw-zebra.json       # Configuração B&W Zebra
│   ├── helpers.js              # Helpers personalizados do Handlebars
│   └── bitable-config.json     # Configuração de campos da tabela online
├── docs/plans/                 # Documentos de design
├── output/                     # Diretório de saída dos PDFs gerados
└── README.md

4. Descrição dos templates

O template PDF contém três tipos de página:

  1. Capa — Nome do projeto, número, data, elaborador, logo (canto superior direito)
  2. Tabela de preços — Resumo dos valores por categoria de obra + Subtotal/Imposto/Total Geral
  3. Páginas de detalhes — Cerca de 8 linhas de dados por página, com título da categoria, linhas de detalhes, linha de subtotal e número de página

5. Observações importantes

  • O Valor Total na tabela online do Feishu é um campo de fórmula (=Quantidade×Preço Unitário), já calculado na leitura
  • O Nº de sequência não precisa ser mantido no Feishu: é gerado automaticamente na renderização (Nº do grupo.Nº dentro do grupo, ordem dentro do grupo conforme a ordem dos registros). Para ajustar a ordem dos detalhes, arraste os registros na tabela online do Feishu
  • Categoria da Obra é um campo de seleção única, as 13 opções correspondem às 13 categorias de obra
  • Área é um campo de texto livre (sugere-se alterar para seleção única no Feishu: Entrada, Sala de Estar, Sala de Jantar, Cozinha, Quarto Principal, Quarto Secundário, Banheiro, Varanda, Escritório, Closet, Corredor, Casa Inteira, etc.), usado apenas ao classificar por área, pode ficar vazio
  • Os títulos dos grupos no modo área exibem o nome bilíngue (ex: Living Room 客厅). Os nomes de área variam de projeto para projeto. O Agente traduz dinamicamente a cada renderização conforme Etapa 5.7 e escreve em region_names; o mapeamento interno de áreas comuns serve apenas como fallback, exibindo "AREA" quando não houver correspondência
  • Unidade é um campo de seleção única, suporta extensão personalizada
  • O Logo suporta formato imagem (recomendado) e texto
  • A taxa de imposto é especificada pelo usuário a cada vez, não é fixa
  • O PDF de saída é tamanho A4, adequado para impressão

6. Tratamento de problemas comuns

ErroCausaAção do Agente
command not found: lark-clilark-cli não instaladoPeça para instalar o lark-cli, consulte Etapa 0.3
lark-cli retorna erro de autenticaçãoNão logado ou token expiradoPeça para executar lark-cli auth login
Executable doesn't existPlaywright Chromium não instaladoExecute npx playwright install chromium
PDF renderizado vazio ou com formato confusoFormato do JSON de dados incorretoVerifique se Nome do Projeto e Número do Projeto não estão vazios e items tem pelo menos 1 item
Nº de sequência diferente do preenchido manualmenteNº de sequência agora é gerado automaticamenteFenômeno normal: O nº de sequência é recalculado automaticamente por grupo (ex: 01 Casa Inteira → 1.1, 1.2…). Para ajustar a ordem, arraste os registros no Feishu
Tamanho/fonte anormaisMuito raro (fontes incorporadas como WOFF2, não dependem de CDN externo)Verifique se os arquivos de fonte no diretório references/fonts/ do projeto estão completos
Falha ao baixar LogoProblema de permissão da API de anexos da tabela onlineConfirme se o usuário autorizou, ou escolha "Não usar logo"
base-token não pode ser extraído da URLO que o usuário forneceu não é um link de tabela onlinePeça ao usuário para fornecer um link de tabela online do Feishu (a URL deve conter /base/).

Habilidades Relacionadas