← 返回文档索引

name: sieta-web-style-guide description: SIETA 内部门户设计系统 — 当前 Neo-brutalism(新粗野主义)风格。旧手绘风已废弃。所有新页面/重构都加载此 skill。 version: 2.1.0 aliases: ["sieta-ui", "neo-brutalism", "管理门户风格"] metadata: hermes: tags: [design, UI, neo-brutalism, portal, SIETA] evaluations: path: evaluations/golden.jsonl description: Golden eval cases validating Neo-brutalism style compliance and SIETA portal conventions.


SIETA 网页设计系统

⚠️ 风格已更新:当前部署的是 Neo-brutalism(新粗野主义) 风格,已替代旧手绘风(Hand-Drawn)。旧手绘风规范保留在下方供参考,但不要用旧风格生成新页面

何时加载

创建或修改 SIETA 域名下的任何管理页面时必须加载此 skill,包括: - admin.html(登录页) - index.html(导航页) - 后续新增的管理/内部页面 - 文件上传等交互组件

不适用:外部面向公众的 landing page(如 sieta.vip 备案页)


🟢 当前风格:Neo-brutalism(新粗野主义)

大头哥2026-05-12切换至此风格,旧手绘风已废弃。所有后续页面/修改必须遵循此规范。

设计哲学

Neo-brutalism 拒绝平滑、精致、圆润的现代UI,拥抱粗粝、高对比、有冲击力的视觉语言。从包豪斯海报和建筑粗野主义中汲取灵感——粗活、直接、毫不掩饰的边界感。

情感目标: 强大、自信、直接、有态度。让用户感觉到这是一个"被设计过"的系统,有明确的视觉个性。

设计原则

颜色

