@somecat/financial-report
H5 页面
基于设计图还原的 Vue3 H5 页面,固定 750px 宽度。
技术栈
- Vue 3 (Composition API)
- Vite 5
- 纯 CSS scoped 样式
项目结构
h5-app/
├── src/
│ ├── assets/ # 切图与字体资源
│ ├── components/
│ │ ├── ReportHeader.vue # 页面头部(周次、标题、日期)
│ │ ├── SectionHeader.vue # 区块标题(编号徽章 + 文字)
│ │ ├── SectionDivider.vue # 区块标题下分隔线
│ │ ├── StatCard.vue # 指标卡片容器(头部指标 + 子标题行 + 图表插槽)
│ │ ├── SavingsSection.vue # Section 1 存款情况(变宽环形图 + 币种分布)
│ │ ├── SectionRepurchase.vue # Section 2 回购情况(34 省市横向条形图)
│ │ ├── SectionLiability.vue # Section 3 带息负债(6 项条形图,红绿交替 + 双指标头部)
│ │ ├── SectionSupplyChain.vue # Section 4 供应链融资余额(分段柱状图)
│ │ ├── SectionSurplus.vue # Section 5 资金结余(5 项条形图 + 双指标头部)
│ │ └── StackedColumnChart.vue # 分段(堆叠)柱状图,纯 SVG 自封装
│ ├── styles/ # 设计变量 / report 样式(样式隔离)
│ ├── utils/ # color.js(CSS 变量解析,保障截图颜色一致)
│ ├── App.vue # 报告主页面(按区块组装,暴露 generateImage)
│ ├── report-data.js # 默认报告数据结构
│ ├── report-image.js # html-to-image PNG 导出
│ └── index.js # 库入口(ReportApp / ReportPlugin)
├── index.html
├── vite.config.js
└── package.json
组件说明
StatCard.vue
指标卡片容器,接收 stats(头部指标数组,支持单/双指标)、unit、subtitle、
unitLabel 等 props;默认插槽放置图表内容,header-extra 具名插槽放置头部右侧插图。
StackedColumnChart.vue(分段柱状图,自封装)
纯 SVG 实现的分段(堆叠)柱状图,无 echarts 依赖,适配 html-to-image PNG 导出:
- 每组渲染一根堆叠柱,所有柱共享比例尺(最高柱撑满绘图区),柱高与组内分段值之和成正比;
- 组内分段默认按数值降序排列(大块在下、小块在上),避免小块贴近 x 轴导致标签拥挤;
- 每个分段以"引导线 + 名称/数值标签"标注,替代图例;首柱标签在柱左侧、其余柱在右侧;
- 不绘制 Y 轴刻度(数值已由标签标注),仅保留底部基线与组名。
数据类型定义:
SegmentItem { name: string, value: number, color?: string } // 分段
StackedGroup { name: string, segments: SegmentItem[] } // 一根堆叠柱
Props:
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
groups |
StackedGroup[] |
必填 | 柱分组数据 |
height |
number |
300 |
SVG 高度,柱体最大高度 = height - 50 |
sortSegments |
boolean |
true |
组内按值降序(大块在下、小块在上) |
formatValue |
(value) => string |
千分位 | 数值格式化 |
分段颜色建议使用 CSS 变量(如 var(--color-primary)),内部会经
resolveCssColor 解析为具体色值,保证页面显示与 PNG 截图一致。
SectionSupplyChain.vue
Section 4 供应链融资余额:仅分段柱状图,不展示卡片头部指标区与子标题文案
(子标题行仅保留右侧"单位:亿元"标注)
(左柱"供应链融资"按融资品种构成,右柱"到期"按到期时间分布)。
Props:groups(结构同 StackedColumnChart 的 groups)。
SectionLiability.vue
Section 3 带息负债:双指标头部(指标 / 实际完成)+ 子标题「带息负债指标完成情况」+ 6 项条形图 + 备注。
条形图与 SectionSurplus 同构,区别是数值恒为正、不区分正负,条形颜色按行序号红绿交替。
Props:stats(头部指标数组,结构同 StatCard)、unit、subtitle、unitLabel、
bars([{ name, value, barWidth? }],条长按 value 等比换算,整组提供 barWidth 时沿用设计稿测量值)、
note(备注文案,为空时不渲染该行)。
运行方式
# 安装依赖
npm install
# 开发模式
npm run dev
# 构建生产包
npm run build
# 预览构建结果
npm run preview
样式隔离说明
库入口(src/index.js)只引入 src/styles/report.scss,其中所有规则均收敛在组件根类 .financial-report 子树内:
- 不包含
*/html/body/#app/:root等全局选择器,不会覆盖宿主应用样式; - CSS 设计变量(
--color-primary等)挂在组件根类上,仅对组件子树生效,同时对html-to-image截图更友好; - 内置组件级 reset(
box-sizing、h1/p默认 margin 清零),宿主未做全局 reset 时组件布局也与设计稿一致; src/styles/base.scss中的全局"页面壳"样式仅供本项目开发预览(src/main.js),不会进入构建产物;- 字体分发策略:D-DIN 数字字体(23KB/38KB)随 CSS base64 内联,对
html-to-image截图零网络依赖;思源宋体(11.77MB)体积过大,由构建插件以文件形式随包分发(dist/assets/fonts/),产物 CSS 以相对路径引用,消费方 bundler 会自动处理。
Vite lib 模式会将 CSS 抽离为独立文件,宿主项目使用 npm 包时需要显式引入:
import { ReportApp } from '@somecat/financial-report'
import '@somecat/financial-report/dist/financial-report.css'
作为报告组件使用
父组件负责准备数据,数据按区块传入;未提供的字段会继续使用当前演示默认值:
<script setup>
import { ref } from 'vue'
import { ReportApp, ReportPlugin } from './src'
const reportRef = ref(null)
const reportData = {
header: {
week: '3',
date: '2026.08.24',
title: '资金周报',
subtitle: '稳资金.降成本.控风险',
description: '本周资金运行整体平稳,结构持续优化'
},
savings: {
headerLabel: '存款余额',
headerValue: '186.4',
currencies: [{ name: '人民币', nameEn: 'CNY', pct: 70, amount: '132.2' }]
},
repurchase: { headerValue: '205.2', provinces: [] },
liability: {
stats: [
{ label: '指标', value: '800.0', color: 'var(--color-green)' },
{ label: '实际完成', value: '825.6' }
],
subtitle: '带息负债指标完成情况',
bars: [{ name: '1年以内', value: '321.2' }],
note: '备注:...'
},
supplyChain: {
groups: [
{
name: '供应链融资',
segments: [
{ name: '银行承兑汇票', value: 142.5, color: '#C13224' },
{ name: '商业承兑汇票', value: 96.2, color: '#FCC2BE' },
{ name: '应付账款保理', value: 58.7, color: '#F68F87' }
]
},
{
name: '到期',
segments: [
{ name: '年内到期', value: 45.2, color: '#53968E' },
{ name: '明年到期', value: 15.8, color: '#82CDC0' }
]
}
]
},
surplus: { bars: [], note: '备注:...' }
}
const exportPng = async () => {
// 默认返回两张图:{ header, body },头部与正文各一张
const { header, body } = await reportRef.value.generateImage({ pixelRatio: 2 })
return { header, body }
}
const exportWholePng = async () => {
// split: false 时返回整个报告的一张图
const dataUrl = await reportRef.value.generateImage({ pixelRatio: 2, split: false })
return dataUrl
}
</script>
<template>
<ReportApp ref="reportRef" :report-data="reportData" />
</template>
也可以注册为全局组件:app.use(ReportPlugin, { name: 'FinancialReport' })。
generateImage() 默认返回 { header, body } 两张 PNG data URL(ReportHeader 一张、header 以下正文一张);传 split: false 时返回整个报告的一张 data URL。调用会等待 Vue 更新、document.fonts.ready 和图片资源加载完成。
截图字体注意事项:DIN 数字字体随 CSS 内联、思源宋体标题字体以文件形式随包分发,生成器会等待 document.fonts.ready 后再截图。正文中文目前依赖系统字体;若要求 Windows、macOS 和 Linux 像素级一致,应把设计指定的中文字体文件放入 public/assets/fonts/,再通过 @font-face 注册并在 $font-sans 中优先使用,且确认字体授权和文件体积。
设计还原说明
- 固定宽度 750px(2x 设计稿宽度)
- 主色调:暖米色背景 #F6E9E7 + 深红色强调 #BD1B13
- 辅助色:橙色 #E48858、绿色 #659C90
- 图表均封装为独立组件,支持 props 自定义数据
- 切图资源均使用原始 @2x 图片
Related Packages
WCAGify's report schemas, scoring and render-only Nuxt layer, for apps that show...
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 0.1.15 | >=3.4.0 | Proprietary | |
| 0.1.14 | >=3.4.0 | Proprietary | |
| 0.1.13 | >=3.4.0 | Proprietary | |
| 0.1.12 | >=3.4.0 | Proprietary | |
| 0.1.11 | >=3.4.0 | Proprietary | |
| 0.1.10 | >=3.4.0 | Proprietary | |
| 0.1.9 | >=3.4.0 | Proprietary | |
| 0.1.8 | >=3.4.0 | Proprietary | |
| 0.1.7 | >=3.4.0 | Proprietary | |
| 0.1.6 | >=3.4.0 | Proprietary | |
| 0.1.5 | >=3.4.0 | Proprietary | |
| 0.1.4 | >=3.4.0 | Proprietary | |
| 0.1.3 | >=3.4.0 | Proprietary | |
| 0.1.2 | >=3.4.0 | Proprietary | |
| 0.1.1 | >=3.4.0 | Proprietary | |
| 0.1.0 | >=3.4.0 | Proprietary |