feat: add tenant content management features for superadmin

- Implemented API endpoints for listing tenant contents and updating content status.
- Added Swagger documentation for new endpoints:
  - GET /super/v1/tenants/{tenantID}/contents
  - PATCH /super/v1/tenants/{tenantID}/contents/{contentID}/status
- Created DTOs for content item and status update form.
- Enhanced frontend to support content management in the tenant detail page.
- Added search and filter functionalities for tenant contents.
- Implemented unpublish functionality with confirmation dialog.
- Updated service layer to handle new content management logic.
This commit is contained in:
2025-12-24 16:10:07 +08:00
parent 8fa321dbf6
commit 568f5cda43
13 changed files with 1344 additions and 3 deletions

View File

@@ -0,0 +1,70 @@
import { requestJson } from './apiClient';
function normalizeItems(items) {
if (Array.isArray(items)) return items;
if (items && typeof items === 'object') return [items];
return [];
}
export const ContentService = {
async listTenantContents(
tenantID,
{
page,
limit,
keyword,
status,
visibility,
user_id,
published_at_from,
published_at_to,
created_at_from,
created_at_to,
sortField,
sortOrder
} = {}
) {
if (!tenantID) throw new Error('tenantID is required');
const iso = (d) => {
if (!d) return undefined;
const date = d instanceof Date ? d : new Date(d);
if (Number.isNaN(date.getTime())) return undefined;
return date.toISOString();
};
const query = {
page,
limit,
keyword,
status,
visibility,
user_id,
published_at_from: iso(published_at_from),
published_at_to: iso(published_at_to),
created_at_from: iso(created_at_from),
created_at_to: iso(created_at_to)
};
if (sortField && sortOrder) {
if (sortOrder === 1) query.asc = sortField;
if (sortOrder === -1) query.desc = sortField;
}
const data = await requestJson(`/super/v1/tenants/${tenantID}/contents`, { query });
return {
page: data?.page ?? page ?? 1,
limit: data?.limit ?? limit ?? 10,
total: data?.total ?? 0,
items: normalizeItems(data?.items)
};
}
,
async updateTenantContentStatus(tenantID, contentID, { status } = {}) {
if (!tenantID) throw new Error('tenantID is required');
if (!contentID) throw new Error('contentID is required');
return requestJson(`/super/v1/tenants/${tenantID}/contents/${contentID}/status`, {
method: 'PATCH',
body: { status }
});
}
};