Add Markdown-driven feasibility report with Typst styling pipeline.
Introduce cmarker/codly-based MD workflow, brutalist cover layout, and shared brand tokens so colleagues can author reports in report.md while the template handles PDF output. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
350d101e0f
commit
b8eed931ac
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
# Typst 编译产物(示例 PDF 除外)
|
# Typst 编译产物(示例 PDF 除外)
|
||||||
*.pdf
|
*.pdf
|
||||||
!resume/sample.pdf
|
!resume/sample.pdf
|
||||||
|
!feasibility/sample.pdf
|
||||||
|
|
||||||
# IDE / 编辑器本地配置
|
# IDE / 编辑器本地配置
|
||||||
.cursor/
|
.cursor/
|
||||||
|
|||||||
@ -5,7 +5,7 @@ GreLin 内部 Typst 模板库,按文档类型分目录维护。目录结构如
|
|||||||
| 文件夹 | 说明 | 入口文件 |
|
| 文件夹 | 说明 | 入口文件 |
|
||||||
|--------|------|----------|
|
|--------|------|----------|
|
||||||
| [`resume/`](resume/) | 团队简历 | `cv.typ` |
|
| [`resume/`](resume/) | 团队简历 | `cv.typ` |
|
||||||
| [`feasibility/`](feasibility/) | 可行性研究报告 | `report.typ` |
|
| [`feasibility/`](feasibility/) | 可行性研究报告 | `report.typ`(正文编辑 `feasibility/content/report.md`) |
|
||||||
|
|
||||||
## 环境要求
|
## 环境要求
|
||||||
|
|
||||||
@ -14,8 +14,9 @@ GreLin 内部 Typst 模板库,按文档类型分目录维护。目录结构如
|
|||||||
|
|
||||||
## 快速开始
|
## 快速开始
|
||||||
|
|
||||||
1. 用 VS Code / Cursor 打开本仓库,打开要编辑的入口文件,例如 `resume/cv.typ`
|
1. 用 VS Code / Cursor 打开本仓库,打开要编辑的入口文件,例如 `resume/cv.typ` 或 `feasibility/report.typ`
|
||||||
2. 看效果(预览):`Ctrl+Shift+P` → 输入 `Typst Preview` → 回车;侧边会实时显示排版效果
|
2. 可行性报告正文在 `feasibility/content/report.md` 用 Markdown 编写,无需改 Typst 代码
|
||||||
3. 导出 PDF:`Ctrl+Shift+P` → 输入 `Typst Export PDF` → 回车;PDF 默认生成在同目录(如 `resume/sample.pdf`)
|
3. 看效果(预览):`Ctrl+Shift+P` → 输入 `Typst Preview` → 回车;侧边会实时显示排版效果
|
||||||
|
4. 导出 PDF:`Ctrl+Shift+P` → 输入 `Typst Export PDF` → 回车;PDF 默认生成在同目录(如 `resume/sample.pdf`)
|
||||||
|
|
||||||
> 不熟悉 Typst?可参考社区维护的 [小蓝书(Typst 中文教程)](https://tutorial.typst.dev/);英文版见 [官方入门教程](https://typst.app/docs/tutorial/)。
|
> 不熟悉 Typst?可参考社区维护的 [小蓝书(Typst 中文教程)](https://tutorial.typst.dev/);英文版见 [官方入门教程](https://typst.app/docs/tutorial/)。
|
||||||
|
|||||||
@ -7,7 +7,8 @@
|
|||||||
#let color-bar-bg = rgb("#EFF0F2")
|
#let color-bar-bg = rgb("#EFF0F2")
|
||||||
#let color-page = rgb("#FDFDFD")
|
#let color-page = rgb("#FDFDFD")
|
||||||
|
|
||||||
// 强调绿同色系:lime → mid(品牌主色)→ olive
|
// 品牌主色(全项目绿色统一)
|
||||||
#let color-lime = rgb("#D7F754")
|
#let color-brand = rgb(200, 216, 98)
|
||||||
#let color-lime-mid = rgb("#C4D94A") // 浅底装饰、技能条、章节强调、图标
|
#let color-lime = color-brand.lighten(10%)
|
||||||
#let color-lime-deep = rgb("#A7C957") // 浅底标题文字
|
#let color-lime-mid = color-brand
|
||||||
|
#let color-lime-deep = color-brand.darken(22%)
|
||||||
|
|||||||
@ -1,32 +1,74 @@
|
|||||||
# Feasibility Report · 可行性研究报告模板
|
# Feasibility Report · 可行性研究报告模板
|
||||||
|
|
||||||
GreLin 可行性报告 Typst 模板,适用于项目论证、内部评审或 BP 附件。
|
GreLin 可行性报告 Typst 模板,面向矿石分选项目论证与客户交付。同事用 **Markdown** 写正文,模板负责封面、页眉页脚与图表排版。
|
||||||
|
|
||||||
## 快速开始
|
## 快速开始
|
||||||
|
|
||||||
|
1. 编辑 [`content/report.md`](content/report.md)(或从 [`content/report.template.md`](content/report.template.md) 复制)
|
||||||
|
2. 用 VS Code / Cursor 打开 [`report.typ`](report.typ)
|
||||||
|
3. `Ctrl+Shift+P` → **Typst Preview** 预览,或 **Typst Export PDF** 导出
|
||||||
|
|
||||||
|
仓库根目录编译(共享 `brand/colors.typ`):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd feasibility-report
|
typst compile feasibility/report.typ feasibility/sample.pdf --root .
|
||||||
typst compile report.typ
|
|
||||||
typst watch report.typ
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 定制
|
示例输出:[`sample.pdf`](sample.pdf)
|
||||||
|
|
||||||
|
## 工作流
|
||||||
|
|
||||||
| 文件 | 说明 |
|
| 文件 | 说明 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| [`data/config.typ`](data/config.typ) | 公司名、项目名、版本、日期、各章节正文 |
|
| [`content/report.md`](content/report.md) | **主编辑入口**:YAML 元数据 + 正文 |
|
||||||
| [`data/theme.typ`](data/theme.typ) | 配色与字号 |
|
| [`content/assets/`](content/assets/) | 图片资源(支持 `.jpg` / `.png` / `.svg`) |
|
||||||
| [`data/layout.typ`](data/layout.typ) | 封面、摘要、章节组件 |
|
| [`data/config.typ`](data/config.typ) | 默认公司名、副标题等(YAML 未写时使用) |
|
||||||
|
| [`data/theme.typ`](data/theme.typ) | 设计 token(字号、间距、表格) |
|
||||||
|
| [`data/styling.typ`](data/styling.typ) | 标题 / 表格 / 图片 `#show` 规范 |
|
||||||
|
| [`data/layout.typ`](data/layout.typ) | 封面、摘要、页眉组件 |
|
||||||
|
| [`report.typ`](report.typ) | 编译入口(一般无需改动) |
|
||||||
|
|
||||||
## 章节结构
|
## YAML 元数据
|
||||||
|
|
||||||
1. 项目概述
|
在 `report.md` 顶部填写:
|
||||||
2. 建设必要性与市场分析
|
|
||||||
3. 技术方案
|
|
||||||
4. 实施计划
|
|
||||||
5. 投资估算与资金用途
|
|
||||||
6. 效益分析
|
|
||||||
7. 风险分析与对策
|
|
||||||
8. 结论
|
|
||||||
|
|
||||||
在 `data/config.typ` 的 `sections` 数组中逐章填写内容即可。
|
```yaml
|
||||||
|
---
|
||||||
|
title: 某某矿山智能分选可行性研究
|
||||||
|
brand: GreLin
|
||||||
|
company: 西安高岭绿能科技有限公司
|
||||||
|
date: 2026-06-22
|
||||||
|
version: v1.0
|
||||||
|
summary: |
|
||||||
|
摘要正文……
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
## Markdown 写法
|
||||||
|
|
||||||
|
- 章节:`# 项目概述`(自动编号为 1. / 1.1 / 1.1.1,无需手写「一、二、三」)
|
||||||
|
- 表格:标准 GFM 表格语法
|
||||||
|
- 图片:`` 或 `assets/chart.png`,文件放在 `content/assets/`
|
||||||
|
- 行内代码:`` `ONNX Runtime` ``(灰底、小圆角、品牌色文字)
|
||||||
|
- 代码块:` ```python ` 围栏 + 语言名,由 [codly](https://typst.app/universe/package/codly) 自动语法高亮并显示语言标签
|
||||||
|
- 下划线:`<u>文字</u>`(品牌色,线下移 5pt)
|
||||||
|
- Emoji:正文可直接写 🐱 等符号(需系统字体支持)
|
||||||
|
- 列表、加粗等均支持(基于 [cmarker](https://typst.app/universe/package/cmarker))
|
||||||
|
|
||||||
|
## 依赖包
|
||||||
|
|
||||||
|
| 包 | 用途 |
|
||||||
|
|----|------|
|
||||||
|
| [cmarker](https://typst.app/universe/package/cmarker) | Markdown → Typst 正文 |
|
||||||
|
| [codly](https://typst.app/universe/package/codly) + [codly-languages](https://typst.app/universe/package/codly-languages) | 代码块高亮与语言标签 |
|
||||||
|
|
||||||
|
可选扩展:[toutu](https://typst.app/universe/package/toutu)(目录)、[hydra](https://typst.app/universe/package/hydra)(页眉章节名)、[cetz](https://typst.app/universe/package/cetz)(矢量图表)。
|
||||||
|
|
||||||
|
## 环境要求
|
||||||
|
|
||||||
|
- **Typst ≥ 0.14.0**;请使用较新版本的 Tinymist 或 Typst CLI
|
||||||
|
- 首次编译会自动下载 `cmarker`、`codly`、`codly-languages`(需网络)
|
||||||
|
|
||||||
|
## 替换外部 MD
|
||||||
|
|
||||||
|
将同事发来的 `.md` 覆盖 `content/report.md`,图片放入 `content/assets/` 并修正文内路径,重新预览即可。
|
||||||
|
|||||||
BIN
feasibility/content/assets/img.jpg
Normal file
BIN
feasibility/content/assets/img.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 251 KiB |
89
feasibility/content/report.md
Normal file
89
feasibility/content/report.md
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
---
|
||||||
|
title: 铝土矿可行性研究报告
|
||||||
|
company: 西安高岭绿能科技有限公司
|
||||||
|
date: 2026-06-22
|
||||||
|
version: v1.0
|
||||||
|
summary: |
|
||||||
|
本项目拟在目标矿山建设智能矿石分选产线,以高光谱感知、深度学习推理与喷阀执行闭环为核心,实现铝土矿预选抛废与品位提升。经现场调研与算法验证,单线设计处理量 25 t/h,精矿 A/S 可达 4.0+,具备工程化落地条件。
|
||||||
|
---
|
||||||
|
|
||||||
|
# 项目概述
|
||||||
|
|
||||||
|
本项目面向铝土矿预选场景,建设「感知—推理—执行—运维」一体化的智能分选系统,将算法能力转化为可部署、可运维的工业产品,降低后续磨选成本并提升资源利用率。
|
||||||
|
|
||||||
|
> 引用块示例:政策与市场需求推动预选抛废技术应用,本段为 blockquote 样式预览。
|
||||||
|
|
||||||
|
**常用 Markdown 语法预览:**
|
||||||
|
|
||||||
|
- **加粗**:单线处理量 `25 t/h`
|
||||||
|
- *斜体*:用于强调术语
|
||||||
|
- ~~删除线~~:已废弃方案
|
||||||
|
- <u>下划线</u>:关键指标标注
|
||||||
|
- Emoji:产线状态 🐱 正常 / ⚠️ 告警
|
||||||
|
- 行内代码:`ONNX Runtime`、`Ratatui`
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 推理回调示例
|
||||||
|
for sample in belt_stream:
|
||||||
|
grade = model.infer(sample)
|
||||||
|
valve.fire(grade)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 项目概述2
|
||||||
|
|
||||||
|
建设内容包括:产线感知与推理控制软件、运营后台、运维工具及现场联调交付。
|
||||||
|
|
||||||
|
# 建设必要性与市场分析
|
||||||
|
|
||||||
|
铝土矿原料品位波动大,传统全量入磨能耗高、尾矿处置压力大。政策层面,绿色矿山与节能降碳要求推动预选抛废技术应用。目标客户在降本增效与环保合规方面需求明确,智能分选在预选环节具备可复制推广价值。
|
||||||
|
|
||||||
|
# 技术方案
|
||||||
|
|
||||||
|
系统采用 <!--raw-typst #gls-long("hsi") --> 与 <!--raw-typst #gls-short("onnx") --> 推理引擎,构建边缘推理与喷阀执行闭环架构。
|
||||||
|
|
||||||
|
<!--raw-typst #ore-sorting-flow()-->
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
核心技术路线:
|
||||||
|
|
||||||
|
- 高光谱采集与样本标准化处理
|
||||||
|
- ONNX 推理服务与产线实时回调
|
||||||
|
- Rust 运维控制台与产线状态监控
|
||||||
|
|
||||||
|
## 验证指标(实验室 / 现场)
|
||||||
|
|
||||||
|
| 指标 | 设计值 | 验证情况 |
|
||||||
|
| ---- | ------ | -------- |
|
||||||
|
| 单线处理量 | 25 t/h | 已验证 |
|
||||||
|
| 精矿 <!--raw-typst #gls-short("as-ratio") --> | ≥ 4.0 | 4.0+ |
|
||||||
|
| 尾矿 A/S | ≤ 1.7 | 1.7- |
|
||||||
|
| 回收率 | ≥ 30% | 30%+ |
|
||||||
|
|
||||||
|
# 实施计划
|
||||||
|
|
||||||
|
1. **研发验证**(1–2 月):算法迭代、软件模块开发与台架测试。
|
||||||
|
2. **试点部署**(2–3 月):单线现场安装、联调与试运行。
|
||||||
|
3. **规模化推广**(持续):复制部署、运维体系与客户培训。
|
||||||
|
|
||||||
|
# 投资估算与资金用途
|
||||||
|
|
||||||
|
投资主要用于光谱传感与执行机构硬件、软件开发与现场实施、人员与运维体系建设。具体金额结合矿山规模与产线配置在商务阶段细化。
|
||||||
|
|
||||||
|
# 效益分析
|
||||||
|
|
||||||
|
- **经济效益**:减少入磨量,降低能耗与药剂成本;提升精矿品位与回收率。
|
||||||
|
- **环保效益**:减少尾矿产生量,降低固废处置压力。
|
||||||
|
- **社会效益**:支撑绿色矿山建设,提升企业技术形象。
|
||||||
|
|
||||||
|
# 风险分析与对策
|
||||||
|
|
||||||
|
| 风险 | 对策 |
|
||||||
|
| ---- | ---- |
|
||||||
|
| 原料波动影响模型稳定性 | 持续采样标注与模型迭代;异常降级策略 |
|
||||||
|
| 现场交付周期 | 标准化模块与运维工具;阶段里程碑管控 |
|
||||||
|
| 客户接受度 | 试点数据透明展示;可量化的效益测算 |
|
||||||
|
|
||||||
|
# 结论
|
||||||
|
|
||||||
|
综合技术验证、市场需求与实施条件,本项目具备可行性。建议推进试点产线建设,以现场数据支撑后续规模化复制。
|
||||||
38
feasibility/data/code.typ
Normal file
38
feasibility/data/code.typ
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#import "@preview/codly:1.3.0": *
|
||||||
|
#import "@preview/codly-languages:0.1.10": codly-languages
|
||||||
|
#import "theme.typ": *
|
||||||
|
|
||||||
|
#let codly-init-rule = codly-init.with()
|
||||||
|
|
||||||
|
#let codly-config = codly(
|
||||||
|
languages: codly-languages,
|
||||||
|
fill: code-block-fill,
|
||||||
|
radius: code-block-radius,
|
||||||
|
stroke: none,
|
||||||
|
zebra-fill: none,
|
||||||
|
number-format: none,
|
||||||
|
display-icon: false,
|
||||||
|
display-name: true,
|
||||||
|
default-color: color-body,
|
||||||
|
lang-stroke: (_) => none,
|
||||||
|
lang-fill: (_) => code-block-fill,
|
||||||
|
lang-radius: 0pt,
|
||||||
|
)
|
||||||
|
|
||||||
|
/// 与 codly 配合的语法高亮色(须在 codly-init 之后注册)
|
||||||
|
#let code-token-highlight-init(doc) = {
|
||||||
|
show raw.where(block: true): it => {
|
||||||
|
show "keyword": set text(fill: code-token-keyword)
|
||||||
|
show "comment": set text(fill: code-token-comment)
|
||||||
|
show "string": set text(fill: code-token-string)
|
||||||
|
show "number": set text(fill: code-token-number)
|
||||||
|
show "builtin": set text(fill: code-token-function)
|
||||||
|
show "function": set text(fill: code-token-function)
|
||||||
|
show "decor": set text(fill: code-token-function)
|
||||||
|
show "operator": set text(fill: code-token-operator)
|
||||||
|
show "punctuation": set text(fill: code-token-operator)
|
||||||
|
set text(fill: color-body)
|
||||||
|
it
|
||||||
|
}
|
||||||
|
doc
|
||||||
|
}
|
||||||
@ -1,64 +1,11 @@
|
|||||||
// =============================================================================
|
// =============================================================================
|
||||||
// 可行性报告 — 修改此处定制内容
|
// 可行性报告 — 默认值(正文在 content/report.md,YAML 可覆盖下列字段)
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
#let company-name = "西安高岭绿能科技有限公司"
|
#let default-brand = "GreLin"
|
||||||
#let project-name = "智能矿石分选系统建设项目"
|
#let default-company = "西安高岭绿能科技有限公司"
|
||||||
#let report-version = "v0.1"
|
#let default-title = "智能矿石分选系统建设项目"
|
||||||
#let report-date = "2026 年 6 月"
|
#let default-version = "v1.0"
|
||||||
|
#let default-date = "2026 年 6 月"
|
||||||
|
|
||||||
#let report-summary = [
|
#let content-path = "content/report.md"
|
||||||
本项目旨在建设面向铝土矿等矿石场景的智能分选软硬件一体化系统,将分选算法工程化为可部署、可运维的产线产品,形成从算法接入、设备控制、运营后台到监控运维的完整闭环,支撑绿色高效矿物加工。
|
|
||||||
]
|
|
||||||
|
|
||||||
#let sections = (
|
|
||||||
(
|
|
||||||
title: "一、项目概述",
|
|
||||||
body: [
|
|
||||||
说明项目背景、建设目标、建设内容与预期成果。可引用 BP 中的产品定位与目标客户。
|
|
||||||
],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
title: "二、建设必要性与市场分析",
|
|
||||||
body: [
|
|
||||||
行业痛点、政策与环保驱动、目标市场规模与竞争格局。建议配合 BP 市场章节数据。
|
|
||||||
],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
title: "三、技术方案",
|
|
||||||
body: [
|
|
||||||
系统架构(感知、推理、控制、后台、运维)、核心技术路线、与现有产线对接方式。
|
|
||||||
可补充已验证指标:精矿 A/S、尾矿 A/S、回收率、处理量等。
|
|
||||||
],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
title: "四、实施计划",
|
|
||||||
body: [
|
|
||||||
阶段划分(研发验证 → 试点部署 → 规模化推广)、里程碑、团队分工与关键依赖。
|
|
||||||
],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
title: "五、投资估算与资金用途",
|
|
||||||
body: [
|
|
||||||
硬件、软件、人员、市场等费用结构。与 BP 财务预测保持一致。
|
|
||||||
],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
title: "六、效益分析",
|
|
||||||
body: [
|
|
||||||
经济效益(降本增效、回收率提升)、社会效益与环保效益。尽量量化。
|
|
||||||
],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
title: "七、风险分析与对策",
|
|
||||||
body: [
|
|
||||||
技术、市场、交付、政策等风险及应对措施。
|
|
||||||
],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
title: "八、结论",
|
|
||||||
body: [
|
|
||||||
综合可行性判断与建议。
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|||||||
51
feasibility/data/decor.typ
Normal file
51
feasibility/data/decor.typ
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#import "theme.typ": *
|
||||||
|
|
||||||
|
/// 点阵底纹
|
||||||
|
#let tech-dots(width: 100%, height: 100%, step: 10pt) = box(width: width, height: height, clip: true)[
|
||||||
|
#for x in range(40) {
|
||||||
|
for y in range(40) {
|
||||||
|
place(
|
||||||
|
left + top,
|
||||||
|
dx: x * step,
|
||||||
|
dy: y * step,
|
||||||
|
circle(radius: 0.35pt, fill: color-grid),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
/// 条形码条
|
||||||
|
#let tech-barcode(width, height, bars: 28) = box(width: width, height: height, clip: true)[
|
||||||
|
#for i in range(bars) {
|
||||||
|
let w = if calc.rem(i, 4) == 0 { 2.2pt } else if calc.rem(i, 2) == 0 { 1.4pt } else { 0.8pt }
|
||||||
|
place(
|
||||||
|
left + top,
|
||||||
|
dx: i * (width / bars),
|
||||||
|
box(width: w, height: 100%, fill: color-ink),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
/// 等宽标签
|
||||||
|
#let tech-label(body, fill: color-ink, size: 7pt) = text(
|
||||||
|
font: mono-font,
|
||||||
|
size: size,
|
||||||
|
fill: fill,
|
||||||
|
tracking: 0.14em,
|
||||||
|
)[#body]
|
||||||
|
|
||||||
|
/// 章节编号
|
||||||
|
#let section-tech-id(..nums) = {
|
||||||
|
let n = nums.pos()
|
||||||
|
let id = if n.len() == 1 {
|
||||||
|
let num = n.first()
|
||||||
|
if num < 10 { "0" + str(num) } else { str(num) }
|
||||||
|
} else if n.len() == 2 {
|
||||||
|
str(n.at(0)) + "." + str(n.at(1))
|
||||||
|
} else {
|
||||||
|
str(n.at(0)) + "." + str(n.at(1)) + "." + str(n.at(2))
|
||||||
|
}
|
||||||
|
box(fill: color-neon, inset: (x: 5pt, y: 2pt))[
|
||||||
|
#text(font: mono-font, size: 7pt, weight: "bold", fill: color-ink)[#id]
|
||||||
|
]
|
||||||
|
}
|
||||||
33
feasibility/data/diagrams.typ
Normal file
33
feasibility/data/diagrams.typ
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#import "@preview/cetz:0.3.4"
|
||||||
|
#import "theme.typ": *
|
||||||
|
|
||||||
|
#let ore-sorting-flow() = figure(
|
||||||
|
caption: [智能分选系统流程(CeTZ 矢量示意)],
|
||||||
|
cetz.canvas(length: 0.85cm, {
|
||||||
|
import cetz.draw: *
|
||||||
|
let w = 1.7
|
||||||
|
let gap = 0.55
|
||||||
|
let labels = ("采集", "推理", "分选", "产出")
|
||||||
|
for (i, label) in labels.enumerate() {
|
||||||
|
let x = i * (w + gap)
|
||||||
|
rect(
|
||||||
|
(x, 0),
|
||||||
|
(x + w, 1),
|
||||||
|
radius: 0.12,
|
||||||
|
fill: color-brand.lighten(72%),
|
||||||
|
stroke: 1pt + color-brand,
|
||||||
|
)
|
||||||
|
content((x + w / 2, 0.5), align(center + horizon)[
|
||||||
|
#text(font: body-font, size: 8pt, fill: color-body)[#label]
|
||||||
|
])
|
||||||
|
if i < labels.len() - 1 {
|
||||||
|
line(
|
||||||
|
(x + w, 0.5),
|
||||||
|
(x + w + gap, 0.5),
|
||||||
|
stroke: 1pt + color-muted,
|
||||||
|
mark: (end: ">", fill: color-muted),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
43
feasibility/data/glossary.typ
Normal file
43
feasibility/data/glossary.typ
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#import "@preview/glossarium:0.5.10": make-glossary, register-glossary, print-glossary, gls-long, gls-short
|
||||||
|
#import "theme.typ": *
|
||||||
|
|
||||||
|
#let glossary-entries = (
|
||||||
|
(
|
||||||
|
key: "hsi",
|
||||||
|
short: "HSI",
|
||||||
|
long: "高光谱成像",
|
||||||
|
description: "Hyperspectral Imaging,获取矿石连续波段光谱信息。",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
key: "onnx",
|
||||||
|
short: "ONNX",
|
||||||
|
long: "开放神经网络交换格式",
|
||||||
|
description: "Open Neural Network Exchange,用于跨平台模型推理部署。",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
key: "as-ratio",
|
||||||
|
short: "A/S",
|
||||||
|
long: "铝硅比",
|
||||||
|
description: "精矿品质评价的关键指标之一。",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
#let init-glossary(doc) = {
|
||||||
|
show: make-glossary
|
||||||
|
doc
|
||||||
|
}
|
||||||
|
|
||||||
|
#let register-report-glossary() = {
|
||||||
|
register-glossary(glossary-entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let print-glossary-block() = {
|
||||||
|
pagebreak(weak: true)
|
||||||
|
block(width: 100%, above: space-chapter)[
|
||||||
|
#box(width: 100%, fill: color-neon, inset: (x: 10pt, y: 6pt))[
|
||||||
|
#text(font: heading-font, size: size-h1, weight: "black", fill: color-ink)[术语与缩写]
|
||||||
|
]
|
||||||
|
#v(space-block)
|
||||||
|
#print-glossary(glossary-entries, show-all: true)
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -1,43 +1,148 @@
|
|||||||
#import "theme.typ": *
|
#import "theme.typ": *
|
||||||
#import "config.typ": *
|
#import "logo.typ": grelin-logo, cover-index-badge
|
||||||
|
#import "decor.typ": tech-dots, tech-barcode, tech-label
|
||||||
|
|
||||||
#let report-title-block() = block(width: 100%, below: space-section)[
|
#let format-cover-date(date) = {
|
||||||
#align(center)[
|
let parts = date.split("-")
|
||||||
#text(font: heading-font, size: size-title, weight: "bold", fill: color-ink)[
|
if parts.len() == 3 {
|
||||||
#project-name
|
parts.at(0) + "." + parts.at(1) + "." + parts.at(2)
|
||||||
]
|
} else {
|
||||||
#v(6pt)
|
date
|
||||||
#text(font: heading-font, size: size-h2, fill: color-muted)[可行性研究报告]
|
}
|
||||||
#v(10pt)
|
}
|
||||||
#text(size: size-meta, fill: color-muted)[
|
|
||||||
#company-name #sym.bar #report-version #sym.bar #report-date
|
#let cover-meta-strip(meta) = box(
|
||||||
]
|
width: 100%,
|
||||||
]
|
fill: color-ink,
|
||||||
#v(space-section)
|
inset: (x: 12pt, y: 8pt),
|
||||||
#line(length: 100%, stroke: color-divider + 0.6pt)
|
)[
|
||||||
|
#grid(
|
||||||
|
columns: (1fr, auto, 1fr, auto, 1fr),
|
||||||
|
column-gutter: 12pt,
|
||||||
|
align: horizon,
|
||||||
|
tech-label("VERSION", fill: color-neon, size: 6.5pt),
|
||||||
|
text(font: mono-font, size: 8pt, fill: white)[#meta.version],
|
||||||
|
tech-label("DATE", fill: color-neon, size: 6.5pt),
|
||||||
|
text(font: mono-font, size: 8pt, fill: white)[#format-cover-date(meta.date)],
|
||||||
|
align(right)[
|
||||||
|
tech-label("STATUS · DRAFT", fill: color-neon, size: 6.5pt)
|
||||||
|
],
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
#let section-block(section) = block(width: 100%, above: space-section, below: space-block)[
|
#let cover-block(meta) = {
|
||||||
#text(font: heading-font, size: size-h1, weight: "bold", fill: color-ink)[#section.title]
|
pagebreak(weak: true)
|
||||||
#v(6pt)
|
block(width: 100%, below: space-chapter)[
|
||||||
#box(width: 18pt, height: 3pt, fill: color-accent)
|
#box(width: 100%, height: cover-block-height, fill: white)[
|
||||||
#v(8pt)
|
#place(top + left)[#grelin-logo()]
|
||||||
#set par(leading: leading-body, spacing: 6pt, justify: true)
|
#place(top + right)[#cover-index-badge("01")]
|
||||||
#set text(size: size-body, fill: color-body)
|
|
||||||
#section.body
|
#place(left + top, dy: 52pt)[#tech-barcode(14pt, 120pt, bars: 5)]
|
||||||
|
#place(right + top, dy: 72pt)[
|
||||||
|
#rotate(-90deg, reflow: true)[
|
||||||
|
#tech-label("FEASIBILITY REPORT", fill: color-caption, size: 6.5pt)
|
||||||
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
#let summary-block() = block(width: 100%, above: space-block, below: space-section)[
|
#place(left + top, dx: 28pt, dy: 100pt)[
|
||||||
#text(font: heading-font, size: size-h2, weight: "bold", fill: color-ink)[摘要]
|
#box(width: 88%, height: 130pt, clip: true)[#tech-dots(width: 100%, height: 100%, step: 11pt)]
|
||||||
#v(6pt)
|
]
|
||||||
|
|
||||||
|
#place(left + top, dx: 24pt, dy: 168pt)[
|
||||||
|
#box(width: 92%, fill: color-neon, inset: (x: 16pt, y: 18pt))[
|
||||||
|
#text(
|
||||||
|
font: heading-font,
|
||||||
|
size: size-cover-title,
|
||||||
|
weight: "black",
|
||||||
|
fill: color-ink,
|
||||||
|
hyphenate: false,
|
||||||
|
)[#meta.title]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
#place(left + bottom, dy: -36pt)[
|
||||||
|
#box(width: 100%)[#cover-meta-strip(meta)]
|
||||||
|
]
|
||||||
|
|
||||||
|
#place(left + bottom, dy: -8pt)[
|
||||||
|
#tech-barcode(100%, 10pt, bars: 48)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
pagebreak()
|
||||||
|
}
|
||||||
|
|
||||||
|
#let accent-line() = box(width: 100%, height: 2pt, fill: color-ink)
|
||||||
|
|
||||||
|
#let summary-block(meta) = {
|
||||||
|
if meta.summary != "" {
|
||||||
|
block(width: 100%, above: space-block, below: space-chapter)[
|
||||||
#box(
|
#box(
|
||||||
width: 100%,
|
width: 100%,
|
||||||
fill: color-bar-bg,
|
fill: white,
|
||||||
inset: 10pt,
|
stroke: 1.5pt + color-ink,
|
||||||
radius: 4pt,
|
inset: summary-inset,
|
||||||
)[
|
)[
|
||||||
#set par(leading: leading-body, justify: true)
|
#box(width: 100%, fill: color-neon, inset: (x: 10pt, y: 5pt))[
|
||||||
|
#tech-label("ABSTRACT", fill: color-ink, size: 7pt)
|
||||||
|
]
|
||||||
|
#v(10pt)
|
||||||
|
#text(font: heading-font, size: size-h2, weight: "black", fill: color-ink)[摘要]
|
||||||
|
#v(space-block)
|
||||||
|
#set par(leading: leading-summary, justify: true)
|
||||||
#set text(size: size-body, fill: color-body)
|
#set text(size: size-body, fill: color-body)
|
||||||
#report-summary
|
#meta.summary
|
||||||
|
#v(space-section)
|
||||||
|
#grid(
|
||||||
|
columns: (auto, 1fr, auto, 1fr),
|
||||||
|
column-gutter: 8pt,
|
||||||
|
align: horizon,
|
||||||
|
tech-label("DATE", size: 6.5pt),
|
||||||
|
text(font: mono-font, size: size-meta, fill: color-body)[#meta.date],
|
||||||
|
tech-label("ORG", size: 6.5pt),
|
||||||
|
text(font: mono-font, size: size-meta, fill: color-body)[#meta.company],
|
||||||
|
)
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#let page-footer() = context {
|
||||||
|
grid(
|
||||||
|
columns: (auto, 1fr, auto),
|
||||||
|
align: horizon,
|
||||||
|
tech-barcode(36pt, 8pt, bars: 10),
|
||||||
|
box(width: 100%, height: 1pt, fill: color-ink),
|
||||||
|
box(fill: color-ink, inset: (x: 8pt, y: 3pt))[
|
||||||
|
#text(font: mono-font, size: 8pt, fill: color-neon)[
|
||||||
|
#counter(page).display("1")
|
||||||
|
#h(0.12em)
|
||||||
|
#sym.slash
|
||||||
|
#h(0.12em)
|
||||||
|
#counter(page).final().first()
|
||||||
|
]
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let page-accent-bar() = place(
|
||||||
|
left + top,
|
||||||
|
tech-barcode(page-accent-bar-width, 100%, bars: 4),
|
||||||
|
)
|
||||||
|
|
||||||
|
#let page-header(meta) = [
|
||||||
|
#grid(
|
||||||
|
columns: (auto, 1fr, auto),
|
||||||
|
column-gutter: 8pt,
|
||||||
|
align: horizon,
|
||||||
|
box(fill: color-neon, inset: (x: 6pt, y: 2pt))[
|
||||||
|
#text(font: mono-font, size: 7pt, weight: "bold", fill: color-ink)[#upper(meta.brand)]
|
||||||
|
],
|
||||||
|
box(width: 100%, height: 1pt, fill: color-ink),
|
||||||
|
align(right)[
|
||||||
|
#text(font: mono-font, size: 7pt, fill: color-caption)[#meta.title]
|
||||||
|
],
|
||||||
|
)
|
||||||
|
#v(6pt)
|
||||||
|
#accent-line()
|
||||||
|
]
|
||||||
|
|||||||
37
feasibility/data/logo.typ
Normal file
37
feasibility/data/logo.typ
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#import "theme.typ": *
|
||||||
|
#import "decor.typ": tech-label
|
||||||
|
|
||||||
|
/// Logo:霓虹绿块 + 白色折线图形 + GreLin | Tech
|
||||||
|
#let grelin-logo(
|
||||||
|
primary: "GreLin",
|
||||||
|
secondary: "Tech",
|
||||||
|
) = grid(
|
||||||
|
columns: (auto, auto),
|
||||||
|
column-gutter: 10pt,
|
||||||
|
align: horizon,
|
||||||
|
box(width: 34pt, height: 34pt, fill: color-neon)[
|
||||||
|
#place(left + top, dx: 7pt, dy: 8pt, box(width: 14pt, height: 3pt, fill: white))
|
||||||
|
#place(left + top, dx: 7pt, dy: 14pt, box(width: 3pt, height: 14pt, fill: white))
|
||||||
|
#place(left + top, dx: 18pt, dy: 14pt, box(width: 9pt, height: 3pt, fill: white))
|
||||||
|
#place(left + top, dx: 18pt, dy: 17pt, box(width: 3pt, height: 11pt, fill: white))
|
||||||
|
],
|
||||||
|
grid(
|
||||||
|
columns: (auto, auto, auto),
|
||||||
|
column-gutter: 7pt,
|
||||||
|
align: horizon,
|
||||||
|
text(font: heading-font, size: 12pt, weight: "black", fill: color-ink, tracking: 0.04em)[#primary],
|
||||||
|
box(width: 1.2pt, height: 1em, fill: color-ink),
|
||||||
|
text(font: heading-font, size: 12pt, weight: "black", fill: color-ink, tracking: 0.16em)[#secondary],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
#let cover-index-badge(index) = box(
|
||||||
|
width: 58pt,
|
||||||
|
height: 58pt,
|
||||||
|
stroke: 2pt + color-ink,
|
||||||
|
fill: white,
|
||||||
|
)[
|
||||||
|
#align(center + horizon)[
|
||||||
|
#text(font: mono-font, size: size-cover-index, weight: "black", fill: color-ink)[#index]
|
||||||
|
]
|
||||||
|
]
|
||||||
70
feasibility/data/md.typ
Normal file
70
feasibility/data/md.typ
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#import "@preview/cmarker:0.1.8": render-with-metadata
|
||||||
|
#import "config.typ": *
|
||||||
|
#import "theme.typ": *
|
||||||
|
#import "styling.typ": underline-accent
|
||||||
|
|
||||||
|
#let source-dir(path) = {
|
||||||
|
let parts = path.split("/")
|
||||||
|
if parts.len() <= 1 {
|
||||||
|
""
|
||||||
|
} else {
|
||||||
|
parts.slice(0, parts.len() - 1).join("/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#let resolve-image(source-path, source, alt: none) = {
|
||||||
|
let dir = source-dir(source-path)
|
||||||
|
let full = if dir == "" { source } else { dir + "/" + source }
|
||||||
|
let path = "../" + full
|
||||||
|
let img = image(path, width: image-max-width, fit: "contain")
|
||||||
|
if alt != none and alt != "" {
|
||||||
|
block(width: 100%)[
|
||||||
|
#align(center)[#img]
|
||||||
|
#v(space-micro)
|
||||||
|
#align(center)[
|
||||||
|
#text(size: size-caption, fill: color-caption)[#alt]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
img
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#let meta-string(meta, key, fallback) = {
|
||||||
|
let value = meta.at(key, default: none)
|
||||||
|
if value == none {
|
||||||
|
fallback
|
||||||
|
} else if type(value) == str {
|
||||||
|
value
|
||||||
|
} else {
|
||||||
|
str(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#let merge-meta(yaml) = (
|
||||||
|
title: meta-string(yaml, "title", default-title),
|
||||||
|
brand: meta-string(yaml, "brand", default-brand),
|
||||||
|
company: meta-string(yaml, "company", default-company),
|
||||||
|
version: meta-string(yaml, "version", default-version),
|
||||||
|
date: meta-string(yaml, "date", default-date),
|
||||||
|
summary: yaml.at("summary", default: ""),
|
||||||
|
)
|
||||||
|
|
||||||
|
#let load-report-md(markdown, source-path: content-path, extra-scope: (:)) = {
|
||||||
|
let (yaml, body) = render-with-metadata(
|
||||||
|
markdown,
|
||||||
|
metadata-block: "frontmatter-yaml",
|
||||||
|
smart-punctuation: true,
|
||||||
|
html: (
|
||||||
|
u: (_, body) => underline-accent(body),
|
||||||
|
),
|
||||||
|
scope: (
|
||||||
|
image: (source, alt: none) => resolve-image(source-path, source, alt: alt),
|
||||||
|
..extra-scope,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
(
|
||||||
|
metadata: merge-meta(if yaml == none { (:) } else { yaml }),
|
||||||
|
body: body,
|
||||||
|
)
|
||||||
|
}
|
||||||
160
feasibility/data/styling.typ
Normal file
160
feasibility/data/styling.typ
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
#import "theme.typ": *
|
||||||
|
#import "decor.typ": section-tech-id, tech-label
|
||||||
|
|
||||||
|
#let underline-accent(body) = underline(
|
||||||
|
body,
|
||||||
|
stroke: underline-stroke,
|
||||||
|
offset: underline-offset,
|
||||||
|
evade: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
#let heading-number(it) = {
|
||||||
|
if it.numbering != none {
|
||||||
|
counter(heading).display(it.numbering)
|
||||||
|
h(heading-number-gap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#let report-heading-numbering(..nums) = {
|
||||||
|
let n = nums.pos()
|
||||||
|
if n.len() == 1 {
|
||||||
|
numbering("1.", n.first())
|
||||||
|
} else if n.len() == 2 {
|
||||||
|
numbering("1.1", n.at(0), n.at(1))
|
||||||
|
} else {
|
||||||
|
numbering("1.1.1", ..n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#let grelin-h1(it) = block(
|
||||||
|
width: 100%,
|
||||||
|
above: space-chapter,
|
||||||
|
below: space-block,
|
||||||
|
)[
|
||||||
|
#grid(
|
||||||
|
columns: (auto, 1fr),
|
||||||
|
column-gutter: 8pt,
|
||||||
|
align: horizon,
|
||||||
|
context section-tech-id(..counter(heading).get()),
|
||||||
|
box(width: 100%, fill: color-neon, inset: (x: 8pt, y: 4pt))[
|
||||||
|
#text(font: heading-font, size: size-h1, weight: "black", fill: color-ink)[
|
||||||
|
#heading-number(it)
|
||||||
|
#it.body
|
||||||
|
]
|
||||||
|
],
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
#let grelin-h2(it) = block(width: 100%, above: space-section, below: space-inline)[
|
||||||
|
#grid(
|
||||||
|
columns: (auto, 1fr),
|
||||||
|
column-gutter: 8pt,
|
||||||
|
align: horizon,
|
||||||
|
box(width: 3pt, height: 1em, fill: color-ink),
|
||||||
|
text(font: heading-font, size: size-h2, weight: "bold", fill: color-ink)[
|
||||||
|
#heading-number(it)
|
||||||
|
#it.body
|
||||||
|
],
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
#let grelin-h3(it) = block(width: 100%, above: space-block, below: space-micro)[
|
||||||
|
#grid(
|
||||||
|
columns: (auto, 1fr),
|
||||||
|
column-gutter: 6pt,
|
||||||
|
align: horizon,
|
||||||
|
tech-label("///", size: 6.5pt),
|
||||||
|
text(font: heading-font, size: size-h3, weight: "bold", fill: color-ink)[
|
||||||
|
#heading-number(it)
|
||||||
|
#it.body
|
||||||
|
],
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
#let grelin-image(it) = block(
|
||||||
|
width: 100%,
|
||||||
|
above: space-figure-before,
|
||||||
|
below: space-figure-after,
|
||||||
|
)[
|
||||||
|
#align(center)[
|
||||||
|
#box(width: image-max-width, stroke: 1pt + color-ink)[
|
||||||
|
#set image(width: 100%, fit: "contain")
|
||||||
|
#it
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
#let grelin-table(it) = block(
|
||||||
|
width: 100%,
|
||||||
|
above: space-figure-before,
|
||||||
|
below: space-figure-after,
|
||||||
|
)[
|
||||||
|
#it
|
||||||
|
]
|
||||||
|
|
||||||
|
#let grelin-figure(it) = block(
|
||||||
|
width: 100%,
|
||||||
|
above: space-figure-before,
|
||||||
|
below: space-figure-after,
|
||||||
|
)[
|
||||||
|
#align(center)[
|
||||||
|
#set image(width: image-max-width, fit: "contain")
|
||||||
|
#set text(size: size-caption, fill: color-caption)
|
||||||
|
#it
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
#let grelin-blockquote(it) = block(
|
||||||
|
width: 100%,
|
||||||
|
above: space-block,
|
||||||
|
below: space-block,
|
||||||
|
inset: (left: blockquote-inset),
|
||||||
|
stroke: (left: blockquote-stroke),
|
||||||
|
fill: white,
|
||||||
|
)[
|
||||||
|
#set par(leading: leading-body, justify: true)
|
||||||
|
#set text(fill: color-quote)
|
||||||
|
#it
|
||||||
|
]
|
||||||
|
|
||||||
|
#let grelin-inline-code(it) = box(
|
||||||
|
fill: code-inline-fill,
|
||||||
|
inset: code-inline-inset,
|
||||||
|
stroke: 0.8pt + color-ink,
|
||||||
|
)[
|
||||||
|
#set text(font: mono-font, size: size-body, fill: color-code-inline)
|
||||||
|
#it
|
||||||
|
]
|
||||||
|
|
||||||
|
#let apply-report-styling(body) = {
|
||||||
|
set heading(numbering: report-heading-numbering)
|
||||||
|
set text(size: size-table)
|
||||||
|
set table(
|
||||||
|
stroke: (x, y) => (
|
||||||
|
top: if y == 0 { 1.5pt + color-ink } else { none },
|
||||||
|
bottom: if y == 0 { 0.8pt + color-ink } else { none },
|
||||||
|
),
|
||||||
|
inset: table-inset,
|
||||||
|
align: (col, row) => if col == 0 { left + horizon } else { center + horizon },
|
||||||
|
fill: (col, row) => {
|
||||||
|
if row == 0 {
|
||||||
|
table-header-fill
|
||||||
|
} else if calc.rem(row, 2) == 0 {
|
||||||
|
table-zebra-fill
|
||||||
|
} else {
|
||||||
|
white
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
show heading.where(level: 1): grelin-h1
|
||||||
|
show heading.where(level: 2): grelin-h2
|
||||||
|
show heading.where(level: 3): grelin-h3
|
||||||
|
show image: grelin-image
|
||||||
|
show table.cell: set text(fill: table-data-text)
|
||||||
|
show table.cell.where(y: 0): set text(weight: "bold", fill: color-ink)
|
||||||
|
show table: grelin-table
|
||||||
|
show figure: grelin-figure
|
||||||
|
show quote.where(block: true): grelin-blockquote
|
||||||
|
show raw.where(block: false): grelin-inline-code
|
||||||
|
body
|
||||||
|
}
|
||||||
@ -1,24 +1,102 @@
|
|||||||
#import "../../brand/colors.typ": *
|
#import "../../brand/colors.typ": *
|
||||||
|
|
||||||
#let color-accent = color-lime-mid
|
// Brutalist / FUI 配色:霓虹绿 · 纯黑 · 冷灰(避免橄榄灰发脏)
|
||||||
#let color-divider = color-muted.lighten(68%)
|
#let color-neon = rgb(210, 255, 72)
|
||||||
|
#let color-heading = color-neon
|
||||||
|
#let color-accent = color-neon
|
||||||
|
#let color-accent-line = color-ink
|
||||||
|
#let color-divider = rgb(205, 205, 205)
|
||||||
|
#let color-caption = rgb(110, 110, 110)
|
||||||
|
#let color-quote = rgb(90, 90, 90)
|
||||||
|
#let color-code-lang = rgb(90, 90, 90)
|
||||||
|
#let color-code-inline = color-ink
|
||||||
|
#let color-header = color-ink
|
||||||
|
#let color-page = rgb(238, 238, 238)
|
||||||
|
#let color-bar-bg = rgb(248, 248, 248)
|
||||||
|
#let color-grid = rgb(220, 220, 220)
|
||||||
|
|
||||||
#let heading-font = ("Microsoft YaHei", "Segoe UI")
|
// 代码块语法高亮
|
||||||
#let body-font = ("Microsoft YaHei UI", "Microsoft YaHei", "Segoe UI")
|
#let code-token-keyword = color-ink
|
||||||
|
#let code-token-comment = rgb(130, 130, 130)
|
||||||
|
#let code-token-string = rgb(40, 40, 40)
|
||||||
|
#let code-token-number = rgb(70, 70, 70)
|
||||||
|
#let code-token-function = color-ink
|
||||||
|
#let code-token-operator = rgb(100, 100, 100)
|
||||||
|
|
||||||
|
#let heading-font = ("Microsoft YaHei", "Segoe UI", "Segoe UI Emoji")
|
||||||
|
#let body-font = ("Microsoft YaHei UI", "Microsoft YaHei", "Segoe UI", "Segoe UI Emoji")
|
||||||
|
#let mono-font = ("Consolas", "Cascadia Mono", "Microsoft YaHei UI")
|
||||||
|
|
||||||
|
// =====================================================================
|
||||||
|
// GreLin Feasibility Report · Design Tokens
|
||||||
|
// =====================================================================
|
||||||
|
|
||||||
|
// --- 字号 ---
|
||||||
#let size-title = 22pt
|
#let size-title = 22pt
|
||||||
|
#let size-cover-title = 34pt
|
||||||
|
#let size-cover-index = 52pt
|
||||||
#let size-h1 = 14pt
|
#let size-h1 = 14pt
|
||||||
#let size-h2 = 12pt
|
#let size-h2 = 12pt
|
||||||
|
#let size-h3 = 11pt
|
||||||
#let size-body = 10.5pt
|
#let size-body = 10.5pt
|
||||||
#let size-meta = 9pt
|
#let size-meta = 9pt
|
||||||
|
#let size-table = 9pt
|
||||||
|
#let size-caption = size-meta
|
||||||
|
|
||||||
|
// --- 行距 ---
|
||||||
#let leading-body = 12.5pt
|
#let leading-body = 12.5pt
|
||||||
#let space-section = 14pt
|
#let leading-summary = leading-body
|
||||||
#let space-block = 10pt
|
|
||||||
|
|
||||||
|
// --- 间距 ---
|
||||||
|
#let space-none = 0pt
|
||||||
|
#let space-micro = 4pt
|
||||||
|
#let space-inline = 6pt
|
||||||
|
#let space-block = 10pt
|
||||||
|
#let space-section = 12pt
|
||||||
|
#let space-chapter = 18pt
|
||||||
|
#let space-figure-before = space-block
|
||||||
|
#let space-figure-after = space-section
|
||||||
|
#let space-cover-line = 3pt
|
||||||
|
#let space-cover-title = 3pt
|
||||||
|
#let space-cover-meta = 6pt
|
||||||
|
#let cover-block-height = 19.5cm
|
||||||
|
|
||||||
|
// --- 线条 / 边框 ---
|
||||||
|
#let underline-stroke = 2pt + color-neon
|
||||||
|
#let underline-offset = 5pt
|
||||||
|
#let heading-number-gap = 0.35em
|
||||||
|
#let stroke-accent = 1.5pt + color-ink
|
||||||
|
#let summary-radius = 0pt
|
||||||
|
#let summary-inset = 14pt
|
||||||
|
|
||||||
|
// --- 页面 ---
|
||||||
#let page-margin = (
|
#let page-margin = (
|
||||||
top: 2.2cm,
|
top: 2.5cm,
|
||||||
bottom: 2cm,
|
bottom: 2.5cm,
|
||||||
left: 2.2cm,
|
left: 2.5cm,
|
||||||
right: 2.2cm,
|
right: 2.5cm,
|
||||||
)
|
)
|
||||||
|
#let page-header-ascent = 1.0cm
|
||||||
|
#let page-footer-descent = 0.8cm
|
||||||
|
#let page-accent-bar-width = 10pt
|
||||||
|
|
||||||
|
// --- 表格 ---
|
||||||
|
#let table-zebra-fill = rgb(245, 255, 228)
|
||||||
|
#let table-header-fill = color-neon
|
||||||
|
#let table-data-text = rgb(50, 50, 50)
|
||||||
|
#let table-inset = (x: 10pt, y: 6pt)
|
||||||
|
|
||||||
|
// --- 图片 ---
|
||||||
|
#let image-max-width = 100%
|
||||||
|
|
||||||
|
// --- 代码 ---
|
||||||
|
#let code-block-inset = 10pt
|
||||||
|
#let code-block-radius = 0pt
|
||||||
|
#let code-block-fill = rgb(255, 255, 255)
|
||||||
|
#let code-inline-fill = rgb(255, 255, 255)
|
||||||
|
#let code-inline-inset = (x: 5pt, y: 0.12em)
|
||||||
|
#let code-inline-radius = 0pt
|
||||||
|
|
||||||
|
// --- 引用 ---
|
||||||
|
#let blockquote-inset = 10pt
|
||||||
|
#let blockquote-stroke = 3pt + color-neon
|
||||||
|
|||||||
@ -1,36 +1,53 @@
|
|||||||
#import "data/config.typ": *
|
#import "data/config.typ": *
|
||||||
#import "data/theme.typ": *
|
#import "data/theme.typ": *
|
||||||
#import "data/layout.typ": *
|
#import "data/glossary.typ": init-glossary, print-glossary-block, register-report-glossary, gls-long, gls-short
|
||||||
|
#import "data/diagrams.typ": ore-sorting-flow
|
||||||
|
#import "data/code.typ": codly-init-rule, codly-config, code-token-highlight-init
|
||||||
|
#import "data/styling.typ": apply-report-styling
|
||||||
|
#import "data/layout.typ": cover-block, summary-block, page-header, page-footer, page-accent-bar
|
||||||
|
#import "data/md.typ": load-report-md
|
||||||
|
|
||||||
|
#show: codly-init-rule
|
||||||
|
#show: code-token-highlight-init
|
||||||
|
#show: init-glossary
|
||||||
|
#codly-config
|
||||||
|
|
||||||
|
#register-report-glossary()
|
||||||
|
|
||||||
|
#let report = load-report-md(
|
||||||
|
read(content-path),
|
||||||
|
source-path: content-path,
|
||||||
|
extra-scope: (
|
||||||
|
ore-sorting-flow: ore-sorting-flow,
|
||||||
|
gls-long: gls-long,
|
||||||
|
gls-short: gls-short,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
#let meta = report.metadata
|
||||||
|
|
||||||
#set page(
|
#set page(
|
||||||
paper: "a4",
|
paper: "a4",
|
||||||
margin: page-margin,
|
margin: page-margin,
|
||||||
|
header-ascent: page-header-ascent,
|
||||||
|
footer-descent: page-footer-descent,
|
||||||
fill: color-page,
|
fill: color-page,
|
||||||
|
background: page-accent-bar(),
|
||||||
header: context {
|
header: context {
|
||||||
if counter(page).get().first() > 1 [
|
if counter(page).get().first() > 1 {
|
||||||
#set text(size: size-meta, fill: color-muted)
|
page-header(meta)
|
||||||
#grid(
|
}
|
||||||
columns: (1fr, 1fr),
|
|
||||||
[#company-name],
|
|
||||||
align(right)[#project-name · 可行性报告],
|
|
||||||
)
|
|
||||||
#v(4pt)
|
|
||||||
#line(length: 100%, stroke: color-divider + 0.5pt)
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
footer: context {
|
footer: context {
|
||||||
set text(size: size-meta, fill: color-muted)
|
if counter(page).get().first() > 1 {
|
||||||
align(center)[#counter(page).display("1")]
|
page-footer()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
#set text(font: body-font, lang: "zh", size: size-body, fill: color-body)
|
#set text(font: body-font, lang: "zh", size: size-body, fill: color-body)
|
||||||
#set par(leading: leading-body, justify: true)
|
#set par(leading: leading-body, justify: true)
|
||||||
#set heading(numbering: none)
|
|
||||||
|
|
||||||
#report-title-block()
|
#cover-block(meta)
|
||||||
#summary-block()
|
#summary-block(meta)
|
||||||
|
#apply-report-styling(report.body)
|
||||||
#for section in sections {
|
#print-glossary-block()
|
||||||
section-block(section)
|
|
||||||
}
|
|
||||||
|
|||||||
5909
feasibility/sample.pdf
Normal file
5909
feasibility/sample.pdf
Normal file
File diff suppressed because it is too large
Load Diff
@ -904,26 +904,34 @@ uUL
|
|||||||
endstream
|
endstream
|
||||||
endobj
|
endobj
|
||||||
126 0 obj
|
126 0 obj
|
||||||
<</Length 5381/Filter/FlateDecode>>
|
<</Length 5392/Filter/FlateDecode>>
|
||||||
stream
|
stream
|
||||||
xœÝ]û$·mÿ]ÅôåZu<5A>€O$ªZí®ÔƱݺ§<š8il5®ãêÎ<C3AA>»4vÓöoïçËyqvg)éV£Sïî#î†C‚ | |||||||