feat(category): 类目树、类目属性、属性字典维护系统构建完成
This commit is contained in:
@@ -1,15 +1,24 @@
|
||||
import { api } from '@/services/api';
|
||||
|
||||
export type CatalogCacheStatus = 'fresh' | 'stale' | 'expired' | 'missing';
|
||||
|
||||
export type AdminPlatform = {
|
||||
id: string; code: string; name: string; status: string;
|
||||
source: { configured: boolean; client_id_hint: string | null; updated_at: string | null };
|
||||
summary: { category_count: number; last_tree_sync_at: string | null; last_error: string | null };
|
||||
summary: {
|
||||
category_count: number; last_tree_sync_at: string | null;
|
||||
next_tree_sync_at: string | null; last_error: string | null;
|
||||
};
|
||||
};
|
||||
|
||||
export type CatalogCategory = {
|
||||
id: string; parent_id: string | null; external_category_id: string;
|
||||
external_type_id: string | null; name: string; path: string;
|
||||
is_active: boolean; synced_at: string | null;
|
||||
attribute_last_success_at: string | null;
|
||||
attribute_cache_status: CatalogCacheStatus | null;
|
||||
attribute_last_error: string | null;
|
||||
attribute_last_error_at: string | null;
|
||||
};
|
||||
|
||||
export type CatalogAttribute = {
|
||||
@@ -19,6 +28,13 @@ export type CatalogAttribute = {
|
||||
is_aspect: boolean; is_collection: boolean; max_value_count: number;
|
||||
dictionary_id: string | null; category_dependent: boolean;
|
||||
is_active: boolean; synced_at: string | null; dictionary_value_count: number;
|
||||
last_success_at: string | null; cache_status: CatalogCacheStatus;
|
||||
last_error_message: string | null; last_error_at: string | null;
|
||||
dictionary_last_success_at: string | null;
|
||||
dictionary_cache_status: CatalogCacheStatus | null;
|
||||
dictionary_is_complete: boolean | null;
|
||||
dictionary_last_error_message: string | null;
|
||||
dictionary_last_error_at: string | null;
|
||||
};
|
||||
|
||||
export type CatalogValue = {
|
||||
@@ -29,12 +45,35 @@ export type CatalogValue = {
|
||||
export type CatalogRun = {
|
||||
id: string; platform_id: string; scope: 'tree' | 'attributes' | 'dictionary';
|
||||
scope_key: string; category_id: string | null; attribute_id: string | null;
|
||||
trigger: string; status: string; result: Record<string, unknown>;
|
||||
trigger: string; priority: 'high' | 'low'; status: string;
|
||||
result: Record<string, unknown> | null;
|
||||
error_code: string | null; error_message: string | null;
|
||||
attempt_count: number; created_at: string;
|
||||
started_at: string | null; completed_at: string | null;
|
||||
};
|
||||
|
||||
export type CatalogRefreshPolicy = {
|
||||
attribute_fresh_days: number; attribute_expire_days: number;
|
||||
dictionary_fresh_days: number; dictionary_expire_days: number;
|
||||
updated_at: string | null;
|
||||
};
|
||||
|
||||
export type CatalogRefreshPolicyInput = Omit<CatalogRefreshPolicy, 'updated_at'>;
|
||||
|
||||
export type AttributeSyncSummary = {
|
||||
total: number; fresh: number; stale: number; expired: number; missing: number;
|
||||
active_batch_id: string | null; evaluated_at: string;
|
||||
};
|
||||
|
||||
export type AttributeBatchMode = 'missing_expired' | 'missing_stale_expired' | 'all';
|
||||
|
||||
export type AttributeSyncBatch = {
|
||||
id: string; platform_id: string; mode: AttributeBatchMode; status: string;
|
||||
total_count: number; pending_count: number; running_count: number;
|
||||
succeeded_count: number; failed_count: number; cancelled_count: number;
|
||||
created_at: string; started_at: string | null; completed_at: string | null;
|
||||
};
|
||||
|
||||
export type SyncRequest =
|
||||
| { scope: 'tree' }
|
||||
| { scope: 'attributes'; category_id: string }
|
||||
@@ -49,6 +88,14 @@ export const platformCatalogAdminApi = {
|
||||
),
|
||||
categories: (platformId: string) =>
|
||||
api.get<CatalogCategory[]>(`/system/platform-catalog/platforms/${platformId}/categories`),
|
||||
refreshPolicy: (platformId: string) =>
|
||||
api.get<CatalogRefreshPolicy>(
|
||||
`/system/platform-catalog/platforms/${platformId}/refresh-policy`,
|
||||
),
|
||||
updateRefreshPolicy: (platformId: string, input: CatalogRefreshPolicyInput) =>
|
||||
api.put<CatalogRefreshPolicy>(
|
||||
`/system/platform-catalog/platforms/${platformId}/refresh-policy`, input,
|
||||
),
|
||||
attributes: (platformId: string, categoryId: string) =>
|
||||
api.get<CatalogAttribute[]>(
|
||||
`/system/platform-catalog/platforms/${platformId}/categories/${categoryId}/attributes`,
|
||||
@@ -65,4 +112,18 @@ export const platformCatalogAdminApi = {
|
||||
),
|
||||
runs: (platformId: string) =>
|
||||
api.get<CatalogRun[]>(`/system/platform-catalog/platforms/${platformId}/syncs?limit=20`),
|
||||
attributeSyncSummary: (platformId: string) =>
|
||||
api.get<AttributeSyncSummary>(
|
||||
`/system/platform-catalog/platforms/${platformId}/attribute-sync-summary`,
|
||||
),
|
||||
attributeSyncBatches: (platformId: string) =>
|
||||
api.get<AttributeSyncBatch[]>(
|
||||
`/system/platform-catalog/platforms/${platformId}/attribute-sync-batches?limit=10`,
|
||||
),
|
||||
createAttributeSyncBatch: (platformId: string, mode: AttributeBatchMode) =>
|
||||
api.post<AttributeSyncBatch>(
|
||||
`/system/platform-catalog/platforms/${platformId}/attribute-sync-batches`,
|
||||
{ mode },
|
||||
{ headers: { 'Idempotency-Key': crypto.randomUUID() } },
|
||||
),
|
||||
};
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import type {
|
||||
ProductAttributeDictionaryValue,
|
||||
ProductAttributeSchema,
|
||||
ProductAttributeDictionaryResult,
|
||||
ProductAttributeSchemaResult,
|
||||
ProductCatalogRefreshRun,
|
||||
ProductEditorCategoryOption,
|
||||
ProductEditorContext,
|
||||
ProductEditorSnapshot,
|
||||
ProductEditorValidation,
|
||||
ProductPublishPreflight,
|
||||
Operation,
|
||||
SaveProductEditorDraftRequest,
|
||||
SaveProductEditorDraftResponse,
|
||||
@@ -40,34 +42,22 @@ export const productEditorApi = {
|
||||
'If-Match': `"${revisions.product}:${revisions.profile}"`,
|
||||
},
|
||||
}),
|
||||
categoryOptions: (
|
||||
profileId: string,
|
||||
platformId: string,
|
||||
search?: string,
|
||||
storeId?: string | null
|
||||
) =>
|
||||
categoryOptions: (profileId: string, platformId: string, search?: string) =>
|
||||
api.get<ProductEditorCategoryOption[]>(
|
||||
`/product-platform-profiles/${profileId}/category-options`,
|
||||
{
|
||||
params: {
|
||||
...(search ? { q: search } : {}),
|
||||
...(storeId ? { store_id: storeId } : {}),
|
||||
},
|
||||
headers: { 'X-Atlas-Platform-Id': platformId },
|
||||
}
|
||||
),
|
||||
attributeSchema: (
|
||||
profileId: string,
|
||||
platformId: string,
|
||||
categoryId?: string | null,
|
||||
storeId?: string | null
|
||||
) =>
|
||||
api.get<ProductAttributeSchema[]>(
|
||||
attributeSchema: (profileId: string, platformId: string, categoryId?: string | null) =>
|
||||
api.get<ProductAttributeSchemaResult>(
|
||||
`/product-platform-profiles/${profileId}/attribute-schema`,
|
||||
{
|
||||
params: {
|
||||
...(categoryId ? { category_id: categoryId } : {}),
|
||||
...(storeId ? { store_id: storeId } : {}),
|
||||
},
|
||||
headers: { 'X-Atlas-Platform-Id': platformId },
|
||||
}
|
||||
@@ -76,8 +66,14 @@ export const productEditorApi = {
|
||||
api.get<ProductEditorValidation>(`/product-platform-profiles/${profileId}/validation`, {
|
||||
headers: { 'X-Atlas-Platform-Id': platformId },
|
||||
}),
|
||||
publishPreflight: (profileId: string, platformId: string, variantIds: string[]) =>
|
||||
api.post<ProductPublishPreflight>(
|
||||
`/product-platform-profiles/${profileId}/publish-preflights`,
|
||||
{ variant_ids: variantIds },
|
||||
{ headers: { 'X-Atlas-Platform-Id': platformId } }
|
||||
),
|
||||
syncAttributeSchema: (profileId: string, platformId: string, categoryId: string) =>
|
||||
api.post<{ operation: Operation }>(
|
||||
api.post<{ run: ProductCatalogRefreshRun }>(
|
||||
`/product-platform-profiles/${profileId}/attribute-schema-syncs`,
|
||||
undefined,
|
||||
{
|
||||
@@ -91,18 +87,16 @@ export const productEditorApi = {
|
||||
attributeDictionary: (
|
||||
profileId: string,
|
||||
platformId: string,
|
||||
dictionaryId: string,
|
||||
attributeId: string,
|
||||
search?: string,
|
||||
categoryId?: string | null,
|
||||
storeId?: string | null,
|
||||
cursor?: string | null
|
||||
) =>
|
||||
api.get<{ items: ProductAttributeDictionaryValue[]; next_cursor: string | null }>(
|
||||
`/product-platform-profiles/${profileId}/attribute-dictionaries/${encodeURIComponent(dictionaryId)}`,
|
||||
api.get<ProductAttributeDictionaryResult>(
|
||||
`/product-platform-profiles/${profileId}/attribute-dictionaries/${encodeURIComponent(attributeId)}`,
|
||||
{
|
||||
params: {
|
||||
...(categoryId ? { category_id: categoryId } : {}),
|
||||
...(storeId ? { store_id: storeId } : {}),
|
||||
...(search ? { q: search } : {}),
|
||||
...(cursor ? { cursor } : {}),
|
||||
},
|
||||
@@ -112,12 +106,12 @@ export const productEditorApi = {
|
||||
syncAttributeDictionary: (
|
||||
profileId: string,
|
||||
platformId: string,
|
||||
dictionaryId: string,
|
||||
attributeId: string,
|
||||
categoryId: string,
|
||||
query: string
|
||||
) =>
|
||||
api.post<{ operation: Operation }>(
|
||||
`/product-platform-profiles/${profileId}/attribute-dictionaries/${encodeURIComponent(dictionaryId)}/syncs`,
|
||||
api.post<{ run: ProductCatalogRefreshRun }>(
|
||||
`/product-platform-profiles/${profileId}/attribute-dictionaries/${encodeURIComponent(attributeId)}/syncs`,
|
||||
undefined,
|
||||
{
|
||||
params: { category_id: categoryId, q: query },
|
||||
|
||||
Reference in New Issue
Block a user