完善图片画布素材库持久化
新增账号级素材文件夹和素材表,并接入 SpacetimeDB procedure、spacetime-client facade 与 api-server BFF。 编辑器素材栏支持文件夹新建、折叠、重命名、删除、多文件上传、拖拽定向上传、框选和批量删除。 画布支持拖拽上传落点创建图层、图层打组、小地图拖拽、普通滚轮纵向滚动和 Ctrl 滚轮缩放。 更新图片画布技术方案、后端数据契约、TRACKING 和团队决策记录。
This commit is contained in:
@@ -51,6 +51,43 @@ pub struct EditorProjectResourceRecord {
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct EditorAssetFolderRecord {
|
||||
pub folder_id: String,
|
||||
pub label: String,
|
||||
pub sort_order: u32,
|
||||
pub collapsed: bool,
|
||||
pub system_default: bool,
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct EditorAssetRecord {
|
||||
pub asset_id: String,
|
||||
pub folder_id: String,
|
||||
pub label: String,
|
||||
pub asset_object_id: Option<String>,
|
||||
pub image_src: String,
|
||||
pub object_key: Option<String>,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub source_type: String,
|
||||
pub prompt: Option<String>,
|
||||
pub actual_prompt: Option<String>,
|
||||
pub model: Option<String>,
|
||||
pub provider: Option<String>,
|
||||
pub task_id: Option<String>,
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct EditorAssetLibraryRecord {
|
||||
pub folders: Vec<EditorAssetFolderRecord>,
|
||||
pub assets: Vec<EditorAssetRecord>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct EditorProjectCreateRecordInput {
|
||||
pub project_id: String,
|
||||
@@ -108,6 +145,66 @@ pub struct EditorProjectResourceCreateRecordInput {
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct EditorAssetFolderCreateRecordInput {
|
||||
pub folder_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub label: String,
|
||||
pub sort_order: u32,
|
||||
pub now_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct EditorAssetFolderUpdateRecordInput {
|
||||
pub folder_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub label: Option<String>,
|
||||
pub collapsed: Option<bool>,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct EditorAssetFolderDeleteRecordInput {
|
||||
pub folder_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct EditorAssetCreateRecordInput {
|
||||
pub asset_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub folder_id: String,
|
||||
pub label: String,
|
||||
pub asset_object_id: Option<String>,
|
||||
pub image_src: String,
|
||||
pub object_key: Option<String>,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub source_type: String,
|
||||
pub prompt: Option<String>,
|
||||
pub actual_prompt: Option<String>,
|
||||
pub model: Option<String>,
|
||||
pub provider: Option<String>,
|
||||
pub task_id: Option<String>,
|
||||
pub now_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct EditorAssetUpdateRecordInput {
|
||||
pub asset_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub label: Option<String>,
|
||||
pub folder_id: Option<String>,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct EditorAssetDeleteRecordInput {
|
||||
pub asset_id: String,
|
||||
pub owner_user_id: String,
|
||||
}
|
||||
|
||||
impl From<EditorProjectCreateRecordInput> for crate::module_bindings::EditorProjectCreateInput {
|
||||
fn from(input: EditorProjectCreateRecordInput) -> Self {
|
||||
Self {
|
||||
@@ -191,6 +288,90 @@ impl From<EditorProjectResourceCreateRecordInput>
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EditorAssetFolderCreateRecordInput>
|
||||
for crate::module_bindings::EditorAssetFolderCreateInput
|
||||
{
|
||||
fn from(input: EditorAssetFolderCreateRecordInput) -> Self {
|
||||
Self {
|
||||
folder_id: input.folder_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
label: input.label,
|
||||
sort_order: input.sort_order,
|
||||
now_micros: input.now_micros,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EditorAssetFolderUpdateRecordInput>
|
||||
for crate::module_bindings::EditorAssetFolderUpdateInput
|
||||
{
|
||||
fn from(input: EditorAssetFolderUpdateRecordInput) -> Self {
|
||||
Self {
|
||||
folder_id: input.folder_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
label: input.label,
|
||||
collapsed: input.collapsed,
|
||||
updated_at_micros: input.updated_at_micros,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EditorAssetFolderDeleteRecordInput>
|
||||
for crate::module_bindings::EditorAssetFolderDeleteInput
|
||||
{
|
||||
fn from(input: EditorAssetFolderDeleteRecordInput) -> Self {
|
||||
Self {
|
||||
folder_id: input.folder_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
updated_at_micros: input.updated_at_micros,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EditorAssetCreateRecordInput> for crate::module_bindings::EditorAssetCreateInput {
|
||||
fn from(input: EditorAssetCreateRecordInput) -> Self {
|
||||
Self {
|
||||
asset_id: input.asset_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
folder_id: input.folder_id,
|
||||
label: input.label,
|
||||
asset_object_id: input.asset_object_id,
|
||||
image_src: input.image_src,
|
||||
object_key: input.object_key,
|
||||
width: input.width,
|
||||
height: input.height,
|
||||
source_type: input.source_type,
|
||||
prompt: input.prompt,
|
||||
actual_prompt: input.actual_prompt,
|
||||
model: input.model,
|
||||
provider: input.provider,
|
||||
task_id: input.task_id,
|
||||
now_micros: input.now_micros,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EditorAssetUpdateRecordInput> for crate::module_bindings::EditorAssetUpdateInput {
|
||||
fn from(input: EditorAssetUpdateRecordInput) -> Self {
|
||||
Self {
|
||||
asset_id: input.asset_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
label: input.label,
|
||||
folder_id: input.folder_id,
|
||||
updated_at_micros: input.updated_at_micros,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EditorAssetDeleteRecordInput> for crate::module_bindings::EditorAssetDeleteInput {
|
||||
fn from(input: EditorAssetDeleteRecordInput) -> Self {
|
||||
Self {
|
||||
asset_id: input.asset_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn map_editor_project_optional_procedure_result(
|
||||
result: EditorProjectProcedureResult,
|
||||
) -> Result<Option<EditorProjectRecord>, SpacetimeClientError> {
|
||||
@@ -248,6 +429,58 @@ pub(crate) fn map_editor_project_resource_procedure_result(
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("图片画布资源快照"))
|
||||
}
|
||||
|
||||
pub(crate) fn map_editor_asset_library_procedure_result(
|
||||
result: EditorAssetLibraryProcedureResult,
|
||||
) -> Result<EditorAssetLibraryRecord, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
result
|
||||
.library
|
||||
.map(map_editor_asset_library_snapshot)
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("图片画布素材库快照"))
|
||||
}
|
||||
|
||||
pub(crate) fn map_editor_asset_folder_procedure_result(
|
||||
result: EditorAssetFolderProcedureResult,
|
||||
) -> Result<EditorAssetFolderRecord, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
result
|
||||
.folder
|
||||
.map(map_editor_asset_folder_snapshot)
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("图片画布素材文件夹快照"))
|
||||
}
|
||||
|
||||
pub(crate) fn map_editor_asset_folder_library_procedure_result(
|
||||
result: EditorAssetFolderProcedureResult,
|
||||
) -> Result<EditorAssetLibraryRecord, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
result
|
||||
.library
|
||||
.map(map_editor_asset_library_snapshot)
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("图片画布素材库快照"))
|
||||
}
|
||||
|
||||
pub(crate) fn map_editor_asset_procedure_result(
|
||||
result: EditorAssetProcedureResult,
|
||||
) -> Result<EditorAssetRecord, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
result
|
||||
.asset
|
||||
.map(map_editor_asset_snapshot)
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("图片画布素材快照"))
|
||||
}
|
||||
|
||||
fn map_editor_project_snapshot(
|
||||
snapshot: EditorProjectSnapshot,
|
||||
) -> Result<EditorProjectRecord, SpacetimeClientError> {
|
||||
@@ -309,3 +542,55 @@ fn map_editor_project_resource_snapshot(
|
||||
updated_at: format_timestamp_micros(snapshot.updated_at_micros),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_editor_asset_library_snapshot(
|
||||
snapshot: EditorAssetLibrarySnapshot,
|
||||
) -> EditorAssetLibraryRecord {
|
||||
EditorAssetLibraryRecord {
|
||||
folders: snapshot
|
||||
.folders
|
||||
.into_iter()
|
||||
.map(map_editor_asset_folder_snapshot)
|
||||
.collect(),
|
||||
assets: snapshot
|
||||
.assets
|
||||
.into_iter()
|
||||
.map(map_editor_asset_snapshot)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_editor_asset_folder_snapshot(
|
||||
snapshot: EditorAssetFolderSnapshot,
|
||||
) -> EditorAssetFolderRecord {
|
||||
EditorAssetFolderRecord {
|
||||
folder_id: snapshot.folder_id,
|
||||
label: snapshot.label,
|
||||
sort_order: snapshot.sort_order,
|
||||
collapsed: snapshot.collapsed,
|
||||
system_default: snapshot.system_default,
|
||||
created_at: format_timestamp_micros(snapshot.created_at_micros),
|
||||
updated_at: format_timestamp_micros(snapshot.updated_at_micros),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_editor_asset_snapshot(snapshot: EditorAssetSnapshot) -> EditorAssetRecord {
|
||||
EditorAssetRecord {
|
||||
asset_id: snapshot.asset_id,
|
||||
folder_id: snapshot.folder_id,
|
||||
label: snapshot.label,
|
||||
asset_object_id: snapshot.asset_object_id,
|
||||
image_src: snapshot.image_src,
|
||||
object_key: snapshot.object_key,
|
||||
width: snapshot.width,
|
||||
height: snapshot.height,
|
||||
source_type: snapshot.source_type,
|
||||
prompt: snapshot.prompt,
|
||||
actual_prompt: snapshot.actual_prompt,
|
||||
model: snapshot.model,
|
||||
provider: snapshot.provider,
|
||||
task_id: snapshot.task_id,
|
||||
created_at: format_timestamp_micros(snapshot.created_at_micros),
|
||||
updated_at: format_timestamp_micros(snapshot.updated_at_micros),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user