Token 用途
--bg #FFFDF5 米白背景
--black #000 纯黑边框/文字
--yellow #FFD93D 品牌/高亮块
--purple #C4B5FD 用户名/成功状态
--red #FF6B6B 危险/强调色
--white #fff 卡片/按钮白色面
--gradient linear-gradient(135deg, #FFFDF5 0%, #F5F0E8 100%) index 页面背景渐变

字体

<link href="https://fonts.loli.net/css2?family=Space+Grotesk:wght@500;700;900&display=block" rel="stylesheet">

边框

阴影

背景选项

当前部署的两个页面背景不同:

页面 背景
admin.html(登录页) #FFFDF5 + 半色调小点 radial-gradient(circle, #000 1.5px, transparent 1.5px) size 20px
index.html(导航页) 无点渐变 linear-gradient(135deg, #FFFDF5 0%, #F5F0E8 100%)

注意:背景风格由大头哥那组 prompt 决定。如果用户说"换背景",先问他指的是哪个 prompt 页面的背景。

Favicon

设计规格

当前部署的 favicon(sieta.vip 根域名):

文件 路径 用途
SVG /var/www/html/favicon.svg 标签页图标(主流浏览器首选)
ICO /var/www/html/favicon.ico 收藏夹图标(Chrome 存储 bookmark 用)
PNG /var/www/html/favicon.png 备用/高分辨率(可加 64x64)

设计参数(与 gallery favicon 完全一致的结构,仅颜色不同): - 64×64 viewBox,rx=12 圆角方形 - 黄色 #FFD93D 底 + 黑色粗体 "S"(gallery 为红底 #b91c1c + 白 "S") - SVG 源文件:/home/ubuntu/svicon.svg

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
  <rect width="64" height="64" rx="12" fill="#FFD93D"/>
  <text x="32" y="50" text-anchor="middle" font-family="Arial, sans-serif" font-size="52" font-weight="bold" fill="black">S</text>
</svg>

HTML <head> 中需要 3 个 link(缺一不可——已踩过坑)

<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="shortcut icon" href="/favicon.ico">
<link rel="icon" type="image/png" sizes="64x64" href="/favicon.png">

⚠️ 每个 SIETA 管理页面必须包含全部 3 个 link。缺 shortcut icon → Chrome bookmark 不存图标;缺 SVG → 标签页模糊;缺 PNG → 高分辨率屏无图标。

nginx Cache-Control(缺了浏览器重启后 bookmark icon 丢失)

nginx location 必须加缓存头,否则浏览器重启后 favicon 不持久:

location ~* \.(svg|ico|png)$ {
    root /var/www/html;
    expires 7d;
    add_header Cache-Control "public, max-age=604800, immutable";
}

不配置的话,浏览器默认不缓存 → 重启后 bookmark 图标空白(已因此修了2次)。这条是 repeat-offense 极高的坑

ICO 生成方式

用 Python PIL 从 SVG 规格转 ICO(64×64,黄底黑 S),或直接运行 skill 内置脚本:

python3 ~/.hermes/skills/design/sieta-web-style-guide/scripts/gen-favicon.py
# 可选参数:--dir /var/www/html --color #FFD93D --letter S --letter-color black
from PIL import Image, ImageDraw, ImageFont
img = Image.new("RGBA", (64, 64), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
draw.rounded_rectangle([(0, 0), (63, 63)], radius=12, fill="#FFD93D")
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 36)
bbox = draw.textbbox((0, 0), "S", font=font)
x = (64 - (bbox[2]-bbox[0])) / 2 - bbox[0]
y = (64 - (bbox[3]-bbox[1])) / 2 - bbox[1] - 1
draw.text((x, y), "S", fill="black", font=font)
img.save("/tmp/favicon.png")
img.save("/tmp/favicon.ico", format="ICO", sizes=[(64, 64)])
# 部署:sudo cp /tmp/favicon.* /var/www/html/

部署路径

所有 favicon 文件放在 sieta.vip 根目录 /var/www/html/,因为 link 引用的是绝对路径 /favicon.*。nginx 的 location ~* \.(svg|ico|png)$ 负责提供服务。

修改流程

  1. 改源文件 /home/ubuntu/svicon.svg(SVG 内容)
  2. 更新 ICO/PNG(如上 Python 脚本)
  3. sudo cp /tmp/favicon.* /var/www/html/
  4. 三步:svg 源 → ICO 转换 → HTML link → nginx cache

图标

Feather Icons(同旧风格,未变):

<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>

初始化:feather.replace()

组件规范

按钮

卡片(导航卡片)

上传区

Chart.js 双轴并列柱状图(sietadata 动态页模式)【v2 — 2026-05-22 校正】

销售分析/库存分析页面使用 Chart.js v4 绘制的双坐标轴并列水平柱状图indexAxis: 'y'),遵循 neo-brutalist 配色。

⚠️ 关键坑:双轴不要用叠加柱(overlaid)

双坐标轴不适合做成叠加柱(两个 dataset 用不同 xAxisID,柱子从 x=0 按各自 scale 延伸)。由于两个轴的量级不同(金额×万 vs 双数×百),叠加柱的视觉位置不匹配,看起来奇怪。必须用分组并列柱(grouped bars),dataset index 决定柱子在组内的上下位置。

柱子黑色边框(2026-05-22 用户确认)

所有柱子加 2px 黑色边框(borderWidth: 2, borderColor: '#000')。组内两柱间距 0(barPercentage: 1.0),中间共享一条 4px 黑框。组间间距保持 categoryPercentage: 0.78

颜色映射

维度 各店图 品牌图(环形图)
销售额(上轴,dataset[0]) #FF6B6B 热红 品牌名映射(见下方)
双数(下轴,dataset[1]) #C4B5FD 淡紫 半透明品牌色 +'88'

品牌颜色映射表(硬编码,按品牌名匹配)

const colorMap={'依歌尔诗':'#C4B5FD','娇娅媚妮':'#F472B6','是她':'#DC2626','迷人角色':'#4ADE80'};
const fallback=['#FF6B6B','#FFD93D','#4361ee'];
const colors=lbls.map(l=>l==='其他'?'#94A3B8':(colorMap[l]||fallback[fi++%fallback.length]));

坐标轴布局

柱子宽度与间距

参数 效果
barPercentage 1.0 柱子撑满自己分配的 50% 空间,组内两柱紧挨无间隙,边框重叠为 4px
categoryPercentage 0.78 每组占分类槽 78%,剩余 22% 上下均分 ≈4px 组间距

完整配置模板(2026-05-22 最新版)

new Chart(canvas, {
  type: 'bar',
  data: {
    labels: items.map(i => i.label),
    datasets: [
      { label: '销售额', data: items.map(i => i.amt),
        backgroundColor: '#FF6B6B', borderWidth: 2, borderColor: '#000',
        yAxisID: 'y', xAxisID: 'x1',
        barPercentage: 1.0, categoryPercentage: 0.78,
        datalabels: { anchor: 'end', align: 'end', offset: 4,
          color: '#000', font: { weight: 'bold', size: 13 },
          formatter: v => '¥' + v.toLocaleString() } },
      { label: '双数', data: items.map(i => i.qty),
        backgroundColor: '#C4B5FD', borderWidth: 2, borderColor: '#000',
        yAxisID: 'y', xAxisID: 'x',
        barPercentage: 1.0, categoryPercentage: 0.78,
        datalabels: { anchor: 'start', align: 'end', offset: 3,
          color: '#000', font: { weight: 'bold', size: 11 },
          formatter: v => v + '双' } }
    ]
  },
  options: {
    indexAxis: 'y',
    responsive: true,
    maintainAspectRatio: false,
    plugins: {
      legend: {
        position: 'bottom',
        labels: { font: { weight: 'bold', size: 11 },
                  boxWidth: 16, boxHeight: 16, padding: 12,
                  usePointStyle: true, pointStyle: 'rectRounded' }
      }
    },
    scales: {
      x: { position: 'bottom', title: { display: true, text: '双数', font: { size: 11, weight: 'bold' } },
           grid: { color: '#ddd' }, beginAtZero: true, max: maxQty },
      x1: { position: 'top', title: { display: true, text: '销售额 (¥)', font: { size: 11, weight: 'bold' } },
            grid: { drawOnChartArea: false }, beginAtZero: true },
      y: { border: { display: true, color: '#000', width: 2 },
           grid: { drawOnChartArea: false },
           ticks: { font: { size: 11, weight: 'bold' } } }
    }
  }
});

环形图(品牌排名,v3)【2026-05-24 更新 — 避免嵌套崩】

⚠️ 重要:不要用 3 层嵌套环形图(weight:2/1/7 + cutout:'2%')。 该配置在静态页面中会静默崩溃(new Chart() 抛出未捕获异常),导致整个页面 JS 停止执行,所有图表和动态内容消失。

静态页面使用单层环形图:

new Chart(canvas, {
  type: 'doughnut',
  data: {
    labels: ['娇娅媚妮', '依歌尔诗', '是她', '迷人角色', '其他'],
    datasets: [{ data: [29120, 21167, 10940, 7871, 3994], backgroundColor: colors }]
  },
  options: {
    responsive: true, maintainAspectRatio: false,
    cutout: '40%',
    plugins: { legend: { position: 'bottom' } }
  }
});

数据标签只标注前4名:

datalabels: {
  display: function(ctx) { return ctx.dataIndex < 4; },
  // ...
}

品牌颜色映射保持不变(见下方),'其他' 统一用 '#94A3B8'

旧版嵌套环形图(v2)配置保留在下文供参考——仅用于动态 SPA 页面(如 sales_analysis_mobile.html),不要在新静态页面中使用。

品牌排名使用 Chart.js doughnut 类型,三层嵌套结构(weight 控制比例):

weight 作用 样式
内饼(销售额) 7 主数据展示 品牌色实心,borderWidth: 3, borderColor: '#000'
间隙 1 视觉分隔 backgroundColor: 'transparent', borderWidth: 0
外环(双数) 2 次要数据 品牌色 +'CC' 半透明(80%不透明),borderWidth: 3, borderColor: '#000' ⚠️ 不要用 '88'——深色(如#DC2626)会跟内饼颜色相差太远

页面规范: - 标题 font-size: 12px; font-weight: 900; uppercase; letter-spacing: 0.05em - 卡片白底 4px solid #000 硬边框 + shadow: 6px 6px 0 #000 - KPI 卡片 5 列 grid,日均值显示在 .s 小字行 - 营业员表格:姓名加 <strong> 粗体,数字 right-align - 白底卡片,8px 硬阴影(比导航卡轻),padding 20px - 标题 14px 900 weight,下划线分隔 - 拖拽区:3px 虚线黑边框,padding 20px,hover 变黄底实线 - 进度条:14px 高,红底填充,3px 黑边框外包 - 文件列表:2px 黑边框 item,hover 淡紫底 - 整体比导航卡片更紧凑(上传是次要功能)

页面新增流程

创建新页面到 SIETA portal 的标准流程: 1. 从已有工作模板复制(销售分析手机版 = KPI + 图表结构,销售图片 = 商店分组 + 图片卡片),不要从零写 2. 创建 HTML 文件到 /var/www/html/portal/ 下(遵循 Neo-brutalism CSS 规范) 3. 添加对应的 API 端点到 /home/ubuntu/admin-auth-server.py(需 auth 保护) 4. 在 index.html 的导航 grid 中添加卡片 5. 所有内部跳转路径使用 /portal/xxx 格式 6. 重复使用已有组件类(.nav-card, .section-title, .btn-refresh 等)

server-directory.html 组件模式

本页实现了以下可复用的 UI 组件模式:

路径选择器(path-selector pattern,2026-05-13 新增)

目录树(server-directory pattern)

磁盘进度条(disk-usage pattern)

Docker 容器卡片(docker-info pattern)

刷新按钮模式

路径选择器模式(v2 — 2026-05-13)

在 directory tree 顶部增加了可切换扫描根路径的组件(预设按钮 + 自定义路径输入 + show hidden 开关)。 详见 references/server-directory-path-selector.md

admin-auth-server.py API 端点

从 SIETA portal (index.html) 点击导航卡片进入子服务时,不需要额外 token(浏览器自动携带 admin_token cookie 免检),但外部直接访问仍需 token

子服务 路径 外部认证 Portal 跳转
相册 Gallery /gallery/ Bearer Sieta@2006 (Express) admin_token cookie 免检
财务 Finance /finance/ finance_auth=Sieta@2006 cookie (nginx) admin_token cookie 免检

Portal 的 JWT cookie 是统一认证屏障。登录后跳转子服务,浏览器自动带入 cookie 通过检查。

关键原则:不要直接删除外部认证(影响5个店已有用户)。应保留原有 token/cookie 认证,叠加 admin_token cookie 豁免通道。

修改方法(详见 nginx-reverse-proxy-patterns skill 的 references/sieta-unified-auth.md): - Finance:nginx location 用 $variable_flag 做 OR 条件($cookie_finance_auth$cookie_admin_token) - Gallery:server.js authMiddleware 中增加 req.headers.cookie.includes('admin_token=') 检查

页面布局

URL 路径

所有内部管理页面统一放在 /portal/ 子路径下(2026-05-13 重组):

页面 URL 说明
登录页 /portal/admin.html 用户名密码 JWT 登录
导航页 /portal/ 导航卡片 + 文件上传 + Hermes profiles
服务器目录 /portal/server-directory.html 目录树 + Docker + 磁盘监控
财务 /portal/finance/ 财务仪表盘(独立 cookie auth)

旧路径(/admin.html, /index.html, /server-directory.html, /finance/)已设 301 永久跳转到新路径。

新页面开发原则:所有新的内部管理页面都放在 /var/www/html/portal/ 下,URL 为 /portal/<page-name>.html

index.html 导航 Grid

当前 index.html 的导航区块用两个 .nav-grid(内置卡片 + 自定义卡片):

当前 index.html 采用 三栏 Grid 居中布局.layout grid container,grid-template-columns: 280px minmax(420px, 600px) 1fr,max-width=1400px):

布局设计原则:导航卡片是页面视觉重心,必须在屏幕中央。Sidebar(Hermes Profiles)是附属信息,紧贴导航左侧但不抢占中心位置。三栏 grid 280px | 居中 420-600px | 右侧平衡 实现了这个效果。

SietaData 页面

sietadata 相关页面放在 /sietadata/ 子路径下,不经过 /api/ auth(nginx 直接 serve 静态文件):

页面 URL 说明
数据入口 /sietadata/index.html 4 块卡片网格:库存分析、销售分析、财务分析、开放文档
开发文档 /sietadata/docs.html 分类文档索引页(即时销售表、SietaData 项目等)
销售分析 /sietadata/sales_analysis.html 动态页,双日期选择器,调 API 拉数据
库存分析 /sietadata/inventory_analysis.html 动态页,单日期选择器,调 API 拉数据
项目文档 /sietadata/soul.html 项目说明

入口页布局/sietadata/index.html): - 2×2 卡片网格(grid-template-columns: 1fr 1fr,gap 20px) - 沿用 Neo-brutalism 样式:Space Grotesk 字体、4px 黑边框、8px 硬阴影、hover 上浮 - 每张卡片含 emoji 图标(32px)+ 标题(22px 900 uppercases)+ 描述(13px opacity 0.5) - 底部「← 返回 SIETA Portal」链接 - 「开放文档」卡片指向 docs.html(非 soul.html——用户纠正:开放文档应该是索引页,不是单一文档) - 财务分析卡片指向 /portal/finance/(需 admin_token cookie 免检) - 移动端单列堆叠

