Keystone 6内容版本控制功能咨询及手动实现建议
Keystone 6 内容版本控制实现方案
Keystone 6 确实没有内置的内容版本控制功能,官方文档也未提供相关配置选项,目前社区相关资源较少。以下是手动实现内容版本控制的可行方案:
1. 新增版本关联实体
创建一个与目标实体(如BlogPost)关联的版本实体,用于存储历史版本的完整内容及元数据:
import { list } from '@keystone-6/core'; import { text, relationship, timestamp, select } from '@keystone-6/core/fields'; // 历史版本实体 export const BlogPostVersion = list({ fields: { post: relationship({ ref: 'BlogPost.versions' }), // 关联原博文 title: text({ validation: { isRequired: true } }), content: text({ ui: { displayMode: 'textarea' } }), versionNumber: select({ options: ['1.0', '1.1', '2.0'], defaultValue: '1.0' }), createdAt: timestamp({ defaultValue: { kind: 'now' } }), createdBy: relationship({ ref: 'User' }), // 记录操作人 status: select({ options: ['draft', 'published', 'archived'], defaultValue: 'draft' }) }, }); // 修改原BlogPost实体,添加版本关联 export const BlogPost = list({ fields: { title: text({ validation: { isRequired: true } }), content: text({ ui: { displayMode: 'textarea' } }), currentVersion: relationship({ ref: 'BlogPostVersion' }), // 标记当前使用的版本 versions: relationship({ ref: 'BlogPostVersion.post', many: true }) // 关联所有历史版本 }, });
2. 利用钩子自动生成版本
在目标实体的update钩子中,检测内容变更并自动创建新的版本记录,同时更新当前版本关联:
export const BlogPost = list({ fields: { /* 上述字段定义 */ }, hooks: { afterUpdate: async ({ context, item, originalItem }) => { // 仅当核心内容(标题/正文)变更时创建新版本 if (item.title !== originalItem.title || item.content !== originalItem.content) { // 查询当前最大版本号,自动生成新版本号(示例逻辑) const existingVersions = await context.db.BlogPostVersion.findMany({ where: { post: { id: item.id } }, orderBy: { createdAt: 'desc' }, take: 1 }); const newVersionNumber = existingVersions.length ? (parseFloat(existingVersions[0].versionNumber) + 0.1).toFixed(1) : '1.0'; // 创建新版本 const newVersion = await context.db.BlogPostVersion.createOne({ data: { post: { connect: { id: item.id } }, title: item.title, content: item.content, versionNumber: newVersionNumber, createdBy: context.session?.itemId ? { connect: { id: context.session.itemId } } : undefined, status: 'published' } }); // 更新当前版本指向新记录 await context.db.BlogPost.updateOne({ where: { id: item.id }, data: { currentVersion: { connect: { id: newVersion.id } } } }); } } } });
3. 实现版本切换功能
- 查看历史版本:通过查询
BlogPost的versions关联字段,获取所有历史版本列表,在UI中展示版本号、创建时间、操作人等信息。 - 切换版本:选择目标版本后,将该版本的
title和content复制回BlogPost的当前字段,同时更新currentVersion关联到选中的版本。如果需要保留当前状态,也可以仅在前端展示选中版本的内容,不修改原实体。
4. UI 优化建议
利用Keystone的自定义UI组件能力,在BlogPost详情页添加版本管理模块:
- 在
fields配置中为versions字段指定自定义组件,展示版本列表及操作按钮(查看、切换、删除)。 - 可以添加版本对比功能,通过比较不同版本的内容差异,帮助用户快速识别变更点。
注意事项
- 性能控制:如果内容量大或版本数量多,建议限制保留的版本数量(如仅保留最近10个版本),或对旧版本进行归档存储。
- 审计追踪:通过
context.session记录操作人,配合createdAt字段,实现完整的版本变更审计。 - 版本号策略:可以根据业务需求选择递增数字、时间戳或语义化版本号,避免手动输入错误。
内容的提问来源于stack exchange,提问作者ptas
相关产品推荐
相关产品推荐

