feat: add image management functionality
- Implemented image folder repository with CRUD operations. - Added image reference repository for managing image references to articles. - Created image repository for handling image assets, including listing, inserting, updating, and deleting images. - Introduced image usage repository to track storage usage and quotas for tenants. - Added SQL queries for image assets, folders, references, and usage. - Developed image handler for HTTP endpoints to manage images and folders. - Created database migration scripts for image-related tables and structures.
This commit is contained in:
@@ -52,6 +52,17 @@ const enUS = {
|
||||
copySuccess: "Content copied",
|
||||
yes: "Yes",
|
||||
no: "No",
|
||||
imageUploadProgress: {
|
||||
title: "Processing image",
|
||||
stages: {
|
||||
idle: "Waiting to start",
|
||||
validating: "Validating file",
|
||||
decoding: "Decoding image",
|
||||
encoding: "Converting to WebP",
|
||||
uploading: "Uploading to server",
|
||||
finishing: "Finishing",
|
||||
},
|
||||
},
|
||||
},
|
||||
nav: {
|
||||
workspace: "Workspace",
|
||||
@@ -66,6 +77,7 @@ const enUS = {
|
||||
trackingDetail: "Data Details",
|
||||
contentManagement: "Content Management",
|
||||
knowledge: "Knowledge Base",
|
||||
images: "Image Management",
|
||||
},
|
||||
auth: {
|
||||
welcomeBack: "Welcome back",
|
||||
@@ -135,6 +147,10 @@ const enUS = {
|
||||
title: "Knowledge Base",
|
||||
description: "No matching backend APIs exist in this repository yet.",
|
||||
},
|
||||
images: {
|
||||
title: "Image Management",
|
||||
description: "Manage image assets, including folders, reference analysis, and cover library usage.",
|
||||
},
|
||||
},
|
||||
workspace: {
|
||||
eyebrow: "Dashboard",
|
||||
@@ -596,6 +612,11 @@ const enUS = {
|
||||
resetSize: "Reset size",
|
||||
delete: "Delete image",
|
||||
},
|
||||
imagePicker: {
|
||||
title: "Select image",
|
||||
emptyTitle: "Choose an image for the article body",
|
||||
emptyHint: "Pick from the image library or upload locally. Local uploads are converted to WebP before upload.",
|
||||
},
|
||||
aiOptimize: {
|
||||
title: "AI Optimize",
|
||||
subtitle: "Supports contiguous multi-block selections and generates a rewrite from your instruction",
|
||||
@@ -741,6 +762,8 @@ const enUS = {
|
||||
local: "Body / Local Upload",
|
||||
ai: "AI Cover",
|
||||
},
|
||||
dropzoneTitle: "Upload image",
|
||||
dropzoneHint: "Supports PNG, JPG, GIF, and WebP up to 10MB. Uploads are converted to WebP in the browser first.",
|
||||
previewTitle: "Cover crop preview",
|
||||
previewHintLocked: "Baijiahao is selected, so the cover will be exported as 16:9 when you confirm.",
|
||||
previewHintFree: "There is no forced cover ratio right now. You can upload the original image directly or adjust framing before confirming.",
|
||||
@@ -754,7 +777,7 @@ const enUS = {
|
||||
fileLabel: "Current cover",
|
||||
emptyTitle: "No publish platform selected",
|
||||
emptyPlatforms: "Choose publish platforms first and each platform's cover requirements will appear here.",
|
||||
emptyHint: "Supports PNG, JPG, GIF, and WebP up to 10MB.",
|
||||
emptyHint: "Supports PNG, JPG, JPEG, GIF, WebP, BMP, SVG, and AVIF up to 10MB.",
|
||||
aiTitle: "AI cover is coming soon",
|
||||
aiHint: "For now this flow supports local upload and cropping. AI cover generation can be plugged in here later.",
|
||||
actions: {
|
||||
@@ -768,7 +791,7 @@ const enUS = {
|
||||
unsupported: "This platform's current integration does not consume a standalone cover yet and falls back to body content or the platform default.",
|
||||
},
|
||||
messages: {
|
||||
invalidType: "Only PNG, JPG, GIF, and WebP images are supported.",
|
||||
invalidType: "Only PNG, JPG, JPEG, GIF, WebP, BMP, SVG, and AVIF images are supported.",
|
||||
tooLarge: "Image size cannot exceed 10MB.",
|
||||
missingImage: "Select a cover image first.",
|
||||
missingArticle: "The article is not ready yet. Refresh and try again.",
|
||||
@@ -981,6 +1004,44 @@ const enUS = {
|
||||
currentStatusText: "The page shell is ready with navigation and auth guard support.",
|
||||
integrationStrategyText: "Keep the UI aligned with tenant-api envelopes and wire real read flows before write flows.",
|
||||
},
|
||||
images: {
|
||||
title: "Image Management",
|
||||
description: "Manage image library with folder organization and reference analysis.",
|
||||
uploadBtn: "Upload Image",
|
||||
folders: "Folders",
|
||||
uncategorized: "Uncategorized",
|
||||
searchPlaceholder: "Search image name...",
|
||||
newFolder: "New Folder",
|
||||
folderName: "Folder Name",
|
||||
rename: "Rename",
|
||||
move: "Move",
|
||||
deleteImage: "Delete Image",
|
||||
deleteFolder: "Delete Folder",
|
||||
forceDelete: "Force Delete",
|
||||
confirmDeleteTitle: "Confirm Delete",
|
||||
confirmDeleteImage: "Are you sure you want to delete this image? This action cannot be undone.",
|
||||
confirmDeleteFolder: "Confirm delete folder {name}?",
|
||||
imageInUse: "Image is in use",
|
||||
folderHasRefs: "This folder contains {count} images. They may already be referenced by articles. Deleting the folder will also delete these images permanently.",
|
||||
refArticleBody: "Body reference",
|
||||
refArticleCover: "Cover reference",
|
||||
storageUsage: "Storage Usage",
|
||||
storageUsageDetail: "{used} / {total} ({percent}%)",
|
||||
quotaExceeded: "Storage is full, please clean up before uploading more.",
|
||||
uploadSuccess: "Image uploaded successfully",
|
||||
uploadReusedSuccess: "Matching image already exists in the library and was reused",
|
||||
uploadFailed: "Image upload failed",
|
||||
deleteSuccess: "Deleted successfully",
|
||||
folderCreated: "Folder created successfully",
|
||||
folderRenamed: "Folder renamed successfully",
|
||||
folderDeleted: "Folder deleted",
|
||||
imageRenamed: "Image renamed successfully",
|
||||
imageMoved: "Image moved successfully",
|
||||
noImages: "No images yet. Click upload to start.",
|
||||
allFolders: "All Folders",
|
||||
selectImage: "Select Image",
|
||||
libraryTab: "Library",
|
||||
},
|
||||
} as const;
|
||||
|
||||
export default enUS;
|
||||
|
||||
@@ -52,6 +52,17 @@ const zhCN = {
|
||||
copySuccess: "内容已复制",
|
||||
yes: "是",
|
||||
no: "否",
|
||||
imageUploadProgress: {
|
||||
title: "图片处理中",
|
||||
stages: {
|
||||
idle: "等待开始",
|
||||
validating: "正在校验文件",
|
||||
decoding: "正在解析图片",
|
||||
encoding: "正在转为 WebP",
|
||||
uploading: "正在上传到服务器",
|
||||
finishing: "正在完成处理",
|
||||
},
|
||||
},
|
||||
},
|
||||
nav: {
|
||||
workspace: "工作台",
|
||||
@@ -66,6 +77,7 @@ const zhCN = {
|
||||
trackingDetail: "数据详情",
|
||||
contentManagement: "内容管理",
|
||||
knowledge: "知识库",
|
||||
images: "图片管理",
|
||||
},
|
||||
auth: {
|
||||
welcomeBack: "欢迎回来",
|
||||
@@ -135,6 +147,10 @@ const zhCN = {
|
||||
title: "知识库",
|
||||
description: "当前仓库还没有匹配的后端接口,页面暂保持为设计占位。",
|
||||
},
|
||||
images: {
|
||||
title: "图片管理",
|
||||
description: "管理图片素材库,支持分组管理、引用分析与封面图库引用。",
|
||||
},
|
||||
},
|
||||
workspace: {
|
||||
eyebrow: "Dashboard",
|
||||
@@ -603,6 +619,11 @@ const zhCN = {
|
||||
resetSize: "重置大小",
|
||||
delete: "删除图片",
|
||||
},
|
||||
imagePicker: {
|
||||
title: "选择图片",
|
||||
emptyTitle: "选择一张图片插入正文",
|
||||
emptyHint: "支持从图片库选择,也支持本地上传后自动转为 WebP。",
|
||||
},
|
||||
aiOptimize: {
|
||||
title: "AI 优化",
|
||||
subtitle: "支持连续多段选中,基于你的优化要求生成候选改写",
|
||||
@@ -748,6 +769,8 @@ const zhCN = {
|
||||
local: "正文/本地上传",
|
||||
ai: "AI封图",
|
||||
},
|
||||
dropzoneTitle: "上传图片",
|
||||
dropzoneHint: "支持 PNG、JPG、GIF、WebP,上传前会在前端转为 WebP,最大 10MB",
|
||||
previewTitle: "封面裁剪预览",
|
||||
previewHintLocked: "已选择百家号,确认时会按 16:9 输出封面。",
|
||||
previewHintFree: "当前不限制封面比例,可直接上传原图;如需调整也可拖拽缩放后再确认。",
|
||||
@@ -761,7 +784,7 @@ const zhCN = {
|
||||
fileLabel: "当前封面",
|
||||
emptyTitle: "暂未选择发布平台",
|
||||
emptyPlatforms: "选择发布平台后,这里会自动显示每个平台的封面要求。",
|
||||
emptyHint: "支持 PNG、JPG、GIF、WebP,最大 10MB",
|
||||
emptyHint: "支持 PNG、JPG、JPEG、GIF、WebP、BMP、SVG、AVIF,最大 10MB",
|
||||
aiTitle: "AI 封图即将开放",
|
||||
aiHint: "当前先支持本地上传和裁剪,后续会把 AI 生成封面接进这里。",
|
||||
actions: {
|
||||
@@ -775,7 +798,7 @@ const zhCN = {
|
||||
unsupported: "该平台当前接入暂不消费独立封面,会沿用正文内容或平台默认样式。",
|
||||
},
|
||||
messages: {
|
||||
invalidType: "仅支持 PNG、JPG、GIF、WebP 图片",
|
||||
invalidType: "仅支持 PNG、JPG、JPEG、GIF、WebP、BMP、SVG、AVIF 图片",
|
||||
tooLarge: "图片不能超过 10MB",
|
||||
missingImage: "请先选择一张封面图",
|
||||
missingArticle: "文章信息还没准备好,请刷新后重试",
|
||||
@@ -987,7 +1010,45 @@ const zhCN = {
|
||||
nextPriority: "下一步重点",
|
||||
integrationStrategy: "联调策略",
|
||||
currentStatusText: "页面壳子已经接入主导航和鉴权守卫,后续可以直接在这里落真实交互。",
|
||||
integrationStrategyText: "保持与 tenant-api 的响应结构对齐,先做真实读接口,再逐个补写接口和表单流。",
|
||||
integrationStrategyText: "保持与 tenant-api 的响应结构对齐,先做真实读接口,再逐个补写接口 and 表单流。",
|
||||
},
|
||||
images: {
|
||||
title: "图片管理",
|
||||
description: "管理图片素材库,支持分组、引用分析与封面引用。",
|
||||
uploadBtn: "上传图片",
|
||||
folders: "文件夹",
|
||||
uncategorized: "未分类",
|
||||
searchPlaceholder: "搜索图片名称...",
|
||||
newFolder: "新建文件夹",
|
||||
folderName: "文件夹名称",
|
||||
rename: "重命名",
|
||||
move: "移动",
|
||||
deleteImage: "删除图片",
|
||||
deleteFolder: "删除文件夹",
|
||||
forceDelete: "仍然删除",
|
||||
confirmDeleteTitle: "确认删除",
|
||||
confirmDeleteImage: "确认删除这张图片吗?该操作不可撤销。",
|
||||
confirmDeleteFolder: "确认删除文件夹 {name} 吗?",
|
||||
imageInUse: "图片正在使用中",
|
||||
folderHasRefs: "该文件夹内有 {count} 张图片,这些图片可能已被文章引用。删除文件夹会一并删除这些图片,且不可恢复。",
|
||||
refArticleBody: "正文引用",
|
||||
refArticleCover: "封面引用",
|
||||
storageUsage: "存储容量",
|
||||
storageUsageDetail: "{used} / {total} ({percent}%)",
|
||||
quotaExceeded: "存储空间已满,请清理后再上传。",
|
||||
uploadSuccess: "图片上传成功",
|
||||
uploadReusedSuccess: "素材库已有相同图片,已直接复用",
|
||||
uploadFailed: "图片上传失败",
|
||||
deleteSuccess: "删除成功",
|
||||
folderCreated: "文件夹创建成功",
|
||||
folderRenamed: "文件夹重命名成功",
|
||||
folderDeleted: "文件夹已删除",
|
||||
imageRenamed: "图片重命名成功",
|
||||
imageMoved: "图片移动成功",
|
||||
noImages: "暂无图片,点击上传开始添加",
|
||||
allFolders: "全部文件夹",
|
||||
selectImage: "选择图片",
|
||||
libraryTab: "素材库",
|
||||
},
|
||||
} as const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user