开发文档索引页/sietadata/docs.html): - 分类文档列表,按 section 分组(如「⚡ 即时销售表」「📦 SietaData 项目」) - 每个 section:.section-title(18px 900 uppercase,3px 下划线)+ .doc-list(垂直排列) - 每条文档链接(.doc-link):白底、3px 黑边框、4px 硬阴影,hover 变黄底 - 左侧小黑点(.dot 8×8)+ 文档名(.label)+ 右侧类型标签(.tag,小字号 uppercase 标签) - 只放开发文档(spec、guide、prd),不放数据报表(用户明确纠正) - md 源文件用 Python markdown 库转 HTML 后部署到 /var/www/sieta/sietadata/sudo tee 写入) - 所有文档页加 ← 返回文档索引 链接指向 docs.html - 底部「← 返回 SietaData」链接

⚠️ 财务分析原来在 Portal 导航页,已迁移到 SietaData 入口页。Portal 导航页不再显示财务卡片。

sietadata 页面全部公开访问(nginx location /sietadata/ 无 auth)。API 端点也不设 auth 检查(get_current_user 已移除)。

admin-auth-server.py API 端点

文件:/home/ubuntu/admin-auth-server.py(uvicorn,port 7891,nginx 代理 /api/ → 7891)

路径 方法 说明 Auth
/api/auth/login POST JWT 登录
/api/auth/verify GET 校验 cookie
/api/auth/logout POST 清除 cookie
/api/auth/users GET/POST 用户管理 POST 需 auth
/api/profiles GET Hermes profile model/provider 否(内部展示)
/api/upload POST 文件上传
/api/uploads GET 上传文件列表
/api/server-tree?path=&root=home&show_hidden=false GET 目录懒加载(可选 root 预设名或绝对路径,show_hidden 显示隐藏文件)
/api/scan-roots GET 可用根目录预设列表(含 label/path)
/api/docker-info GET Docker 容器 + 关联目录
/api/disk-usage GET 磁盘空间
/api/serve-file?path=&root=home GET 返回 .md 文件内容(需指定 root)
/api/sietadata/sales?date=YYYY-MM-DD GET 单日销售数据 否(公开)
/api/sietadata/sales-range?start_date=YYYY-MM-DD&end_date=YYYY-MM-DD GET 日期范围销售聚合(含每日明细) 否(公开)
/api/sietadata/available-dates GET 有数据的日期列表(sales + inventory) 否(公开)
/api/sietadata/inventory?date=YYYY-MM-DD GET 单日库存快照 否(公开)

