feat(aihr): 重构运营后台与租户知识治理
- 重构运营总览、侧栏和内容运营工作台\n- 增加大喇叭、成果审核与运营统计链路\n- 补齐租户、知识空间、分类和知识维护闭环\n- 加固标签页租户上下文、停用租户写保护与迁移预检
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import request from '@/utils/request';
|
||||
|
||||
type ApiResult<T> = {
|
||||
code: number;
|
||||
msg: string;
|
||||
data: T;
|
||||
};
|
||||
|
||||
export type BroadcastStatus = 'PUBLISHED' | 'WITHDRAWN';
|
||||
|
||||
export type BroadcastAdminMessage = {
|
||||
id: number;
|
||||
title: string;
|
||||
content: string;
|
||||
status: BroadcastStatus;
|
||||
currentVersion: number;
|
||||
publishedBy: number;
|
||||
publishedAt: string;
|
||||
withdrawnBy?: number;
|
||||
withdrawnAt?: string;
|
||||
withdrawReason?: string;
|
||||
};
|
||||
|
||||
export type BroadcastAdminPage = {
|
||||
/** Effective request tenant, including an administrator's dynamic-tenant selection. */
|
||||
tenantId: string;
|
||||
total: number;
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
rows: BroadcastAdminMessage[];
|
||||
};
|
||||
|
||||
export type PublishBroadcastRequest = {
|
||||
requestId: string;
|
||||
title: string;
|
||||
content: string;
|
||||
expectedTenantId: string;
|
||||
};
|
||||
|
||||
export type WithdrawBroadcastRequest = {
|
||||
reason: string;
|
||||
expectedTenantId: string;
|
||||
};
|
||||
|
||||
export function listBroadcastAdminMessages(params: {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
status?: BroadcastStatus;
|
||||
}): Promise<ApiResult<BroadcastAdminPage>> {
|
||||
return request({
|
||||
url: '/api/aihr/broadcast/admin/messages',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
export function publishBroadcast(data: PublishBroadcastRequest): Promise<ApiResult<{ id: number; version: number }>> {
|
||||
return request({
|
||||
url: '/api/aihr/broadcast/messages',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
export function withdrawBroadcast(id: number, data: WithdrawBroadcastRequest): Promise<ApiResult<void>> {
|
||||
return request({
|
||||
url: `/api/aihr/broadcast/messages/${id}/withdraw`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
@@ -6,27 +6,44 @@ type ApiResult<T> = {
|
||||
data: T;
|
||||
};
|
||||
|
||||
export type DashboardHeroEntry = {
|
||||
export type DashboardState = 'success' | 'warning' | 'danger' | 'info';
|
||||
export type DashboardRecordState = DashboardState | 'active' | 'done';
|
||||
|
||||
export type DashboardTodo = {
|
||||
key: string;
|
||||
status: string;
|
||||
type: string;
|
||||
note: string;
|
||||
};
|
||||
|
||||
export type DashboardStage = {
|
||||
step: number;
|
||||
name: string;
|
||||
desc: string;
|
||||
label: string;
|
||||
state: string;
|
||||
tagType: string;
|
||||
count: number;
|
||||
detail: string;
|
||||
path: string;
|
||||
actionLabel: string;
|
||||
tone: DashboardState;
|
||||
available?: boolean;
|
||||
};
|
||||
|
||||
export type DashboardRisk = {
|
||||
name: string;
|
||||
owner: string;
|
||||
status: string;
|
||||
type: string;
|
||||
export type DashboardPilotProgress = {
|
||||
key: string;
|
||||
label: string;
|
||||
value: string;
|
||||
detail: string;
|
||||
state: DashboardState;
|
||||
available?: boolean;
|
||||
};
|
||||
|
||||
export type DashboardAcceptance = {
|
||||
key: string;
|
||||
label: string;
|
||||
detail: string;
|
||||
state: DashboardState;
|
||||
};
|
||||
|
||||
export type DashboardKnowledge = {
|
||||
key: string;
|
||||
label: string;
|
||||
value: string;
|
||||
detail: string;
|
||||
tone: DashboardState;
|
||||
path: string;
|
||||
available?: boolean;
|
||||
};
|
||||
|
||||
export type DashboardTrainingRecord = {
|
||||
@@ -34,36 +51,27 @@ export type DashboardTrainingRecord = {
|
||||
scene: string;
|
||||
score: number;
|
||||
status: string;
|
||||
state: string;
|
||||
state: DashboardRecordState;
|
||||
time: string;
|
||||
};
|
||||
|
||||
export type DashboardPipelineStep = {
|
||||
name: string;
|
||||
count: string;
|
||||
state: string;
|
||||
};
|
||||
|
||||
export type DashboardMetric = {
|
||||
export type DashboardHealth = {
|
||||
key: string;
|
||||
label: string;
|
||||
value: string;
|
||||
target: string;
|
||||
type: string;
|
||||
detail: string;
|
||||
state: DashboardState;
|
||||
available?: boolean;
|
||||
};
|
||||
|
||||
export type DashboardOverview = {
|
||||
snapshotTime: string;
|
||||
heroEntries: DashboardHeroEntry[];
|
||||
stages: DashboardStage[];
|
||||
risks: DashboardRisk[];
|
||||
todos: DashboardTodo[];
|
||||
pilotProgress: DashboardPilotProgress[];
|
||||
acceptance: DashboardAcceptance[];
|
||||
knowledge: DashboardKnowledge[];
|
||||
records: DashboardTrainingRecord[];
|
||||
pipeline: DashboardPipelineStep[];
|
||||
pipelineSummary: {
|
||||
todayNew: string;
|
||||
pending: string;
|
||||
completed: string;
|
||||
};
|
||||
metrics: DashboardMetric[];
|
||||
health: DashboardHealth[];
|
||||
};
|
||||
|
||||
export function getDashboardOverview(): Promise<ApiResult<DashboardOverview>> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import axios from 'axios';
|
||||
import request, { globalHeaders } from '@/utils/request';
|
||||
import request, { globalHeaders, reconcileTenantContextBlobResponse } from '@/utils/request';
|
||||
|
||||
type ApiResult<T> = {
|
||||
code: number;
|
||||
@@ -210,13 +210,22 @@ export function getPracticeReview(id: number): Promise<ApiResult<ReviewDetail>>
|
||||
}
|
||||
|
||||
export async function getPracticeAudioBlobUrl(ossId: number | string): Promise<string> {
|
||||
const response = await axios({
|
||||
method: 'get',
|
||||
url: `${import.meta.env.VITE_APP_BASE_API}/api/aihr/mobile/oss/${ossId}`,
|
||||
responseType: 'blob',
|
||||
headers: globalHeaders()
|
||||
});
|
||||
return URL.createObjectURL(response.data);
|
||||
try {
|
||||
const response = await axios({
|
||||
method: 'get',
|
||||
url: `${import.meta.env.VITE_APP_BASE_API}/api/aihr/mobile/oss/${ossId}`,
|
||||
responseType: 'blob',
|
||||
headers: globalHeaders()
|
||||
});
|
||||
const contentType = String(response.headers['content-type'] || '');
|
||||
if (contentType.includes('application/json') && (await reconcileTenantContextBlobResponse(response.data))) {
|
||||
throw new Error('租户上下文已变更,请刷新后重试');
|
||||
}
|
||||
return URL.createObjectURL(response.data);
|
||||
} catch (error) {
|
||||
await reconcileTenantContextBlobResponse(axios.isAxiosError(error) ? error.response?.data : undefined);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export function markPracticeReviewed(id: number, data: ReviewAdviceRequest): Promise<ApiResult<null>> {
|
||||
|
||||
@@ -29,11 +29,24 @@ export type KnowledgeDocument = {
|
||||
name: string;
|
||||
type: string;
|
||||
status: string;
|
||||
categoryId?: number | null;
|
||||
categoryName?: string | null;
|
||||
ossId?: number | null;
|
||||
fragmentCount: number;
|
||||
updateTime?: string | null;
|
||||
};
|
||||
|
||||
export type KnowledgeCategory = {
|
||||
id: number;
|
||||
code: string;
|
||||
name: string;
|
||||
status: 'ACTIVE' | 'DISABLED';
|
||||
sortOrder: number;
|
||||
documentCount: number;
|
||||
};
|
||||
|
||||
export type CategoryForm = Pick<KnowledgeCategory, 'code' | 'name' | 'status' | 'sortOrder'>;
|
||||
|
||||
export type UnbindDocumentResult = {
|
||||
attachId: number;
|
||||
spaceCode: string;
|
||||
@@ -68,8 +81,7 @@ export type AppForm = {
|
||||
export type IssuedToken = { appCode: string; token: string; expiresTime?: string | null };
|
||||
export type CreatedApp = { app: KnowledgeApp; token?: string | null };
|
||||
|
||||
export const listKnowledgeSpaces = (): Promise<ApiResult<KnowledgeSpace[]>> =>
|
||||
request({ url: '/api/knowledge/admin/spaces', method: 'get' });
|
||||
export const listKnowledgeSpaces = (): Promise<ApiResult<KnowledgeSpace[]>> => request({ url: '/api/knowledge/admin/spaces', method: 'get' });
|
||||
|
||||
export const createKnowledgeSpace = (data: SpaceForm): Promise<ApiResult<KnowledgeSpace>> =>
|
||||
request({ url: '/api/knowledge/admin/spaces', method: 'post', data });
|
||||
@@ -80,17 +92,31 @@ export const updateKnowledgeSpace = (id: number, data: SpaceForm): Promise<ApiRe
|
||||
export const listSpaceDocuments = (id: number): Promise<ApiResult<KnowledgeDocument[]>> =>
|
||||
request({ url: `/api/knowledge/admin/spaces/${id}/documents`, method: 'get' });
|
||||
|
||||
export const assignSpaceDocumentCategory = (id: number, attachId: number, categoryId?: number | null): Promise<ApiResult<KnowledgeDocument>> =>
|
||||
request({ url: `/api/knowledge/admin/spaces/${id}/documents/${attachId}/category`, method: 'put', data: { categoryId: categoryId ?? null } });
|
||||
|
||||
export const unbindSpaceDocument = (id: number, attachId: number): Promise<ApiResult<UnbindDocumentResult>> =>
|
||||
request({ url: `/api/knowledge/admin/spaces/${id}/documents/${attachId}`, method: 'delete' });
|
||||
|
||||
export const listKnowledgeCategories = (id: number): Promise<ApiResult<KnowledgeCategory[]>> =>
|
||||
request({ url: `/api/knowledge/admin/spaces/${id}/categories`, method: 'get' });
|
||||
|
||||
export const createKnowledgeCategory = (id: number, data: CategoryForm): Promise<ApiResult<KnowledgeCategory>> =>
|
||||
request({ url: `/api/knowledge/admin/spaces/${id}/categories`, method: 'post', data });
|
||||
|
||||
export const updateKnowledgeCategory = (id: number, categoryId: number, data: CategoryForm): Promise<ApiResult<KnowledgeCategory>> =>
|
||||
request({ url: `/api/knowledge/admin/spaces/${id}/categories/${categoryId}`, method: 'put', data });
|
||||
|
||||
export const deleteKnowledgeCategory = (id: number, categoryId: number): Promise<ApiResult<void>> =>
|
||||
request({ url: `/api/knowledge/admin/spaces/${id}/categories/${categoryId}`, method: 'delete' });
|
||||
|
||||
export const listSpaceGrants = (id: number): Promise<ApiResult<SpaceGrant[]>> =>
|
||||
request({ url: `/api/knowledge/admin/spaces/${id}/grants`, method: 'get' });
|
||||
|
||||
export const replaceSpaceGrants = (id: number, grants: SpaceGrant[]): Promise<ApiResult<SpaceGrant[]>> =>
|
||||
request({ url: `/api/knowledge/admin/spaces/${id}/grants`, method: 'put', data: { grants } });
|
||||
|
||||
export const listKnowledgeApps = (): Promise<ApiResult<KnowledgeApp[]>> =>
|
||||
request({ url: '/api/knowledge/admin/apps', method: 'get' });
|
||||
export const listKnowledgeApps = (): Promise<ApiResult<KnowledgeApp[]>> => request({ url: '/api/knowledge/admin/apps', method: 'get' });
|
||||
|
||||
export const createKnowledgeApp = (data: AppForm): Promise<ApiResult<CreatedApp>> =>
|
||||
request({ url: '/api/knowledge/admin/apps', method: 'post', data });
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import request from '@/utils/request';
|
||||
|
||||
type ApiResult<T> = {
|
||||
code: number;
|
||||
msg: string;
|
||||
data: T;
|
||||
};
|
||||
|
||||
export type WorkReport = {
|
||||
id: number;
|
||||
type: string;
|
||||
typeLabel: string;
|
||||
title: string;
|
||||
content: string;
|
||||
attachmentName?: string;
|
||||
attachmentAvailable?: boolean;
|
||||
attachmentUrl?: string;
|
||||
status: string;
|
||||
statusLabel: string;
|
||||
submitterName: string;
|
||||
reviewNote?: string;
|
||||
createdAt: string;
|
||||
reviewedAt?: string;
|
||||
};
|
||||
|
||||
export type WorkReportReview = {
|
||||
decision: 'APPROVE' | 'REJECT';
|
||||
note?: string;
|
||||
};
|
||||
|
||||
export function listWorkReports(status?: string): Promise<ApiResult<WorkReport[]>> {
|
||||
return request({
|
||||
url: '/api/aihr/work-report/reports',
|
||||
method: 'get',
|
||||
params: { status }
|
||||
});
|
||||
}
|
||||
|
||||
export function reviewWorkReport(id: number, data: WorkReportReview): Promise<ApiResult<WorkReport>> {
|
||||
return request({
|
||||
url: `/api/aihr/work-report/reports/${id}/review`,
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
export function getWorkReportAttachment(url: string): Promise<Blob> {
|
||||
return request({
|
||||
url,
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
}) as Promise<Blob>;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import request from '@/utils/request';
|
||||
|
||||
type ApiResult<T> = {
|
||||
code: number;
|
||||
msg: string;
|
||||
data: T;
|
||||
};
|
||||
|
||||
export type WorkResultProject = {
|
||||
projectCode: string;
|
||||
projectName: string;
|
||||
};
|
||||
|
||||
export type WorkResultItem = {
|
||||
captureId: number;
|
||||
suggestedType: string;
|
||||
category: string;
|
||||
summary: string;
|
||||
businessStatus: string;
|
||||
deliveryStatus: string;
|
||||
occurredAt: string;
|
||||
sourceType: string;
|
||||
sourceUrl: string;
|
||||
};
|
||||
|
||||
export type MemberWorkResult = {
|
||||
ownerUserId: number;
|
||||
ownerName: string;
|
||||
projectCode: string;
|
||||
projectName: string;
|
||||
workDate: string;
|
||||
version: number;
|
||||
generatedAt: string;
|
||||
sections: Record<string, WorkResultItem[]>;
|
||||
total: number;
|
||||
pending: number;
|
||||
};
|
||||
|
||||
export type ProjectWorkResult = {
|
||||
projectCode: string;
|
||||
projectName: string;
|
||||
workDate: string;
|
||||
contributorCount: number;
|
||||
resultCount: number;
|
||||
pendingCount: number;
|
||||
highPriorityCount: number;
|
||||
members: MemberWorkResult[];
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
};
|
||||
|
||||
export function listWorkResultProjects(): Promise<ApiResult<WorkResultProject[]>> {
|
||||
return request({
|
||||
url: '/api/aihr/work-results/projects',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
export function getProjectWorkResult(params: {
|
||||
projectCode: string;
|
||||
workDate: string;
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
}): Promise<ApiResult<ProjectWorkResult>> {
|
||||
return request({
|
||||
url: '/api/aihr/work-results/project',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
@@ -71,6 +71,14 @@ export function dynamicTenant(tenantId: string | number) {
|
||||
});
|
||||
}
|
||||
|
||||
// 查询当前超级管理员的动态租户上下文
|
||||
export function getDynamicTenant(): AxiosPromise<string | null> {
|
||||
return request({
|
||||
url: '/system/tenant/dynamic',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 清除动态租户
|
||||
export function dynamicClear() {
|
||||
return request({
|
||||
|
||||
@@ -51,6 +51,7 @@ export interface TenantVO {
|
||||
companyName: string;
|
||||
domain: any;
|
||||
tenantId: string;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
export interface TenantInfo {
|
||||
|
||||
Reference in New Issue
Block a user