feat: add tenant and user management with migrations, handlers, and tests

- Implemented tenant and user management features including:
  - Tenant creation and management with associated migrations.
  - User creation and management with associated migrations.
  - Tenant membership management with associated migrations.
  - Platform user roles management with associated migrations.
  - Quota management with associated migrations.
  - Article and template management with associated migrations.
- Added HTTP handlers for templates and workspaces.
- Created tests for protected and public routes.
- Introduced a script to check tenant scope in SQL queries.
- Documented task plan for backend completion and frontend foundation.
This commit is contained in:
2026-04-01 00:58:42 +08:00
commit de30497f59
210 changed files with 23733 additions and 0 deletions
+363
View File
@@ -0,0 +1,363 @@
const zhCN = {
app: {
name: "GEO工具平台",
loginIntro: "面向企业的品牌资产管理与内容生产协作系统",
},
locale: {
"zh-CN": "中文简体",
"en-US": "English",
},
common: {
cancel: "取消",
close: "关闭",
confirm: "确认",
create: "新建",
edit: "编辑",
delete: "删除",
reset: "重置",
refresh: "刷新数据",
search: "搜索",
save: "保存",
next: "下一步",
previous: "上一步",
submit: "提交",
submitGenerate: "提交生成",
actions: "操作",
title: "标题",
description: "描述",
website: "官网",
wordCount: "字数",
createdAt: "创建时间",
updatedAt: "更新时间",
status: "状态",
required: "必填",
noData: "暂无数据",
optional: "可选",
preview: "预览",
details: "详情",
versions: "版本记录",
total: "总量",
balance: "剩余",
used: "已使用",
source: "来源",
templateType: "模版类型",
generateStatus: "生成状态",
publishStatus: "发布状态",
selectPlease: "请选择",
inputPlease: "请输入",
upgrade: "去升级",
},
nav: {
workspace: "工作台",
articleCreation: "文章创作",
templates: "模版创作",
custom: "自定义生成",
optimize: "文章优化",
media: "媒体管理",
brandManagement: "品牌管理",
brands: "品牌词库",
tracking: "数据追踪",
trackingDetail: "数据详情",
contentManagement: "内容管理",
knowledge: "知识库",
},
auth: {
welcomeBack: "欢迎回来",
tenantAdminLogin: "租户后台登录",
loginAndEnter: "登录并进入工作台",
email: "邮箱",
password: "密码",
defaultTestAccount: "默认测试账号",
defaultTestPassword: "默认测试密码",
},
shell: {
localeLabel: "语言",
quotaTitle: "套餐与额度",
quotaStatus: "状态正常",
remainingQuota: "生成文章",
resetAt: "重置时间",
userFallback: "管理员",
logout: "退出",
planFallback: "免费版",
},
route: {
login: {
title: "欢迎回来",
description: "使用真实租户账号登录 GEO 工具平台。",
},
workspace: {
title: "工作台",
description: "模板入口、数据总览和最近生成都集中在这里。",
},
templates: {
title: "模版创作",
description: "筛选已有文章、选择模版并发起新一轮内容生成。",
},
custom: {
title: "自定义生成",
description: "当前仓库还没有匹配的后端接口,页面暂保持为设计占位。",
},
optimize: {
title: "文章优化",
description: "当前仓库还没有匹配的后端接口,页面暂保持为设计占位。",
},
media: {
title: "媒体管理",
description: "当前仓库还没有匹配的后端接口,页面暂保持为设计占位。",
},
brands: {
title: "品牌词库",
description: "围绕品牌维护关键词、问题集和竞品信息。",
},
tracking: {
title: "数据详情",
description: "当前仓库还没有匹配的后端接口,页面暂保持为设计占位。",
},
knowledge: {
title: "知识库",
description: "当前仓库还没有匹配的后端接口,页面暂保持为设计占位。",
},
},
workspace: {
eyebrow: "Dashboard",
metrics: {
articles: "生成数",
published: "发布数",
brands: "品牌数",
platforms: "媒体平台数",
},
sections: {
templates: "文章模版类型",
recent: "最近生成",
overview: "数据总览",
quota: "套餐与额度",
},
actions: {
enterTemplates: "进入模版创作",
},
quota: {
remaining: "剩余生成额度",
total: "总额度",
used: "已使用",
},
emptyTemplates: "暂无模版卡片数据",
noRecentArticles: "暂无最近生成内容",
},
templateMeta: {
top_x_article: {
eyebrow: "榜单内容",
helper: "排序推荐类文章,适合快节奏种草和结构化比较。",
accent: "Top X",
action: "创建榜单",
},
product_review: {
eyebrow: "单品评测",
helper: "突出卖点、优缺点与适用人群,适合高转化内容。",
accent: "评测稿",
action: "发起评测",
},
research_report: {
eyebrow: "研究报告",
helper: "更长、更专业的分析内容,适合趋势和行业洞察。",
accent: "深度稿",
action: "创建报告",
},
brand_search_expansion: {
eyebrow: "品牌扩写",
helper: "把品牌词和搜索需求扩展成更完整的问答式内容。",
accent: "GEO",
action: "继续扩写",
},
default: {
eyebrow: "内容模版",
helper: "当前模版已经可用,可直接进入生成流程。",
accent: "Ready",
action: "进入模版",
},
},
status: {
generate: {
draft: "草稿",
generating: "生成中",
running: "运行中",
completed: "已完成",
failed: "生成失败",
},
publish: {
unpublished: "未发布",
publishing: "发布中",
published: "发布成功",
publish_success: "发布成功",
publish_failed: "发布失败",
pending_review: "待审核",
},
sourceType: {
template: "模版单次生成",
},
},
templates: {
eyebrow: "Article Creation",
actions: {
batchGenerate: "批量生成文章",
chooseTemplate: "选择模版创作",
},
filters: {
template: "模版类型",
publishStatus: "发布状态",
generateStatus: "生成状态",
keyword: "搜索文章",
keywordPlaceholder: "请输入标题内容搜索",
unsupportedDate: "当前后端尚未提供按时间范围筛选",
},
list: {
count: "共 {count} 篇文章",
empty: "还未创建文章,暂无相关数据~",
preview: "预览正文",
versions: "查看版本",
deleteConfirm: "确认删除这篇文章吗?",
deleteSuccess: "文章已删除",
deleteError: "删除文章失败",
},
picker: {
title: "选择你需要的模版创作",
viewExample: "查看示例",
},
wizard: {
drawerTitle: "模版生成",
steps: {
basic: "基本信息",
basicDesc: "语言、模版字段与品牌上下文",
structure: "文章结构",
structureDesc: "标题方案、关键要点与结构段落",
generate: "生成文章",
generateDesc: "确认参数并提交生成任务",
},
sections: {
templateFields: "模版字段",
brandContext: "品牌上下文",
language: "文章语言",
brandInfo: "品牌信息",
keywords: "关键词",
competitors: "竞品列表",
chooseTitle: "选择文章标题",
customTitle: "自定义标题",
structure: "文章结构",
keyPoints: "文章关键要点",
review: "提交前确认",
notes: "生成说明",
inputParams: "输入参数",
},
hints: {
brandContext: "可选。选择后会自动带出关键词与竞品信息。",
competitorEmpty: "当前品牌下暂无竞品数据",
customTitle: "如需手动改写,可在这里输入最终标题",
keyPoints: "补充希望文章强调的卖点、观点或风格要求",
async: "后端会立即创建文章和任务记录,再异步完成正文生成。提交成功后,列表会自动刷新。",
},
review: {
templateName: "模版名称",
articleTitle: "文章标题",
brandContext: "品牌上下文",
outline: "结构段落",
currentTemplate: "当前模版",
promptVisibility: "Prompt 可见性",
selectedKeywords: "已选关键词",
selectedCompetitors: "已选竞品",
},
localeOptions: {
zh: "中文简体",
en: "English",
},
promptVisible: "Prompt 可见",
promptSealed: "Prompt 已封装",
messages: {
requiredField: "请先填写 {field}",
missingTitle: "请先选择或输入文章标题",
missingOutline: "请至少选择一个文章结构段落",
submitted: "生成任务已提交,正在刷新文章列表。",
},
},
},
article: {
drawerTitle: "文章详情",
preview: "正文预览",
versionHistory: "版本记录",
untitled: "未命名文章",
noContent: "当前文章还没有正文内容",
meta: {
templateType: "模版类型",
currentVersion: "当前版本",
source: "生成来源",
wordCount: "文章字数",
},
versionUntitled: "未命名版本",
},
brands: {
eyebrow: "Brand Library",
title: "品牌词库",
description: "通过品牌名称和品牌相关信息维护关键词、问题集和竞品资产。",
railTitle: "品牌库",
selectBrand: "选择品牌后即可继续维护关键词和问题集。",
newBrand: "新建品牌",
editBrand: "编辑品牌",
deleteBrand: "删除品牌",
tabs: {
keywords: "关键词",
competitors: "竞品库",
},
sections: {
keywords: "关键词",
questions: "问题集",
competitors: "竞品库",
versions: "版本记录",
},
actions: {
newKeyword: "新建关键词",
newQuestion: "新建问题",
newCompetitor: "新建竞品",
viewVersions: "查看版本",
},
empty: {
brands: "还没有品牌数据,先创建一个品牌。",
questions: "当前关键词下暂无问题集。",
competitors: "当前品牌下暂无竞品数据。",
},
form: {
brandName: "品牌名称",
brandDescription: "品牌描述",
keywordName: "关键词名称",
questionText: "问题内容",
competitorName: "竞品名称",
competitorWebsite: "竞品官网",
competitorDescription: "竞品描述",
competitorLines: "重点产品线",
competitorLinesHint: "使用英文逗号分隔多个产品线",
},
messages: {
createBrand: "品牌已创建",
updateBrand: "品牌已更新",
deleteBrand: "品牌已删除",
createKeyword: "关键词已创建",
updateKeyword: "关键词已更新",
deleteKeyword: "关键词已删除",
createQuestion: "问题已创建",
updateQuestion: "问题已更新",
deleteQuestion: "问题已删除",
createCompetitor: "竞品已创建",
updateCompetitor: "竞品已更新",
deleteCompetitor: "竞品已删除",
chooseBrand: "请先选择品牌",
chooseKeyword: "请先选择关键词",
},
},
featureStub: {
eyebrow: "Feature Placeholder",
currentStatus: "当前状态",
nextPriority: "下一步重点",
integrationStrategy: "联调策略",
currentStatusText: "页面壳子已经接入主导航和鉴权守卫,后续可以直接在这里落真实交互。",
integrationStrategyText: "保持与 tenant-api 的响应结构对齐,先做真实读接口,再逐个补写接口和表单流。",
},
} as const;
export default zhCN;