Merge pull request #282 from SuanmoSuanyangTechnology/feature/ontology_v2_zy
Feature/ontology v2 zy
This commit is contained in:
@@ -1,33 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 13:59:41
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 13:59:41
|
||||||
|
*/
|
||||||
import { request } from '@/utils/request'
|
import { request } from '@/utils/request'
|
||||||
import type { ApiKey } from '@/views/ApiKeyManagement/types'
|
import type { ApiKey } from '@/views/ApiKeyManagement/types'
|
||||||
|
|
||||||
// API Key列表
|
// API Key list
|
||||||
export const getApiKeyListUrl = '/apikeys'
|
export const getApiKeyListUrl = '/apikeys'
|
||||||
export const getApiKeyList = (data: Record<string, unknown>) => {
|
export const getApiKeyList = (data: Record<string, unknown>) => {
|
||||||
return request.get(getApiKeyListUrl, data)
|
return request.get(getApiKeyListUrl, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// API Key详情
|
// API Key details
|
||||||
export const getApiKey = (id: string) => {
|
export const getApiKey = (id: string) => {
|
||||||
return request.get(`/apikeys/${id}`)
|
return request.get(`/apikeys/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建API Key
|
// Create API Key
|
||||||
export const createApiKey = (values: ApiKey) => {
|
export const createApiKey = (values: ApiKey) => {
|
||||||
return request.post('/apikeys', values)
|
return request.post('/apikeys', values)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新API Key
|
// Update API Key
|
||||||
export const updateApiKey = (id: string, values: ApiKey) => {
|
export const updateApiKey = (id: string, values: ApiKey) => {
|
||||||
return request.put(`/apikeys/${id}`, values)
|
return request.put(`/apikeys/${id}`, values)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除 API Key
|
// Delete API Key
|
||||||
export const deleteApiKey = (id: string) => {
|
export const deleteApiKey = (id: string) => {
|
||||||
return request.delete(`/apikeys/${id}`)
|
return request.delete(`/apikeys/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用统计
|
// Usage statistics
|
||||||
export const getApiKeyStats = (app_key_id: string) => {
|
export const getApiKeyStats = (app_key_id: string) => {
|
||||||
return request.get(`/apikeys/${app_key_id}/stats`)
|
return request.get(`/apikeys/${app_key_id}/stats`)
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 13:59:45
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 13:59:45
|
||||||
|
*/
|
||||||
import { request } from '@/utils/request'
|
import { request } from '@/utils/request'
|
||||||
import type { ApplicationModalData } from '@/views/ApplicationManagement/types'
|
import type { ApplicationModalData } from '@/views/ApplicationManagement/types'
|
||||||
import type { Config } from '@/views/ApplicationConfig/types'
|
import type { Config } from '@/views/ApplicationConfig/types'
|
||||||
@@ -5,71 +11,72 @@ import { handleSSE, type SSEMessage } from '@/utils/stream'
|
|||||||
import type { QueryParams } from '@/views/Conversation/types'
|
import type { QueryParams } from '@/views/Conversation/types'
|
||||||
import type { WorkflowConfig } from '@/views/Workflow/types'
|
import type { WorkflowConfig } from '@/views/Workflow/types'
|
||||||
|
|
||||||
// 应用列表
|
// Application list
|
||||||
export const getApplicationListUrl = '/apps'
|
export const getApplicationListUrl = '/apps'
|
||||||
export const getApplicationList = (data: Record<string, unknown>) => {
|
export const getApplicationList = (data: Record<string, unknown>) => {
|
||||||
return request.get(getApplicationListUrl, data)
|
return request.get(getApplicationListUrl, data)
|
||||||
}
|
}
|
||||||
// 获取应用配置
|
// Get application config
|
||||||
export const getApplicationConfig = (id: string) => {
|
export const getApplicationConfig = (id: string) => {
|
||||||
return request.get(`/apps/${id}/config`)
|
return request.get(`/apps/${id}/config`)
|
||||||
}
|
}
|
||||||
// 获取集群应用配置
|
// Get multi-agent config
|
||||||
export const getMultiAgentConfig = (id: string) => {
|
export const getMultiAgentConfig = (id: string) => {
|
||||||
return request.get(`/apps/${id}/multi-agent`)
|
return request.get(`/apps/${id}/multi-agent`)
|
||||||
}
|
}
|
||||||
// 获取 workflow应用配置
|
// Get workflow config
|
||||||
export const getWorkflowConfig = (id: string) => {
|
export const getWorkflowConfig = (id: string) => {
|
||||||
return request.get(`/apps/${id}/workflow`)
|
return request.get(`/apps/${id}/workflow`)
|
||||||
}
|
}
|
||||||
// 应用详情
|
// Application details
|
||||||
export const getApplication = (id: string) => {
|
export const getApplication = (id: string) => {
|
||||||
return request.get(`/apps/${id}`)
|
return request.get(`/apps/${id}`)
|
||||||
}
|
}
|
||||||
// 更新应用
|
// Update application
|
||||||
export const updateApplication = (id: string, values: ApplicationModalData) => {
|
export const updateApplication = (id: string, values: ApplicationModalData) => {
|
||||||
return request.put(`/apps/${id}`, values)
|
return request.put(`/apps/${id}`, values)
|
||||||
}
|
}
|
||||||
// 创建应用
|
// Create application
|
||||||
export const addApplication = (values: ApplicationModalData) => {
|
export const addApplication = (values: ApplicationModalData) => {
|
||||||
return request.post('/apps', values)
|
return request.post('/apps', values)
|
||||||
}
|
}
|
||||||
// 保存Agent配置
|
// Save agent config
|
||||||
export const saveAgentConfig = (app_id: string, values: Config) => {
|
export const saveAgentConfig = (app_id: string, values: Config) => {
|
||||||
return request.put(`/apps/${app_id}/config`, values)
|
return request.put(`/apps/${app_id}/config`, values)
|
||||||
}
|
}
|
||||||
// 保存集群配置
|
// Save multi-agent config
|
||||||
export const saveMultiAgentConfig = (app_id: string, values: Config) => {
|
export const saveMultiAgentConfig = (app_id: string, values: Config) => {
|
||||||
return request.put(`/apps/${app_id}/multi-agent`, values)
|
return request.put(`/apps/${app_id}/multi-agent`, values)
|
||||||
}
|
}
|
||||||
// 保存workflow配置
|
// Save workflow config
|
||||||
export const saveWorkflowConfig = (app_id: string, values: WorkflowConfig) => {
|
export const saveWorkflowConfig = (app_id: string, values: WorkflowConfig) => {
|
||||||
return request.put(`/apps/${app_id}/workflow`, values)
|
return request.put(`/apps/${app_id}/workflow`, values)
|
||||||
}
|
}
|
||||||
// 模型比对试运行
|
// Model comparison test run
|
||||||
export const runCompare = (app_id: string, values: Record<string, unknown>, onMessage?: (data: SSEMessage[]) => void) => {
|
export const runCompare = (app_id: string, values: Record<string, unknown>, onMessage?: (data: SSEMessage[]) => void) => {
|
||||||
return handleSSE(`/apps/${app_id}/draft/run/compare`, values, onMessage)
|
return handleSSE(`/apps/${app_id}/draft/run/compare`, values, onMessage)
|
||||||
}
|
}
|
||||||
|
// Test run
|
||||||
export const draftRun = (app_id: string, values: Record<string, unknown>, onMessage?: (data: SSEMessage[]) => void) => {
|
export const draftRun = (app_id: string, values: Record<string, unknown>, onMessage?: (data: SSEMessage[]) => void) => {
|
||||||
return handleSSE(`/apps/${app_id}/draft/run`, values, onMessage)
|
return handleSSE(`/apps/${app_id}/draft/run`, values, onMessage)
|
||||||
}
|
}
|
||||||
// 删除应用
|
// Delete application
|
||||||
export const deleteApplication = (app_id: string) => {
|
export const deleteApplication = (app_id: string) => {
|
||||||
return request.delete(`/apps/${app_id}`)
|
return request.delete(`/apps/${app_id}`)
|
||||||
}
|
}
|
||||||
// 发布版本列表
|
// Release version list
|
||||||
export const getReleaseList = (app_id: string) => {
|
export const getReleaseList = (app_id: string) => {
|
||||||
return request.get(`/apps/${app_id}/releases`)
|
return request.get(`/apps/${app_id}/releases`)
|
||||||
}
|
}
|
||||||
// 发布版本
|
// Publish release
|
||||||
export const publishRelease = (app_id: string, values: Record<string, unknown>) => {
|
export const publishRelease = (app_id: string, values: Record<string, unknown>) => {
|
||||||
return request.post(`/apps/${app_id}/publish`, values)
|
return request.post(`/apps/${app_id}/publish`, values)
|
||||||
}
|
}
|
||||||
// 回滚版本
|
// Rollback release
|
||||||
export const rollbackRelease = (app_id: string, version: string) => {
|
export const rollbackRelease = (app_id: string, version: string) => {
|
||||||
return request.post(`/apps/${app_id}/rollback/${version}`)
|
return request.post(`/apps/${app_id}/rollback/${version}`)
|
||||||
}
|
}
|
||||||
// 发布版本分享
|
// Share release
|
||||||
export const shareRelease = (app_id: string, release_id: string) => {
|
export const shareRelease = (app_id: string, release_id: string) => {
|
||||||
return request.post(`/apps/${app_id}/releases/${release_id}/share`, {
|
return request.post(`/apps/${app_id}/releases/${release_id}/share`, {
|
||||||
"is_enabled": true,
|
"is_enabled": true,
|
||||||
@@ -77,7 +84,7 @@ export const shareRelease = (app_id: string, release_id: string) => {
|
|||||||
"allow_embed": true
|
"allow_embed": true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 获取体验对话历史
|
// Get conversation history
|
||||||
export const getConversationHistory = (share_token: string, data: { page: number; pagesize: number }) => {
|
export const getConversationHistory = (share_token: string, data: { page: number; pagesize: number }) => {
|
||||||
return request.get(`/public/share/conversations`, data, {
|
return request.get(`/public/share/conversations`, data, {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -85,7 +92,7 @@ export const getConversationHistory = (share_token: string, data: { page: number
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 发送体验对话
|
// Send conversation
|
||||||
export const sendConversation = (values: QueryParams, onMessage: (data: SSEMessage[]) => void, shareToken: string) => {
|
export const sendConversation = (values: QueryParams, onMessage: (data: SSEMessage[]) => void, shareToken: string) => {
|
||||||
return handleSSE(`/public/share/chat`, values, onMessage, {
|
return handleSSE(`/public/share/chat`, values, onMessage, {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -93,7 +100,7 @@ export const sendConversation = (values: QueryParams, onMessage: (data: SSEMessa
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 获取体验会话详情
|
// Get conversation details
|
||||||
export const getConversationDetail = (share_token: string, conversation_id: string) => {
|
export const getConversationDetail = (share_token: string, conversation_id: string) => {
|
||||||
return request.get(`/public/share/conversations/${conversation_id}`, {}, {
|
return request.get(`/public/share/conversations/${conversation_id}`, {}, {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -101,15 +108,15 @@ export const getConversationDetail = (share_token: string, conversation_id: stri
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 获取体验对话token
|
// Get share token
|
||||||
export const getShareToken = (share_token: string, user_id: string) => {
|
export const getShareToken = (share_token: string, user_id: string) => {
|
||||||
return request.post(`/public/share/${share_token}/token`, { user_id })
|
return request.post(`/public/share/${share_token}/token`, { user_id })
|
||||||
}
|
}
|
||||||
// 复制应用
|
// Copy application
|
||||||
export const copyApplication = (app_id: string, new_name: string) => {
|
export const copyApplication = (app_id: string, new_name: string) => {
|
||||||
return request.post(`/apps/${app_id}/copy?new_name=${new_name}`)
|
return request.post(`/apps/${app_id}/copy?new_name=${new_name}`)
|
||||||
}
|
}
|
||||||
// 数据统计
|
// Data statistics
|
||||||
export const getAppStatistics = (app_id: string, data: { start_date: number; end_date: number; }) => {
|
export const getAppStatistics = (app_id: string, data: { start_date: number; end_date: number; }) => {
|
||||||
return request.get(`/apps/${app_id}/statistics`, data)
|
return request.get(`/apps/${app_id}/statistics`, data)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { request } from "@/utils/request";
|
import { request } from "@/utils/request";
|
||||||
// 列表查询参数
|
// List query parameters
|
||||||
export interface Query {
|
export interface Query {
|
||||||
page?: number;
|
page?: number;
|
||||||
pagesize?: number;
|
pagesize?: number;
|
||||||
@@ -38,15 +38,15 @@ export interface versionResponse{
|
|||||||
codeName: string;
|
codeName: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// 首页数据统计
|
// Dashboard data statistics
|
||||||
export const getDashboardData = `/home-page/workspaces`
|
export const getDashboardData = `/home-page/workspaces`
|
||||||
|
|
||||||
// 首页数据看板统计
|
// Dashboard statistics
|
||||||
export const getDashboardStatistics = async () => {
|
export const getDashboardStatistics = async () => {
|
||||||
const response = await request.get(`/home-page/statistics`);
|
const response = await request.get(`/home-page/statistics`);
|
||||||
return response as DataResponse;
|
return response as DataResponse;
|
||||||
};
|
};
|
||||||
// 获取版本号
|
// Get version
|
||||||
export const getVersion = async () => {
|
export const getVersion = async () => {
|
||||||
const response = await request.get(`/home-page/version`);
|
const response = await request.get(`/home-page/version`);
|
||||||
return response as versionResponse;
|
return response as versionResponse;
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 13:59:56
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 13:59:56
|
||||||
|
*/
|
||||||
import { request, API_PREFIX } from '@/utils/request'
|
import { request, API_PREFIX } from '@/utils/request'
|
||||||
|
|
||||||
// Upload file,file storage has expiration period
|
// Upload file,file storage has expiration period
|
||||||
|
|||||||
@@ -1,20 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:00:01
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:00:01
|
||||||
|
*/
|
||||||
import { request } from '@/utils/request'
|
import { request } from '@/utils/request'
|
||||||
|
|
||||||
// 成员列表
|
// Member list
|
||||||
export const memberListUrl = '/workspaces/members'
|
export const memberListUrl = '/workspaces/members'
|
||||||
// 邀请成员
|
// Invite member
|
||||||
export const inviteMember = (values: { email: string }) => {
|
export const inviteMember = (values: { email: string }) => {
|
||||||
return request.post(`/workspaces/invites`, values)
|
return request.post(`/workspaces/invites`, values)
|
||||||
}
|
}
|
||||||
// 删除成员
|
// Delete member
|
||||||
export const deleteMember = (id: string) => {
|
export const deleteMember = (id: string) => {
|
||||||
return request.delete(`/workspaces/members/${id}`)
|
return request.delete(`/workspaces/members/${id}`)
|
||||||
}
|
}
|
||||||
// 更新成员
|
// Update member
|
||||||
export const updateMember = (values: { id: string, role: string }) => {
|
export const updateMember = (values: { id: string, role: string }) => {
|
||||||
return request.put(`/workspaces/members`, [values])
|
return request.put(`/workspaces/members`, [values])
|
||||||
}
|
}
|
||||||
// 验证邀请token
|
// Validate invite token
|
||||||
export const validateInviteToken = (token: string) => {
|
export const validateInviteToken = (token: string) => {
|
||||||
return request.get(`/workspaces/invites/validate/${token}`)
|
return request.get(`/workspaces/invites/validate/${token}`)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:00:06
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:00:06
|
||||||
|
*/
|
||||||
import { request } from '@/utils/request'
|
import { request } from '@/utils/request'
|
||||||
import type {
|
import type {
|
||||||
MemoryFormData,
|
MemoryFormData,
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:00:09
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:00:09
|
||||||
|
*/
|
||||||
import { request } from '@/utils/request'
|
import { request } from '@/utils/request'
|
||||||
import type { MultiKeyForm, Query, KeyConfigModalForm, CompositeModelForm, CustomModelForm } from '@/views/ModelManagement/types'
|
import type { MultiKeyForm, Query, KeyConfigModalForm, CompositeModelForm, CustomModelForm } from '@/views/ModelManagement/types'
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 13:59:12
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 13:59:12
|
||||||
|
*/
|
||||||
import { request } from '@/utils/request'
|
import { request } from '@/utils/request'
|
||||||
import type { Query, OntologyModalData, OntologyClassModalData, OntologyClassExtractModalData } from '@/views/Ontology/types'
|
import type { Query, OntologyModalData, OntologyClassModalData, OntologyClassExtractModalData, OntologyExportModalData } from '@/views/Ontology/types'
|
||||||
|
|
||||||
// Scene list
|
// Scene list
|
||||||
export const getOntologyScenesUrl = '/memory/ontology/scenes'
|
export const getOntologyScenesUrl = '/memory/ontology/scenes'
|
||||||
@@ -37,3 +43,11 @@ export const createOntologyClass = (data: OntologyClassModalData) => {
|
|||||||
export const deleteOntologyClass = (class_id: string) => {
|
export const deleteOntologyClass = (class_id: string) => {
|
||||||
return request.delete(`/memory/ontology/class/${class_id}`)
|
return request.delete(`/memory/ontology/class/${class_id}`)
|
||||||
}
|
}
|
||||||
|
// Import scenario
|
||||||
|
export const ontologyImport = (data: unknown) => {
|
||||||
|
return request.uploadFile('/memory/ontology/import', data)
|
||||||
|
}
|
||||||
|
// Export scenario
|
||||||
|
export const ontologyExport = (data: OntologyExportModalData, fileName: string, callback: () => void) => {
|
||||||
|
return request.downloadFile('/memory/ontology/export', fileName, data, callback)
|
||||||
|
}
|
||||||
@@ -1,16 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:00:14
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:00:14
|
||||||
|
*/
|
||||||
import { request } from '@/utils/request'
|
import { request } from '@/utils/request'
|
||||||
import type { VoucherForm } from '@/views/OrderPayment/types'
|
import type { VoucherForm } from '@/views/OrderPayment/types'
|
||||||
|
|
||||||
export const getOrderListUrl = '/v1/orders/customer'
|
export const getOrderListUrl = '/v1/orders/customer'
|
||||||
|
|
||||||
// 提交支付凭证API
|
// Submit payment voucher API
|
||||||
export const submitPaymentVoucherAPI = (voucherData: VoucherForm) => {
|
export const submitPaymentVoucherAPI = (voucherData: VoucherForm) => {
|
||||||
return request.post('/v1/orders/', voucherData)
|
return request.post('/v1/orders/', voucherData)
|
||||||
}
|
}
|
||||||
// 订单详情
|
// Order details
|
||||||
export const getOrderDetail = (order_no: string) => {
|
export const getOrderDetail = (order_no: string) => {
|
||||||
return request.get(`/v1/orders/customer/${order_no}`)
|
return request.get(`/v1/orders/customer/${order_no}`)
|
||||||
}
|
}
|
||||||
|
// Order status enum
|
||||||
export const orderStatusUrl = '/v1/order-status/'
|
export const orderStatusUrl = '/v1/order-status/'
|
||||||
export const getOrderStatus = () => {
|
export const getOrderStatus = () => {
|
||||||
return request.get(orderStatusUrl)
|
return request.get(orderStatusUrl)
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:00:17
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:00:17
|
||||||
|
*/
|
||||||
import { request } from '@/utils/request'
|
import { request } from '@/utils/request'
|
||||||
import type { AiPromptForm } from '@/views/ApplicationConfig/types'
|
import type { AiPromptForm } from '@/views/ApplicationConfig/types'
|
||||||
import type { PromptReleaseData } from '@/views/Prompt/types'
|
import type { PromptReleaseData } from '@/views/Prompt/types'
|
||||||
|
|||||||
@@ -1,40 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:00:23
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:00:23
|
||||||
|
*/
|
||||||
import { request } from '@/utils/request'
|
import { request } from '@/utils/request'
|
||||||
import type { CreateModalData } from '@/views/UserManagement/types'
|
import type { CreateModalData } from '@/views/UserManagement/types'
|
||||||
import { cookieUtils } from '@/utils/request'
|
import { cookieUtils } from '@/utils/request'
|
||||||
|
|
||||||
// 用户信息
|
// User info
|
||||||
export const getUsers = () => {
|
export const getUsers = () => {
|
||||||
return request.get('/users')
|
return request.get('/users')
|
||||||
}
|
}
|
||||||
// 用户列表
|
// User list
|
||||||
export const getUserListUrl = '/users/superusers'
|
export const getUserListUrl = '/users/superusers'
|
||||||
// 登录
|
// Login
|
||||||
export const loginUrl = '/token'
|
export const loginUrl = '/token'
|
||||||
export const login = (data: { email: string; password: string; invite?: string; username?: string }) => {
|
export const login = (data: { email: string; password: string; invite?: string; username?: string }) => {
|
||||||
return request.post(loginUrl, data)
|
return request.post(loginUrl, data)
|
||||||
}
|
}
|
||||||
// 刷新token
|
// Refresh token
|
||||||
export const refreshTokenUrl = '/refresh'
|
export const refreshTokenUrl = '/refresh'
|
||||||
export const refreshToken = () => {
|
export const refreshToken = () => {
|
||||||
return request.post(refreshTokenUrl, { refresh_token: cookieUtils.get('refreshToken') })
|
return request.post(refreshTokenUrl, { refresh_token: cookieUtils.get('refreshToken') })
|
||||||
}
|
}
|
||||||
// 重置密码
|
// Reset password
|
||||||
export const changePassword = (data: { user_id: string; new_password: string }) => {
|
export const changePassword = (data: { user_id: string; new_password: string }) => {
|
||||||
return request.put('/users/admin/change-password', data)
|
return request.put('/users/admin/change-password', data)
|
||||||
}
|
}
|
||||||
// 禁用用户
|
// Disable user
|
||||||
export const deleteUser = (user_id: string) => {
|
export const deleteUser = (user_id: string) => {
|
||||||
return request.delete(`/users/${user_id}`)
|
return request.delete(`/users/${user_id}`)
|
||||||
}
|
}
|
||||||
// 启用用户
|
// Enable user
|
||||||
export const enableUser = (user_id: string) => {
|
export const enableUser = (user_id: string) => {
|
||||||
return request.post(`/users/${user_id}/activate`)
|
return request.post(`/users/${user_id}/activate`)
|
||||||
}
|
}
|
||||||
// 创建用户
|
// Create user
|
||||||
export const addUser = (data: CreateModalData) => {
|
export const addUser = (data: CreateModalData) => {
|
||||||
return request.post('/users/superuser', data)
|
return request.post('/users/superuser', data)
|
||||||
}
|
}
|
||||||
// 注销
|
// Logout
|
||||||
export const logoutUrl = '/logout'
|
export const logoutUrl = '/logout'
|
||||||
export const logout = () => {
|
export const logout = () => {
|
||||||
return request.post(logoutUrl)
|
return request.post(logoutUrl)
|
||||||
|
|||||||
@@ -1,28 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:00:26
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:00:26
|
||||||
|
*/
|
||||||
import { request } from '@/utils/request'
|
import { request } from '@/utils/request'
|
||||||
import type { SpaceModalData } from '@/views/SpaceManagement/types'
|
import type { SpaceModalData } from '@/views/SpaceManagement/types'
|
||||||
import type { ConfigModalData } from '@/views/UserMemory/types'
|
import type { SpaceConfigData } from '@/views/SpaceConfig/types'
|
||||||
|
|
||||||
// 空间列表
|
// Workspace list
|
||||||
export const getWorkspaces = () => {
|
export const getWorkspaces = () => {
|
||||||
return request.get('/workspaces')
|
return request.get('/workspaces')
|
||||||
}
|
}
|
||||||
// 创建空间
|
// Create workspace
|
||||||
export const createWorkspace = (values: SpaceModalData) => {
|
export const createWorkspace = (values: SpaceModalData) => {
|
||||||
return request.post('/workspaces', values)
|
return request.post('/workspaces', values)
|
||||||
}
|
}
|
||||||
// 切换空间
|
// Switch workspace
|
||||||
export const switchWorkspace = (workspaceId: string) => {
|
export const switchWorkspace = (workspaceId: string) => {
|
||||||
return request.put(`/workspaces/${workspaceId}/switch`)
|
return request.put(`/workspaces/${workspaceId}/switch`)
|
||||||
}
|
}
|
||||||
// 获取空间存储类型
|
// Get workspace storage type
|
||||||
export const getWorkspaceStorageType = () => {
|
export const getWorkspaceStorageType = () => {
|
||||||
return request.get(`/workspaces/storage`)
|
return request.get(`/workspaces/storage`)
|
||||||
}
|
}
|
||||||
// 获取空间模型配置
|
// Get workspace model config
|
||||||
export const getWorkspaceModels = () => {
|
export const getWorkspaceModels = () => {
|
||||||
return request.get(`/workspaces/workspace_models`)
|
return request.get(`/workspaces/workspace_models`)
|
||||||
}
|
}
|
||||||
// 更新空间模型配置
|
// Update workspace model config
|
||||||
export const updateWorkspaceModels = (data: ConfigModalData) => {
|
export const updateWorkspaceModels = (data: SpaceConfigData) => {
|
||||||
return request.put(`/workspaces/workspace_models`, data)
|
return request.put(`/workspaces/workspace_models`, data)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ const ALL_FILE_TYPE: {
|
|||||||
htm: 'text/html',
|
htm: 'text/html',
|
||||||
html: 'text/html',
|
html: 'text/html',
|
||||||
json: 'application/json',
|
json: 'application/json',
|
||||||
|
owl: 'application/rdf+xml',
|
||||||
|
ttl: 'text/turtle',
|
||||||
|
rdf: 'application/rdf+xml',
|
||||||
|
xml: 'application/rdf+xml',
|
||||||
}
|
}
|
||||||
export interface UploadFilesRef {
|
export interface UploadFilesRef {
|
||||||
fileList: UploadFile[];
|
fileList: UploadFile[];
|
||||||
@@ -122,7 +126,7 @@ const UploadFiles = forwardRef<UploadFilesRef, UploadFilesProps>(({
|
|||||||
if (fileSize) {
|
if (fileSize) {
|
||||||
const isLtMaxSize = (file.size / 1024 / 1024) < fileSize;
|
const isLtMaxSize = (file.size / 1024 / 1024) < fileSize;
|
||||||
if (!isLtMaxSize) {
|
if (!isLtMaxSize) {
|
||||||
message.error(`文件大小不能超过 ${fileSize}MB`);
|
message.error(t('common.fileSizeTip', { size: fileSize }));
|
||||||
return Upload.LIST_IGNORE;
|
return Upload.LIST_IGNORE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,7 +143,7 @@ const UploadFiles = forwardRef<UploadFilesRef, UploadFilesProps>(({
|
|||||||
const isValidMimeType = file.type && accept ? accept.includes(file.type) : true;
|
const isValidMimeType = file.type && accept ? accept.includes(file.type) : true;
|
||||||
|
|
||||||
if (!isValidExtension && !isValidMimeType) {
|
if (!isValidExtension && !isValidMimeType) {
|
||||||
message.error(`不支持的文件类型: ${fileExtension || file.type}`);
|
message.error(`${t('common.fileAcceptTip')}${fileExtension || file.type}`);
|
||||||
return Upload.LIST_IGNORE;
|
return Upload.LIST_IGNORE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,12 +240,12 @@ const UploadFiles = forwardRef<UploadFilesRef, UploadFilesProps>(({
|
|||||||
fileList,
|
fileList,
|
||||||
beforeUpload,
|
beforeUpload,
|
||||||
headers: {
|
headers: {
|
||||||
authorization: cookieUtils.get('authToken') || '',
|
authorization: `Bearer ${cookieUtils.get('authToken')}`,
|
||||||
},
|
},
|
||||||
onRemove: handleRemove,
|
onRemove: handleRemove,
|
||||||
onChange: handleChange,
|
onChange: handleChange,
|
||||||
accept,
|
accept,
|
||||||
disabled,
|
disabled: disabled || fileList.length >= maxCount,
|
||||||
showUploadList: {
|
showUploadList: {
|
||||||
showPreviewIcon: false,
|
showPreviewIcon: false,
|
||||||
showRemoveIcon: true,
|
showRemoveIcon: true,
|
||||||
@@ -249,12 +253,12 @@ const UploadFiles = forwardRef<UploadFilesRef, UploadFilesProps>(({
|
|||||||
},
|
},
|
||||||
itemRender: (_, file, __, actions) => {
|
itemRender: (_, file, __, actions) => {
|
||||||
return (
|
return (
|
||||||
<div key={file.uid} className="rb:relative rb:w-full rb:pt-[8px] rb:pl-[10px] rb:pr-[10px] rb-pb-[10px] rb:border-1 rb:border-[#EBEBEB] rb:rounded rb:p-2 rb:mt-2 rb:bg-white">
|
<div key={file.uid} className="rb:relative rb:w-full rb:pt-2 rb:pl-2.5 rb:pr-2.5 rb-pb-[10px] rb:border rb:border-[#EBEBEB] rb:rounded rb:p-2 rb:mt-2 rb:bg-white">
|
||||||
<div className="rb:text-[12px] rb:flex rb:items-center rb:justify-between rb:mb-[2px]">
|
<div className="rb:text-[12px] rb:flex rb:items-center rb:justify-between rb:mb-0.5">
|
||||||
{file.name}
|
{file.name}
|
||||||
<span className="rb:text-[#5B6167] rb:cursor-pointer" onClick={() => actions?.remove()}>Cancel</span>
|
<span className="rb:text-[#5B6167] rb:cursor-pointer" onClick={() => actions?.remove()}>{t('common.cancel')}</span>
|
||||||
</div>
|
</div>
|
||||||
<Progress percent={file.percent || 0} strokeColor={file.status === 'error' ? '#FF5D34' : '#155EEF'} size="small" showInfo={false} />
|
{isAutoUpload && <Progress percent={file.percent || 0} strokeColor={file.status === 'error' ? '#FF5D34' : '#155EEF'} size="small" showInfo={false} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -267,20 +271,20 @@ const UploadFiles = forwardRef<UploadFilesRef, UploadFilesProps>(({
|
|||||||
clearFiles
|
clearFiles
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const hasProgress = fileList.some((item) => item.percent !== 100);
|
const hasProgress = isAutoUpload && fileList.some((item) => item.percent !== 100);
|
||||||
|
|
||||||
if (isCanDrag) {
|
if (isCanDrag) {
|
||||||
return (
|
return (
|
||||||
<div className="rb:mb-[24px] rb:w-full">
|
<div className="rb:mb-6 rb:w-full">
|
||||||
<Dragger {...uploadProps} style={{ height: '270px' }}>
|
<Dragger {...uploadProps} style={{ height: '270px' }}>
|
||||||
<div className="rb:flex rb:justify-center rb:flex-col rb:items-center">
|
<div className="rb:flex rb:justify-center rb:flex-col rb:items-center">
|
||||||
<img className="rb:w-[48px] rb:h-[48px]" src={CloudUploadOutlined} />
|
<img className="rb:w-12 rb:h-12" src={CloudUploadOutlined} />
|
||||||
{!hasProgress && (!fileList || !fileList.length) &&
|
{(!isAutoUpload || !hasProgress && (!fileList || !fileList.length)) &&
|
||||||
<>
|
<>
|
||||||
<div className="rb:text-base rb:text-[14px] rb:font-medium rb:flex rb:items-center rb:mt-[8px] rb:leading-[20px]">
|
<div className="rb:text-base rb:text-[14px] rb:font-medium rb:flex rb:items-center rb:mt-2 rb:leading-5">
|
||||||
{t('common.dragUploadTip')}<span className="rb:ml-[4px] rb:text-[#155EEF]">{t('common.uploadClickTip')}</span>
|
{t('common.dragUploadTip')}<span className="rb:ml-1 rb:text-[#155EEF]">{t('common.uploadClickTip')}</span>
|
||||||
</div>
|
</div>
|
||||||
{fileType && <div className="rb:text-[12px] rb:text-[#A8A9AA] rb:leading-[14px] rb:mt-[8px] rb:cursor-pointer">{t('common.supportedFileTypes', { types: fileType.join(',') })}</div>}
|
{fileType && <div className="rb:text-[12px] rb:text-[#A8A9AA] rb:leading-3.5 rb:mt-2 rb:cursor-pointer">{t('common.supportedFileTypes', { types: fileType.join(',') })}</div>}
|
||||||
{(fileSize || fileType || maxCount > 1) && (
|
{(fileSize || fileType || maxCount > 1) && (
|
||||||
<div className='rb:text-xs rb:mt-2 rb:text-[#A8A9AA]'>
|
<div className='rb:text-xs rb:mt-2 rb:text-[#A8A9AA]'>
|
||||||
{t('common.uploadFileTipMax', { max: fileSize, maxCount: maxCount })}
|
{t('common.uploadFileTipMax', { max: fileSize, maxCount: maxCount })}
|
||||||
@@ -288,7 +292,7 @@ const UploadFiles = forwardRef<UploadFilesRef, UploadFilesProps>(({
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
{hasProgress && <div className="rb:text-base rb:text-[14px] rb:font-medium rb:flex rb:items-center rb:mt-[8px] rb:mb-[24px] rb:leading-[20px]">{t('common.uploading')}</div>}
|
{hasProgress && <div className="rb:text-base rb:text-[14px] rb:font-medium rb:flex rb:items-center rb:mt-2 rb:mb-6 rb:leading-5">{t('common.uploading')}</div>}
|
||||||
</div>
|
</div>
|
||||||
</Dragger>
|
</Dragger>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -426,6 +426,7 @@ export const en = {
|
|||||||
fileAcceptTip: 'Unsupported file type:',
|
fileAcceptTip: 'Unsupported file type:',
|
||||||
nextStep: 'Next Step',
|
nextStep: 'Next Step',
|
||||||
prevStep: 'Previous Step',
|
prevStep: 'Previous Step',
|
||||||
|
exportSuccess: 'Export successful',
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
searchPlaceholder: 'search model…',
|
searchPlaceholder: 'search model…',
|
||||||
@@ -2471,6 +2472,11 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
|||||||
extract: 'Project Inference',
|
extract: 'Project Inference',
|
||||||
source: 'Not Added',
|
source: 'Not Added',
|
||||||
target: 'Added',
|
target: 'Added',
|
||||||
|
import: 'Import Scenario',
|
||||||
|
format: 'Export Format',
|
||||||
|
export: 'Export Scenario',
|
||||||
|
scene_id: 'Scenario',
|
||||||
|
file: 'Import File',
|
||||||
},
|
},
|
||||||
prompt: {
|
prompt: {
|
||||||
editor: 'Prompt Generator',
|
editor: 'Prompt Generator',
|
||||||
|
|||||||
@@ -980,6 +980,7 @@ export const zh = {
|
|||||||
fileAcceptTip: '不支持的文件类型:',
|
fileAcceptTip: '不支持的文件类型:',
|
||||||
nextStep: '下一步',
|
nextStep: '下一步',
|
||||||
prevStep: '上一步',
|
prevStep: '上一步',
|
||||||
|
exportSuccess: '导出成功',
|
||||||
},
|
},
|
||||||
product: {
|
product: {
|
||||||
applicationManagement: '应用管理',
|
applicationManagement: '应用管理',
|
||||||
@@ -2560,6 +2561,11 @@ export const zh = {
|
|||||||
extract: '工程推理',
|
extract: '工程推理',
|
||||||
source: '未添加项',
|
source: '未添加项',
|
||||||
target: '已添加项',
|
target: '已添加项',
|
||||||
|
import: '导入场景',
|
||||||
|
format: '导出格式',
|
||||||
|
export: '导出场景',
|
||||||
|
scene_id: '场景',
|
||||||
|
file: '导入文件',
|
||||||
},
|
},
|
||||||
prompt: {
|
prompt: {
|
||||||
editor: '提示词生成器',
|
editor: '提示词生成器',
|
||||||
|
|||||||
@@ -288,19 +288,20 @@ export const request = {
|
|||||||
...config
|
...config
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
downloadFile(url: string, fileName: string, data?: unknown) {
|
downloadFile(url: string, fileName: string, data?: unknown, callback?: () => void) {
|
||||||
service.post(url, data, {
|
service.post(url, data, {
|
||||||
responseType: "blob",
|
responseType: "blob",
|
||||||
})
|
})
|
||||||
.then(res =>{
|
.then(res =>{
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
const blob = new Blob([res.data], { type: "application/vnd.ms-excel" });
|
const blob = new Blob([res as unknown as BlobPart]);
|
||||||
link.style.display = "none";
|
link.style.display = "none";
|
||||||
link.href = URL.createObjectURL(blob);
|
link.href = URL.createObjectURL(blob);
|
||||||
link.setAttribute("download", decodeURI(res.headers['filename'] || fileName));
|
link.setAttribute("download", decodeURI(fileName || fileName));
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click();
|
||||||
document.body.removeChild(link);
|
document.body.removeChild(link);
|
||||||
|
callback?.()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:10:42
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:10:42
|
||||||
|
*/
|
||||||
import { forwardRef, useImperativeHandle, useState } from 'react';
|
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||||
import { Form, Input, App, Transfer, type TransferProps, Flex } from 'antd';
|
import { Form, Input, App, Transfer, type TransferProps, Flex } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@@ -12,24 +18,37 @@ import Tag from '@/components/Tag';
|
|||||||
|
|
||||||
const FormItem = Form.Item;
|
const FormItem = Form.Item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Props for OntologyClassExtractModal component
|
||||||
|
*/
|
||||||
interface OntologyClassExtractModalProps {
|
interface OntologyClassExtractModalProps {
|
||||||
|
/** Callback function to refresh parent list after extraction */
|
||||||
refresh: () => void;
|
refresh: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modal component for extracting ontology classes using LLM
|
||||||
|
* Two-step process: 1) Extract classes from scenario 2) Select and confirm classes to add
|
||||||
|
*/
|
||||||
const OntologyClassExtractModal = forwardRef<OntologyClassExtractModalRef, OntologyClassExtractModalProps>(({
|
const OntologyClassExtractModal = forwardRef<OntologyClassExtractModalRef, OntologyClassExtractModalProps>(({
|
||||||
refresh
|
refresh
|
||||||
}, ref) => {
|
}, ref) => {
|
||||||
|
// Hooks
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { message } = App.useApp();
|
const { message } = App.useApp();
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const [form] = Form.useForm<OntologyClassExtractModalData>();
|
const [form] = Form.useForm<OntologyClassExtractModalData>();
|
||||||
|
|
||||||
|
// State
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [data, setData] = useState<OntologyClassData | null>(null)
|
const [data, setData] = useState<OntologyClassData | null>(null)
|
||||||
const [extractData, setExtractData] = useState<ExtractData | null>(null)
|
const [extractData, setExtractData] = useState<ExtractData | null>(null)
|
||||||
const [targetKeys, setTargetKeys] = useState<TransferProps['targetKeys']>([]);
|
const [targetKeys, setTargetKeys] = useState<TransferProps['targetKeys']>([]);
|
||||||
const [selectedKeys, setSelectedKeys] = useState<TransferProps['selectedKeys']>([]);
|
const [selectedKeys, setSelectedKeys] = useState<TransferProps['selectedKeys']>([]);
|
||||||
|
|
||||||
// 封装取消方法,添加关闭弹窗逻辑
|
/**
|
||||||
|
* Close modal and reset all state
|
||||||
|
*/
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
@@ -38,12 +57,19 @@ const OntologyClassExtractModal = forwardRef<OntologyClassExtractModalRef, Ontol
|
|||||||
setExtractData(null)
|
setExtractData(null)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open modal with scene data
|
||||||
|
* @param vo - Ontology class data containing scene information
|
||||||
|
*/
|
||||||
const handleOpen = (vo: OntologyClassData) => {
|
const handleOpen = (vo: OntologyClassData) => {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
setData(vo)
|
setData(vo)
|
||||||
};
|
};
|
||||||
// 封装保存方法,添加提交逻辑
|
|
||||||
|
/**
|
||||||
|
* Execute LLM extraction to get class suggestions
|
||||||
|
*/
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
if (!data?.scene_id) return;
|
if (!data?.scene_id) return;
|
||||||
form
|
form
|
||||||
@@ -69,6 +95,10 @@ const OntologyClassExtractModal = forwardRef<OntologyClassExtractModalRef, Ontol
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm and create selected classes
|
||||||
|
* First click runs extraction, second click creates classes
|
||||||
|
*/
|
||||||
const handleConfirm = () => {
|
const handleConfirm = () => {
|
||||||
if (!extractData) {
|
if (!extractData) {
|
||||||
handleSave()
|
handleSave()
|
||||||
@@ -92,11 +122,19 @@ const OntologyClassExtractModal = forwardRef<OntologyClassExtractModalRef, Ontol
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle transfer component target keys change
|
||||||
|
* @param nextTargetKeys - New target keys after transfer
|
||||||
|
*/
|
||||||
const onChange: TransferProps['onChange'] = (nextTargetKeys) => {
|
const onChange: TransferProps['onChange'] = (nextTargetKeys) => {
|
||||||
setTargetKeys(nextTargetKeys.filter(Boolean));
|
setTargetKeys(nextTargetKeys.filter(Boolean));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle transfer component selection change
|
||||||
|
* @param sourceSelectedKeys - Selected keys in source list
|
||||||
|
* @param targetSelectedKeys - Selected keys in target list
|
||||||
|
*/
|
||||||
const onSelectChange: TransferProps['onSelectChange'] = (
|
const onSelectChange: TransferProps['onSelectChange'] = (
|
||||||
sourceSelectedKeys,
|
sourceSelectedKeys,
|
||||||
targetSelectedKeys,
|
targetSelectedKeys,
|
||||||
@@ -104,7 +142,9 @@ const OntologyClassExtractModal = forwardRef<OntologyClassExtractModalRef, Ontol
|
|||||||
setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys].filter(Boolean));
|
setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys].filter(Boolean));
|
||||||
};
|
};
|
||||||
|
|
||||||
// 暴露给父组件的方法
|
/**
|
||||||
|
* Expose methods to parent component via ref
|
||||||
|
*/
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
handleOpen,
|
handleOpen,
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:10:39
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:10:39
|
||||||
|
*/
|
||||||
import { forwardRef, useImperativeHandle, useState } from 'react';
|
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||||
import { Form, Input, App } from 'antd';
|
import { Form, Input, App } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@@ -8,33 +14,53 @@ import { createOntologyClass } from '@/api/ontology'
|
|||||||
|
|
||||||
const FormItem = Form.Item;
|
const FormItem = Form.Item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Props for OntologyClassModal component
|
||||||
|
*/
|
||||||
interface OntologyClassModalProps {
|
interface OntologyClassModalProps {
|
||||||
|
/** Callback function to refresh parent list after save */
|
||||||
refresh: () => void;
|
refresh: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modal component for adding new ontology classes
|
||||||
|
* Provides form interface for class name and description
|
||||||
|
*/
|
||||||
const OntologyClassModal = forwardRef<OntologyClassModalRef, OntologyClassModalProps>(({
|
const OntologyClassModal = forwardRef<OntologyClassModalRef, OntologyClassModalProps>(({
|
||||||
refresh
|
refresh
|
||||||
}, ref) => {
|
}, ref) => {
|
||||||
|
// Hooks
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { message } = App.useApp();
|
const { message } = App.useApp();
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
const [form] = Form.useForm<AddClassItem>();
|
const [form] = Form.useForm<AddClassItem>();
|
||||||
|
|
||||||
|
// State
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [scene_id, setSceneId] = useState<string | null>(null)
|
const [scene_id, setSceneId] = useState<string | null>(null)
|
||||||
|
|
||||||
// 封装取消方法,添加关闭弹窗逻辑
|
/**
|
||||||
|
* Close modal and reset form state
|
||||||
|
*/
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open modal for adding a new class
|
||||||
|
* @param scene_id - Target scene identifier
|
||||||
|
*/
|
||||||
const handleOpen = (scene_id: string) => {
|
const handleOpen = (scene_id: string) => {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
setSceneId(scene_id)
|
setSceneId(scene_id)
|
||||||
};
|
};
|
||||||
// 封装保存方法,添加提交逻辑
|
|
||||||
|
/**
|
||||||
|
* Validate and submit form data to create new class
|
||||||
|
*/
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
if (!scene_id) return;
|
if (!scene_id) return;
|
||||||
form
|
form
|
||||||
@@ -56,7 +82,9 @@ const OntologyClassModal = forwardRef<OntologyClassModalRef, OntologyClassModalP
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 暴露给父组件的方法
|
/**
|
||||||
|
* Expose methods to parent component via ref
|
||||||
|
*/
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
handleOpen,
|
handleOpen,
|
||||||
}));
|
}));
|
||||||
|
|||||||
144
web/src/views/Ontology/components/OntologyExportModal.tsx
Normal file
144
web/src/views/Ontology/components/OntologyExportModal.tsx
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:10:46
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:10:46
|
||||||
|
*/
|
||||||
|
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||||
|
import { Form, App, Select, type SelectProps } from 'antd';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import type { OntologyExportModalData, OntologyExportModalRef } from '../types'
|
||||||
|
import RbModal from '@/components/RbModal'
|
||||||
|
import { ontologyExport, getOntologyScenesUrl } from '@/api/ontology'
|
||||||
|
import CustomSelect from '@/components/CustomSelect';
|
||||||
|
|
||||||
|
const FormItem = Form.Item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Props for OntologyExportModal component
|
||||||
|
*/
|
||||||
|
interface OntologyExportModalProps {
|
||||||
|
/** Callback function to refresh parent list after export */
|
||||||
|
refresh: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modal component for exporting ontology scenes
|
||||||
|
* Supports RDF/XML (.owl) and Turtle (.ttl) formats
|
||||||
|
*/
|
||||||
|
const OntologyExportModal = forwardRef<OntologyExportModalRef, OntologyExportModalProps>(({
|
||||||
|
refresh
|
||||||
|
}, ref) => {
|
||||||
|
// Hooks
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { message } = App.useApp();
|
||||||
|
const [form] = Form.useForm<OntologyExportModalData>();
|
||||||
|
|
||||||
|
// State
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [fileName, setFileName] = useState('')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close modal and reset form state
|
||||||
|
*/
|
||||||
|
const handleClose = () => {
|
||||||
|
setVisible(false);
|
||||||
|
form.resetFields();
|
||||||
|
setLoading(false)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the export modal
|
||||||
|
*/
|
||||||
|
const handleOpen = () => {
|
||||||
|
form.resetFields();
|
||||||
|
setVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle scene selection change to set export filename
|
||||||
|
* @param _value - Selected scene ID
|
||||||
|
* @param option - Selected option containing scene name
|
||||||
|
*/
|
||||||
|
const handleChange: SelectProps['onChange'] = (_value, option) => {
|
||||||
|
const name = Array.isArray(option) ? option[0]?.children : option?.children;
|
||||||
|
setFileName(String(name || ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate and submit form data to export ontology
|
||||||
|
* Downloads file with appropriate extension based on format
|
||||||
|
*/
|
||||||
|
const handleSave = () => {
|
||||||
|
form
|
||||||
|
.validateFields()
|
||||||
|
.then((values) => {
|
||||||
|
setLoading(true)
|
||||||
|
ontologyExport(values, `${fileName}.${values.format === 'rdfxml' ?'owl' : 'ttl'}`, () => {
|
||||||
|
message.success(t('common.exportSuccess'));
|
||||||
|
handleClose();
|
||||||
|
refresh();
|
||||||
|
setLoading(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log('err', err)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose methods to parent component via ref
|
||||||
|
*/
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
handleOpen,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RbModal
|
||||||
|
title={t('ontology.export')}
|
||||||
|
open={visible}
|
||||||
|
onCancel={handleClose}
|
||||||
|
okText={t('common.export')}
|
||||||
|
onOk={handleSave}
|
||||||
|
confirmLoading={loading}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
form={form}
|
||||||
|
layout="vertical"
|
||||||
|
initialValues={{ format: 'rdfxml' }}
|
||||||
|
>
|
||||||
|
<FormItem
|
||||||
|
name="scene_id"
|
||||||
|
label={t('ontology.scene_id')}
|
||||||
|
rules={[{ required: true, message: t('common.pleaseEnter') }]}
|
||||||
|
>
|
||||||
|
<CustomSelect
|
||||||
|
url={getOntologyScenesUrl}
|
||||||
|
params={{ page: 1, pagesize: 100 }}
|
||||||
|
valueKey="scene_id"
|
||||||
|
labelKey="scene_name"
|
||||||
|
hasAll={false}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
</FormItem>
|
||||||
|
|
||||||
|
<FormItem
|
||||||
|
name="format"
|
||||||
|
label={t('ontology.format')}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
placeholder={t('common.pleaseSelect')}
|
||||||
|
options={[
|
||||||
|
{ value: 'rdfxml', label: 'RDF/XML' },
|
||||||
|
{ value: 'turtle', label: 'Turtle' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</FormItem>
|
||||||
|
</Form>
|
||||||
|
</RbModal>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default OntologyExportModal;
|
||||||
139
web/src/views/Ontology/components/OntologyImportModal.tsx
Normal file
139
web/src/views/Ontology/components/OntologyImportModal.tsx
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:10:32
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:10:32
|
||||||
|
*/
|
||||||
|
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||||
|
import { Form, Input, App } from 'antd';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import type { OntologyImportModalData, OntologyImportModalRef } from '../types'
|
||||||
|
import RbModal from '@/components/RbModal'
|
||||||
|
import { ontologyImport } from '@/api/ontology'
|
||||||
|
import UploadFiles from '@/components/Upload/UploadFiles';
|
||||||
|
|
||||||
|
const FormItem = Form.Item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Props for OntologyImportModal component
|
||||||
|
*/
|
||||||
|
interface OntologyImportModalProps {
|
||||||
|
/** Callback function to refresh parent list after import */
|
||||||
|
refresh: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modal component for importing ontology files
|
||||||
|
* Supports OWL, TTL, RDF, XML file formats
|
||||||
|
*/
|
||||||
|
const OntologyImportModal = forwardRef<OntologyImportModalRef, OntologyImportModalProps>(({
|
||||||
|
refresh
|
||||||
|
}, ref) => {
|
||||||
|
// Hooks
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { message } = App.useApp();
|
||||||
|
const [form] = Form.useForm<OntologyImportModalData>();
|
||||||
|
|
||||||
|
// State
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close modal and reset form state
|
||||||
|
*/
|
||||||
|
const handleClose = () => {
|
||||||
|
setVisible(false);
|
||||||
|
form.resetFields();
|
||||||
|
setLoading(false)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the import modal
|
||||||
|
*/
|
||||||
|
const handleOpen = () => {
|
||||||
|
form.resetFields();
|
||||||
|
setVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate and submit form data to import ontology file
|
||||||
|
* Creates FormData with file and scene information
|
||||||
|
*/
|
||||||
|
const handleSave = () => {
|
||||||
|
form
|
||||||
|
.validateFields()
|
||||||
|
.then((values) => {
|
||||||
|
const { scene_name, scene_description, file } = values
|
||||||
|
console.log('values', file);
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file[0]);
|
||||||
|
formData.append('scene_name', scene_name);
|
||||||
|
if (scene_description) {
|
||||||
|
formData.append('scene_description', scene_description);
|
||||||
|
}
|
||||||
|
setLoading(true)
|
||||||
|
ontologyImport(formData)
|
||||||
|
.then(() => {
|
||||||
|
message.success(t('common.saveSuccess'));
|
||||||
|
handleClose();
|
||||||
|
refresh();
|
||||||
|
})
|
||||||
|
.finally(() => setLoading(false))
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log('err', err)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose methods to parent component via ref
|
||||||
|
*/
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
handleOpen,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RbModal
|
||||||
|
title={t('ontology.import')}
|
||||||
|
open={visible}
|
||||||
|
onCancel={handleClose}
|
||||||
|
okText={t('common.create')}
|
||||||
|
onOk={handleSave}
|
||||||
|
confirmLoading={loading}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
form={form}
|
||||||
|
layout="vertical"
|
||||||
|
>
|
||||||
|
<FormItem
|
||||||
|
name="scene_name"
|
||||||
|
label={t('ontology.scene_name')}
|
||||||
|
rules={[{ required: true, message: t('common.pleaseEnter') }]}
|
||||||
|
>
|
||||||
|
<Input placeholder={t('common.enter')} />
|
||||||
|
</FormItem>
|
||||||
|
<FormItem
|
||||||
|
name="scene_description"
|
||||||
|
label={t('ontology.scene_description')}
|
||||||
|
>
|
||||||
|
<Input.TextArea placeholder={t('common.enter')} />
|
||||||
|
</FormItem>
|
||||||
|
|
||||||
|
<FormItem
|
||||||
|
name="file"
|
||||||
|
label={t('ontology.file')}
|
||||||
|
rules={[{ required: true, message: t('common.pleaseSelect') }]}
|
||||||
|
>
|
||||||
|
<UploadFiles
|
||||||
|
isCanDrag={true}
|
||||||
|
fileType={['owl', 'ttl', 'rdf', 'xml']}
|
||||||
|
isAutoUpload={false}
|
||||||
|
/>
|
||||||
|
</FormItem>
|
||||||
|
</Form>
|
||||||
|
</RbModal>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default OntologyImportModal;
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:10:28
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:10:28
|
||||||
|
*/
|
||||||
import { forwardRef, useImperativeHandle, useState } from 'react';
|
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||||
import { Form, Input, App } from 'antd';
|
import { Form, Input, App } from 'antd';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@@ -8,21 +14,34 @@ import { createOntologyScene, updateOntologyScene } from '@/api/ontology'
|
|||||||
|
|
||||||
const FormItem = Form.Item;
|
const FormItem = Form.Item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Props for OntologyModal component
|
||||||
|
*/
|
||||||
interface OntologyModalProps {
|
interface OntologyModalProps {
|
||||||
|
/** Callback function to refresh parent list after save */
|
||||||
refresh: () => void;
|
refresh: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modal component for creating or editing ontology scenes
|
||||||
|
* Provides form interface for scene name and description
|
||||||
|
*/
|
||||||
const OntologyModal = forwardRef<OntologyModalRef, OntologyModalProps>(({
|
const OntologyModal = forwardRef<OntologyModalRef, OntologyModalProps>(({
|
||||||
refresh
|
refresh
|
||||||
}, ref) => {
|
}, ref) => {
|
||||||
|
// Hooks
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { message } = App.useApp();
|
const { message } = App.useApp();
|
||||||
|
const [form] = Form.useForm<OntologyModalData>();
|
||||||
|
|
||||||
|
// State
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const [editVo, setEditVo] = useState<OntologyItem | null>(null)
|
const [editVo, setEditVo] = useState<OntologyItem | null>(null)
|
||||||
const [form] = Form.useForm<OntologyModalData>();
|
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
|
|
||||||
// 封装取消方法,添加关闭弹窗逻辑
|
/**
|
||||||
|
* Close modal and reset form state
|
||||||
|
*/
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
@@ -30,6 +49,10 @@ const OntologyModal = forwardRef<OntologyModalRef, OntologyModalProps>(({
|
|||||||
setEditVo(null)
|
setEditVo(null)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open modal for creating or editing
|
||||||
|
* @param vo - Optional ontology item data for edit mode
|
||||||
|
*/
|
||||||
const handleOpen = (vo?: OntologyItem) => {
|
const handleOpen = (vo?: OntologyItem) => {
|
||||||
if (vo) {
|
if (vo) {
|
||||||
setEditVo(vo);
|
setEditVo(vo);
|
||||||
@@ -39,7 +62,11 @@ const OntologyModal = forwardRef<OntologyModalRef, OntologyModalProps>(({
|
|||||||
}
|
}
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
};
|
};
|
||||||
// 封装保存方法,添加提交逻辑
|
|
||||||
|
/**
|
||||||
|
* Validate and submit form data
|
||||||
|
* Creates new scene or updates existing one based on editVo
|
||||||
|
*/
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
form
|
form
|
||||||
.validateFields()
|
.validateFields()
|
||||||
@@ -59,7 +86,9 @@ const OntologyModal = forwardRef<OntologyModalRef, OntologyModalProps>(({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 暴露给父组件的方法
|
/**
|
||||||
|
* Expose methods to parent component via ref
|
||||||
|
*/
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
handleOpen,
|
handleOpen,
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:10:24
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:10:56
|
||||||
|
*/
|
||||||
import { type FC, type ReactNode } from 'react';
|
import { type FC, type ReactNode } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { Layout, Button } from 'antd';
|
import { Layout, Button } from 'antd';
|
||||||
@@ -6,11 +12,23 @@ import logoutIcon from '@/assets/images/logout_hover.svg'
|
|||||||
|
|
||||||
const { Header } = Layout;
|
const { Header } = Layout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Props for PageHeader component
|
||||||
|
*/
|
||||||
interface ConfigHeaderProps {
|
interface ConfigHeaderProps {
|
||||||
|
/** Page title/name */
|
||||||
name?: string;
|
name?: string;
|
||||||
|
/** Subtitle content displayed below the title */
|
||||||
subTitle?: ReactNode | string;
|
subTitle?: ReactNode | string;
|
||||||
|
/** Extra content displayed on the right side */
|
||||||
extra?: ReactNode;
|
extra?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page header component for ontology pages
|
||||||
|
* Displays title, subtitle, back button and extra actions
|
||||||
|
* @param props - Component props
|
||||||
|
*/
|
||||||
const PageHeader: FC<ConfigHeaderProps> = ({
|
const PageHeader: FC<ConfigHeaderProps> = ({
|
||||||
name,
|
name,
|
||||||
subTitle,
|
subTitle,
|
||||||
@@ -19,6 +37,9 @@ const PageHeader: FC<ConfigHeaderProps> = ({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate back to previous page
|
||||||
|
*/
|
||||||
const goBack = () => {
|
const goBack = () => {
|
||||||
navigate(-1)
|
navigate(-1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:10:15
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:10:15
|
||||||
|
*/
|
||||||
import { type FC, useState, useRef, type MouseEvent } from 'react';
|
import { type FC, useState, useRef, type MouseEvent } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@@ -5,29 +11,57 @@ import { Row, Col, Button, Flex, Divider, Space, App, Tooltip } from 'antd'
|
|||||||
|
|
||||||
import SearchInput from '@/components/SearchInput';
|
import SearchInput from '@/components/SearchInput';
|
||||||
import OntologyModal from './components/OntologyModal'
|
import OntologyModal from './components/OntologyModal'
|
||||||
import type { OntologyModalRef, OntologyItem, Query } from './types'
|
import type { OntologyModalRef, OntologyItem, Query, OntologyImportModalRef, OntologyExportModalRef } from './types'
|
||||||
import RbCard from '@/components/RbCard/Card'
|
import RbCard from '@/components/RbCard/Card'
|
||||||
import Tag from '@/components/Tag'
|
import Tag from '@/components/Tag'
|
||||||
import PageScrollList, { type PageScrollListRef } from '@/components/PageScrollList'
|
import PageScrollList, { type PageScrollListRef } from '@/components/PageScrollList'
|
||||||
import { getOntologyScenesUrl, deleteOntologyScene } from '@/api/ontology'
|
import { getOntologyScenesUrl, deleteOntologyScene } from '@/api/ontology'
|
||||||
import { formatDateTime } from '@/utils/format'
|
import { formatDateTime } from '@/utils/format'
|
||||||
|
import OntologyImportModal from './components/OntologyImportModal'
|
||||||
|
import OntologyExportModal from './components/OntologyExportModal'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ontology management page component
|
||||||
|
* Displays a list of ontology scenes with search, create, import, export functionality
|
||||||
|
*/
|
||||||
const Ontology: FC = () => {
|
const Ontology: FC = () => {
|
||||||
|
// Hooks
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { modal, message } = App.useApp();
|
const { modal, message } = App.useApp();
|
||||||
|
|
||||||
|
// State
|
||||||
const [query, setQuery] = useState<Query>({});
|
const [query, setQuery] = useState<Query>({});
|
||||||
|
|
||||||
|
// Refs
|
||||||
const scrollListRef = useRef<PageScrollListRef>(null)
|
const scrollListRef = useRef<PageScrollListRef>(null)
|
||||||
const entityModalRef = useRef<OntologyModalRef>(null)
|
const entityModalRef = useRef<OntologyModalRef>(null)
|
||||||
|
const ontologyImportModalRef = useRef<OntologyImportModalRef>(null)
|
||||||
|
const ontologyExportModalRef = useRef<OntologyExportModalRef>(null)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open modal to create a new ontology scene
|
||||||
|
*/
|
||||||
const handleCreate = () => {
|
const handleCreate = () => {
|
||||||
entityModalRef.current?.handleOpen()
|
entityModalRef.current?.handleOpen()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open modal to edit an existing ontology scene
|
||||||
|
* @param record - The ontology item to edit
|
||||||
|
* @param e - Mouse event to prevent propagation
|
||||||
|
*/
|
||||||
const handleEdit = (record: OntologyItem, e: MouseEvent) => {
|
const handleEdit = (record: OntologyItem, e: MouseEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
entityModalRef.current?.handleOpen(record)
|
entityModalRef.current?.handleOpen(record)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an ontology scene with confirmation
|
||||||
|
* @param item - The ontology item to delete
|
||||||
|
* @param e - Mouse event to prevent propagation
|
||||||
|
*/
|
||||||
const handleDelete = (item: OntologyItem, e: MouseEvent) => {
|
const handleDelete = (item: OntologyItem, e: MouseEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -45,9 +79,35 @@ const Ontology: FC = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to ontology detail page
|
||||||
|
* @param record - The ontology item to view
|
||||||
|
*/
|
||||||
const handleJump = (record: OntologyItem) => {
|
const handleJump = (record: OntologyItem) => {
|
||||||
navigate(`/ontology/${record.scene_id}`)
|
navigate(`/ontology/${record.scene_id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the ontology list
|
||||||
|
*/
|
||||||
|
const handleRefresh = () => {
|
||||||
|
scrollListRef.current?.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open export modal
|
||||||
|
*/
|
||||||
|
const handleExport = () => {
|
||||||
|
ontologyExportModalRef.current?.handleOpen()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open import modal
|
||||||
|
*/
|
||||||
|
const handleImport = () => {
|
||||||
|
ontologyImportModalRef.current?.handleOpen()
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -60,9 +120,17 @@ const Ontology: FC = () => {
|
|||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={16} className="rb:text-right">
|
<Col span={16} className="rb:text-right">
|
||||||
<Button type="primary" onClick={handleCreate}>
|
<Space size={12}>
|
||||||
+ {t('ontology.create')}
|
<Button onClick={handleExport}>
|
||||||
</Button>
|
{t('ontology.export')}
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleImport}>
|
||||||
|
{t('ontology.import')}
|
||||||
|
</Button>
|
||||||
|
<Button type="primary" onClick={handleCreate}>
|
||||||
|
+ {t('ontology.create')}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
@@ -124,7 +192,15 @@ const Ontology: FC = () => {
|
|||||||
|
|
||||||
<OntologyModal
|
<OntologyModal
|
||||||
ref={entityModalRef}
|
ref={entityModalRef}
|
||||||
refresh={() => scrollListRef.current?.refresh()}
|
refresh={handleRefresh}
|
||||||
|
/>
|
||||||
|
<OntologyImportModal
|
||||||
|
ref={ontologyImportModalRef}
|
||||||
|
refresh={handleRefresh}
|
||||||
|
/>
|
||||||
|
<OntologyExportModal
|
||||||
|
ref={ontologyExportModalRef}
|
||||||
|
refresh={handleRefresh}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:10:20
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:10:20
|
||||||
|
*/
|
||||||
import { type FC, useEffect, useState, useRef } from 'react'
|
import { type FC, useEffect, useState, useRef } from 'react'
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@@ -12,22 +18,35 @@ import SearchInput from '@/components/SearchInput';
|
|||||||
import OntologyClassExtractModal from '../components/OntologyClassExtractModal'
|
import OntologyClassExtractModal from '../components/OntologyClassExtractModal'
|
||||||
import BodyWrapper from '@/components/Empty/BodyWrapper'
|
import BodyWrapper from '@/components/Empty/BodyWrapper'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ontology detail page component
|
||||||
|
* Displays and manages classes within a specific ontology scene
|
||||||
|
*/
|
||||||
const Detail: FC = () => {
|
const Detail: FC = () => {
|
||||||
|
// Hooks
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { id } = useParams()
|
const { id } = useParams()
|
||||||
const { modal, message } = App.useApp()
|
const { modal, message } = App.useApp()
|
||||||
|
|
||||||
|
// Refs
|
||||||
const ontologyClassModalRef = useRef<OntologyClassModalRef>(null)
|
const ontologyClassModalRef = useRef<OntologyClassModalRef>(null)
|
||||||
const ontologyClassExtractModalRef = useRef<OntologyClassExtractModalRef>(null)
|
const ontologyClassExtractModalRef = useRef<OntologyClassExtractModalRef>(null)
|
||||||
|
|
||||||
|
// State
|
||||||
const [query, setQuery] = useState<{
|
const [query, setQuery] = useState<{
|
||||||
class_name?: string;
|
class_name?: string;
|
||||||
}>({});
|
}>({});
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [data, setData] = useState<OntologyClassData>({} as OntologyClassData)
|
const [data, setData] = useState<OntologyClassData>({} as OntologyClassData)
|
||||||
|
|
||||||
|
// Fetch data when component mounts or dependencies change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getData()
|
getData()
|
||||||
}, [id, query])
|
}, [id, query])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch ontology class list data
|
||||||
|
*/
|
||||||
const getData = () => {
|
const getData = () => {
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
@@ -42,6 +61,11 @@ const Detail: FC = () => {
|
|||||||
setLoading(false)
|
setLoading(false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an ontology class with confirmation
|
||||||
|
* @param item - The class item to delete
|
||||||
|
*/
|
||||||
const handleDelete = (item: OntologyClassItem) => {
|
const handleDelete = (item: OntologyClassItem) => {
|
||||||
modal.confirm({
|
modal.confirm({
|
||||||
title: t('common.confirmDeleteDesc', { name: item.class_name }),
|
title: t('common.confirmDeleteDesc', { name: item.class_name }),
|
||||||
@@ -57,9 +81,17 @@ const Detail: FC = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open modal to add a new class
|
||||||
|
*/
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
ontologyClassModalRef.current?.handleOpen(data.scene_id)
|
ontologyClassModalRef.current?.handleOpen(data.scene_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open modal to extract classes using LLM
|
||||||
|
*/
|
||||||
const handleExtract = () => {
|
const handleExtract = () => {
|
||||||
ontologyClassExtractModalRef.current?.handleOpen(data)
|
ontologyClassExtractModalRef.current?.handleOpen(data)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,79 +1,214 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 14:10:10
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-03 14:10:10
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Query parameters for ontology list pagination and filtering
|
||||||
|
*/
|
||||||
export interface Query {
|
export interface Query {
|
||||||
|
/** Number of items per page */
|
||||||
pagesize?: number;
|
pagesize?: number;
|
||||||
|
/** Current page number */
|
||||||
page?: number;
|
page?: number;
|
||||||
|
/** Scene name for filtering */
|
||||||
scene_name?: string;
|
scene_name?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ontology scene item data structure
|
||||||
|
*/
|
||||||
export interface OntologyItem {
|
export interface OntologyItem {
|
||||||
|
/** Unique identifier for the scene */
|
||||||
scene_id: string;
|
scene_id: string;
|
||||||
|
/** Name of the ontology scene */
|
||||||
scene_name: string;
|
scene_name: string;
|
||||||
|
/** Description of the ontology scene */
|
||||||
scene_description: string;
|
scene_description: string;
|
||||||
|
/** Number of entity types in the scene */
|
||||||
type_num: number;
|
type_num: number;
|
||||||
|
/** Array of entity type names */
|
||||||
entity_type: string[];
|
entity_type: string[];
|
||||||
|
/** Associated workspace identifier */
|
||||||
workspace_id: string;
|
workspace_id: string;
|
||||||
|
/** Creation timestamp */
|
||||||
created_at: number;
|
created_at: number;
|
||||||
|
/** Last update timestamp */
|
||||||
updated_at: number;
|
updated_at: number;
|
||||||
|
/** Total count of classes in the scene */
|
||||||
classes_count: number;
|
classes_count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form data for creating/editing ontology scene
|
||||||
|
*/
|
||||||
export interface OntologyModalData {
|
export interface OntologyModalData {
|
||||||
|
/** Scene name */
|
||||||
scene_name: string;
|
scene_name: string;
|
||||||
|
/** Scene description */
|
||||||
scene_description: string;
|
scene_description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ref methods exposed by OntologyModal component
|
||||||
|
*/
|
||||||
export interface OntologyModalRef {
|
export interface OntologyModalRef {
|
||||||
|
/**
|
||||||
|
* Open the modal for creating or editing
|
||||||
|
* @param data - Optional ontology item data for editing mode
|
||||||
|
*/
|
||||||
handleOpen: (data?: OntologyItem) => void;
|
handleOpen: (data?: OntologyItem) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ontology class item data structure
|
||||||
|
*/
|
||||||
export interface OntologyClassItem {
|
export interface OntologyClassItem {
|
||||||
|
/** Unique identifier for the class */
|
||||||
class_id: string;
|
class_id: string;
|
||||||
|
/** Name of the class */
|
||||||
class_name: string;
|
class_name: string;
|
||||||
|
/** Description of the class */
|
||||||
class_description: string;
|
class_description: string;
|
||||||
|
/** Associated scene identifier */
|
||||||
scene_id: string;
|
scene_id: string;
|
||||||
|
/** Creation timestamp */
|
||||||
created_at: number;
|
created_at: number;
|
||||||
|
/** Last update timestamp */
|
||||||
updated_at: number;
|
updated_at: number;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Response data structure for ontology class list
|
||||||
|
*/
|
||||||
export interface OntologyClassData {
|
export interface OntologyClassData {
|
||||||
|
/** Total number of classes */
|
||||||
total: number;
|
total: number;
|
||||||
|
/** Scene identifier */
|
||||||
scene_id: string;
|
scene_id: string;
|
||||||
|
/** Scene name */
|
||||||
scene_name: string;
|
scene_name: string;
|
||||||
|
/** Scene description */
|
||||||
scene_description: string;
|
scene_description: string;
|
||||||
|
/** Array of class items */
|
||||||
items: OntologyClassItem[];
|
items: OntologyClassItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data structure for adding a new class
|
||||||
|
*/
|
||||||
export interface AddClassItem {
|
export interface AddClassItem {
|
||||||
|
/** Name of the class to add */
|
||||||
class_name: string;
|
class_name: string;
|
||||||
|
/** Description of the class to add */
|
||||||
class_description: string;
|
class_description: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Form data for creating ontology classes
|
||||||
|
*/
|
||||||
export interface OntologyClassModalData {
|
export interface OntologyClassModalData {
|
||||||
|
/** Target scene identifier */
|
||||||
scene_id: string;
|
scene_id: string;
|
||||||
|
/** Array of classes to create */
|
||||||
classes: AddClassItem[]
|
classes: AddClassItem[]
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Ref methods exposed by OntologyClassModal component
|
||||||
|
*/
|
||||||
export interface OntologyClassModalRef {
|
export interface OntologyClassModalRef {
|
||||||
|
/**
|
||||||
|
* Open the modal for adding classes
|
||||||
|
* @param scene_id - Target scene identifier
|
||||||
|
*/
|
||||||
handleOpen: (scene_id: string) => void;
|
handleOpen: (scene_id: string) => void;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Form data for extracting ontology classes using LLM
|
||||||
|
*/
|
||||||
export interface OntologyClassExtractModalData {
|
export interface OntologyClassExtractModalData {
|
||||||
|
/** LLM model identifier */
|
||||||
llm_id: string;
|
llm_id: string;
|
||||||
|
/** Target scene identifier */
|
||||||
scene_id: string;
|
scene_id: string;
|
||||||
|
/** Scenario description for extraction */
|
||||||
scenario: string;
|
scenario: string;
|
||||||
domain: string; // scene_name
|
/** Domain name (same as scene_name) */
|
||||||
|
domain: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Ref methods exposed by OntologyClassExtractModal component
|
||||||
|
*/
|
||||||
export interface OntologyClassExtractModalRef {
|
export interface OntologyClassExtractModalRef {
|
||||||
|
/**
|
||||||
|
* Open the modal for extracting classes
|
||||||
|
* @param vo - Ontology class data containing scene information
|
||||||
|
*/
|
||||||
handleOpen: (vo: OntologyClassData) => void;
|
handleOpen: (vo: OntologyClassData) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracted class item from LLM
|
||||||
|
*/
|
||||||
export interface ExtractClassItem {
|
export interface ExtractClassItem {
|
||||||
|
/** Unique identifier for the extracted class */
|
||||||
id: string;
|
id: string;
|
||||||
|
/** English name of the class */
|
||||||
name: string;
|
name: string;
|
||||||
|
/** Chinese name of the class */
|
||||||
name_chinese: string;
|
name_chinese: string;
|
||||||
|
/** Description of the class */
|
||||||
description: string;
|
description: string;
|
||||||
|
/** Example instances of the class */
|
||||||
examples: string[];
|
examples: string[];
|
||||||
|
/** Parent class name if exists */
|
||||||
parent_class: string | null;
|
parent_class: string | null;
|
||||||
|
/** Entity type classification */
|
||||||
entity_type: string;
|
entity_type: string;
|
||||||
|
/** Domain the class belongs to */
|
||||||
domain: string;
|
domain: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Response data structure for class extraction
|
||||||
|
*/
|
||||||
export interface ExtractData {
|
export interface ExtractData {
|
||||||
|
/** Domain name */
|
||||||
domain: string;
|
domain: string;
|
||||||
|
/** Number of classes extracted */
|
||||||
extracted_count: number;
|
extracted_count: number;
|
||||||
|
/** Array of extracted class items */
|
||||||
classes: ExtractClassItem[]
|
classes: ExtractClassItem[]
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Ref methods exposed by OntologyImportModal component
|
||||||
|
*/
|
||||||
|
export interface OntologyImportModalRef {
|
||||||
|
/** Open the import modal */
|
||||||
|
handleOpen: () => void;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Form data for importing ontology
|
||||||
|
*/
|
||||||
|
export interface OntologyImportModalData {
|
||||||
|
/** Name for the imported scene */
|
||||||
|
scene_name: string;
|
||||||
|
/** Optional description for the imported scene */
|
||||||
|
scene_description?: string;
|
||||||
|
/** File to import (OWL, TTL, RDF, XML formats) */
|
||||||
|
file: any;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Ref methods exposed by OntologyExportModal component
|
||||||
|
*/
|
||||||
|
export interface OntologyExportModalRef {
|
||||||
|
/** Open the export modal */
|
||||||
|
handleOpen: () => void;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Form data for exporting ontology
|
||||||
|
*/
|
||||||
|
export interface OntologyExportModalData {
|
||||||
|
/** Scene identifier to export */
|
||||||
|
scene_id: string;
|
||||||
|
/** Export format: 'rdfxml' (.owl) or 'turtle' (.ttl) */
|
||||||
|
format: 'rdfxml' | 'turtle';
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user