auth 检查:_auth_check(request) 函数解密 JWT cookie,失败返回 401。sietadata API 已移除 auth 检查。

⚠️ 用户数据文件 admin-users.json — 易丢失 路径:/home/ubuntu/admin-users.json,存 bcrypt hash 用户数据。 - 进程重启不会丢失(只读不写),但文件被删除/从未创建时任何人无法登录 - JWT 过期时间:7 天JWT_EXPIRE_HOURS = 24 * 7),关闭浏览器后 7 天内自动登录,无需重新输密码 - 重建命令(admin / sieta2024): bash python3 -c "import bcrypt, json; h = bcrypt.hashpw(b'sieta2024', bcrypt.gensalt()).decode(); open('/home/ubuntu/admin-users.json','w').write(json.dumps({'admin':{'hash':h}}))" - 不要在源码中硬编码明文密码做初始化(见 references/internal-auth-pattern.md

依赖:PyYAML(/api/profiles 用)、bcrypt(登录用)、PyJWT(JWT)。

响应式


🔴 已废弃:旧手绘风(Hand-Drawn)

以下内容仅作历史参考。新页面不要用。

设计原则

颜色

Token 用途
--bg #fdfbf7 暖纸背景
--fg #2d2d2d 铅笔黑(不用纯黑)
--muted #e5e0d8 旧纸/擦除色
--accent #ff4d4d 红修正笔
--border #2d2d2d 铅笔线
--blue #2d5da1 蓝圆珠笔
--yellow #fff9c4 便利贴黄

字体

<link href="https://fonts.loli.net/css2?family=Kalam:wght@400;700&family=Patrick+Hand&display=swap" rel="stylesheet">

边框(wobbly)

不要用标准 border-radius 或 tailwind rounded-*。用多值不规则 radius:

/* 标准 - 小容器/按钮 */
border-radius: 255px 15px 225px 15px / 15px 225px 15px 255px;

/* 中等 - 卡片/大框 */
border-radius: 60px 15px 55px 15px / 15px 55px 15px 60px;

边框宽度至少 border: 3px solid #2d2d2d,次要元素可用 border: 2px dashed #2d2d2d

阴影

不用 blur。纯硬偏移:

/* 标准 */
box-shadow: 4px 4px 0px 0px #2d2d2d;

/* 强调(大卡片/弹窗) */
box-shadow: 8px 8px 0px 0px #2d2d2d;

/* Hover 缩小模拟抬起 */
box-shadow: 2px 2px 0px 0px #2d2d2d;

背景纹理

body {
  background-color: #fdfbf7;
  background-image: radial-gradient(#e5e0d8 1px, transparent 1px);
  background-size: 24px 24px;
}

组件规范

按钮

输入框

卡片

.card {
  background: #fff;
  border: 3px solid #2d2d2d;
  border-radius: 255px 15px 225px 15px / 15px 225px 15px 255px;
  box-shadow: 4px 4px 0px 0px #2d2d2d;
  transform: rotate(-1deg);
  transition: transform 0.15s;
}
.card:hover {
  transform: rotate(0deg) translate(-2px, -2px);
  box-shadow: 6px 6px 0px 0px #2d2d2d;
}

装饰(可选)

布局

动画

布局策略

非泛化设计选择(Unique Visual Signatures)

图标

使用 Feather Icons,不用 emoji。 Emoji 在不同平台渲染差异大,不适合手绘风格的管理页面。

引入方式

<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>

使用方式

<!-- 静态图标 -->
<i data-feather="image" width="36" height="36"></i>
<i data-feather="dollar-sign" width="36" height="36"></i>
<i data-feather="bar-chart-2" width="36" height="36"></i>
<i data-feather="upload-cloud" width="28" height="28"></i>
<i data-feather="folder-plus" width="48" height="48"></i>
<i data-feather="file-text" width="20" height="20"></i>
<i data-feather="map-pin" width="28" height="28"></i>

初始化

// 页面加载后
feather.replace();

// 动态注入图标后(如文件列表渲染后),再次调用 feather.replace()

常用图标映射

用途 Feather Icon 尺寸
相册/图片 image 36px
财务 dollar-sign 36px
数据/统计 bar-chart-2 36px
上传 upload-cloud 28px
文件夹/拖拽 folder-plus 48px
文件列表 file-text 20px
图钉装饰 map-pin 28px(红色)

样式

参考文件


📊 财务 Dashboard 配置(来自 absorbed skill: finance-dashboard-config)

本页是 SIETA 门户内 /portal/finance/ 的特定配置。此内容原为独立 skill finance-dashboard-config,已整合至此。

配色方案

对比柱状图: - 本期(current):紫罗兰 #8B5CF6 - 环比(MoM):琥珀 #FBBF24 - 同比(YoY):浅灰 #CBD5E1

趋势图: - 销售:紫罗兰 #8B5CF6 - 毛利:琥珀 #FBBF24 - 净利润:粉色 #F472B6

Bar 配置

Chart.js grouped bar 的宽度和间距控制:

需求 方案 说明
固定柱宽 dataset.barThickness: 24 每根柱子固定 24px
限制最大宽度 dataset.maxBarThickness: 28 dataset 级别属性(非 scale)
组间间距 scale.x.categoryPercentage: 0.85 分类槽占可用宽度百分比
组内间距 scale.x.barPercentage: 0.9 组内柱子占分类槽百分比

坑: maxBarThickness 是 dataset 级别属性,写在 scale 上会被 Chart.js 忽略。

布局

依赖: - chart.umd.min.js/var/www/sieta/finance/chart.umd.min.js(Chart.js 本地副本) - 源代码:~/sietadata/dashboard/index.html - nginx alias:/var/www/sieta/finance/

店铺选择模式

三种模式(selectedMode: 'summary' | 'all' | 'multi'):

核心函数:getTargetStores() 代替旧的 selectedStores.includes(0) 判断。

财务分析模块 v1(基础版)

页面底部 #analysisSection 区块,纯文字 + 突出数字:

卡片 内容
期间概览 总营收、毛利、净利润、费用 + 环比变化
波动提醒 各指标环比波动 >20% 的项,按幅度排序
店铺诊断 亏损店标红、费用率>50%标黄、其余标绿

切换时间/店铺时自动更新。

财务分析模块 v2(深度版,含资产负债表)

finance_source.xlsx资产负债表 sheet 提取 12 个字段嵌入 HTML 为 BALANCE_DATA 常量:

卡片 指标
经营概览 三月营收趋势(连续升/降判断)、毛利率趋势、费用结构 + 后台费用率告警
资产负债表 银行存款及变化、库存及变化、库存周转率(季度)、周转天数、应收/应付/信用卡负债、净资产、流动比率
逐店诊断 每家店营收/净利/毛利率/费用率 + 环比波动 >20% 标记 + 健康标签
重点关注与建议 亏损店汇总、库存积压、费用控制、现金流紧张、营收下滑提示

BALANCE_DATA 嵌入方式:从 xlsx 读取 → json.dumps → 插入 HTML 中 DATA 常量之后(用 html.replace() 单次替换)。

大文件修改坑

Dashboard 的 index.html ~95KB,含 40 月 × 7 店 JSON 数据 + 资产负债表。

审计命令:grep -n 'storeSel\|includes(0)\|activeStores\|momAllZero\|yoyAllZero' index.html

详细参考