手作创作者的本地优先项目台账系统:用SQLite实现过程记录与成本核算
上个月我整理手作台的时候看着一堆半成品、几卷棉绳、十几张写满配色灵感的便签纸忽然意识到一个问题我每天都在用手机拍下创作过程电脑里堆了几百张照片但从来没有一个地方能把这个作品用了什么材料、花了多少小时、走了哪些弯路、最终成本是多少完整地串起来。灵感靠记忆材料靠翻柜子结案全靠一张嘴。于是我就动手做了一个小工具名字叫ArtCraft现在用了快三个月很想把整个设计思路和踩过的坑写出来。ArtCraft 本质上是一个面向手作创作者的本地优先项目台账系统。它不追求花哨的界面也不依赖云端账号而是把所有创作过程拆成项目—材料—步骤—媒体四类数据存在一个 SQLite 数据库里最后能一键生成一份自带封面和过程图的独立网页作品集。适合玩拼布、木工、模型、滴胶、编织或者任何需要记录过程和核算成本的手工领域。如果你也是那种做完就忘的创作者这篇文章应该能提供一套可以直接抄作业的思路。1. ArtCraft是什么给手作创作者的项目台账系统1.1 手作创作不等于随便记记缺的是结构化很多人觉得手作是感性的灵感来了就做哪需要什么项目管理。但真正把创作当成长期爱好甚至副业的人会明白不结构化的结果就是重复采购、遗忘工序、无法复盘。我见过太多手作博主分享作品时只能放成品图问配色怎么调的、布料用的哪个牌子完全答不上来——不是不想答是真的没记。市面上不是没有工具。通用的笔记软件像白纸什么都能记但正因为太自由最终沦为收藏夹表格软件能统计但用来记录创作过程脑子里得先画出一堆复杂的行列关系反而增加负担而很多垂直领域的专业软件要么只针对织布要么只针对木工换一个兴趣方向就废了。ArtCraft 的设计理念恰好是反过来的先承认手作过程很乱再用最简单的数据模型去兜住这些乱。它不强求你在创作时填完所有字段而是允许你像发朋友圈一样零散地往项目里追加图片和备注。等作品收尾时再去补材料清单和工时系统就能自动算出成本和形成过程记录。1.2 ArtCraft的设计目标与使用场景我当时给自己列了三个硬指标。第一本地优先所有数据保存在一个文件里不需要登录、不需要联网备份就是复制文件隐私不用担心。第二操作要快到不打断手感记录一条步骤备注不应该超过十秒最好是命令行敲几个字母就搞定。第三导出要漂亮每次做完一个作品我希望自动生成一个像博客文章一样的 HTML 页面可以发给朋友也可以以后回忆。围绕这三个目标ArtCraft 的具体使用场景逐渐清晰个人创作者做创作档案每个作品从灵感、草图、买料到成品结束全程留存。手工工作室做备料核算同一种材料在多个项目里用了多少进价和消耗一目了然。业余卖家做成本定价材料成本加时间成本避免卖一件亏一件。这个工具本质上不是一个社交平台也不是图片编辑器而是一个专门为动手型创作者设计的轻量级数据入口。它后端是数据库和脚本前端只有最后生成的静态页面整条链路非常朴素但极度可控。接下来我要重点聊聊数据建模部分——这是整个工具里我花时间最多、也最庆幸自己做对的地方。2. 数据建模最容易被忽略却决定成败的部分2.1 项目、材料、步骤、媒体四张核心表的由来几乎所有创作过程都可以归纳成这样的叙事我计划做某样东西用了若干材料按某个顺序操作最后留下照片。沿着这条叙事我把数据库拆成了四张核心表projects、materials、steps、media。projects表只存项目的身份信息比如标题、状态、创建时间和完成时间CREATE TABLE projects ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, status TEXT DEFAULT draft, cover_image_id INTEGER, start_date TEXT, finish_date TEXT, notes TEXT, created_at TEXT DEFAULT (datetime(now, localtime)) );materials表专门记录每个项目消耗了什么材料以及数量和单价。比单纯记备注好的是它让成本变成了可聚合的数据CREATE TABLE materials ( id INTEGER PRIMARY KEY AUTOINCREMENT, project_id INTEGER NOT NULL, name TEXT NOT NULL, category TEXT, quantity REAL DEFAULT 0, unit TEXT DEFAULT 个, unit_price REAL DEFAULT 0, purchased_from TEXT, FOREIGN KEY (project_id) REFERENCES projects(id) );steps表用来按顺序记录操作过程附带消耗的分钟数。这是我觉得最值钱的一张表因为很多手作人根本不记得自己花了多久CREATE TABLE steps ( id INTEGER PRIMARY KEY AUTOINCREMENT, project_id INTEGER NOT NULL, step_number INTEGER, description TEXT NOT NULL, duration_minutes INTEGER DEFAULT 0, image_id INTEGER, FOREIGN KEY (project_id) REFERENCES projects(id) );media表负责所有图片素材的管理。让图片独立成表而不是直接塞进步骤说明里是因为同一张过程图既可能出现在步骤记录里也可能成为封面还可能用于将来的作品集封面轮播。分开存查询才灵活CREATE TABLE media ( id INTEGER PRIMARY KEY AUTOINCREMENT, project_id INTEGER NOT NULL, file_path TEXT NOT NULL, caption TEXT, taken_at TEXT, FOREIGN KEY (project_id) REFERENCES projects(id) );四条表之间通过外键关联整个库的结构一眼就能看懂。实际使用中我甚至没有为它写复杂的关系映射代码直接用一个轻量封装执行 SQL 查询既透明又高效。2.2 成本核算的数据逻辑材料成本、工具折旧、时间成本很多手作人羞于谈钱但作为项目台账成本不能回避。ArtCraft 的成本逻辑分三层直接材料成本是最容易算的把materials表里的 quantity 乘 unit_price 累加即可。第二层是工具损耗成本比如切割垫板、热熔胶枪这类反复使用的工具我建议在项目里记录一个折旧摊分字段并不需要精确到每次一毛而是按使用次数估算。第三层是时间成本把steps表里所有 duration_minutes 累加再乘以你给自己定的时薪。前端生成作品集时我写了这样一段处理逻辑总成本 材料成本 工具摊分 总工时 / 60 × 时薪。手工定价最怕拍脑袋有了这组数字之后心里踏实得多。至少不会再出现卖了一百块材料成本就八十块的尴尬情况。2.3 为什么用SQLite而不是Notion或Excel有人可能会问直接用 Notion 加数据库视图或者 Excel 做数据透视不是也挺好吗我的回答是能但慢。Notion 的表格需要手动定义属性移动端体验也不稳定每次记录至少要点四五次Excel 虽然能做数据透视但图片管理和最终作品集呈现完全帮不上忙。SQLite 的优势在于单个文件就是数据库没有服务端和网络依赖查询能力完整能够轻松跨项目统计某材料用了多少次可以配合命令行脚本实现极速录入比如我用一个artcraft add step 3 刷第一层清漆 -t 25就能在五秒内完成记录。从长远看SQLite 这么多年没有过时稳定性和可迁移性都顶尖。这个选型直接决定了 ArtCraft 能保持轻量但能干的定位。3. 一个完整的ArtCraft使用流程从创建项目到导出作品集3.1 创建项目与拆解任务先规划再动手我的习惯是每次开始一件新的手作前先不急着拿材料而是在终端里运行一行命令artcraft create 木质收纳托盘这条命令会在数据库里插入一条状态为draft的项目记录。然后我再按自己的想法拆出几个阶段写进备注里比如备料→开料→组装→打磨→上油。实际上这些阶段不一定对应最终的真实步骤但有了它们后面记录过程时不容易漏掉重要节点。拆解任务这个动作虽然简单却能极大缓解开工即混乱的状态。ArtCraft 鼓励你只写关键词不需要写成完整句。像开料或上油这种两三个字就够了数据库里的步骤描述允许短得离谱——这恰恰是为了不打断你的手感。3.2 边创作边记录怎么让记录不打断手作很多工具使用频率低就是因为记录成本太高。ArtCraft 的做法是提供一组非常短的自然语言命令。比如我在打磨的时候可以转头在电脑上敲artcraft note 第一次打磨发现边角不够圆润如果拍了照片就先把照片丢进一个约定好的inbox文件夹然后运行artcraft import img/20240602_1530.jpg -p 1 --caption 组装侧面夹具位置需要调整-p 1表示项目编号脚本会自动把图片从 inbox 移动到项目专属目录并在media表里插入一条记录。整个过程不需要打开任何软件界面终端速度最快。如果你觉得命令行吓人也可以把这两条封装成简单的双击脚本或者绑定到快捷键上用起来和随手记一笔没什么差别。关键的设计原则是记录动作永远发生在创作间隙而不是等全部做完后补录。补录会丢掉大量真实细节尤其是等待时间和失误率这些恰恰是复盘中最重要的信息。3.3 一键导出作品集从数据库到可视化页面的实现当项目状态改为finished之后ArtCraft 会触发一次静态页面生成。我用的是非常经典的组合SQLite 查询 Jinja2 模板。生成一个独立的 HTML 文件里面内嵌了所有文字和图片的引用图片以相对文件路径指向同目录的 assets 文件夹所以整个作品集可以随意拷贝到 U 盘或压缩发给朋友。导出命令很简单artcraft export 1 --out ./gallery/tray-001生成出来的页面结构大致包括作品标题与封面、材料清单表格、步骤时间线带照片、成本汇总、创作者备注。模板只是普通的 HTML 和 CSS没有用任何前端框架。之所以坚持生成静态页是因为它不依赖服务器十年后打开还能看这种长期可访问性对于个人档案来说太重要了。下面是模板中渲染成本汇总的片段示意div classcost-summary h3成本核算/h3 p材料成本{{ total_material_cost }} 元/p p工具摊分{{ tool_cost }} 元/p p时间成本{{ total_hours }} 小时 × {{ hourly_rate }} 元/小时{{ time_cost }} 元/p p classtotal总成本{{ total_cost }} 元/p /div实际导出的页面效果比大多数笔记软件的打印视图好看。我在过去三个月里给朋友展示过几次每次他们都会惊讶这是你那个命令行工具生成的——这反向验证了一件事数据结构的整洁最终会体现在输出质量上。4. 实测踩坑记录开发和使用ArtCraft时遇到的五个问题4.1 图片增量同步照片越来越多导致卡顿一开始我的import命令会把照片全部复制到项目目录但重复导入同一张照片或者命名混乱时数据库里会出现大量垃圾媒体记录。后来我加了按文件哈希去重的逻辑导入前先计算文件哈希如果哈希已存在就直接关联旧记录不再复制文件。# 核心思路用文件哈希判断是否已导入 import hashlib def file_hash(path): h hashlib.sha256() with open(path, rb) as f: for chunk in iter(lambda: f.read(4096), b): h.update(chunk) return h.hexdigest()这个改动带来的变化非常明显项目的media表不再出现重复照片导出作品集时也少了大量冗余文件。建议你也把去重作为第一步就纳入设计而不是等数据脏了再清洗。4.2 单位不统一克、个、米的成本计算混乱手作材料的计量单位五花八门线材按米、树脂按克、木板按张、珠子按颗。最初我把所有 quantity 都塞在一个 numeric 字段里导致算成本时经常出现50g 的树脂 × 1 米的价格这种荒谬结果。解决方式并不复杂我把单位写进材料记录里计算成本时不再直接做乘法而是要求unit_price必须遵循每 unit 价格的约定。如果你买了 200 克树脂花了 40 元那 unit 就是克unit_price 就是 0.2如果一袋珠子 100 颗卖 12 元unit 就是颗unit_price 就是 0.12。录入时多花十秒钟统一单位导出时少算错一百次。4.3 项目状态机草稿、进行中、完成、废弃的迁移问题项目的状态一开始只设计了draft和finished但用着用着发现有些项目做到一半放弃了有些做完了但还缺封面图。如果不区分统计时会把它们全算作进行中导致完成率失真。我后来把状态调整成四个draft只是记了想法、in_progress真正动工了、finished完工且资料齐全、archived彻底弃坑或需要封存。迁移时加了一个简单约束只有finished状态才能导出作品集in_progress可以导出预览页但会带水印标记。这套简单状态机帮我把大量半成品从待办里解放出来。4.4 导出作品集时图片路径被浏览器拦截这是最折磨人的问题。用本地浏览器打开生成的 HTML 页面时图片经常加载不出来控制台报错提示Not allowed to load local resource。原因是页面通过相对路径访问assets/xxx.jpg时部分浏览器出于安全策略限制了本地文件读取。我的解决办法是把图片转成 base64 内嵌到 HTML 里或者启动一个最简单本地静态服务器来预览。后者操作起来更省事在作品集文件夹下运行一行命令python -m http.server 8000 --directory .然后访问http://localhost:8000/index.html就一切正常。分享给别人的时候也可以打包整个文件夹对方打开时如果不方便起服务我再提供一个内嵌图片的导出选项把每张图压缩后转 base64牺牲一点体积换取即开即看。4.5 移动端预览相对路径和宽高适配前几次导出作品集我用手机点开 HTML 时发现布局基本崩掉因为 CSS 里写了固定像素宽度。后来把所有容器改成流式布局给图片加上了max-width: 100%并让步骤文字块按clamp()调整字号。现在同一份 HTML 在手机和电脑上都能舒服地看属于一举解决和朋友分享的需求。这套适配经验本质上是前端基本功但放在一个本地工具里特别容易忽略。很多人觉得反正页面是我自己看结果分享时才发现出丑。建议所有导出模板在写 CSS 的一开始就按响应式思路设计。5. 还能怎么扩展ArtCraft的下一步与个人经验5.1 给材料打标签色彩、风格、季节维度目前的材料表还比较原始只有名称和分类。后续我打算增加一个tags表用多对多关联把材料打上复古浅色系夏季之类的标签。这样在复盘配色时可以快速筛选出所有属于大地色系的材料对做系列作品特别有用。标签数据的意义不在于当下而在于将来你想复刻一种风格时不用再翻几十张截图。5.2 把作品集同步到任意博客或社交平台静态 HTML 作品集有一个天然优势它可以被脚本继续处理。我现在的计划是写一个解析器把导出的 HTML 内容进一步提取成 Markdown 片段甚至可以自动配上简短文案作为发朋友圈或社交平台的基础内容。这样每次完工既有了私人档案也有了公开分享的素材一举两得。5.3 使用三个月后的真心话如果你问我是否推荐每个人都去搞一套这样的工具我会说先分清自己是需要管理创作还是喜欢管理创作。前者只要建立一个带有材料表和步骤表的文件夹就够了用任何工具都行后者才会从 ArtCraft 这种自定义系统中获得巨大乐趣。我属于后者所以我玩得很开心。我记得最明显的变化是开始用 ArtCraft 之后我丢掉了一支专门记灵感的旧圆珠笔——因为所有灵感都变成了draft项目它们躺在一张表里永远不会丢也不会因为换本子而消失。而且每次看到finish数量一点点增加那种成就感是社交平台点赞完全无法替代的。最后再分享一个小技巧不要急着把所有字段和功能做完整。我的 ArtCraft 第一版只有创建项目、添加步骤、导入照片这三件事用了两周才慢慢加成本和导出。工具是越用越顺手不是在开发时一步到位的。如果你也想做一个类似的东西从你眼下最疼的一个痛点出发就好。