Files
TradeMate Dev 4755cc75ba feat: 管理后台完整可用 + 注册登录记日志 + 提取信息结构化展示 + 微信配置就绪
- 管理后台用户/统计/日志/配置四页签全部对接真实后端API
- auth注册/登录/游客/微信登录事件写入usage_logs表
- 提取信息结果从原始JSON改为卡片式字段列表(中文标签)
- 管理后台搜索按钮增加加载态和结果数提示
- 配置WECHAT_APP_ID/WECHAT_APP_SECRET
- 客户/产品/报价单CRUD页面完整(导出导入批量操作)
2026-05-18 23:50:48 +08:00

192 lines
6.9 KiB
Python

from typing import List, Dict, Any
import csv
import io
import logging
logger = logging.getLogger(__name__)
try:
import openpyxl
from openpyxl.styles import Font, PatternFill, Alignment
HAS_OPENPYXL = True
except ImportError:
HAS_OPENPYXL = False
def export_customers_csv(customers: List[Dict[str, Any]]) -> bytes:
output = io.StringIO()
writer = csv.writer(output)
writer.writerow(["Name", "Company", "Country", "Phone", "Email", "Status", "Last Contact"])
for c in customers:
writer.writerow([
c.get("name", ""),
c.get("company", ""),
c.get("country", ""),
c.get("phone", ""),
c.get("email", ""),
c.get("status", ""),
c.get("last_contact_at", ""),
])
return output.getvalue().encode("utf-8-sig")
def export_customers_xlsx(customers: List[Dict[str, Any]]) -> bytes:
if not HAS_OPENPYXL:
logger.warning("openpyxl not installed, falling back to CSV")
return export_customers_csv(customers)
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "Customers"
headers = ["姓名", "公司", "国家", "电话", "WhatsApp", "邮箱", "状态", "最后联系"]
header_font = Font(bold=True, color="FFFFFF")
header_fill = PatternFill(start_color="1890FF", end_color="1890FF", fill_type="solid")
for col, h in enumerate(headers, 1):
cell = ws.cell(row=1, column=col, value=h)
cell.font = header_font
cell.fill = header_fill
cell.alignment = Alignment(horizontal="center")
for row, c in enumerate(customers, 2):
ws.cell(row=row, column=1, value=c.get("name", ""))
ws.cell(row=row, column=2, value=c.get("company", ""))
ws.cell(row=row, column=3, value=c.get("country", ""))
ws.cell(row=row, column=4, value=c.get("phone", ""))
ws.cell(row=row, column=5, value=c.get("whatsapp_id", ""))
ws.cell(row=row, column=6, value=c.get("email", ""))
ws.cell(row=row, column=7, value=c.get("status", ""))
ws.cell(row=row, column=8, value=c.get("last_contact_at", ""))
ws.column_dimensions["A"].width = 20
ws.column_dimensions["B"].width = 25
ws.column_dimensions["C"].width = 15
ws.column_dimensions["D"].width = 18
ws.column_dimensions["E"].width = 18
ws.column_dimensions["F"].width = 30
ws.column_dimensions["G"].width = 12
ws.column_dimensions["H"].width = 20
output = io.BytesIO()
wb.save(output)
return output.getvalue()
def export_quotations_csv(quotations: List[Dict[str, Any]]) -> bytes:
output = io.StringIO()
writer = csv.writer(output)
writer.writerow(["Title", "Customer", "Currency", "Subtotal", "Total", "Status", "Date"])
for q in quotations:
writer.writerow([
q.get("title", ""),
q.get("customer_name", ""),
q.get("currency", "USD"),
q.get("subtotal", 0),
q.get("total", 0),
q.get("status", ""),
q.get("created_at", ""),
])
return output.getvalue().encode("utf-8-sig")
def export_quotations_xlsx(quotations: List[Dict[str, Any]]) -> bytes:
if not HAS_OPENPYXL:
logger.warning("openpyxl not installed, falling back to CSV")
return export_quotations_csv(quotations)
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "Quotations"
headers = ["标题", "客户", "货币", "小计", "总计", "状态", "日期"]
header_font = Font(bold=True, color="FFFFFF")
header_fill = PatternFill(start_color="722ED1", end_color="722ED1", fill_type="solid")
for col, h in enumerate(headers, 1):
cell = ws.cell(row=1, column=col, value=h)
cell.font = header_font
cell.fill = header_fill
cell.alignment = Alignment(horizontal="center")
for row, q in enumerate(quotations, 2):
ws.cell(row=row, column=1, value=q.get("title", ""))
ws.cell(row=row, column=2, value=q.get("customer_name", ""))
ws.cell(row=row, column=3, value=q.get("currency", "USD"))
ws.cell(row=row, column=4, value=float(q.get("subtotal", 0)))
ws.cell(row=row, column=5, value=float(q.get("total", 0)))
ws.cell(row=row, column=6, value=q.get("status", ""))
ws.cell(row=row, column=7, value=str(q.get("created_at", "")))
ws.column_dimensions["A"].width = 30
ws.column_dimensions["B"].width = 20
ws.column_dimensions["C"].width = 10
ws.column_dimensions["D"].width = 15
ws.column_dimensions["E"].width = 15
ws.column_dimensions["F"].width = 12
ws.column_dimensions["G"].width = 20
output = io.BytesIO()
wb.save(output)
return output.getvalue()
def export_products_csv(products: List[Dict[str, Any]]) -> bytes:
output = io.StringIO()
writer = csv.writer(output)
writer.writerow(["名称", "英文名", "分类", "描述", "价格", "货币", "MOQ", "关键词"])
for p in products:
writer.writerow([
p.get("name", ""),
p.get("name_en", ""),
p.get("category", ""),
p.get("description", ""),
p.get("price", ""),
p.get("price_unit", "USD"),
p.get("moq", ""),
", ".join(p.get("keywords", [])),
])
return output.getvalue().encode("utf-8-sig")
def export_products_xlsx(products: List[Dict[str, Any]]) -> bytes:
if not HAS_OPENPYXL:
logger.warning("openpyxl not installed, falling back to CSV")
return export_products_csv(products)
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "Products"
headers = ["名称", "英文名", "分类", "描述", "价格", "货币", "MOQ", "关键词"]
header_font = Font(bold=True, color="FFFFFF")
header_fill = PatternFill(start_color="07C160", end_color="07C160", fill_type="solid")
for col, h in enumerate(headers, 1):
cell = ws.cell(row=1, column=col, value=h)
cell.font = header_font
cell.fill = header_fill
cell.alignment = Alignment(horizontal="center")
for row, p in enumerate(products, 2):
ws.cell(row=row, column=1, value=p.get("name", ""))
ws.cell(row=row, column=2, value=p.get("name_en", ""))
ws.cell(row=row, column=3, value=p.get("category", ""))
ws.cell(row=row, column=4, value=p.get("description", ""))
ws.cell(row=row, column=5, value=p.get("price", ""))
ws.cell(row=row, column=6, value=p.get("price_unit", "USD"))
ws.cell(row=row, column=7, value=p.get("moq", ""))
ws.cell(row=row, column=8, value=", ".join(p.get("keywords", [])))
ws.column_dimensions["A"].width = 20
ws.column_dimensions["B"].width = 20
ws.column_dimensions["C"].width = 15
ws.column_dimensions["D"].width = 40
ws.column_dimensions["E"].width = 12
ws.column_dimensions["F"].width = 10
ws.column_dimensions["G"].width = 12
ws.column_dimensions["H"].width = 30
output = io.BytesIO()
wb.save(output)
return output.getvalue()