feat: common

This commit is contained in:
wangdan-fit2cloud 2025-06-26 20:25:24 +08:00
parent c2c1d4eeb9
commit d626601672
124 changed files with 462 additions and 11422 deletions

View File

@ -1,7 +1,7 @@
import type { Ref } from 'vue'
import { Result } from '@/request/Result'
import { get, put } from '@/request/index'
import type { ChatUserGroupItem, ChatUserGroupUserItem, ChatUserResourceParams, putUserGroupUserParams } from '@/api/type/workspaceChatUser'
import type { ChatUserGroupItem, ChatUserGroupUserItem, putUserGroupUserParams } from '@/api/type/workspaceChatUser'
import type { pageRequest, PageList } from '@/api/type/common'
import useStore from '@/stores'
@ -15,14 +15,14 @@ Object.defineProperty(prefix, 'value', {
/**
*
*/
const getUserGroupList: (resource: ChatUserResourceParams, loading?: Ref<boolean>) => Promise<Result<ChatUserGroupItem[]>> = (resource, loading) => {
const getUserGroupList: (resource: any, loading?: Ref<boolean>) => Promise<Result<ChatUserGroupItem[]>> = (resource, loading) => {
return get(`${prefix.value}/${resource.resource_type}/${resource.resource_id}/user_group`, undefined, loading)
}
/**
*
*/
const editUserGroupList: (resource: ChatUserResourceParams, data: { user_group_id: string, is_auth: boolean }[], loading?: Ref<boolean>) => Promise<Result<any>> = (resource, data, loading) => {
const editUserGroupList: (resource: any, data: { user_group_id: string, is_auth: boolean }[], loading?: Ref<boolean>) => Promise<Result<any>> = (resource, data, loading) => {
return put(`${prefix.value}/${resource.resource_type}/${resource.resource_id}/user_group`, data, undefined, loading)
}
@ -30,7 +30,7 @@ const editUserGroupList: (resource: ChatUserResourceParams, data: { user_group_i
*
*/
const getUserGroupUserList: (
resource: ChatUserResourceParams,
resource: any,
user_group_id: string,
page: pageRequest,
username_or_nickname: string,
@ -47,7 +47,7 @@ const getUserGroupUserList: (
*
*/
const putUserGroupUser: (
resource: ChatUserResourceParams,
resource: any,
user_group_id: string,
data: putUserGroupUserParams[],
loading?: Ref<boolean>,

View File

@ -1,63 +0,0 @@
import { Result } from '@/request/Result'
import { get, post, del, put, exportFile, exportExcel } from '@/request/index'
import { type Ref } from 'vue'
import type { pageRequest } from '@/api/type/common'
import type { knowledgeData } from '@/api/type/knowledge'
const prefix = '/system/resource'
const getSharedAuthorizationKnowledge: (
knowledge_id: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (knowledge_id, loading) => {
return get(`${prefix}/knowledge/${knowledge_id}/authorization`, {}, loading)
}
const postSharedAuthorizationKnowledge: (
knowledge_id: string,
param?: any,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (knowledge_id, param, loading) => {
return post(`${prefix}/knowledge/${knowledge_id}/authorization`, param, loading)
}
const getSharedAuthorizationTool: (
knowledge_id: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (knowledge_id, loading) => {
return get(`${prefix}/tool/${knowledge_id}/authorization`, {}, loading)
}
const postSharedAuthorizationTool: (
knowledge_id: string,
param?: any,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (knowledge_id, param, loading) => {
return post(`${prefix}/tool/${knowledge_id}/authorization`, param, loading)
}
const getSharedAuthorizationModel: (
knowledge_id: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (knowledge_id, loading) => {
return get(`${prefix}/model/${knowledge_id}/authorization`, {}, loading)
}
const postSharedAuthorizationModel: (
knowledge_id: string,
param?: any,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (knowledge_id, param, loading) => {
return post(`${prefix}/model/${knowledge_id}/authorization`, param, loading)
}
export default {
getSharedAuthorizationKnowledge,
postSharedAuthorizationKnowledge,
getSharedAuthorizationTool,
postSharedAuthorizationTool,
getSharedAuthorizationModel,
postSharedAuthorizationModel,
} as {
[key: string]: any
}

View File

@ -1,503 +0,0 @@
import { Result } from '@/request/Result'
import { get, post, del, put, exportExcel, exportFile } from '@/request/index'
import type { Ref } from 'vue'
import type { KeyValue } from '@/api/type/common'
import type { pageRequest } from '@/api/type/common'
const prefix = '/system/resource/knowledge'
/**
*
* @param knowledge_id,
* param {
" name": "string",
}
*/
const getDocument: (
knowledge_id: string,
page: pageRequest,
param: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, page, param, loading) => {
return get(
`${prefix}/${knowledge_id}/document/${page.current_page}/${page.page_size}`,
param,
loading,
)
}
/**
*
* @param knowledge_id
*/
const getDocumentDetail: (
knowledge_id: string,
document_id: string,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, document_id, loading) => {
return get(`${prefix}/${knowledge_id}/document/${document_id}`,
{},
loading,)
}
/**
*
* @param
* knowledge_id, document_id,
* {
"name": "string",
"is_active": true,
"meta": {}
}
*/
const putDocument: (
knowledge_id: string,
document_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, document_id, data: any, loading) => {
return put(`${prefix}/${knowledge_id}/document/${document_id}`, data, undefined, loading)
}
/**
*
* @param knowledge_id, document_id,
*/
const delDocument: (
knowledge_id: string,
document_id: string,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, document_id, loading) => {
return del(`${prefix}/${knowledge_id}/document/${document_id}`, loading)
}
/**
*
* @param knowledge_id,
*{
"id_list": [
"3fa85f64-5717-4562-b3fc-2c963f66afa6"
],
"type": 0
}
*/
const putBatchCancelTask: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, data, loading) => {
return put(`${prefix}/${knowledge_id}/document/batch_cancel_task`, data, undefined, loading)
}
/**
*
* @param knowledge_id, document_id,
*/
const putCancelTask: (
knowledge_id: string,
document_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, document_id, data, loading) => {
return put(
`${prefix}/${knowledge_id}/document/${document_id}/cancel_task`,
data,
undefined,
loading,
)
}
/**
*
* @param knowledge_id
*/
const getDownloadSourceFile: (knowledge_id: string, document_id: string) => Promise<Result<any>> = (
knowledge_id,
document_id,
) => {
return get(`${prefix}/${knowledge_id}/document/${document_id}/download_source_file`)
}
/**
*
* @param document_name
* @param knowledge_id id
* @param document_id id
* @param loading
* @returns
*/
const exportDocument: (
document_name: string,
knowledge_id: string,
document_id: string,
loading?: Ref<boolean>,
) => Promise<any> = (document_name, knowledge_id, document_id, loading) => {
return exportExcel(
document_name + '.xlsx',
`${prefix}/${knowledge_id}/document/${document_id}/export`,
{},
loading,
)
}
/**
*
* @param document_name
* @param knowledge_id id
* @param document_id id
* @param loading
* @returns
*/
const exportDocumentZip: (
document_name: string,
knowledge_id: string,
document_id: string,
loading?: Ref<boolean>,
) => Promise<any> = (document_name, knowledge_id, document_id, loading) => {
return exportFile(
document_name + '.zip',
`${prefix}/${knowledge_id}/document/${document_id}/export_zip`,
{},
loading,
)
}
/**
*
* @param
* knowledge_id, document_id,
* {
"state_list": [
"string"
]
}
*/
const putDocumentRefresh: (
knowledge_id: string,
document_id: string,
state_list: Array<string>,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, document_id, state_list, loading) => {
return put(
`${prefix}/${knowledge_id}/document/${document_id}/refresh`,
{ state_list },
undefined,
loading,
)
}
/**
* web站点类型
* @param
* knowledge_id, document_id,
*/
const putDocumentSync: (
knowledge_id: string,
document_id: string,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, document_id, loading) => {
return put(
`${prefix}/${knowledge_id}/document/${document_id}/sync`,
undefined,
undefined,
loading,
)
}
/**
*
* @param
{
"name": "string",
"paragraphs": [
{
"content": "string",
"title": "string",
"problem_list": [
{
"id": "string",
"content": "string"
}
],
"is_active": true
}
],
"source_file_id": string
}
*/
const putMulDocument: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, data, loading) => {
return put(`${prefix}/${knowledge_id}/document/batch_create`, data, {}, loading, 1000 * 60 * 5)
}
/**
*
* @param knowledge_id,
* {
"id_list": [String]
}
*/
const delMulDocument: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, data, loading) => {
return del(
`${prefix}/${knowledge_id}/document/bach_delete`,
undefined,
{ id_list: data },
loading,
)
}
/**
*
* @param knowledge_id,
{
"document_id_list": [
"string"
],
"model_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"prompt": "string",
"state_list": [
"string"
]
}
*/
const putBatchGenerateRelated: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, data, loading) => {
return put(`${prefix}/${knowledge_id}/document/batch_generate_related`, data, undefined, loading)
}
/**
*
* @param knowledge_id id
* @param data
* {id_list:[],hit_handling_method:'directly_return|optimization',directly_return_similarity}
* @param loading
* @returns
*/
const putBatchEditHitHandling: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, data, loading) => {
return put(`${prefix}/${knowledge_id}/document/batch_hit_handling`, data, undefined, loading)
}
/**
*
* @param knowledge_id id
* @param data
{
"id_list": [
"string"
],
"state_list": [
"string"
]
}
* @param loading
* @returns
*/
const putBatchRefresh: (
knowledge_id: string,
data: any,
stateList: Array<string>,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, data, stateList, loading) => {
return put(
`${prefix}/${knowledge_id}/document/batch_refresh`,
{ id_list: data, state_list: stateList },
undefined,
loading,
)
}
/**
*
* @param knowledge_id,
*/
const putMulSyncDocument: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, data, loading) => {
return put(`${prefix}/${knowledge_id}/document/batch_sync`, { id_list: data }, undefined, loading)
}
/**
*
* @param knowledge_id,target_knowledge_id,
*/
const putMigrateMulDocument: (
knowledge_id: string,
target_knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, target_knowledge_id, data, loading) => {
return put(
`${prefix}/${knowledge_id}/document/migrate/${target_knowledge_id}`,
data,
undefined,
loading,
)
}
/**
* QA文档
* @param
* file
}
*/
const postQADocument: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, data, loading) => {
return post(`${prefix}/${knowledge_id}/document/qa`, data, undefined, loading)
}
/**
*
* @param file:file,limit:number,patterns:array,with_filter:boolean
*/
const postSplitDocument: (data: any, id: string) => Promise<Result<any>> = (data, id) => {
return post(`${prefix}/${id}/document/split`, data, undefined, undefined, 1000 * 60 * 60)
}
/**
*
* @param loading
* @returns
*/
const listSplitPattern: (
loading?: Ref<boolean>,
) => Promise<Result<Array<KeyValue<string, string>>>> = (loading) => {
return get(`${prefix}/document/split_pattern`, {}, loading)
}
/**
*
* @param
* file
*/
const postTableDocument: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, data, loading) => {
return post(`${prefix}/${knowledge_id}/document/table`, data, undefined, loading)
}
/**
* QA模版
* @param fileName,type,
*/
const exportQATemplate: (fileName: string, type: string, loading?: Ref<boolean>) => void = (
fileName,
type,
loading,
) => {
return exportExcel(fileName, `${prefix}/document/template/export`, { type }, loading)
}
/**
* table模版
* @param fileName,type,
*/
const exportTableTemplate: (fileName: string, type: string, loading?: Ref<boolean>) => void = (
fileName,
type,
loading,
) => {
return exportExcel(fileName, `${prefix}/document/table_template/export`, { type }, loading)
}
/**
* Web站点文档
* @param
* {
"source_url_list": [
"string"
],
"selector": "string"
}
}
*/
const postWebDocument: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, data, loading) => {
return post(`${prefix}/${knowledge_id}/document/web`, data, undefined, loading)
}
const getAllDocument: (knowledge_id: string, loading?: Ref<boolean>) => Promise<Result<any>> = (
knowledge_id,
loading,
) => {
return get(`${prefix}/${knowledge_id}/document`, undefined, loading)
}
const putLarkDocumentSync: (
knowledge_id: string,
document_id: string,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, document_id, loading) => {
return put(
`${prefix}/lark/${knowledge_id}/document/${document_id}/sync`,
undefined,
undefined,
loading,
)
}
const delMulLarkSyncDocument: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, data, loading) => {
return put(`${prefix}/lark/${knowledge_id}/_batch`, { id_list: data }, undefined, loading)
}
export default {
getDocument,
getDocumentDetail,
putDocument,
delDocument,
putBatchCancelTask,
putCancelTask,
getDownloadSourceFile,
exportDocument,
exportDocumentZip,
putDocumentRefresh,
putDocumentSync,
putMulDocument,
delMulDocument,
putBatchGenerateRelated,
putBatchEditHitHandling,
putBatchRefresh,
putMulSyncDocument,
putMigrateMulDocument,
postQADocument,
postSplitDocument,
listSplitPattern,
postTableDocument,
exportQATemplate,
exportTableTemplate,
postWebDocument,
getAllDocument,
putLarkDocumentSync,
delMulLarkSyncDocument,
}

View File

@ -1,305 +0,0 @@
import { Result } from '@/request/Result'
import { get, post, del, put, exportFile, exportExcel } from '@/request/index'
import { type Ref } from 'vue'
import type { pageRequest } from '@/api/type/common'
import type { knowledgeData } from '@/api/type/knowledge'
import useStore from '@/stores'
const prefix = '/system/resource'
/**
*
* @params
* {folder_id: string,
* name: string,
* user_id: string
* desc: string,}
*/
const getKnowledgeByFolder: (data?: any, loading?: Ref<boolean>) => Promise<Result<Array<any>>> = (
data,
loading,
) => {
return get(`${prefix}/knowledge`, data, loading)
}
/**
*
* @param
* param {
"folder_id": "string",
"name": "string",
"tool_type": "string",
desc: string,
}
*/
const getKnowledgeList: (param?: any, loading?: Ref<boolean>) => Promise<Result<any>> = (
param,
loading,
) => {
return get(`${prefix}/knowledge`, param, loading)
}
/**
*
* @param
* param {
"folder_id": "string",
"name": "string",
"tool_type": "string",
desc: string,
}
*/
const getKnowledgeListPage: (
page: pageRequest,
param?: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (page, param, loading) => {
return get(`${prefix}/knowledge/${page.current_page}/${page.page_size}`, param, loading)
}
/**
*
* @param knowledge_id
*/
const getKnowledgeDetail: (knowledge_id: string, loading?: Ref<boolean>) => Promise<Result<any>> = (
knowledge_id,
loading,
) => {
return get(`${prefix}/knowledge/${knowledge_id}`, undefined, loading)
}
/**
*
* @param
* knowledge_id
* {
"name": "string",
"desc": true
}
*/
const putKnowledge: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, data, loading) => {
return put(`${prefix}/knowledge/${knowledge_id}`, data, undefined, loading)
}
/**
*
* @param knowledge_id
*/
const delKnowledge: (knowledge_id: String, loading?: Ref<boolean>) => Promise<Result<boolean>> = (
knowledge_id,
loading,
) => {
return del(`${prefix}/${knowledge_id}`, undefined, {}, loading)
}
/**
*
* @param knowledge_id
*/
const putReEmbeddingKnowledge: (
knowledge_id: string,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, loading) => {
return put(`${prefix}/knowledge/${knowledge_id}/embedding`, undefined, undefined, loading)
}
/**
*
* @param knowledge_name
* @param knowledge_id id
* @returns
*/
const exportKnowledge: (
knowledge_name: string,
knowledge_id: string,
loading?: Ref<boolean>,
) => Promise<any> = (knowledge_name, knowledge_id, loading) => {
return exportExcel(
knowledge_name + '.xlsx',
`${prefix}/${knowledge_id}/knowledge/${knowledge_id}/export`,
undefined,
loading,
)
}
/**
*Zip知识库
* @param knowledge_name
* @param knowledge_id id
* @param loading
* @returns
*/
const exportZipKnowledge: (
knowledge_name: string,
knowledge_id: string,
loading?: Ref<boolean>,
) => Promise<any> = (knowledge_name, knowledge_id, loading) => {
return exportFile(
knowledge_name + '.zip',
`${prefix}/${knowledge_id}/knowledge/${knowledge_id}/export_zip`,
undefined,
loading,
)
}
/**
*
* @param knowledge_id id
* @param data
* @param loading
* @returns
*/
const putGenerateRelated: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (knowledge_id, data, loading) => {
return put(`${prefix}/${knowledge_id}/generate_related`, data, null, loading)
}
/**
*
* @param knowledge_id
* @param loading
* @query { query_text: string, top_number: number, similarity: number }
* @returns
*/
const getKnowledgeHitTest: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (knowledge_id, data, loading) => {
return get(`${prefix}/${knowledge_id}/hit_test`, data, loading)
}
/**
*
* @param knowledge_id
* @query sync_type // 同步类型->replace:替换同步,complete:完整同步
*/
const putSyncWebKnowledge: (
knowledge_id: string,
sync_type: string,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, sync_type, loading) => {
return put(`${prefix}/knowledge/${knowledge_id}/sync`, undefined, { sync_type }, loading)
}
/**
*
* @param
* {
"name": "string",
"folder_id": "string",
"desc": "string",
"embedding": "string"
}
*/
const postKnowledge: (data: knowledgeData, loading?: Ref<boolean>) => Promise<Result<any>> = (
data,
loading,
) => {
return post(`${prefix}/knowledge/base`, data, undefined, loading, 1000 * 60 * 5)
}
/**
* 使
* @param application_id
* @param loading
* @query { query_text: string, top_number: number, similarity: number }
* @returns
*/
const getKnowledgeEmdeddingModel: (
knowledge_id: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (knowledge_id, loading) => {
return get(`${prefix}/${knowledge_id}/emdedding_model`, loading)
}
/**
* 使
* @param application_id
* @param loading
* @query { query_text: string, top_number: number, similarity: number }
* @returns
*/
const getKnowledgeModel: (loading?: Ref<boolean>) => Promise<Result<Array<any>>> = (loading) => {
return get(`${prefix}/knowledge/model`, loading)
}
/**
* Web知识库
* @param
* {
"name": "string",
"folder_id": "string",
"desc": "string",
"embedding": "string",
"source_url": "string",
"selector": "string"
}
*/
const postWebKnowledge: (data: any, loading?: Ref<boolean>) => Promise<Result<any>> = (
data,
loading,
) => {
return post(`${prefix}/knowledge/web`, data, undefined, loading)
}
/**
*
* @param knowledge_id
* @param folder_token
* @param loading
* @returns
*/
const getLarkDocumentList: (
knowledge_id: string,
folder_token: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (knowledge_id, folder_token, data, loading) => {
return post(`${prefix}/lark/${knowledge_id}/${folder_token}/doc_list`, data, null, loading)
}
const importLarkDocument: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (knowledge_id, data, loading) => {
return post(`${prefix}/lark/${knowledge_id}/import`, data, null, loading)
}
const postLarkKnowledge: (data: any, loading?: Ref<boolean>) => Promise<Result<Array<any>>> = (
data,
loading,
) => {
return post(`${prefix}/knowledge/lark/save`, data, null, loading)
}
export default {
getKnowledgeByFolder,
getKnowledgeList,
getKnowledgeListPage,
getKnowledgeDetail,
putKnowledge,
delKnowledge,
putReEmbeddingKnowledge,
exportKnowledge,
exportZipKnowledge,
putGenerateRelated,
getKnowledgeHitTest,
putSyncWebKnowledge,
postKnowledge,
getKnowledgeModel,
postWebKnowledge,
getLarkDocumentList,
importLarkDocument,
postLarkKnowledge,
} as {
[key: string]: any
}

View File

@ -1,133 +0,0 @@
import { Result } from '@/request/Result'
import { get, post, del, put } from '@/request/index'
import { type Ref } from 'vue'
import type {
ListModelRequest,
Model,
CreateModelRequest,
EditModelRequest,
} from '@/api/type/model'
import type { FormField } from '@/components/dynamics-form/type'
const prefix = '/system/resource'
const workspace_id = localStorage.getItem('workspace_id') || 'default'
/**
*
* @params name, model_type, model_name
*/
const getModelList: (
request?: ListModelRequest,
loading?: Ref<boolean>,
) => Promise<Result<Array<Model>>> = (data, loading) => {
return get(`${prefix}/model`, data, loading)
}
/**
*
* @param model_id id
* @param loading
* @returns
*/
const getModelParamsForm: (
model_id: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<FormField>>> = (model_id, loading) => {
return get(`${prefix}/model/${model_id}/model_params_form`, {}, loading)
}
/**
*
* @param request
* @param loading
* @returns
*/
const createModel: (
request: CreateModelRequest,
loading?: Ref<boolean>,
) => Promise<Result<Model>> = (request, loading) => {
return post(`${prefix}/model`, request, {}, loading)
}
/**
*
* @param request
* @param loading
* @returns
*/
const updateModel: (
model_id: string,
request: EditModelRequest,
loading?: Ref<boolean>,
) => Promise<Result<Model>> = (model_id, request, loading) => {
return put(`${prefix}/model/${model_id}`, request, {}, loading)
}
/**
*
* @param request
* @param loading
* @returns
*/
const updateModelParamsForm: (
model_id: string,
request: any[],
loading?: Ref<boolean>,
) => Promise<Result<Model>> = (model_id, request, loading) => {
return put(`${prefix}/model/${model_id}/model_params_form`, request, {}, loading)
}
/**
* id
* @param model_id id
* @param loading
* @returns
*/
const getModelById: (model_id: string, loading?: Ref<boolean>) => Promise<Result<Model>> = (
model_id,
loading,
) => {
return get(`${prefix}/model/${model_id}`, {}, loading)
}
/**
* id
* @param model_id id
* @param loading
* @returns
*/
const getModelMetaById: (model_id: string, loading?: Ref<boolean>) => Promise<Result<Model>> = (
model_id,
loading,
) => {
return get(`${prefix}/model/${model_id}/meta`, {}, loading)
}
/**
*
* @param model_id id
* @param loading
* @returns
*/
const pauseDownload: (model_id: string, loading?: Ref<boolean>) => Promise<Result<boolean>> = (
model_id,
loading,
) => {
return put(`${prefix}/model/${model_id}/pause_download`, undefined, {}, loading)
}
const deleteModel: (model_id: string, loading?: Ref<boolean>) => Promise<Result<boolean>> = (
model_id,
loading,
) => {
return del(`${prefix}/model/${model_id}`, undefined, {}, loading)
}
export default {
getModelList,
createModel,
updateModel,
deleteModel,
getModelById,
getModelMetaById,
pauseDownload,
getModelParamsForm,
updateModelParamsForm,
}

View File

@ -1,268 +0,0 @@
import { Result } from '@/request/Result'
import { get, post, del, put } from '@/request/index'
import type { pageRequest } from '@/api/type/common'
import type { Ref } from 'vue'
const prefix = '/system/resource/knowledge'
/**
*
* @param
* knowledge_id, document_id
* {
"content": "string",
"title": "string",
"is_active": true,
"problem_list": [
{
"content": "string"
}
]
}
*/
const postParagraph: (
knowledge_id: string,
document_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, document_id, data, loading) => {
return post(
`${prefix}/${knowledge_id}/document/${document_id}/paragraph`,
data,
undefined,
loading,
)
}
/**
*
* @param knowledge_id document_id
* param {
"title": "string",
"content": "string",
}
*/
const getParagraph: (
knowledge_id: string,
document_id: string,
page: pageRequest,
param: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, document_id, page, param, loading) => {
return get(
`${prefix}/${knowledge_id}/document/${document_id}/paragraph/${page.current_page}/${page.page_size}`,
param,
loading,
)
}
/**
*
* @param
* knowledge_id, document_id, paragraph_id
* {
"content": "string",
"title": "string",
"is_active": true,
"problem_list": [
{
"content": "string"
}
]
}
*/
const putParagraph: (
knowledge_id: string,
document_id: string,
paragraph_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, document_id, paragraph_id, data, loading) => {
return put(
`${prefix}/${knowledge_id}/document/${document_id}/paragraph/${paragraph_id}`,
data,
undefined,
loading,
)
}
/**
*
* @param knowledge_id, document_id, paragraph_id
*/
const delParagraph: (
knowledge_id: string,
document_id: string,
paragraph_id: string,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, document_id, paragraph_id, loading) => {
return del(
`${prefix}/${knowledge_id}/document/${document_id}/paragraph/${paragraph_id}`,
undefined,
{},
loading,
)
}
/**
*
* @param knowledge_iddocument_idparagraph_id
*/
const getParagraphProblem: (
knowledge_id: string,
document_id: string,
paragraph_id: string,
) => Promise<Result<any>> = (knowledge_id, document_id, paragraph_id: string) => {
return get(`${prefix}/${knowledge_id}/document/${document_id}/paragraph/${paragraph_id}/problem`)
}
/**
*
* @param
* knowledge_id, document_id, paragraph_id
* {
content": "string"
}
*/
const postParagraphProblem: (
knowledge_id: string,
document_id: string,
paragraph_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, document_id, paragraph_id, data: any, loading) => {
return post(
`${prefix}/${knowledge_id}/document/${document_id}/paragraph/${paragraph_id}/problem`,
data,
{},
loading,
)
}
/**
*
* @param knowledge_id id
* @param document_id id
* @param loading
* @query data {
* paragraph_id id problem_id id
* }
*/
const putAssociationProblem: (
knowledge_id: string,
document_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, document_id, data, loading) => {
return put(
`${prefix}/${knowledge_id}/document/${document_id}/paragraph/association`,
{},
data,
loading,
)
}
/**
*
* @param knowledge_id, document_id
*/
const putMulParagraph: (
knowledge_id: string,
document_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, document_id, data, loading) => {
return put(
`${prefix}/${knowledge_id}/document/${document_id}/paragraph/batch_delete`,
{ id_list: data },
undefined,
loading,
)
}
/**
*
* @param knowledge_id, document_id
* {
"paragraph_id_list": [
"3fa85f64-5717-4562-b3fc-2c963f66afa6"
],
"model_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"prompt": "string",
"document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
*/
const putBatchGenerateRelated: (
knowledge_id: string,
document_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, document_id, data, loading) => {
return put(
`${prefix}/${knowledge_id}/document/${document_id}/paragraph/batch_generate_related`,
data,
undefined,
loading,
)
}
/**
*
* @param knowledge_id,target_knowledge_id,
*/
const putMigrateMulParagraph: (
knowledge_id: string,
document_id: string,
target_knowledge_id: string,
target_document_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (
knowledge_id,
document_id,
target_knowledge_id,
target_document_id,
data,
loading,
) => {
return put(
`${prefix}/${knowledge_id}/document/${document_id}/paragraph/migrate/knowledge/${target_knowledge_id}/document/${target_document_id}`,
data,
undefined,
loading,
)
}
/**
*
* @param knowledge_id, document_id,
* @query data {
* paragraph_id id problem_id id
* }
*/
const putDisassociationProblem: (
knowledge_id: string,
document_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, document_id, data, loading) => {
return put(
`${prefix}/${knowledge_id}/document/${document_id}/paragraph/unassociation`,
{},
data,
loading,
)
}
export default {
postParagraph,
getParagraph,
putParagraph,
delParagraph,
getParagraphProblem,
postParagraphProblem,
putAssociationProblem,
putMulParagraph,
putBatchGenerateRelated,
putMigrateMulParagraph,
putDisassociationProblem,
}

View File

@ -1,121 +0,0 @@
import { Result } from '@/request/Result'
import { get, post, del, put } from '@/request/index'
import type { Ref } from 'vue'
import type { pageRequest } from '@/api/type/common'
const prefix = '/system/resource/knowledge'
/**
*
* @param knowledge_id
* data: array[string]
*/
const postProblems: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, data, loading) => {
return post(`${prefix}/${knowledge_id}/problem`, data, undefined, loading)
}
/**
*
* @param knowledge_id,
* query {
"content": "string",
}
*/
const getProblems: (
knowledge_id: string,
page: pageRequest,
param: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, page, param, loading) => {
return get(
`${prefix}/${knowledge_id}/problem/${page.current_page}/${page.page_size}`,
param,
loading,
)
}
/**
*
* @param
* knowledge_id, problem_id,
* {
"content": "string",
}
*/
const putProblems: (
knowledge_id: string,
problem_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, problem_id, data: any, loading) => {
return put(`${prefix}/${knowledge_id}/problem/${problem_id}`, data, undefined, loading)
}
/**
*
* @param knowledge_id, problem_id,
*/
const delProblems: (
knowledge_id: string,
problem_id: string,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, problem_id, loading) => {
return del(`${prefix}/${knowledge_id}/problem/${problem_id}`, loading)
}
/**
*
* @param
* knowledge_id, problem_id,
*/
const getDetailProblems: (
knowledge_id: string,
problem_id: string,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (knowledge_id, problem_id, loading) => {
return get(`${prefix}/${knowledge_id}/problem/${problem_id}/paragraph`, undefined, loading)
}
/**
*
* @param knowledge_id,
* {
"problem_id_list": "Array",
"paragraph_list": "Array",
}
*/
const putMulAssociationProblem: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, data, loading) => {
return put(`${prefix}/${knowledge_id}/problem/batch_association`, data, undefined, loading)
}
/**
*
* @param knowledge_id,
* data: array[string]
*/
const putMulProblem: (
knowledge_id: string,
data: any,
loading?: Ref<boolean>,
) => Promise<Result<boolean>> = (knowledge_id, data, loading) => {
return put(`${prefix}/${knowledge_id}/problem/batch_delete`, data, undefined, loading)
}
export default {
postProblems,
getProblems,
putProblems,
delProblems,
getDetailProblems,
putMulAssociationProblem,
putMulProblem,
}

View File

@ -1,86 +0,0 @@
import {Result} from '@/request/Result'
import {get, post} from '@/request/index'
import type {Ref} from 'vue'
import type {Provider, BaseModel} from '@/api/type/model'
import type {FormField} from '@/components/dynamics-form/type'
import type {KeyValue} from '../type/common'
const prefix_provider = '/provider'
/**
*
*/
const getProvider: (loading?: Ref<boolean>) => Promise<Result<Array<Provider>>> = (loading) => {
return get(`${prefix_provider}`, {}, loading)
}
/**
*
*/
const getProviderByModelType: (
model_type: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<Provider>>> = (model_type, loading) => {
return get(`${prefix_provider}`, {model_type}, loading)
}
/**
*
* @param provider
* @param model_type
* @param model_name
* @param loading
* @returns
*/
const getModelCreateForm: (
provider: string,
model_type: string,
model_name: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<FormField>>> = (provider, model_type, model_name, loading) => {
return get(`${prefix_provider}/model_form`, {provider, model_type, model_name}, loading)
}
/**
*
* @param provider
* @param loading
* @returns
*/
const listModelType: (
provider: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<KeyValue<string, string>>>> = (provider, loading?: Ref<boolean>) => {
return get(`${prefix_provider}/model_type_list`, {provider}, loading)
}
/**
*
* @param provider
* @param model_type
* @param loading
* @returns
*/
const listBaseModel: (
provider: string,
model_type: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<BaseModel>>> = (provider, model_type, loading) => {
return get(`${prefix_provider}/model_list`, {provider, model_type}, loading)
}
const listBaseModelParamsForm: (
provider: string,
model_type: string,
model_name: string,
loading?: Ref<boolean>,
) => Promise<Result<Array<BaseModel>>> = (provider, model_type, model_name, loading) => {
return get(`${prefix_provider}/model_params_form`, {provider, model_type, model_name}, loading)
}
export default {
getProvider,
getModelCreateForm,
getProviderByModelType,
listModelType,
listBaseModel,
listBaseModelParamsForm,
}

View File

@ -1,78 +0,0 @@
import {Result} from '@/request/Result'
import {get, post, del, put, exportFile, exportExcel} from '@/request/index'
import {type Ref} from 'vue'
import type {pageRequest} from '@/api/type/common'
import type {knowledgeData} from '@/api/type/knowledge'
import useStore from '@/stores'
const prefix = '/system/resource'
const prefix_workspace: any = {_value: 'workspace/'}
Object.defineProperty(prefix_workspace, 'value', {
get: function () {
const {user} = useStore()
return this._value + user.getWorkspaceId()
},
})
const getSharedWorkspaceKnowledge: (loading?: Ref<boolean>) => Promise<Result<Array<any>>> = (
loading,
) => {
return get(`${prefix}/${prefix_workspace.value}/knowledge`, {}, loading)
}
const getSharedWorkspaceKnowledgePage: (
page: pageRequest,
param: any,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (page, param, loading) => {
return get(
`${prefix}/${prefix_workspace.value}/knowledge/${page.current_page}/${page.page_size}`,
param,
loading,
)
}
const getSharedWorkspaceModel: (loading?: Ref<boolean>) => Promise<Result<Array<any>>> = (
loading,
) => {
return get(`${prefix}/${prefix_workspace.value}/model`, {}, loading)
}
const getCESharedWorkspaceModel: (loading?: Ref<boolean>) => Promise<Result<Array<any>>> = (
loading,
) => {
return get(`/${prefix_workspace.value}/model`, {}, loading)
}
const getSharedWorkspaceModelPage: (
param: any,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (param: any, loading) => {
console.log(`${prefix}/${prefix_workspace.value}/model`)
return get(`${prefix}/${prefix_workspace.value}/model`, param, loading)
}
const getSharedWorkspaceTool: (loading?: Ref<boolean>) => Promise<Result<Array<any>>> = (
loading,
) => {
return get(`${prefix}/${prefix_workspace.value}/tool`, {}, loading)
}
const getSharedWorkspaceToolPage: (
param: any,
loading?: Ref<boolean>,
) => Promise<Result<Array<any>>> = (param: any, loading) => {
return get(`${prefix}/${prefix_workspace.value}/tool`, param, loading)
}
export default {
getSharedWorkspaceKnowledge,
getSharedWorkspaceKnowledgePage,
getSharedWorkspaceModel,
getSharedWorkspaceModelPage,
getSharedWorkspaceTool,
getSharedWorkspaceToolPage,
getCESharedWorkspaceModel
}

View File

@ -4,45 +4,37 @@ import { type Ref } from 'vue'
import type { pageRequest } from '@/api/type/common'
import type { toolData } from '@/api/type/tool'
const prefix = '/system/resource'
const prefix = '/system/resource/tool'
/**
*
* @params {folder_id: string}
*
* @params
* param {
"name": "string",
"tool_type": "string",
}
*/
const getToolByFolder: (data?: any, loading?: Ref<boolean>) => Promise<Result<Array<any>>> = (
const getToolList: (data?: any, loading?: Ref<boolean>) => Promise<Result<Array<any>>> = (
data,
loading,
) => {
return get(`${prefix}/tool`, data, loading)
return get(`${prefix}`, data, loading)
}
/**
*
*
* @param
* param {
"folder_id": "string",
"name": "string",
"tool_type": "string",
}
*/
const getToolList: (
const getToolListPage: (
page: pageRequest,
param?: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (page, param, loading) => {
return get(`${prefix}/tool/${page.current_page}/${page.page_size}`, param, loading)
}
/**
*
* @param
*/
const postTool: (data: toolData, loading?: Ref<boolean>) => Promise<Result<any>> = (
data,
loading,
) => {
return post(`${prefix}/tool`, data, undefined, loading)
return get(`${prefix}/${page.current_page}/${page.page_size}`, param, loading)
}
/**
@ -55,7 +47,7 @@ const putTool: (tool_id: string, data: toolData, loading?: Ref<boolean>) => Prom
data,
loading,
) => {
return put(`${prefix}/tool/${tool_id}`, data, undefined, loading)
return put(`${prefix}/${tool_id}`, data, undefined, loading)
}
/**
@ -68,14 +60,14 @@ const getToolById: (tool_id: string, loading?: Ref<boolean>) => Promise<Result<a
tool_id,
loading,
) => {
return get(`${prefix}/tool/${tool_id}`, undefined, loading)
return get(`${prefix}/${tool_id}`, undefined, loading)
}
/**
*
* @param tool_id
*/
const delTool: (tool_id: String, loading?: Ref<boolean>) => Promise<Result<boolean>> = (
const delTool: (tool_id: string, loading?: Ref<boolean>) => Promise<Result<boolean>> = (
tool_id,
loading,
) => {
@ -91,7 +83,7 @@ const putToolIcon: (id: string, data: any, loading?: Ref<boolean>) => Promise<Re
}
const exportTool = (id: string, name: string, loading?: Ref<boolean>) => {
return exportFile(name + '.fx', `${prefix}/${id}/export`, undefined, loading)
return exportFile(name + '.tool', `${prefix}/${id}/export`, undefined, loading)
}
/**
@ -106,30 +98,19 @@ const postToolDebug: (data: any, loading?: Ref<boolean>) => Promise<Result<any>>
return post(`${prefix}/debug`, data, undefined, loading)
}
const postImportTool: (data: any, loading?: Ref<boolean>) => Promise<Result<any>> = (
data,
loading,
) => {
return post(`${prefix}/import`, data, undefined, loading)
}
const postPylint: (code: string, loading?: Ref<boolean>) => Promise<Result<any>> = (
code,
loading,
) => {
return post(`${prefix}/tool/pylint`, { code }, {}, loading)
return post(`${prefix}/pylint`, { code }, {}, loading)
}
export default {
getToolByFolder,
getToolListPage,
getToolList,
putTool,
getToolById,
postTool,
postToolDebug,
postImportTool,
postPylint,
exportTool,
putToolIcon,

39
ui/src/api/tool/store.ts Normal file
View File

@ -0,0 +1,39 @@
import { Result } from '@/request/Result'
import { get, post, del, put, exportFile } from '@/request/index'
import { type Ref } from 'vue'
import type { AddInternalToolParam } from '@/api/type/tool'
import useStore from '@/stores'
const prefix: any = { _value: '/workspace/' }
Object.defineProperty(prefix, 'value', {
get: function () {
const { user } = useStore()
return this._value + user.getWorkspaceId() + '/tool'
},
})
/**
* -
*/
const getInternalToolList: (param?: any, loading?: Ref<boolean>) => Promise<Result<any>> = (
param,
loading,
) => {
return get('/workspace/internal/tool', param, loading)
}
/**
* -
*/
const addInternalTool: (
tool_id: string,
param: AddInternalToolParam,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (tool_id, param, loading) => {
return post(`${prefix.value}/${tool_id}/add_internal_tool`, param, undefined, loading)
}
export default {
getInternalToolList,
addInternalTool,
}

View File

@ -2,7 +2,7 @@ import { Result } from '@/request/Result'
import { get, post, del, put, exportFile } from '@/request/index'
import { type Ref } from 'vue'
import type { pageRequest } from '@/api/type/common'
import type { toolData,AddInternalToolParam } from '@/api/type/tool'
import type { toolData } from '@/api/type/tool'
import useStore from '@/stores'
@ -128,26 +128,7 @@ const postPylint: (code: string, loading?: Ref<boolean>) => Promise<Result<any>>
return post(`${prefix.value}/pylint`, { code }, {}, loading)
}
/**
* -
*/
const getInternalToolList: (
param?: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (param, loading) => {
return get('/workspace/internal/tool', param, loading)
}
/**
* -
*/
const addInternalTool: (tool_id: string, param: AddInternalToolParam, loading?: Ref<boolean>) => Promise<Result<any>> = (
tool_id,
param,
loading,
) => {
return post(`${prefix.value}/${tool_id}/add_internal_tool`, param, undefined, loading)
}
export default {
getToolList,
getToolListPage,
@ -160,6 +141,4 @@ export default {
exportTool,
putToolIcon,
delTool,
getInternalToolList,
addInternalTool
}

View File

@ -1,10 +1,5 @@
import { ChatUserResourceEnum } from '@/enums/workspaceChatUser'
interface ChatUserResourceParams {
resource_id: string,
resource_type: ChatUserResourceEnum
}
import { SourceTypeEnum } from '@/enums/common'
interface ChatUserGroupItem {
id: string,
@ -30,4 +25,4 @@ interface putUserGroupUserParams {
chat_user_id: string,
is_auth: boolean
}
export type { ChatUserGroupItem, putUserGroupUserParams, ChatUserResourceParams, ChatUserGroupUserItem }
export type { ChatUserGroupItem, putUserGroupUserParams, ChatUserGroupUserItem }

View File

@ -422,8 +422,8 @@
<!-- 函数库 -->
<template
v-if="
item.type === WorkflowType.FunctionLib ||
item.type === WorkflowType.FunctionLibCustom
item.type === WorkflowType.ToolLib ||
item.type === WorkflowType.ToolLibCustom
"
>
<div class="card-never border-r-6 mt-8">
@ -716,7 +716,7 @@ import { cloneDeep } from 'lodash'
import ParagraphCard from './component/ParagraphCard.vue'
import { arraySort } from '@/utils/utils'
import { iconComponent } from '@/workflow/icons/utils'
import { WorkflowType } from '@/enums/workflow'
import { WorkflowType } from '@/enums/application'
import { getImgUrl } from '@/utils/utils'
import DynamicsForm from '@/components/dynamics-form/index.vue'

View File

@ -282,4 +282,29 @@ export default {
])
},
},
'app-resource-management': {
iconReader: () => {
return h('i', [
h(
'svg',
{
style: { height: '100%', width: '100%' },
viewBox: '0 0 20 20',
version: '1.1',
xmlns: 'http://www.w3.org/2000/svg',
},
[
h('path', {
d: 'M1.25 3.33335C1.25 2.41288 1.99619 1.66669 2.91667 1.66669H7.91667C8.16398 1.66669 8.39852 1.77654 8.55685 1.96653L10.3903 4.16669H17.0833C18.0038 4.16669 18.75 4.91287 18.75 5.83335V9.08335C18.75 9.3595 18.5261 9.58335 18.25 9.58335H17.5833C17.3072 9.58335 17.0833 9.3595 17.0833 9.08335V5.83335H10C9.75268 5.83335 9.51814 5.7235 9.35982 5.53351L7.52635 3.33335H2.91667V16.6667H8.66667C8.94281 16.6667 9.16667 16.8905 9.16667 17.1667C9.16667 17.3889 9.16667 17.6111 9.16667 17.8334C9.16667 18.1095 8.94281 18.3334 8.66667 18.3334H2.91667C1.9962 18.3334 1.25 17.5872 1.25 16.6667V3.33335Z',
fill: 'currentColor',
}),
h('path', {
d: 'M10.9148 16.7795C10.9584 16.829 11.0239 16.8533 11.0895 16.8461L12.2101 16.7242C12.4809 16.6948 12.7397 16.8442 12.8496 17.0935L13.3048 18.1263C13.3315 18.1868 13.3853 18.2314 13.4501 18.2444C13.742 18.3027 14.0439 18.3334 14.353 18.3334C14.662 18.3334 14.9639 18.3027 15.2558 18.2444C15.3207 18.2314 15.3745 18.1868 15.4012 18.1263L15.8564 17.0935C15.9663 16.8442 16.225 16.6948 16.4959 16.7242L17.6164 16.8461C17.6821 16.8533 17.7475 16.829 17.7912 16.7795C18.1889 16.3281 18.4992 15.7978 18.6956 15.2151C18.7167 15.1525 18.705 15.0838 18.666 15.0305L17.9991 14.1191C17.8382 13.8993 17.8382 13.6007 17.9991 13.3809L18.666 12.4696C18.705 12.4163 18.7167 12.3475 18.6956 12.2849C18.4992 11.7022 18.1889 11.1719 17.7912 10.7206C17.7475 10.671 17.6821 10.6468 17.6164 10.6539L16.4959 10.7758C16.225 10.8053 15.9663 10.6559 15.8564 10.4065L15.4012 9.37373C15.3745 9.31319 15.3207 9.26862 15.2558 9.25565C14.9639 9.1973 14.662 9.16669 14.353 9.16669C14.0439 9.16669 13.742 9.1973 13.4501 9.25565C13.3853 9.26862 13.3315 9.31319 13.3048 9.37373L12.8496 10.4065C12.7397 10.6559 12.4809 10.8053 12.2101 10.7758L11.0895 10.6539C11.0239 10.6468 10.9584 10.671 10.9148 10.7206C10.517 11.1719 10.2067 11.7022 10.0104 12.2849C9.98927 12.3475 10.001 12.4163 10.04 12.4696L10.7069 13.3809C10.8677 13.6007 10.8677 13.8993 10.7069 14.1191L10.04 15.0305C10.001 15.0838 9.98927 15.1525 10.0104 15.2151C10.2067 15.7978 10.517 16.3281 10.9148 16.7795ZM16.0196 13.75C16.0196 14.6705 15.2735 15.4167 14.353 15.4167C13.4325 15.4167 12.6863 14.6705 12.6863 13.75C12.6863 12.8295 13.4325 12.0834 14.353 12.0834C15.2735 12.0834 16.0196 12.8295 16.0196 13.75Z',
fill: 'currentColor',
}),
],
),
])
},
},
}

View File

@ -77,9 +77,9 @@
<script setup lang="ts">
import { reactive, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import documentApi from '@/api/resource-management/document'
import paragraphApi from '@/api/resource-management/paragraph'
import knowledgeApi from '@/api/resource-management/knowledge'
import documentApi from '@/api/system-resource-management/document'
import paragraphApi from '@/api/system-resource-management/paragraph'
import knowledgeApi from '@/api/system-resource-management/knowledge'
import useStoreShared from '@/stores/modules-resource-management'
import useStore from '@/stores'
import { groupBy } from 'lodash'

View File

@ -12,8 +12,8 @@ export enum WorkflowType {
Question = 'question-node',
Condition = 'condition-node',
Reply = 'reply-node',
FunctionLib = 'function-lib-node',
FunctionLibCustom = 'function-node',
ToolLib = 'tool-lib-node',
ToolLibCustom = 'tool-node',
RrerankerNode = 'reranker-node',
Application = 'application-node',
DocumentExtractNode = 'document-extract-node',

View File

@ -15,7 +15,7 @@ export enum ValidCount {
User = 2,
}
export enum FolderSource {
export enum SourceTypeEnum {
KNOWLEDGE = 'KNOWLEDGE',
APPLICATION = 'APPLICATION',
TOOL = 'TOOL',

3
ui/src/enums/tool.ts Normal file
View File

@ -0,0 +1,3 @@
export enum ToolType {
CUSTOM = 'common.custom',
}

View File

@ -1,21 +0,0 @@
export enum WorkflowType {
Base = 'base-node',
Start = 'start-node',
AiChat = 'ai-chat-node',
SearchKnowledge = 'search-knowledge-node',
Question = 'question-node',
Condition = 'condition-node',
Reply = 'reply-node',
FunctionLib = 'function-lib-node',
FunctionLibCustom = 'function-node',
RrerankerNode = 'reranker-node',
Application = 'application-node',
DocumentExtractNode = 'document-extract-node',
ImageUnderstandNode = 'image-understand-node',
VariableAssignNode = 'variable-assign-node',
FormNode = 'form-node',
TextToSpeechNode = 'text-to-speech-node',
SpeechToTextNode = 'speech-to-text-node',
ImageGenerateNode = 'image-generate-node',
McpNode = 'mcp-node',
}

View File

@ -1,4 +0,0 @@
export enum ChatUserResourceEnum {
KNOWLEDGE = 'KNOWLEDGE',
APPLICATION = 'APPLICATION',
}

View File

@ -80,7 +80,6 @@ export default {
customizeUpload: 'Custom Upload',
upload: 'Upload',
default: 'Default Logo',
custom: 'Custom',
sizeTip: 'Recommended size: 32×32 pixels. Supports JPG, PNG, and GIF formats. Max size: 10 MB',
fileSizeExceeded: 'File size exceeds 10 MB',
uploadImagePrompt: 'Please upload an image',
@ -96,4 +95,5 @@ export default {
message: 'Unable to Access APP',
operate: 'Back to Home',
},
custom: 'Custom',
}

View File

@ -4,7 +4,6 @@ export default {
platformDisplayTheme: 'Platform Display Theme',
customTheme: 'Custom Theme',
platformLoginSettings: 'Platform Login Settings',
custom: 'Custom',
pagePreview: 'Page Preview',
default: 'Default',
restoreDefaults: 'Restore Defaults',

View File

@ -88,7 +88,6 @@ export default {
past30Days: 'Last 30 Days',
past90Days: 'Last 90 Days',
past183Days: 'Last 6 Months',
other: 'Custom'
},
charts: {
customerTotal: 'Total Users',

View File

@ -32,7 +32,7 @@ export default {
notRecyclable: 'Loop connections are not allowed',
onlyLeft: 'Connections can only be made to the left anchor',
applicationNodeError: 'This application is unavailable',
functionNodeError: 'This function node is unavailable',
toolNodeError: 'This tool node is unavailable',
repeatedNodeError: 'A node with this name already exists',
cannotCopy: 'Cannot be copied',
copyError: 'Node already copied',
@ -161,7 +161,6 @@ export default {
content: 'Content',
replyContent: {
label: 'Reply Content',
custom: 'Custom',
reference: 'Reference Variable'
}
},
@ -260,8 +259,8 @@ export default {
label: 'Select Text Content'
}
},
functionNode: {
label: 'Custom Function',
toolNode: {
label: 'Custom Tool',
text: 'Execute custom scripts to achieve data processing'
},
applicationNode: {

View File

@ -22,6 +22,5 @@ export default {
priority: {
label: 'Resource permission priority',
role: 'Role',
customize: 'Customize',
},
}

View File

@ -55,7 +55,6 @@ export default {
},
source: {
label: 'Source',
custom: 'Custom',
reference: 'Reference Parameter',
},
required: {

View File

@ -84,7 +84,6 @@ export default {
customizeUpload: '自定义上传',
upload: '上传',
default: '默认Logo',
custom: '自定义',
sizeTip: '建议尺寸 32*32支持 JPG、PNG、GIF大小不超过 10 MB',
fileSizeExceeded: '文件大小超过 10 MB',
uploadImagePrompt: '请上传一张图片',
@ -100,4 +99,5 @@ export default {
message: '无法访问应用',
operate: '返回首页',
},
custom: '自定义',
}

View File

@ -4,7 +4,6 @@ export default {
platformDisplayTheme: '平台显示主题',
customTheme: '自定义主题',
platformLoginSettings: '平台登录设置',
custom: '自定义',
pagePreview: '页面预览',
default: '默认',
restoreDefaults: '恢复默认',

View File

@ -27,16 +27,6 @@ export default {
enabledSuccess: '已启用',
disabledSuccess: '已禁用'
},
EditAvatarDialog: {
title: '应用头像',
customizeUpload: '自定义上传',
upload: '上传',
default: '默认logo',
custom: '自定义',
sizeTip: '建议尺寸 32*32支持 JPG、PNG、GIF大小不超过 10 MB',
fileSizeExceeded: '文件大小超过 10 MB',
uploadImagePrompt: '请上传一张图片'
},
EmbedDialog: {
fullscreenModeTitle: '全屏模式',
copyInstructions: '复制以下代码进行嵌入',
@ -98,7 +88,6 @@ export default {
past30Days: '过去30天',
past90Days: '过去90天',
past183Days: '过去半年',
other: '自定义'
},
charts: {
customerTotal: '用户总数',

View File

@ -32,7 +32,7 @@ export default {
notRecyclable: '不可循环连线',
onlyLeft: '只允许连接左边的锚点',
applicationNodeError: '该应用不可用',
functionNodeError: '该函数不可用',
toolNodeError: '该函数不可用',
repeatedNodeError: '节点名称已存在!',
cannotCopy: '不能被复制',
copyError: '已复制节点',
@ -164,7 +164,6 @@ export default {
content: '内容',
replyContent: {
label: '回复内容',
custom: '自定义',
reference: '引用变量'
}
},
@ -272,7 +271,7 @@ export default {
label: '选择文本内容'
}
},
functionNode: {
toolNode: {
label: '自定义函数',
text: '通过执行自定义脚本,实现数据处理'
},

View File

@ -21,6 +21,5 @@ export default {
priority: {
label: '资源权限优先级',
role: '按角色',
customize: '自定义',
},
}

View File

@ -49,7 +49,6 @@ export default {
},
source: {
label: '来源',
custom: '自定义',
reference: '引用参数',
},
required: {

View File

@ -80,7 +80,6 @@ export default {
customizeUpload: '自訂上傳',
upload: '上傳',
default: '預設logo',
custom: '自訂',
sizeTip: '建議尺寸 32*32支援 JPG、PNG、GIF大小不超過 10 MB',
fileSizeExceeded: '檔案大小超過 10 MB',
uploadImagePrompt: '請上傳一張圖片',
@ -96,4 +95,5 @@ export default {
message: '無法訪問應用',
operate: '返回首頁',
},
custom: '自定義',
}

View File

@ -4,7 +4,6 @@ export default {
platformDisplayTheme: '平台顯示主題',
customTheme: '自定義主題',
platformLoginSettings: '平台登錄設置',
custom: '自定義',
pagePreview: '頁面預覽',
default: '默認',
restoreDefaults: '恢復默認',

View File

@ -32,7 +32,7 @@ export default {
notRecyclable: '不可循環連線',
onlyLeft: '只允許連接左邊的錨點',
applicationNodeError: '該應用不可用',
functionNodeError: '該函數不可用',
toolNodeError: '該函數不可用',
repeatedNodeError: '節點名稱已存在!',
cannotCopy: '不能被複製',
copyError: '已複製節點',
@ -162,7 +162,6 @@ export default {
content: '內容',
replyContent: {
label: '回覆內容',
custom: '自定義',
reference: '引用變量'
}
},
@ -259,7 +258,7 @@ export default {
label: '選擇文本內容'
}
},
functionNode: {
toolNode: {
label: '自定義函數',
text: '通過執行自定義腳本,實現數據處理'
},

View File

@ -52,7 +52,6 @@ export default {
},
source: {
label: '來源',
custom: '自定義',
reference: '引用參數',
},
required: {

View File

@ -1,4 +1,4 @@
import { ChatUserResourceEnum } from '@/enums/workspaceChatUser'
import { SourceTypeEnum } from '@/enums/common'
import { get_next_route } from '@/utils/permission'
import { PermissionConst, RoleConst } from '@/utils/permission/data'
@ -92,7 +92,7 @@ const ApplicationDetailRouter = {
active: 'chat-log',
parentPath: '/application/:id/:type',
parentName: 'ApplicationDetail',
resourceType: ChatUserResourceEnum.APPLICATION,
resourceType: SourceTypeEnum.APPLICATION,
permission: [
RoleConst.ADMIN,
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,

View File

@ -1,62 +0,0 @@
const DocumentRouter = {
path: '/knowledge/resource-management/:id/',
name: 'KnowledgeDetailResourceManagement',
meta: { title: 'common.fileUpload.document', activeMenu: '/knowledge', breadcrumb: true },
component: () => import('@/layout/layout-template/MainLayout.vue'),
hidden: true,
children: [
{
path: 'documentResource',
name: 'DocumentResourceManagement',
meta: {
icon: 'app-document',
iconActive: 'app-document-active',
title: 'common.fileUpload.document',
active: 'documentResource',
parentPath: '/knowledge/resource/:id/',
parentName: 'KnowledgeDetailResourceManagement',
},
component: () => import('@/views/resource-management/document/index.vue'),
},
{
path: 'problemResource',
name: 'ProblemResourceManagement',
meta: {
icon: 'app-problems',
iconActive: 'QuestionFilled',
title: 'views.problem.title',
active: 'problemResource',
parentPath: '/knowledge/resource/:id/',
parentName: 'KnowledgeDetailResourceManagement',
},
component: () => import('@/views/resource-management/problem/index.vue'),
},
{
path: 'hit-test-Resource',
name: 'KnowledgeHitTestResourceManagement',
meta: {
icon: 'app-hit-test',
title: 'views.application.hitTest.title',
active: 'hit-test-Resource',
parentPath: '/knowledge/resource/:id/',
parentName: 'KnowledgeDetailResourceManagement',
},
component: () => import('@/views/resource-management/hit-test/index.vue'),
},
{
path: 'settingResource',
name: 'settingResourceManagement',
meta: {
icon: 'app-setting',
iconActive: 'app-setting-active',
title: 'common.setting',
active: 'settingResource',
parentPath: '/knowledge/resource/:id/',
parentName: 'KnowledgeDetailResourceManagement',
},
component: () => import('@/views/resource-management/knowledge/KnowledgeSetting.vue'),
}
],
}
export default DocumentRouter

View File

@ -1,4 +1,4 @@
import { ChatUserResourceEnum } from '@/enums/workspaceChatUser'
import { SourceTypeEnum } from '@/enums/common'
import { get_next_route } from '@/utils/permission'
import { PermissionConst, RoleConst } from '@/utils/permission/data'
const DocumentRouter = {
@ -81,7 +81,7 @@ const DocumentRouter = {
active: 'chat-log',
parentPath: '/knowledge/:id/:folderId',
parentName: 'KnowledgeDetail',
resourceType: ChatUserResourceEnum.KNOWLEDGE,
resourceType: SourceTypeEnum.KNOWLEDGE,
group: 'KnowledgeDetail',
permission: [
RoleConst.ADMIN,

View File

@ -1,20 +0,0 @@
const ModelRouter = {
path: '/knowledge/resource-management',
name: 'knowledgeResourceManagement',
meta: { title: 'views.knowledge.title', permission: 'KNOWLEDGE:READ' },
hidden: true,
redirect: '/knowledge',
component: () => import('@/layout/layout-template/SimpleLayout.vue'),
children: [
{
path: '/knowledge/resource-management/document/upload',
name: 'UploadDocumentResourceManagement',
meta: { activeMenu: '/knowledge/resource' },
component: () => import('@/views/resource-management/document/UploadDocument.vue'),
hidden: true,
},
],
}
export default ModelRouter

View File

@ -1,17 +0,0 @@
const ParagraphRouter = {
path: '/paragraph/resource-management/:id/:documentId',
name: 'ParagraphResourceManagement',
meta: { title: 'common.fileUpload.document', activeMenu: '/knowledge', breadcrumb: true },
component: () => import('@/layout/layout-template/SimpleLayout.vue'),
hidden: true,
children: [
{
path: '/paragraph/resource-management/:id/:documentId',
name: 'ParagraphIndexResourceManagement',
meta: { activeMenu: '/knowledge' },
component: () => import('@/views/resource-management/paragraph/index.vue'),
},
],
}
export default ParagraphRouter

View File

@ -67,42 +67,31 @@ const systemRouter = {
},
component: () => import('@/views/system/workspace/index.vue'),
},
// {
// path: '/system/resource-management',
// name: 'resourceManagement',
// meta: {
// icon: 'app-shared',
// iconActive: 'app-shared-active',
// title: 'views.system.resource_management.label',
// activeMenu: '/system',
// parentPath: '/system',
// parentName: 'system',
// },
// children: [
// {
// path: '/system/resource-management/knowledge',
// name: 'knowledgeResourceManagement',
// meta: {
// title: 'views.knowledge.title',
// activeMenu: '/system',
// parentPath: '/system',
// parentName: 'system',
// },
// component: () => import('@/views/resource-management/knowledge/index.vue'),
// },
// {
// path: '/system/resource-management/tool',
// name: 'toolResourceManagement',
// meta: {
// title: 'views.tool.title',
// activeMenu: '/system',
// parentPath: '/system',
// parentName: 'system',
// },
// component: () => import('@/views/resource-management/tool/index.vue'),
// },
// ],
// },
{
path: '/system/resource-management',
name: 'resourceManagement',
meta: {
icon: 'app-resource-management',
iconActive: 'app-resource-management',
title: 'views.system.resource_management.label',
activeMenu: '/system',
parentPath: '/system',
parentName: 'system',
},
children: [
{
path: '/system/resource-management/tool',
name: 'ToolResourceIndex',
meta: {
title: 'views.tool.title',
activeMenu: '/system',
parentPath: '/system',
parentName: 'system',
},
component: () => import('@/views/system-resource-management/ToolResourceIndex.vue'),
},
],
},
{
path: '/system/authorization',
name: 'authorization',

View File

@ -1,52 +0,0 @@
import { defineStore } from 'pinia'
import { DeviceType, ValidType } from '@/enums/common'
// import type { Ref } from 'vue'
// import userApi from '@/api/user/user'
export interface commonTypes {
breadcrumb: any
paginationConfig: any | null
search: any
device: string
}
const useCommonStore = defineStore('comm',{
state: (): commonTypes => ({
breadcrumb: null,
// 搜索和分页缓存
paginationConfig: {},
search: {},
device: DeviceType.Desktop
}),
actions: {
saveBreadcrumb(data: any) {
this.breadcrumb = data
},
savePage(val: string, data: any) {
this.paginationConfig[val] = data
},
saveCondition(val: string, data: any) {
this.search[val] = data
},
toggleDevice(value: DeviceType) {
this.device = value
},
isMobile() {
return this.device === DeviceType.Mobile
},
// async asyncGetValid(valid_type: ValidType, valid_count: number, loading?: Ref<boolean>) {
// return new Promise((resolve, reject) => {
// userApi
// .getValid(valid_type, valid_count, loading)
// .then((data) => {
// resolve(data)
// })
// .catch((error) => {
// reject(error)
// })
// })
// }
}
})
export default useCommonStore

View File

@ -1,35 +0,0 @@
import { defineStore } from 'pinia'
import documentApi from '@/api/resource-management/document'
import { type Ref } from 'vue'
const useDocumentStore = defineStore('docume', {
state: () => ({}),
actions: {
async asyncGetAllDocument(id: string, loading?: Ref<boolean>) {
return new Promise((resolve, reject) => {
documentApi
.getAllDocument(id, loading)
.then((res) => {
resolve(res)
})
.catch((error) => {
reject(error)
})
})
},
async asyncPutDocument(knowledgeId: string, data: any, loading?: Ref<boolean>) {
return new Promise((resolve, reject) => {
documentApi
.putMulDocument(knowledgeId, data, loading)
.then((data) => {
resolve(data)
})
.catch((error) => {
reject(error)
})
})
},
},
})
export default useDocumentStore

View File

@ -1,23 +0,0 @@
import {defineStore} from 'pinia'
import {type Ref} from 'vue'
import folderApi from '@/api/folder'
const useFolderStore = defineStore('fold', {
state: () => ({}),
actions: {
async asyncGetFolder(source: string, data: any, loading?: Ref<boolean>) {
return new Promise((resolve, reject) => {
folderApi
.getFolder(source, data, loading)
.then((res) => {
resolve(res)
})
.catch((error) => {
reject(error)
})
})
},
},
})
export default useFolderStore

View File

@ -1,23 +0,0 @@
import useCommonStore from './common'
import useLoginStore from './login'
import useFolderStore from './folder'
import useKnowledgeStore from './knowledge'
import useModelStore from './model'
import usePromptStore from './prompt'
import useProblemStore from './problem'
import useParagraphStore from './paragraph'
import useDocumentStore from './document'
const useStore = () => ({
common: useCommonStore(),
login: useLoginStore(),
folder: useFolderStore(),
knowledge: useKnowledgeStore(),
model: useModelStore(),
prompt: usePromptStore(),
problem: useProblemStore(),
paragraph: useParagraphStore(),
document: useDocumentStore(),
})
export default useStore

View File

@ -1,76 +0,0 @@
import { defineStore } from 'pinia'
import type { knowledgeData } from '@/api/type/knowledge'
import type { UploadUserFile } from 'element-plus'
import knowledgeApi from '@/api/resource-management/knowledge'
import { type Ref } from 'vue'
export interface knowledgeStateTypes {
baseInfo: knowledgeData | null
webInfo: any
documentsType: string
documentsFiles: UploadUserFile[]
}
const useKnowledgeStore = defineStore('knowled', {
state: (): knowledgeStateTypes => ({
baseInfo: null,
webInfo: null,
documentsType: '',
documentsFiles: [],
}),
actions: {
saveBaseInfo(info: knowledgeData | null) {
this.baseInfo = info
},
saveWebInfo(info: any) {
this.webInfo = info
},
saveDocumentsType(val: string) {
this.documentsType = val
},
saveDocumentsFile(file: UploadUserFile[]) {
this.documentsFiles = file
},
async asyncGetFolderKnowledge(loading?: Ref<boolean>) {
return new Promise((resolve, reject) => {
const params = {
folder_id: localStorage.getItem('workspace_id'),
}
knowledgeApi
.getKnowledgeList(params, loading)
.then((data) => {
resolve(data)
})
.catch((error) => {
reject(error)
})
})
},
async asyncGetKnowledgeDetail(knowledge_id: string, loading?: Ref<boolean>) {
return new Promise((resolve, reject) => {
knowledgeApi
.getKnowledgeDetail(knowledge_id, loading)
.then((data) => {
resolve(data)
})
.catch((error) => {
reject(error)
})
})
},
async asyncSyncKnowledge(id: string, sync_type: string, loading?: Ref<boolean>) {
return new Promise((resolve, reject) => {
knowledgeApi
.putSyncWebKnowledge(id, sync_type, loading)
.then((data) => {
resolve(data)
})
.catch((error) => {
reject(error)
})
})
},
},
})
export default useKnowledgeStore

View File

@ -1,51 +0,0 @@
import {defineStore} from 'pinia'
import {type Ref} from 'vue'
import loginApi from '@/api/user/login'
import type {LoginRequest} from '@/api/type/login'
import useUserStore from '@/stores/modules/user'
const useLoginStore = defineStore('log', {
state: () => ({
token: '',
userAccessToken: '',
}),
actions: {
getToken(): string | null {
if (this.token) {
return this.token
}
const user = useUserStore()
return user.userType === 1 ? localStorage.getItem('token') : this.getAccessToken()
},
getAccessToken() {
const token = sessionStorage.getItem(`${this.userAccessToken}-accessToken`)
if (token) {
return token
}
const local_token = localStorage.getItem(`${token}-accessToken`)
if (local_token) {
return local_token
}
return localStorage.getItem(`accessToken`)
},
async asyncLogin(data: LoginRequest, loading?: Ref<boolean>) {
return loginApi.login(data).then((ok) => {
this.token = ok?.data?.token
localStorage.setItem('token', ok?.data?.token)
const user = useUserStore()
return user.profile(loading)
})
},
async asyncLdapLogin(data: LoginRequest, loading?: Ref<boolean>) {
return loginApi.ldapLogin(data).then((ok) => {
this.token = ok?.data?.token
localStorage.setItem('token', ok?.data?.token)
const user = useUserStore()
return user.profile(loading)
})
},
},
})
export default useLoginStore

View File

@ -1,35 +0,0 @@
import {defineStore} from 'pinia'
import {type Ref} from 'vue'
import ModelApi from '@/api/resource-management/model'
import ProviderApi from '@/api/resource-management/provider'
import type {ListModelRequest} from '@/api/type/model'
const useModelStore = defineStore('mod', {
state: () => ({}),
actions: {
async asyncGetSelectModel(data?: ListModelRequest, loading?: Ref<boolean>) {
return new Promise((resolve, reject) => {
ModelApi.getModelList(data, loading)
.then((res) => {
resolve(res)
})
.catch((error) => {
reject(error)
})
})
},
async asyncGetProvider(loading?: Ref<boolean>) {
return new Promise((resolve, reject) => {
ProviderApi.getProvider(loading)
.then((res) => {
resolve(res)
})
.catch((error) => {
reject(error)
})
})
},
},
})
export default useModelStore

View File

@ -1,91 +0,0 @@
import { defineStore } from 'pinia'
import paragraphApi from '@/api/resource-management/paragraph'
import type { Ref } from 'vue'
const useParagraphStore = defineStore('paragra', {
state: () => ({}),
actions: {
async asyncPutParagraph(
knowledgeId: string,
documentId: string,
paragraphId: string,
data: any,
loading?: Ref<boolean>,
) {
return new Promise((resolve, reject) => {
paragraphApi
.putParagraph(knowledgeId, documentId, paragraphId, data, loading)
.then((data) => {
resolve(data)
})
.catch((error) => {
reject(error)
})
})
},
async asyncDelParagraph(
knowledgeId: string,
documentId: string,
paragraphId: string,
loading?: Ref<boolean>,
) {
return new Promise((resolve, reject) => {
paragraphApi
.delParagraph(knowledgeId, documentId, paragraphId, loading)
.then((data) => {
resolve(data)
})
.catch((error) => {
reject(error)
})
})
},
async asyncDisassociationProblem(
knowledgeId: string,
documentId: string,
paragraphId: string,
problemId: string,
loading?: Ref<boolean>,
) {
return new Promise((resolve, reject) => {
const obj = {
paragraphId,
problemId,
}
paragraphApi
.putDisassociationProblem(knowledgeId, documentId, obj, loading)
.then((data) => {
resolve(data)
})
.catch((error) => {
reject(error)
})
})
},
async asyncAssociationProblem(
knowledgeId: string,
documentId: string,
paragraphId: string,
problemId: string,
loading?: Ref<boolean>,
) {
return new Promise((resolve, reject) => {
const obj = {
paragraphId,
problemId,
}
paragraphApi
.putAssociationProblem(knowledgeId, documentId, obj, loading)
.then((data) => {
resolve(data)
})
.catch((error) => {
reject(error)
})
})
},
},
})
export default useParagraphStore

View File

@ -1,41 +0,0 @@
import { defineStore } from 'pinia'
import { type Ref } from 'vue'
import problemApi from '@/api/resource-management/problem'
import type { pageRequest } from '@/api/type/common'
const useProblemStore = defineStore('probl', {
state: () => ({}),
actions: {
async asyncPostProblem(knowledgeId: string, data: any, loading?: Ref<boolean>) {
return new Promise((resolve, reject) => {
problemApi
.postProblems(knowledgeId, data, loading)
.then((data) => {
resolve(data)
})
.catch((error) => {
reject(error)
})
})
},
async asyncGetProblem(
knowledgeId: string,
page: pageRequest,
param: any,
loading?: Ref<boolean>,
) {
return new Promise((resolve, reject) => {
problemApi
.getProblems(knowledgeId, page, param, loading)
.then((data) => {
resolve(data)
})
.catch((error) => {
reject(error)
})
})
},
},
})
export default useProblemStore

View File

@ -1,37 +0,0 @@
import { defineStore } from 'pinia'
import { t } from '@/locales'
export interface promptTypes {
user: string
formValue: { model_id: string; prompt: string }
}
const usePromptStore = defineStore('prom', {
state: (): promptTypes[] => JSON.parse(localStorage.getItem('PROMPT_CACHE') || '[]'),
actions: {
save(user: string, formValue: any) {
this.$state.forEach((item: any, index: number) => {
if (item.user === user) {
this.$state.splice(index, 1)
}
})
this.$state.push({ user, formValue })
localStorage.setItem('PROMPT_CACHE', JSON.stringify(this.$state))
},
get(user: string) {
for (let i = 0; i < this.$state.length; i++) {
if (this.$state[i].user === user) {
return this.$state[i].formValue
}
}
return {
model_id: '',
prompt:
t('views.document.generateQuestion.prompt1', { data: '{data}' }) +
'<question></question>' +
t('views.document.generateQuestion.prompt2'),
}
},
},
})
export default usePromptStore

View File

@ -1,6 +1,6 @@
<template>
<el-dialog
:title="$t('views.applicationOverview.appInfo.EditAvatarDialog.title')"
:title="$t('common.EditAvatarDialog.title')"
v-model="dialogVisible"
:close-on-click-modal="false"
:close-on-press-escape="false"
@ -8,7 +8,7 @@
>
<el-radio-group v-model="radioType" class="radio-block mb-16">
<el-radio value="default">
<p>{{ $t('views.applicationOverview.appInfo.EditAvatarDialog.default') }}</p>
<p>{{ $t('common.EditAvatarDialog.default') }}</p>
<el-avatar
v-if="detail?.name"
:name="detail?.name"
@ -19,7 +19,7 @@
/>
</el-radio>
<el-radio value="custom">
<p>{{ $t('views.applicationOverview.appInfo.EditAvatarDialog.customizeUpload') }}</p>
<p>{{ $t('common.EditAvatarDialog.customizeUpload') }}</p>
<div class="flex mt-8">
<el-avatar
v-if="fileURL"
@ -39,12 +39,12 @@
:on-change="onChange"
>
<el-button icon="Upload" :disabled="radioType !== 'custom'">{{
$t('views.applicationOverview.appInfo.EditAvatarDialog.upload')
$t('common.EditAvatarDialog.upload')
}}</el-button>
</el-upload>
</div>
<div class="el-upload__tip info mt-8">
{{ $t('views.applicationOverview.appInfo.EditAvatarDialog.sizeTip') }}
{{ $t('common.EditAvatarDialog.sizeTip') }}
</div>
</el-radio>
</el-radio-group>
@ -104,7 +104,7 @@ const onChange = (file: any) => {
const isLimit = file?.size / 1024 / 1024 < 10
if (!isLimit) {
// @ts-ignore
MsgError(t('views.applicationOverview.appInfo.EditAvatarDialog.fileSizeExceeded'))
MsgError(t('common.EditAvatarDialog.fileSizeExceeded'))
return false
} else {
iconFile.value = file
@ -128,7 +128,7 @@ function submit() {
dialogVisible.value = false
})
} else {
MsgError(t('views.applicationOverview.appInfo.EditAvatarDialog.uploadImagePrompt'))
MsgError(t('common.EditAvatarDialog.uploadImagePrompt'))
}
}

View File

@ -288,7 +288,7 @@ const dayOptions = [
},
{
value: 'other',
label: t('views.applicationOverview.monitor.pastDayOptions.other'),
label: t('common.other'),
},
]

View File

@ -524,7 +524,7 @@ const onChange = (file: any, fileList: UploadFiles, attr: string) => {
const isLimit = file?.size / 1024 / 1024 < 10
if (!isLimit) {
// @ts-ignore
MsgError(t('views.applicationOverview.appInfo.EditAvatarDialog.fileSizeExceeded'))
MsgError(t('common.EditAvatarDialog.fileSizeExceeded'))
return false
} else {
xpackForm.value[attr] = file.raw

View File

@ -35,28 +35,28 @@
</div>
</el-scrollbar>
</el-tab-pane>
<el-tab-pane :label="$t('views.tool.title')" name="function">
<el-tab-pane :label="$t('views.tool.title')" name="tool">
<el-scrollbar height="400">
<div
class="workflow-dropdown-item cursor flex p-8-12"
@click.stop="clickNodes(functionNode)"
@mousedown.stop="onmousedown(functionNode)"
@click.stop="clickNodes(toolNode)"
@mousedown.stop="onmousedown(toolNode)"
>
<component :is="iconComponent(`function-lib-node-icon`)" class="mr-8 mt-4" :size="32" />
<component :is="iconComponent(`tool-lib-node-icon`)" class="mr-8 mt-4" :size="32" />
<div class="pre-wrap">
<div class="lighter">{{ functionNode.label }}</div>
<el-text type="info" size="small">{{ functionNode.text }}</el-text>
<div class="lighter">{{ toolNode.label }}</div>
<el-text type="info" size="small">{{ toolNode.text }}</el-text>
</div>
</div>
<template v-for="(item, index) in filter_function_lib_list" :key="index">
<template v-for="(item, index) in filter_tool_lib_list" :key="index">
<div
class="workflow-dropdown-item cursor flex p-8-12 align-center"
@click.stop="clickNodes(toolNode, item, 'function')"
@mousedown.stop="onmousedown(toolNode, item, 'function')"
@click.stop="clickNodes(toolNode, item, 'tool')"
@mousedown.stop="onmousedown(toolNode, item, 'tool')"
>
<component
:is="iconComponent(`function-lib-node-icon`)"
:is="iconComponent(`tool-lib-node-icon`)"
class="mr-8"
:size="32"
:item="item"
@ -130,7 +130,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue'
import { menuNodes, toolNode, functionNode, applicationNode } from '@/workflow/common/data'
import { menuNodes, toolNode, toolNode, applicationNode } from '@/workflow/common/data'
import { iconComponent } from '@/workflow/icons/utils'
import applicationApi from '@/api/application/application'
import { isWorkFlow } from '@/utils/application'
@ -154,7 +154,7 @@ const loading = ref(false)
const activeName = ref('base')
const toolList = ref<any[]>([])
const filter_function_lib_list = computed(() => {
const filter_tool_lib_list = computed(() => {
return toolList.value.filter((item: any) =>
item.name.toLocaleLowerCase().includes(search_text.value.toLocaleLowerCase())
)
@ -171,13 +171,13 @@ const filter_menu_nodes = computed(() => {
item.label.toLocaleLowerCase().includes(search_text.value.toLocaleLowerCase())
)
})
function clickNodes(item: any, data?: any, type?: string) {
tool clickNodes(item: any, data?: any, type?: string) {
if (data) {
item['properties']['stepName'] = data.name
if (type == 'function') {
if (type == 'tool') {
item['properties']['node_data'] = {
...data,
function_lib_id: data.id,
tool_lib_id: data.id,
input_field_list: data.input_field_list.map((field: any) => ({
...field,
value: field.source == 'reference' ? [] : ''
@ -216,13 +216,13 @@ function clickNodes(item: any, data?: any, type?: string) {
emit('clickNodes', item)
}
function onmousedown(item: any, data?: any, type?: string) {
tool onmousedown(item: any, data?: any, type?: string) {
if (data) {
item['properties']['stepName'] = data.name
if (type == 'function') {
if (type == 'tool') {
item['properties']['node_data'] = {
...data,
function_lib_id: data.id,
tool_lib_id: data.id,
input_field_list: data.input_field_list.map((field: any) => ({
...field,
value: field.source == 'reference' ? [] : ''
@ -260,7 +260,7 @@ function onmousedown(item: any, data?: any, type?: string) {
emit('onmousedown', item)
}
function getList() {
tool getList() {
// applicationApi.listTool(props.id, loading).then((res: any) => {
// toolList.value = res.data
// })

View File

@ -3,7 +3,7 @@
<template #left>
<h4 class="p-12-16 pb-0 mt-12">{{ $t('views.application.title') }}</h4>
<folder-tree
:source="FolderSource.APPLICATION"
:source="SourceTypeEnum.APPLICATION"
:data="folderList"
:currentNodeKey="currentFolder?.id"
@handleNodeClick="folderClickHandel"
@ -285,7 +285,7 @@ import { t } from '@/locales'
import { useRouter, useRoute } from 'vue-router'
import { isWorkFlow } from '@/utils/application'
import { dateFormat } from '@/utils/time'
import { FolderSource } from '@/enums/common'
import { SourceTypeEnum } from '@/enums/common'
import permissionMap from '@/permission'
const router = useRouter()
@ -484,12 +484,12 @@ const importApplication = (file: any) => {
//
const CreateFolderDialogRef = ref()
function openCreateFolder() {
CreateFolderDialogRef.value.open(FolderSource.APPLICATION, currentFolder.value.id)
CreateFolderDialogRef.value.open(SourceTypeEnum.APPLICATION, currentFolder.value.id)
}
function getFolder(bool?: boolean) {
const params = {}
folder.asyncGetFolder(FolderSource.APPLICATION, params, loading).then((res: any) => {
folder.asyncGetFolder(SourceTypeEnum.APPLICATION, params, loading).then((res: any) => {
folderList.value = res.data
if (bool) {
//

View File

@ -332,7 +332,7 @@ const dayOptions = [
},
{
value: 'other',
label: t('views.applicationOverview.monitor.pastDayOptions.other'),
label: t('common.other'),
},
]
const daterangeValue = ref('')

View File

@ -3,7 +3,7 @@
<template #header>
<div>
<h2>{{ $t('views.chatUser.title') }}</h2>
<div class="color-secondary">{{ resource.resource_type === ChatUserResourceEnum.APPLICATION ?
<div class="color-secondary">{{ resource.resource_type === SourceTypeEnum.APPLICATION ?
$t('views.chatUser.applicationTitleTip') : $t('views.chatUser.knowledgeTitleTip') }}</div>
</div>
</template>
@ -109,9 +109,9 @@
import { onMounted, ref, watch, reactive, computed } from 'vue'
import ChatUserApi from '@/api/chat-user/chat-user'
import { t } from '@/locales'
import type { ChatUserGroupItem, ChatUserResourceParams, ChatUserGroupUserItem } from '@/api/type/workspaceChatUser'
import type { ChatUserGroupItem, ChatUserGroupUserItem } from '@/api/type/workspaceChatUser'
import { useRoute } from 'vue-router'
import { ChatUserResourceEnum } from '@/enums/workspaceChatUser'
import { SourceTypeEnum } from '@/enums/common'
import { MsgSuccess } from '@/utils/message'
import permissionMap from '@/permission'
@ -128,7 +128,7 @@ const {
params: { id },
} = route as any
const resource: ChatUserResourceParams = reactive({ resource_id: route.params.id as string, resource_type: route.meta.resourceType as ChatUserResourceEnum })
const resource = reactive({ resource_id: route.params.id as string, resource_type: route.meta.resourceType as string })
const filterText = ref('')
const loading = ref(false)

View File

@ -320,7 +320,7 @@ import useStore from '@/stores'
import { numberFormat } from '@/utils/common'
import { t } from '@/locales'
import { useRouter, useRoute } from 'vue-router'
import { FolderSource } from '@/enums/common'
import { SourceTypeEnum } from '@/enums/common'
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
import permissionMap from '@/permission'
@ -463,7 +463,7 @@ function openAuthorizedWorkspaceDialog(row: any) {
//
const CreateFolderDialogRef = ref()
function openCreateFolder() {
CreateFolderDialogRef.value.open(FolderSource.KNOWLEDGE, folder.currentFolder.id)
CreateFolderDialogRef.value.open(SourceTypeEnum.KNOWLEDGE, folder.currentFolder.id)
}
watch(
() => folder.currentFolder,

View File

@ -3,7 +3,7 @@
<template #left>
<h4 class="p-12-16 pb-0 mt-12">{{ $t('views.knowledge.title') }}</h4>
<folder-tree
:source="FolderSource.KNOWLEDGE"
:source="SourceTypeEnum.KNOWLEDGE"
:data="folderList"
:currentNodeKey="currentFolder?.id"
@handleNodeClick="folderClickHandel"
@ -24,7 +24,7 @@
<script lang="ts" setup>
import { onMounted, ref, reactive, shallowRef, nextTick, computed } from 'vue'
import KnowledgeListContainer from '@/views/knowledge/component/KnowledgeListContainer.vue'
import { FolderSource } from '@/enums/common'
import { SourceTypeEnum } from '@/enums/common'
import permissionMap from '@/permission'
import { useRoute } from 'vue-router'
import useStore from '@/stores'
@ -49,7 +49,7 @@ const currentFolder = ref<any>({})
function getFolder(bool?: boolean) {
const params = {}
folder.asyncGetFolder(FolderSource.KNOWLEDGE, params, loading).then((res: any) => {
folder.asyncGetFolder(SourceTypeEnum.KNOWLEDGE, params, loading).then((res: any) => {
folderList.value = res.data
if (bool) {
//

View File

@ -1,215 +0,0 @@
<template>
<div class="upload-document p-12-24">
<div class="flex align-center mb-16">
<back-button to="-1" style="margin-left: -4px"></back-button>
<h3 style="display: inline-block">{{ $t('views.document.uploadDocument') }}</h3>
</div>
<el-card style="--el-card-padding: 0">
<div class="upload-document__main flex" v-loading="loading">
<div class="upload-document__component main-calc-height">
<el-scrollbar>
<template v-if="active === 0">
<div class="upload-component p-24">
<!-- 上传文档 -->
<UploadComponent ref="UploadComponentRef" />
</div>
</template>
<template v-else-if="active === 1">
<SetRules ref="SetRulesRef" />
</template>
<template v-else-if="active === 2">
<ResultSuccess :data="successInfo" />
</template>
</el-scrollbar>
</div>
</div>
</el-card>
<div class="upload-document__footer text-right border-t" v-if="active !== 2">
<el-button @click="router.go(-1)" :disabled="SetRulesRef?.loading || loading">{{
$t('common.cancel')
}}</el-button>
<el-button @click="prev" v-if="active === 1" :disabled="SetRulesRef?.loading || loading">{{
$t('views.document.buttons.prev')
}}</el-button>
<el-button
@click="next"
type="primary"
v-if="active === 0"
:disabled="SetRulesRef?.loading || loading"
>
{{
documentsType === 'txt'
? $t('views.document.buttons.next')
: $t('views.document.buttons.import')
}}
</el-button>
<el-button
@click="submit"
type="primary"
v-if="active === 1"
:disabled="SetRulesRef?.loading || loading"
>
{{ $t('views.document.buttons.import') }}
</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onUnmounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import SetRules from './upload/SetRules.vue'
import ResultSuccess from './upload/ResultSuccess.vue'
import UploadComponent from './upload/UploadComponent.vue'
import documentApi from '@/api/resource-management/document'
import { MsgConfirm, MsgSuccess } from '@/utils/message'
import { t } from '@/locales'
import useStore from '@/stores/modules-resource-management'
const { knowledge, document } = useStore()
const documentsFiles = computed(() => knowledge.documentsFiles)
const documentsType = computed(() => knowledge.documentsType)
const router = useRouter()
const route = useRoute()
const {
query: { id }, // idknowledgeIDid
} = route
const SetRulesRef = ref()
const UploadComponentRef = ref()
const loading = ref(false)
const disabled = ref(false)
const active = ref(0)
const successInfo = ref<any>(null)
async function next() {
disabled.value = true
if (await UploadComponentRef.value.validate()) {
if (documentsType.value === 'QA') {
const fd = new FormData()
documentsFiles.value.forEach((item: any) => {
if (item?.raw) {
fd.append('file', item?.raw)
}
})
if (id) {
// QA
documentApi.postQADocument(id as string, fd, loading).then((res) => {
MsgSuccess(t('common.submitSuccess'))
clearStore()
router.push({ path: `/knowledge/${id}/document` })
})
}
} else if (documentsType.value === 'table') {
const fd = new FormData()
documentsFiles.value.forEach((item: any) => {
if (item?.raw) {
fd.append('file', item?.raw)
}
})
if (id) {
// table
documentApi.postTableDocument(id as string, fd, loading).then((res) => {
MsgSuccess(t('common.submitSuccess'))
clearStore()
router.push({ path: `/knowledge/${id}/document` })
})
}
} else {
if (active.value++ > 2) active.value = 0
}
} else {
disabled.value = false
}
}
const prev = () => {
active.value = 0
}
function clearStore() {
knowledge.saveDocumentsFile([])
knowledge.saveDocumentsType('')
}
function submit() {
loading.value = true
const documents = [] as any
SetRulesRef.value?.paragraphList.map((item: any) => {
if (!SetRulesRef.value?.checkedConnect) {
item.content.map((v: any) => {
delete v['problem_list']
})
}
documents.push({
name: item.name,
paragraphs: item.content,
})
})
if (id) {
//
document
.asyncPutDocument(id as string, documents)
.then(() => {
MsgSuccess(t('common.submitSuccess'))
clearStore()
router.push({ path: `/knowledge/system/${id}/documentResource` })
})
.catch(() => {
loading.value = false
})
}
}
function back() {
if (documentsFiles.value?.length > 0) {
MsgConfirm(t('common.tip'), t('views.document.tip.saveMessage'), {
confirmButtonText: t('common.confirm'),
type: 'warning',
})
.then(() => {
router.go(-1)
clearStore()
})
.catch(() => {})
} else {
router.go(-1)
}
}
onUnmounted(() => {
clearStore()
})
</script>
<style lang="scss" scoped>
.upload-document {
&__steps {
min-width: 450px;
max-width: 800px;
width: 80%;
margin: 0 auto;
padding-right: 60px;
:deep(.el-step__line) {
left: 64% !important;
right: -33% !important;
}
}
&__component {
width: 100%;
margin: 0 auto;
overflow: hidden;
}
&__footer {
padding: 16px 24px;
position: fixed;
bottom: 0;
left: 0;
background: #ffffff;
width: 100%;
box-sizing: border-box;
}
.upload-component {
width: 70%;
margin: 0 auto;
margin-bottom: 20px;
}
}
</style>

View File

@ -1,48 +0,0 @@
<template>
<el-dialog
v-model="dialogVisible"
:title="$t('components.selectParagraph.title')"
:before-close="close"
width="450"
>
<el-radio-group v-model="state" class="radio-block">
<el-radio value="error" size="large">{{
$t('components.selectParagraph.error')
}}</el-radio>
<el-radio value="all" size="large">{{ $t('components.selectParagraph.all') }}</el-radio>
</el-radio-group>
<template #footer>
<div class="dialog-footer">
<el-button @click="close">{{ $t('common.cancel') }} </el-button>
<el-button type="primary" @click="submit"> {{ $t('common.submit') }} </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const dialogVisible = ref<boolean>(false)
const state = ref<'all' | 'error'>('error')
const stateMap = {
all: ['0', '1', '2', '3', '4', '5', 'n'],
error: ['0', '1', '3', '4', '5', 'n']
}
const submit_handle = ref<(stateList: Array<string>) => void>()
const submit = () => {
if (submit_handle.value) {
submit_handle.value(stateMap[state.value])
}
close()
}
const open = (handle: (stateList: Array<string>) => void) => {
submit_handle.value = handle
dialogVisible.value = true
}
const close = () => {
submit_handle.value = undefined
dialogVisible.value = false
}
defineExpose({ open, close })
</script>
<style lang="scss" scoped></style>

View File

@ -1,233 +0,0 @@
<template>
<el-dialog
:title="title"
v-model="dialogVisible"
:close-on-click-modal="false"
:close-on-press-escape="false"
:destroy-on-close="true"
width="550"
>
<el-form
label-position="top"
ref="webFormRef"
:rules="rules"
:model="form"
require-asterisk-position="right"
>
<el-form-item
:label="$t('views.document.form.source_url.label')"
prop="source_url"
v-if="isImport"
>
<el-input
v-model="form.source_url"
:placeholder="$t('views.document.form.source_url.placeholder')"
:rows="10"
type="textarea"
/>
</el-form-item>
<el-form-item
v-else-if="!isImport && documentType === '1'"
:label="$t('views.document.form.source_url.label')"
prop="source_url"
>
<el-input
v-model="form.source_url"
:placeholder="$t('views.document.form.source_url.requiredMessage')"
/>
</el-form-item>
<el-form-item :label="$t('views.document.form.selector.label')" v-if="documentType === '1'">
<el-input
v-model="form.selector"
:placeholder="$t('views.document.form.selector.placeholder')"
/>
</el-form-item>
<el-form-item v-if="!isImport">
<template #label>
<div class="flex align-center">
<span class="mr-4">{{ $t('views.document.form.hit_handling_method.label') }}</span>
<el-tooltip
effect="dark"
:content="$t('views.document.form.hit_handling_method.tooltip')"
placement="right"
>
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
</el-tooltip>
</div>
</template>
<el-radio-group v-model="form.hit_handling_method" class="radio-block mt-4">
<template v-for="(value, key) of hitHandlingMethod" :key="key">
<el-radio :value="key">{{ $t(value) }} </el-radio>
</template>
</el-radio-group>
</el-form-item>
<el-form-item
prop="directly_return_similarity"
v-if="!isImport && form.hit_handling_method === 'directly_return'"
>
<div class="lighter w-full" style="margin-top: -20px">
<span>{{ $t('views.document.form.similarity.label') }}</span>
<el-input-number
v-model="form.directly_return_similarity"
:min="0"
:max="1"
:precision="3"
:step="0.1"
:value-on-clear="0"
controls-position="right"
size="small"
class="ml-4 mr-4"
/><span>{{ $t('views.document.form.similarity.placeholder') }}</span>
</div>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
<el-button type="primary" @click="submit(webFormRef)" :loading="loading">
{{ $t('common.confirm') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
import { useRoute } from 'vue-router'
import type { FormInstance } from 'element-plus'
import documentApi from '@/api/resource-management/document'
import { MsgSuccess } from '@/utils/message'
import { hitHandlingMethod } from '@/enums/document'
import { t } from '@/locales'
const route = useRoute()
const {
params: { id }
} = route as any
const props = defineProps({
title: String
})
const emit = defineEmits(['refresh'])
const webFormRef = ref()
const loading = ref<boolean>(false)
const isImport = ref<boolean>(false)
const form = ref<any>({
source_url: '',
selector: '',
hit_handling_method: 'optimization',
directly_return_similarity: 0.9
})
//
const documentId = ref('')
const documentType = ref<string | number>('') //1: web0:
//
const documentList = ref<Array<string>>([])
const rules = reactive({
source_url: [
{
required: true,
message: t('views.document.form.source_url.requiredMessage'),
trigger: 'blur'
}
],
directly_return_similarity: [
{
required: true,
message: t('views.document.form.similarity.requiredMessage'),
trigger: 'blur'
}
]
})
const dialogVisible = ref<boolean>(false)
watch(dialogVisible, (bool) => {
if (!bool) {
form.value = {
source_url: '',
selector: '',
hit_handling_method: 'optimization',
directly_return_similarity: 0.9
}
isImport.value = false
documentType.value = ''
documentId.value = ''
documentList.value = []
}
})
const open = (row: any, list: Array<string>) => {
if (row) {
documentType.value = row.type
documentId.value = row.id
form.value = {
hit_handling_method: row.hit_handling_method,
directly_return_similarity: row.directly_return_similarity,
...row.meta
}
isImport.value = false
} else if (list) {
//
documentList.value = list
} else {
// web
documentType.value = '1'
isImport.value = true
}
dialogVisible.value = true
}
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid) => {
if (valid) {
if (isImport.value) {
const obj = {
source_url_list: form.value.source_url.split('\n'),
selector: form.value.selector
}
documentApi.postWebDocument(id, obj, loading).then(() => {
MsgSuccess(t('views.document.tip.importMessage'))
emit('refresh')
dialogVisible.value = false
})
} else {
if (documentId.value) {
const obj = {
hit_handling_method: form.value.hit_handling_method,
directly_return_similarity: form.value.directly_return_similarity,
meta: {
source_url: form.value.source_url,
selector: form.value.selector
}
}
documentApi.putDocument(id, documentId.value, obj, loading).then(() => {
MsgSuccess(t('common.settingSuccess'))
emit('refresh')
dialogVisible.value = false
})
} else if (documentList.value.length > 0) {
//
const obj = {
hit_handling_method: form.value.hit_handling_method,
directly_return_similarity: form.value.directly_return_similarity,
id_list: documentList.value
}
documentApi.putBatchEditHitHandling(id, obj, loading).then(() => {
MsgSuccess(t('common.settingSuccess'))
emit('refresh')
dialogVisible.value = false
})
}
}
}
})
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@ -1,119 +0,0 @@
<template>
<el-dialog
:title="$t('views.chatLog.selectKnowledge')"
v-model="dialogVisible"
width="600"
class="select-knowledge-dialog"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<template #header="{ titleId, titleClass }">
<div class="my-header flex">
<h4 :id="titleId" :class="titleClass">{{ $t('views.chatLog.selectKnowledge') }}</h4>
<el-button link class="ml-16" @click="refresh">
<el-icon class="mr-4"><Refresh /></el-icon>{{ $t('common.refresh') }}
</el-button>
</div>
</template>
<div class="content-height">
<el-radio-group v-model="selectKnowledge" class="card__radio">
<el-scrollbar height="500">
<div class="p-16">
<el-row :gutter="12" v-loading="loading">
<el-col :span="12" v-for="(item, index) in knowledgeList" :key="index" class="mb-16">
<el-card shadow="never" :class="item.id === selectKnowledge ? 'active' : ''">
<el-radio :value="item.id" size="large">
<div class="flex align-center">
<KnowledgeIcon :type="item.type" class="mr-12" />
<span class="ellipsis" :title="item.name">
{{ item.name }}
</span>
</div>
</el-radio>
</el-card>
</el-col>
</el-row>
</div>
</el-scrollbar>
</el-radio-group>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
<el-button type="primary" @click="submitHandle" :disabled="!selectKnowledge || loading">
{{ $t('common.confirm') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import documentApi from '@/api/resource-management/document'
import useStore from '@/stores/modules-resource-management'
const { knowledge } = useStore()
const route = useRoute()
const {
params: { id }, // idknowledgeID
} = route as any
const emit = defineEmits(['refresh'])
const loading = ref<boolean>(false)
const dialogVisible = ref<boolean>(false)
const selectKnowledge = ref('')
const knowledgeList = ref<any>([])
const documentList = ref<any>([])
watch(dialogVisible, (bool) => {
if (!bool) {
selectKnowledge.value = ''
knowledgeList.value = []
documentList.value = []
}
})
const open = (list: any) => {
documentList.value = list
getKnowledge()
dialogVisible.value = true
}
const submitHandle = () => {
documentApi
.putMigrateMulDocument(id, selectKnowledge.value, documentList.value, loading)
.then((res) => {
emit('refresh')
dialogVisible.value = false
})
}
function getKnowledge() {
knowledge.asyncGetFolderKnowledge(loading).then((res: any) => {
knowledgeList.value = res.data?.filter((v: any) => v.id !== id)
})
}
const refresh = () => {
getKnowledge()
}
defineExpose({ open })
</script>
<style lang="scss">
.select-knowledge-dialog {
padding: 0;
.el-dialog__header {
padding: 24px 24px 0 24px;
}
.el-dialog__body {
padding: 8px !important;
}
.el-dialog__footer {
padding: 0 24px 24px;
}
}
</style>

View File

@ -1,87 +0,0 @@
<template>
<el-popover
v-model:visible="visible"
placement="top"
trigger="hover"
:popper-style="{ width: 'auto' }"
>
<template #default
><StatusTable
v-if="visible"
:status="status"
:statusMeta="statusMeta"
:taskTypeMap="taskTypeMap"
:stateMap="stateMap"
></StatusTable>
</template>
<template #reference>
<el-text v-if="aggStatus?.value === State.SUCCESS || aggStatus?.value === State.REVOKED">
<el-icon class="color-success"><SuccessFilled /></el-icon>
{{ stateMap[aggStatus.value](aggStatus.key) }}
</el-text>
<el-text v-else-if="aggStatus?.value === State.FAILURE">
<el-icon class="color-danger"><CircleCloseFilled /></el-icon>
{{ stateMap[aggStatus.value](aggStatus.key) }}
</el-text>
<el-text v-else-if="aggStatus?.value === State.STARTED">
<el-icon class="is-loading color-primary"><Loading /></el-icon>
{{ stateMap[aggStatus.value](aggStatus.key) }}
</el-text>
<el-text v-else-if="aggStatus?.value === State.PENDING">
<el-icon class="is-loading color-primary"><Loading /></el-icon>
{{ stateMap[aggStatus.value](aggStatus.key) }}
</el-text>
<el-text v-else-if="aggStatus?.value === State.REVOKE">
<el-icon class="is-loading color-primary"><Loading /></el-icon>
{{ stateMap[aggStatus.value](aggStatus.key) }}
</el-text>
</template>
</el-popover>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { TaskType, State } from '@/utils/status'
import StatusTable from '@/views/resource-management/document/component/StatusTable.vue'
import { t } from '@/locales'
const props = defineProps<{ status: string; statusMeta: any }>()
const visible = ref<boolean>(false)
const checkList: Array<string> = [
State.REVOKE,
State.STARTED,
State.PENDING,
State.FAILURE,
State.REVOKED,
State.SUCCESS
]
const aggStatus = computed(() => {
let obj = { key: 0, value: '' }
for (const i in checkList) {
const state = checkList[i]
const index = props.status.indexOf(state)
if (index > -1) {
obj = { key: props.status.length - index, value: state }
break
}
}
return obj
})
const startedMap = {
[TaskType.EMBEDDING]: t('views.document.fileStatus.EMBEDDING'),
[TaskType.GENERATE_PROBLEM]: t('views.document.fileStatus.GENERATE'),
[TaskType.SYNC]: t('views.document.fileStatus.SYNC')
}
const taskTypeMap = {
[TaskType.EMBEDDING]: t('views.knowledge.setting.vectorization'),
[TaskType.GENERATE_PROBLEM]: t('views.document.generateQuestion.title'),
[TaskType.SYNC]: t('views.knowledge.setting.sync')
}
const stateMap: any = {
[State.PENDING]: (type: number) => t('views.document.fileStatus.PENDING'),
[State.STARTED]: (type: number) => startedMap[type],
[State.REVOKE]: (type: number) => t('views.document.fileStatus.REVOKE'),
[State.REVOKED]: (type: number) => t('views.document.fileStatus.SUCCESS'),
[State.FAILURE]: (type: number) => t('views.document.fileStatus.FAILURE'),
[State.SUCCESS]: (type: number) => t('views.document.fileStatus.SUCCESS'),
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,109 +0,0 @@
<template>
<div v-for="status in statusTable" :key="status.type" >
<span> {{ taskTypeMap[status.type] }}</span>
<span>
<el-text v-if="status.state === State.SUCCESS || status.state === State.REVOKED">
<el-icon class="color-success"><SuccessFilled /></el-icon>
{{ stateMap[status.state](status.type) }}
</el-text>
<el-text v-else-if="status.state === State.FAILURE">
<el-icon class="color-danger"><CircleCloseFilled /></el-icon>
{{ stateMap[status.state](status.type) }}
</el-text>
<el-text v-else-if="status.state === State.STARTED">
<el-icon class="is-loading color-primary"><Loading /></el-icon>
{{ stateMap[status.state](status.type) }}
</el-text>
<el-text v-else-if="status.state === State.PENDING">
<el-icon class="is-loading color-primary"><Loading /></el-icon>
{{ stateMap[status.state](status.type) }}
</el-text>
<el-text v-else-if="status.state === State.REVOKE">
<el-icon class="is-loading color-primary"><Loading /></el-icon>
{{ stateMap[status.state](status.type) }}
</el-text>
</span>
<span
class="ml-8 lighter"
:style="{ color: [State.FAILURE, State.REVOKED].includes(status.state) ? '#F54A45' : '' }"
>
{{ $t('views.document.fileStatus.finish') }}
{{
Object.keys(status.aggs ? status.aggs : {})
.filter((k) => k == State.SUCCESS)
.map((k) => status.aggs[k])
.reduce((x: any, y: any) => x + y, 0)
}}/{{
Object.values(status.aggs ? status.aggs : {}).reduce((x: any, y: any) => x + y, 0)
}}</span
>
<el-text type="info" class="ml-12">
{{
status.time
? status.time[status.state == State.REVOKED ? State.REVOKED : State.PENDING]?.substring(
0,
19
)
: undefined
}}
</el-text>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { Status, TaskType, State, type TaskTypeInterface } from '@/utils/status'
import { mergeWith } from 'lodash'
const props = defineProps<{ status: string; statusMeta: any; stateMap: any; taskTypeMap: any }>()
const parseAgg = (agg: { count: number; status: string }) => {
const status = new Status(agg.status)
return Object.keys(TaskType)
.map((key) => {
const value = TaskType[key as keyof TaskTypeInterface]
return { [value]: { [status.task_status[value]]: agg.count } }
})
.reduce((x, y) => ({ ...x, ...y }), {})
}
const customizer: (x: any, y: any) => any = (objValue: any, srcValue: any) => {
if (objValue == undefined && srcValue) {
return srcValue
}
if (srcValue == undefined && objValue) {
return objValue
}
//
if (typeof objValue === 'object' && typeof srcValue === 'object') {
// object
return mergeWith(objValue, srcValue, customizer)
} else {
//
return objValue + srcValue
}
}
const aggs = computed(() => {
return (props.statusMeta.aggs ? props.statusMeta.aggs : [])
.map((agg: any) => {
return parseAgg(agg)
})
.reduce((x: any, y: any) => {
return mergeWith(x, y, customizer)
}, {})
})
const statusTable = computed(() => {
return Object.keys(TaskType)
.map((key) => {
const value = TaskType[key as keyof TaskTypeInterface]
const parseStatus = new Status(props.status)
return {
type: value,
state: parseStatus.task_status[value],
aggs: aggs.value[value],
time: props.statusMeta.state_time[value]
}
})
.filter((item) => item.state !== State.IGNORED)
})
</script>
<style lang="scss"></style>

File diff suppressed because it is too large Load Diff

View File

@ -1,98 +0,0 @@
<template>
<el-scrollbar>
<el-result icon="color-success" :title="`🎉 ${$t('views.knowledge.ResultSuccess.title')} 🎉`">
<template #sub-title>
<div class="mt-8">
<span class="bold">{{ data?.document_list.length || 0 }}</span>
<el-text type="info" class="ml-4">{{ $t('common.fileUpload.document') }}</el-text>
<el-divider direction="vertical" />
<span class="bold">{{ paragraph_count || 0 }}</span>
<el-text type="info" class="ml-4">{{
$t('views.knowledge.ResultSuccess.paragraph')
}}</el-text>
<el-divider direction="vertical" />
<span class="bold">{{ numberFormat(char_length) || 0 }}</span>
<el-text type="info" class="ml-4">{{ $t('common.character') }} </el-text>
</div>
</template>
<template #extra>
<el-button @click="router.push({ path: `/knowledge` })">{{
$t('views.knowledge.ResultSuccess.buttons.toknowledge')
}}</el-button>
<el-button
type="primary"
@click="router.push({ path: `/knowledge/${data?.id}/${folderId}/document` })"
>{{ $t('views.knowledge.ResultSuccess.buttons.toDocument') }}</el-button
>
</template>
</el-result>
<div class="result-success">
<p class="bolder">{{ $t('views.knowledge.ResultSuccess.documentList') }}</p>
<el-card
shadow="never"
class="file-List-card mt-8"
v-for="(item, index) in data?.document_list"
:key="index"
>
<div class="flex-between">
<div class="flex">
<img :src="getImgUrl(item && item?.name)" alt="" width="40" />
<div class="ml-8">
<p>{{ item && item?.name }}</p>
<el-text type="info" size="small">{{ filesize(item && item?.char_length) }}</el-text>
</div>
</div>
<div>
<el-text type="info" class="mr-16"
>{{ item && item?.paragraph_count }}
{{ $t('views.knowledge.ResultSuccess.paragraph_count') }}</el-text
>
<el-text v-if="item.status === '1'">
<el-icon class="color-success"><SuccessFilled /></el-icon>
</el-text>
<el-text v-else-if="item.status === '2'">
<el-icon class="color-danger"><CircleCloseFilled /></el-icon>
</el-text>
<el-text v-else-if="item.status === '0'">
<el-icon class="is-loading primary"><Loading /></el-icon>
{{ $t('views.knowledge.ResultSuccess.loading') }}...
</el-text>
</div>
</div>
</el-card>
</div>
</el-scrollbar>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { numberFormat } from '@/utils/utils'
import { filesize, getImgUrl } from '@/utils/utils'
const route = useRoute()
const props = defineProps({
data: {
type: Object,
default: () => {},
},
})
const {
params: { id, folderId }, // idknowledgeID
} = route as any
const router = useRouter()
const paragraph_count = computed(() =>
props.data?.document_list.reduce((sum: number, obj: any) => (sum += obj.paragraph_count), 0),
)
const char_length = computed(
() =>
props.data?.document_list.reduce((sum: number, obj: any) => (sum += obj.char_length), 0) || 0,
)
</script>
<style scoped lang="scss">
.result-success {
width: 70%;
margin: 0 auto;
margin-bottom: 30px;
}
</style>

View File

@ -1,257 +0,0 @@
<template>
<div class="set-rules">
<el-row>
<el-col :span="10" class="p-24">
<h4 class="title-decoration-1 mb-16">{{ $t('views.document.setRules.title.setting') }}</h4>
<div class="set-rules__right">
<el-scrollbar>
<div class="left-height" @click.stop>
<el-radio-group v-model="radio" class="card__radio">
<el-card shadow="never" class="mb-16" :class="radio === '1' ? 'active' : ''">
<el-radio value="1" size="large">
<p class="mb-4">{{ $t('views.document.setRules.intelligent.label') }}</p>
<el-text type="info">{{
$t('views.document.setRules.intelligent.text')
}}</el-text>
</el-radio>
</el-card>
<el-card shadow="never" class="mb-16" :class="radio === '2' ? 'active' : ''">
<el-radio value="2" size="large">
<p class="mb-4">{{ $t('views.document.setRules.advanced.label') }}</p>
<el-text type="info">
{{ $t('views.document.setRules.advanced.text') }}
</el-text>
</el-radio>
<el-card
v-if="radio === '2'"
shadow="never"
class="card-never mt-16"
style="margin-left: 30px"
>
<div class="set-rules__form">
<div class="form-item mb-16">
<div class="title flex align-center mb-8">
<span style="margin-right: 4px">{{
$t('views.document.setRules.patterns.label')
}}</span>
<el-tooltip
effect="dark"
:content="$t('views.document.setRules.patterns.tooltip')"
placement="right"
>
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
</el-tooltip>
</div>
<div @click.stop>
<el-select
v-model="form.patterns"
multiple
allow-create
default-first-option
filterable
:placeholder="$t('views.document.setRules.patterns.placeholder')"
>
<el-option
v-for="(item, index) in splitPatternList"
:key="index"
:label="item.key"
:value="item.value"
>
</el-option>
</el-select>
</div>
</div>
<div class="form-item mb-16">
<div class="title mb-8">
{{ $t('views.document.setRules.limit.label') }}
</div>
<el-slider
v-model="form.limit"
show-input
:show-input-controls="false"
:min="50"
:max="100000"
/>
</div>
<div class="form-item mb-16">
<div class="title mb-8">
{{ $t('views.document.setRules.with_filter.label') }}
</div>
<el-switch size="small" v-model="form.with_filter" />
<div style="margin-top: 4px">
<el-text type="info">
{{ $t('views.document.setRules.with_filter.text') }}</el-text
>
</div>
</div>
</div>
</el-card>
</el-card>
</el-radio-group>
</div>
</el-scrollbar>
<div>
<el-checkbox
v-model="checkedConnect"
@change="changeHandle"
style="white-space: normal"
>
{{ $t('views.document.setRules.checkedConnect.label') }}
</el-checkbox>
</div>
<div class="text-right mt-8">
<el-button @click="splitDocument">
{{ $t('views.document.buttons.preview') }}</el-button
>
</div>
</div>
</el-col>
<el-col :span="14" class="p-24 border-l">
<div v-loading="loading">
<h4 class="title-decoration-1 mb-8">{{ $t('views.document.setRules.title.preview') }}</h4>
<ParagraphPreview v-model:data="paragraphList" :isConnect="checkedConnect" />
</div>
</el-col>
</el-row>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, reactive, watch } from 'vue'
import ParagraphPreview from '@/views/resource-management/knowledge/component/ParagraphPreview.vue'
import { useRoute } from 'vue-router'
import { cutFilename } from '@/utils/utils'
import documentApi from '@/api/resource-management/document'
import useStore from '@/stores/modules-resource-management'
import type { KeyValue } from '@/api/type/common'
const { knowledge } = useStore()
const documentsFiles = computed(() => knowledge.documentsFiles)
const splitPatternList = ref<Array<KeyValue<string, string>>>([])
const route = useRoute()
const {
query: { id }, // iddatasetID
} = route as any
const radio = ref('1')
const loading = ref(false)
const paragraphList = ref<any[]>([])
const patternLoading = ref<boolean>(false)
const checkedConnect = ref<boolean>(false)
const firstChecked = ref(true)
const form = reactive<{
patterns: Array<string>
limit: number
with_filter: boolean
[propName: string]: any
}>({
patterns: [],
limit: 500,
with_filter: true,
})
function changeHandle(val: boolean) {
if (val && firstChecked.value) {
paragraphList.value = paragraphList.value.map((item: any) => ({
...item,
content: item.content.map((v: any) => ({
...v,
problem_list: v.title.trim()
? [
{
content: v.title.trim(),
},
]
: [],
})),
}))
firstChecked.value = false
}
}
function splitDocument() {
loading.value = true
const fd = new FormData()
documentsFiles.value.forEach((item) => {
if (item?.raw) {
fd.append('file', item?.raw)
}
})
if (radio.value === '2') {
Object.keys(form).forEach((key) => {
if (key == 'patterns') {
form.patterns.forEach((item) => fd.append('patterns', item))
} else {
fd.append(key, form[key])
}
})
}
documentApi
.postSplitDocument(fd, id)
.then((res: any) => {
const list = res.data
list.map((item: any) => {
if (item.name.length > 128) {
item.name = cutFilename(item.name, 128)
}
if (checkedConnect.value) {
item.content.map((v: any) => {
v['problem_list'] = v.title.trim()
? [
{
content: v.title.trim(),
},
]
: []
})
}
})
paragraphList.value = list
loading.value = false
})
.catch(() => {
loading.value = false
})
}
const initSplitPatternList = () => {
documentApi.listSplitPattern(patternLoading).then((ok) => {
splitPatternList.value = ok.data
})
}
watch(radio, () => {
if (radio.value === '2') {
initSplitPatternList()
}
})
onMounted(() => {
splitDocument()
})
defineExpose({
paragraphList,
checkedConnect,
loading,
})
</script>
<style scoped lang="scss">
.set-rules {
width: 100%;
.left-height {
max-height: calc(var(--create-knowledge-height) - 110px);
overflow-x: hidden;
}
&__form {
.title {
font-size: 14px;
font-weight: 400;
}
}
}
</style>

View File

@ -1,328 +0,0 @@
<template>
<h4 class="title-decoration-1 mb-8">{{ $t('views.document.uploadDocument') }}</h4>
<el-form
ref="FormRef"
:model="form"
:rules="rules"
label-position="top"
require-asterisk-position="right"
>
<div class="mt-16 mb-16">
<el-radio-group v-model="form.fileType" @change="radioChange" class="app-radio-button-group">
<el-radio-button value="txt">{{ $t('views.document.fileType.txt.label') }}</el-radio-button>
<el-radio-button value="table">{{
$t('views.document.fileType.table.label')
}}</el-radio-button>
<el-radio-button value="QA">{{ $t('views.document.fileType.QA.label') }}</el-radio-button>
</el-radio-group>
</div>
<el-form-item prop="fileList" v-if="form.fileType === 'QA'">
<div class="update-info flex p-8-12 border-r-4 mb-16 w-full">
<div class="mt-4">
<AppIcon iconName="app-warning-colorful" style="font-size: 16px"></AppIcon>
</div>
<div class="ml-16 lighter">
<p>
{{ $t('views.document.fileType.QA.tip1') }}
<el-button type="primary" link @click="downloadTemplate('excel')">
{{ $t('views.document.upload.download') }} Excel
{{ $t('views.document.upload.template') }}
</el-button>
<el-button type="primary" link @click="downloadTemplate('csv')">
{{ $t('views.document.upload.download') }} CSV
{{ $t('views.document.upload.template') }}
</el-button>
</p>
<p>{{ $t('views.document.fileType.QA.tip2') }}</p>
<p>{{ $t('views.document.fileType.QA.tip3') }}</p>
</div>
</div>
<el-upload
:webkitdirectory="false"
class="w-full mb-4"
drag
multiple
v-model:file-list="form.fileList"
action="#"
:auto-upload="false"
:show-file-list="false"
accept=".xlsx, .xls, .csv,.zip"
:limit="50"
:on-exceed="onExceed"
:on-change="fileHandleChange"
@click.prevent="handlePreview(false)"
>
<img src="@/assets/upload-icon.svg" alt="" />
<div class="el-upload__text">
<p>
{{ $t('views.document.upload.uploadMessage') }}
<em class="hover" @click.prevent="handlePreview(false)">
{{ $t('views.document.upload.selectFile') }}
</em>
<em class="hove ml-4" @click.prevent="handlePreview(true)">
{{ $t('views.document.upload.selectFiles') }}
</em>
</p>
<div class="upload__decoration">
<p>{{ $t('views.document.upload.formats') }}XLSXLSXCSVZIP</p>
</div>
</div>
</el-upload>
</el-form-item>
<el-form-item prop="fileList" v-else-if="form.fileType === 'table'">
<div class="update-info flex p-8-12 border-r-4 mb-16 w-full">
<div class="mt-4">
<AppIcon iconName="app-warning-colorful" style="font-size: 16px"></AppIcon>
</div>
<div class="ml-16 lighter">
<p>
{{ $t('views.document.fileType.table.tip1') }}
<el-button type="primary" link @click="downloadTableTemplate('excel')">
{{ $t('views.document.upload.download') }} Excel
{{ $t('views.document.upload.template') }}
</el-button>
<el-button type="primary" link @click="downloadTableTemplate('csv')">
{{ $t('views.document.upload.download') }} CSV
{{ $t('views.document.upload.template') }}
</el-button>
</p>
<p>{{ $t('views.document.fileType.table.tip2') }}</p>
<p>{{ $t('views.document.fileType.table.tip3') }}</p>
<p>{{ $t('views.document.fileType.table.tip4') }}</p>
</div>
</div>
<el-upload
:webkitdirectory="false"
class="w-full mb-4"
drag
multiple
v-model:file-list="form.fileList"
action="#"
:auto-upload="false"
:show-file-list="false"
accept=".xlsx, .xls, .csv"
:limit="50"
:on-exceed="onExceed"
:on-change="fileHandleChange"
@click.prevent="handlePreview(false)"
>
<img src="@/assets/upload-icon.svg" alt="" />
<div class="el-upload__text">
<p>
{{ $t('views.document.upload.uploadMessage') }}
<em class="hover" @click.prevent="handlePreview(false)">
{{ $t('views.document.upload.selectFile') }}
</em>
<em class="hover ml-4" @click.prevent="handlePreview(true)">
{{ $t('views.document.upload.selectFiles') }}
</em>
</p>
<div class="upload__decoration">
<p>{{ $t('views.document.upload.formats') }}XLSXLSXCSV</p>
</div>
</div>
</el-upload>
</el-form-item>
<el-form-item prop="fileList" v-else>
<div class="update-info flex p-8-12 border-r-4 mb-16 w-full">
<div class="mt-4">
<AppIcon iconName="app-warning-colorful" style="font-size: 16px"></AppIcon>
</div>
<div class="ml-16 lighter">
<p>{{ $t('views.document.fileType.txt.tip1') }}</p>
<p>{{ $t('views.document.fileType.txt.tip2') }}</p>
</div>
</div>
<el-upload
:webkitdirectory="false"
class="w-full"
drag
multiple
v-model:file-list="form.fileList"
action="#"
:auto-upload="false"
:show-file-list="false"
accept=".txt, .md, .log, .docx, .pdf, .html,.zip,.xlsx,.xls,.csv"
:limit="50"
:on-exceed="onExceed"
:on-change="fileHandleChange"
@click.prevent="handlePreview(false)"
>
<img src="@/assets/upload-icon.svg" alt="" />
<div class="el-upload__text">
<p>
{{ $t('views.document.upload.uploadMessage') }}
<em class="hover" @click.prevent="handlePreview(false)">
{{ $t('views.document.upload.selectFile') }}
</em>
<em class="hover ml-4" @click.prevent="handlePreview(true)">
{{ $t('views.document.upload.selectFiles') }}
</em>
</p>
<div class="upload__decoration">
<p>
{{
$t('views.document.upload.formats')
}}TXTMarkdownPDFDOCXHTMLXLSXLSXCSVZIP
</p>
</div>
</div>
</el-upload>
</el-form-item>
</el-form>
<el-row :gutter="8" v-if="form.fileList?.length">
<template v-for="(item, index) in form.fileList" :key="index">
<el-col :span="12" class="mb-8">
<el-card shadow="never" class="file-List-card">
<div class="flex-between">
<div class="flex">
<img :src="getImgUrl(item && item?.name)" alt="" width="40" />
<div class="ml-8">
<p>{{ item && item?.name }}</p>
<el-text type="info" size="small">{{
filesize(item && item?.size) || '0K'
}}</el-text>
</div>
</div>
<el-button text @click="deleteFile(index)">
<el-icon><Delete /></el-icon>
</el-button>
</div>
</el-card>
</el-col>
</template>
</el-row>
</template>
<script setup lang="ts">
import { ref, reactive, onUnmounted, onMounted, computed, watch, nextTick } from 'vue'
import type { UploadFiles } from 'element-plus'
import { filesize, getImgUrl, isRightType } from '@/utils/utils'
import { MsgError } from '@/utils/message'
import documentApi from '@/api/resource-management/document'
import useStore from '@/stores/modules-resource-management'
import { t } from '@/locales'
const { knowledge } = useStore()
const documentsFiles = computed(() => knowledge.documentsFiles)
const documentsType = computed(() => knowledge.documentsType)
const form = ref({
fileType: 'txt',
fileList: [] as any
})
const rules = reactive({
fileList: [
{ required: true, message: t('views.document.upload.requiredMessage'), trigger: 'change' }
]
})
const FormRef = ref()
watch(form.value, (value) => {
knowledge.saveDocumentsType(value.fileType)
knowledge.saveDocumentsFile(value.fileList)
})
function downloadTemplate(type: string) {
documentApi.exportQATemplate(
`${type}${t('views.document.upload.template')}.${type == 'csv' ? type : 'xlsx'}`,
type
)
}
function downloadTableTemplate(type: string) {
documentApi.exportTableTemplate(
`${type}${t('views.document.upload.template')}.${type == 'csv' ? type : 'xlsx'}`,
type
)
}
function radioChange() {
form.value.fileList = []
}
function deleteFile(index: number) {
form.value.fileList.splice(index, 1)
}
// on-change
const fileHandleChange = (file: any, fileList: UploadFiles) => {
//1100M
const isLimit = file?.size / 1024 / 1024 < 100
if (!isLimit) {
MsgError(t('views.document.upload.errorMessage1'))
fileList.splice(-1, 1) //
return false
}
if (!isRightType(file?.name, form.value.fileType)) {
if (file?.name !== '.DS_Store') {
MsgError(t('views.document.upload.errorMessage2'))
}
fileList.splice(-1, 1)
return false
}
if (file?.size === 0) {
MsgError(t('views.document.upload.errorMessage3'))
fileList.splice(-1, 1)
return false
}
}
const onExceed = () => {
MsgError(t('views.document.upload.errorMessage4'))
}
const handlePreview = (bool: boolean) => {
let inputDom: any = null
nextTick(() => {
if (document.querySelector('.el-upload__input') != null) {
inputDom = document.querySelector('.el-upload__input')
inputDom.webkitdirectory = bool
}
})
}
/*
表单校验
*/
function validate() {
if (!FormRef.value) return
return FormRef.value.validate((valid: any) => {
return valid
})
}
onMounted(() => {
if (documentsType.value) {
form.value.fileType = documentsType.value
}
if (documentsFiles.value) {
form.value.fileList = documentsFiles.value
}
})
onUnmounted(() => {
form.value = {
fileType: 'txt',
fileList: []
}
})
defineExpose({
validate,
form
})
</script>
<style scoped lang="scss">
.upload__decoration {
font-size: 12px;
line-height: 20px;
color: var(--el-text-color-secondary);
}
.el-upload__text {
.hover:hover {
color: var(--el-color-primary-light-5);
}
}
</style>

View File

@ -1,434 +0,0 @@
<template>
<div class="hit-test p-16-24">
<h4>
{{ $t('views.application.hitTest.title') }}
<el-text type="info" class="ml-4"> {{ $t('views.application.hitTest.text') }}</el-text>
</h4>
<el-card style="--el-card-padding: 0" class="hit-test__main p-16 mt-16 mb-16" v-loading="loading">
<div class="question-title" :style="{ visibility: questionTitle ? 'visible' : 'hidden' }">
<div class="avatar">
<el-avatar>
<img src="@/assets/user-icon.svg" style="width: 54%" alt="" />
</el-avatar>
</div>
<div class="content">
<h4 class="text break-all">{{ questionTitle }}</h4>
</div>
</div>
<el-scrollbar>
<div class="hit-test-height">
<el-empty
v-if="first"
:image="emptyImg"
:description="$t('views.application.hitTest.emptyMessage1')"
style="padding-top: 160px"
:image-size="125"
/>
<el-empty
v-else-if="paragraphDetail.length == 0"
:description="$t('views.application.hitTest.emptyMessage2')"
style="padding-top: 160px"
:image-size="125"
/>
<el-row v-else>
<el-col
:xs="24"
:sm="12"
:md="12"
:lg="8"
:xl="6"
v-for="(item, index) in paragraphDetail"
:key="index"
class="p-8"
>
<CardBox
shadow="hover"
:title="item.title || '-'"
:description="item.content"
class="document-card layout-bg layout-bg cursor"
:class="item.is_active ? '' : 'disabled'"
:showIcon="false"
@click="editParagraph(item)"
>
<template #icon>
<el-avatar class="mr-12 avatar-light" :size="22"> {{ index + 1 + '' }}</el-avatar>
</template>
<div class="active-button primary">{{ item.similarity?.toFixed(3) }}</div>
<template #footer>
<div class="footer-content flex-between">
<el-text>
<el-icon>
<Document />
</el-icon>
{{ item?.document_name }}
</el-text>
<div v-if="item.trample_num || item.star_num">
<span v-if="item.star_num">
<AppIcon iconName="app-like-color"></AppIcon>
{{ item.star_num }}
</span>
<span v-if="item.trample_num" class="ml-4">
<AppIcon iconName="app-oppose-color"></AppIcon>
{{ item.trample_num }}
</span>
</div>
</div>
</template>
</CardBox>
</el-col>
</el-row>
</div>
</el-scrollbar>
</el-card>
<ParagraphDialog ref="ParagraphDialogRef" :title="title" @refresh="refresh" />
<div class="hit-test__operate">
<el-popover :visible="popoverVisible" placement="right-end" :width="500" trigger="click">
<template #reference>
<el-button icon="Setting" class="mb-8" @click="settingChange('open')">{{
$t('common.paramSetting')
}}</el-button>
</template>
<div class="mb-16">
<div class="title mb-8">
{{ $t('views.application.dialog.selectSearchMode') }}
</div>
<el-radio-group
v-model="cloneForm.search_mode"
class="card__radio"
@change="changeHandle"
>
<el-card
shadow="never"
class="mb-16"
:class="cloneForm.search_mode === 'embedding' ? 'active' : ''"
>
<el-radio value="embedding" size="large">
<p class="mb-4">
{{ $t('views.application.dialog.vectorSearch') }}
</p>
<el-text type="info">{{
$t('views.application.dialog.vectorSearchTooltip')
}}</el-text>
</el-radio>
</el-card>
<el-card
shadow="never"
class="mb-16"
:class="cloneForm.search_mode === 'keywords' ? 'active' : ''"
>
<el-radio value="keywords" size="large">
<p class="mb-4">
{{ $t('views.application.dialog.fullTextSearch') }}
</p>
<el-text type="info">{{
$t('views.application.dialog.fullTextSearchTooltip')
}}</el-text>
</el-radio>
</el-card>
<el-card
shadow="never"
class="mb-16"
:class="cloneForm.search_mode === 'blend' ? 'active' : ''"
>
<el-radio value="blend" size="large">
<p class="mb-4">
{{ $t('views.application.dialog.hybridSearch') }}
</p>
<el-text type="info">{{
$t('views.application.dialog.hybridSearchTooltip')
}}</el-text>
</el-radio>
</el-card>
</el-radio-group>
</div>
<el-row :gutter="20">
<el-col :span="12">
<div class="mb-16">
<div class="title mb-8">
{{ $t('views.application.dialog.similarityThreshold') }}
</div>
<el-input-number
v-model="cloneForm.similarity"
:min="0"
:max="cloneForm.search_mode === 'blend' ? 2 : 1"
:precision="3"
:step="0.1"
:value-on-clear="0"
controls-position="right"
class="w-full"
/>
</div>
</el-col>
<el-col :span="12">
<div class="mb-16">
<div class="title mb-8">
{{ $t('views.application.dialog.topReferences') }}
</div>
<el-input-number
v-model="cloneForm.top_number"
:min="1"
:max="10000"
controls-position="right"
class="w-full"
/>
</div>
</el-col>
</el-row>
<div class="text-right">
<el-button @click="popoverVisible = false">{{ $t('common.cancel') }}</el-button>
<el-button type="primary" @click="settingChange('close')">{{
$t('common.confirm')
}}</el-button>
</div>
</el-popover>
<div class="operate-textarea flex">
<el-input
ref="quickInputRef"
v-model="inputValue"
type="textarea"
:placeholder="$t('common.inputPlaceholder')"
:autosize="{ minRows: 1, maxRows: 8 }"
@keydown.enter="sendChatHandle($event)"
/>
<div class="operate">
<el-button
text
class="sent-button"
:disabled="isDisabledChart || loading"
@click="sendChatHandle"
>
<img v-show="isDisabledChart || loading" src="@/assets/icon_send.svg" alt="" />
<img
v-show="!isDisabledChart && !loading"
src="@/assets/icon_send_colorful.svg"
alt=""
/>
</el-button>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { nextTick, ref, onMounted, computed } from 'vue'
import { useRoute } from 'vue-router'
import { cloneDeep } from 'lodash'
import KnowledgeApi from '@/api/resource-management/knowledge'
// import applicationApi from '@/api/application/application'
import ParagraphDialog from '@/views/resource-management/paragraph/component/ParagraphDialog.vue'
import { arraySort } from '@/utils/common'
import emptyImg from '@/assets/hit-test-empty.png'
import { t } from '@/locales'
const route = useRoute()
const {
meta: { activeMenu },
params: { id },
} = route as any
const quickInputRef = ref()
const ParagraphDialogRef = ref()
const loading = ref(false)
const paragraphDetail = ref<any[]>([])
const title = ref('')
const inputValue = ref('')
const formInline = ref({
similarity: 0.6,
top_number: 5,
search_mode: 'embedding',
})
//
const first = ref(true)
const cloneForm = ref<any>({})
const popoverVisible = ref(false)
const questionTitle = ref('')
const isDisabledChart = computed(() => !inputValue.value)
const isApplication = computed(() => {
return activeMenu.includes('application')
})
const isDataset = computed(() => {
return activeMenu.includes('knowledge')
})
function changeHandle(val: string) {
if (val === 'keywords') {
cloneForm.value.similarity = 0
} else {
cloneForm.value.similarity = 0.6
}
}
function settingChange(val: string) {
if (val === 'open') {
popoverVisible.value = true
cloneForm.value = cloneDeep(formInline.value)
} else if (val === 'close') {
popoverVisible.value = false
formInline.value = cloneDeep(cloneForm.value)
}
}
function editParagraph(row: any) {
title.value = t('views.paragraph.paragraphDetail')
ParagraphDialogRef.value.open(row)
}
function sendChatHandle(event: any) {
if (!event?.ctrlKey && !event?.shiftKey && !event?.altKey && !event?.metaKey) {
//
event.preventDefault()
if (!isDisabledChart.value && !loading.value) {
getHitTestList()
}
} else {
// ctrl/shift/cmd/opt +enter
insertNewlineAtCursor(event)
}
}
const insertNewlineAtCursor = (event?: any) => {
const textarea = quickInputRef.value.$el.querySelector(
'.el-textarea__inner',
) as HTMLTextAreaElement
const startPos = textarea.selectionStart
const endPos = textarea.selectionEnd
//
event.preventDefault()
//
inputValue.value = inputValue.value.slice(0, startPos) + '\n' + inputValue.value.slice(endPos)
nextTick(() => {
textarea.setSelectionRange(startPos + 1, startPos + 1) //
})
}
function getHitTestList() {
const obj = {
query_text: inputValue.value,
...formInline.value,
}
if (isDataset.value) {
KnowledgeApi.getKnowledgeHitTest(id, obj, loading).then((res) => {
paragraphDetail.value = res.data && arraySort(res.data, 'comprehensive_score', true)
questionTitle.value = inputValue.value
inputValue.value = ''
first.value = false
})
} else if (isApplication.value) {
// applicationApi.getApplicationHitTest(id, obj, loading).then((res) => {
// paragraphDetail.value = res.data && arraySort(res.data, 'comprehensive_score', true)
// questionTitle.value = inputValue.value
// inputValue.value = ''
// first.value = false
// })
}
}
function refresh(data: any) {
if (data) {
const obj = paragraphDetail.value.filter((v) => v.id === data.id)[0]
obj.content = data.content
obj.title = data.title
} else {
paragraphDetail.value = []
getHitTestList()
}
}
onMounted(() => {})
</script>
<style lang="scss" scoped>
.hit-test {
.question-title {
.avatar {
float: left;
}
.content {
padding-left: 40px;
.text {
padding: 6px 0;
height: 34px;
box-sizing: border-box;
}
}
}
&__operate {
.operate-textarea {
box-shadow: 0px 6px 24px 0px rgba(31, 35, 41, 0.08);
background-color: #ffffff;
border-radius: 8px;
border: 1px solid #ffffff;
box-sizing: border-box;
&:has(.el-textarea__inner:focus) {
border: 1px solid var(--el-color-primary);
}
:deep(.el-textarea__inner) {
border-radius: 8px !important;
box-shadow: none;
resize: none;
padding: 12px 16px;
}
.operate {
padding: 6px 10px;
.sent-button {
max-height: none;
.el-icon {
font-size: 24px;
}
}
:deep(.el-loading-spinner) {
margin-top: -15px;
.circular {
width: 31px;
height: 31px;
}
}
}
}
}
}
.hit-test {
&__header {
position: absolute;
right: calc(var(--app-base-px) * 3);
}
.hit-test-height {
height: calc(100vh - 300px);
}
.document-card {
height: 210px;
border: 1px solid var(--app-layout-bg-color);
&:hover {
background: #ffffff;
border: 1px solid var(--el-border-color);
}
&.disabled {
background: var(--app-layout-bg-color);
border: 1px solid var(--app-layout-bg-color);
:deep(.description) {
color: var(--app-border-color-dark);
}
:deep(.title) {
color: var(--app-border-color-dark);
}
}
:deep(.description) {
-webkit-line-clamp: 5 !important;
height: 110px;
}
.active-button {
position: absolute;
right: 16px;
top: 16px;
}
}
}
</style>

View File

@ -1,290 +0,0 @@
<template>
<LayoutContainer :header="$t('views.document.importDocument')" class="create-knowledge">
<template #backButton>
<back-button @click="back"></back-button>
</template>
<div class="create-knowledge__main flex" v-loading="loading">
<div class="create-knowledge__component main-calc-height">
<div class="upload-document p-24" style="min-width: 850px">
<h4 class="title-decoration-1 mb-8">
{{ $t('views.document.feishu.selectDocument') }}
</h4>
<el-form
ref="FormRef"
:model="form"
:rules="rules"
label-position="top"
require-asterisk-position="right"
>
<div class="mt-16 mb-16">
<el-radio-group v-model="form.fileType" class="app-radio-button-group">
<el-radio-button value="txt"
>{{ $t('views.document.fileType.txt.label') }}
</el-radio-button>
</el-radio-group>
</div>
<div class="update-info flex p-8-12 border-r-4 mb-16">
<div class="mt-4">
<AppIcon iconName="app-warning-colorful" style="font-size: 16px"></AppIcon>
</div>
<div class="ml-16 lighter">
<p>{{ $t('views.document.feishu.tip1') }}</p>
<p>{{ $t('views.document.feishu.tip2') }}</p>
</div>
</div>
<div class="card-never border-r-4 mb-16">
<el-checkbox
v-model="allCheck"
:label="$t('views.document.feishu.allCheck')"
size="large"
class="ml-24"
@change="handleAllCheckChange"
/>
</div>
<div style="height: calc(100vh - 450px)">
<el-scrollbar>
<el-tree
:props="props"
:load="loadNode"
lazy
show-checkbox
node-key="token"
ref="treeRef"
>
<template #default="{ node, data }">
<div class="custom-tree-node flex align-center lighter">
<img
src="@/assets/fileType/file-icon.svg"
alt=""
height="20"
v-if="data.type === 'folder'"
/>
<img
src="@/assets/fileType/docx-icon.svg"
alt=""
height="22"
v-else-if="data.type === 'docx' || data.name.endsWith('.docx')"
/>
<img
src="@/assets/fileType/xlsx-icon.svg"
alt=""
height="22"
v-else-if="data.type === 'sheet' || data.name.endsWith('.xlsx')"
/>
<img
src="@/assets/fileType/xls-icon.svg"
alt=""
height="22"
v-else-if="data.name.endsWith('xls')"
/>
<img
src="@/assets/fileType/csv-icon.svg"
alt=""
height="22"
v-else-if="data.name.endsWith('csv')"
/>
<img
src="@/assets/fileType/pdf-icon.svg"
alt=""
height="22"
v-else-if="data.name.endsWith('.pdf')"
/>
<img
src="@/assets/fileType/html-icon.svg"
alt=""
height="22"
v-else-if="data.name.endsWith('.html')"
/>
<img
src="@/assets/fileType/txt-icon.svg"
alt=""
height="22"
v-else-if="data.name.endsWith('.txt')"
/>
<img
src="@/assets/fileType/zip-icon.svg"
alt=""
height="22"
v-else-if="data.name.endsWith('.zip')"
/>
<img
src="@/assets/fileType/md-icon.svg"
alt=""
height="22"
v-else-if="data.name.endsWith('.md')"
/>
<span class="ml-4">{{ node.label }}</span>
</div>
</template>
</el-tree>
</el-scrollbar>
</div>
</el-form>
</div>
</div>
</div>
<div class="create-knowledge__footer text-right border-t">
<el-button @click="router.go(-1)">{{ $t('common.cancel') }}</el-button>
<el-button @click="submit" type="primary" :disabled="disabled">
{{ $t('views.document.buttons.import') }}
</el-button>
</div>
</LayoutContainer>
</template>
<script setup lang="ts">
import { ref, reactive, computed, onUnmounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { MsgConfirm, MsgSuccess, MsgWarning } from '@/utils/message'
import { getImgUrl } from '@/utils/utils'
import { t } from '@/locales'
import type Node from 'element-plus/es/components/tree/src/model/node'
import knowledgeApi from '@/api/resource-management/knowledge'
const router = useRouter()
const route = useRoute()
const {
query: { id, folder_token }, // idknowledgeIDid folder_tokentoken
} = route
const knowledgeId = id as string
const folderToken = folder_token as string
const loading = ref(false)
const disabled = ref(false)
const allCheck = ref(false)
const treeRef = ref<any>(null)
interface Tree {
name: string
leaf?: boolean
type: string
token: string
is_exist: boolean
}
const form = ref({
fileType: 'txt',
fileList: [] as any,
})
const rules = reactive({
fileList: [
{ required: true, message: t('views.document.upload.requiredMessage'), trigger: 'change' },
],
})
const props = {
label: 'name',
children: 'zones',
isLeaf: (data: any) => data.type !== 'folder',
disabled: (data: any) => data.is_exist,
}
const loadNode = (node: Node, resolve: (nodeData: Tree[]) => void) => {
const token = node.level === 0 ? folderToken : node.data.token // 使 folder_token使 node.data.token
knowledgeApi
.getLarkDocumentList(knowledgeId, token, {}, loading)
.then((res: any) => {
const nodes = res.data.files as Tree[]
resolve(nodes)
nodes.forEach((childNode) => {
if (childNode.is_exist) {
treeRef.value?.setChecked(childNode.token, true, false)
}
})
})
.catch((err) => {
console.error('Failed to load tree nodes:', err)
})
}
const handleAllCheckChange = (checked: boolean) => {
if (checked) {
//
const nodes = Object.values(treeRef.value?.store.nodesMap || {}) as any[]
nodes.forEach((node) => {
//
if (!node.disabled) {
treeRef.value?.setChecked(node.data, true, false)
}
})
} else {
treeRef.value?.setCheckedKeys([])
}
}
function submit() {
loading.value = true
disabled.value = true
// token
const checkedNodes = treeRef.value?.getCheckedNodes() || []
const filteredNodes = checkedNodes.filter((node: any) => !node.is_exist)
const newList = filteredNodes.map((node: any) => {
return {
name: node.name,
token: node.token,
type: node.type,
}
})
if (newList.length === 0) {
disabled.value = false
MsgWarning(t('views.document.feishu.errorMessage1'))
loading.value = false
return
}
knowledgeApi
.importLarkDocument(knowledgeId, newList, loading)
.then((res) => {
MsgSuccess(t('views.document.tip.importMessage'))
disabled.value = false
router.go(-1)
})
.catch((err) => {
console.error('Failed to load tree nodes:', err)
})
.finally(() => {
disabled.value = false
})
loading.value = false
}
function back() {
router.go(-1)
}
</script>
<style lang="scss" scoped>
.create-knowledge {
&__component {
width: 100%;
margin: 0 auto;
overflow: hidden;
}
&__footer {
padding: 16px 24px;
position: fixed;
bottom: 0;
left: 0;
background: #ffffff;
width: 100%;
box-sizing: border-box;
}
.upload-document {
width: 70%;
margin: 0 auto;
margin-bottom: 20px;
}
}
.xlsx-icon {
svg {
width: 24px;
height: 24px;
stroke: #000000 !important;
fill: #ffffff !important;
}
}
</style>

View File

@ -1,285 +0,0 @@
<template>
<div class="p-16-24">
<h2 class="mb-16">{{ $t('common.setting') }}</h2>
<el-card style="--el-card-padding: 0">
<div class="knowledge-setting main-calc-height">
<el-scrollbar>
<div class="p-24" v-loading="loading">
<h4 class="title-decoration-1 mb-16">
{{ $t('common.info') }}
</h4>
<BaseForm ref="BaseFormRef" :data="detail" />
<el-form
ref="webFormRef"
:rules="rules"
:model="form"
label-position="top"
require-asterisk-position="right"
>
<el-form-item :label="$t('views.knowledge.knowledgeType.label')" required>
<el-card
shadow="never"
class="mb-8 w-full"
style="line-height: 22px"
v-if="detail.type === 0"
>
<div class="flex align-center">
<el-avatar class="mr-8 avatar-blue" shape="square" :size="32">
<img src="@/assets/knowledge/icon_document.svg" style="width: 58%" alt="" />
</el-avatar>
<div>
<div>{{ $t('views.knowledge.knowledgeType.generalKnowledge') }}</div>
<el-text type="info"
>{{ $t('views.knowledge.knowledgeType.generalInfo') }}
</el-text>
</div>
</div>
</el-card>
<el-card
shadow="never"
class="mb-8 w-full"
style="line-height: 22px"
v-if="detail?.type === 1"
>
<div class="flex align-center">
<el-avatar class="mr-8 avatar-purple" shape="square" :size="32">
<img src="@/assets/knowledge/icon_web.svg" style="width: 58%" alt="" />
</el-avatar>
<div>
<div>{{ $t('views.knowledge.knowledgeType.webKnowledge') }}</div>
<el-text type="info">
{{ $t('views.knowledge.knowledgeType.webInfo') }}
</el-text>
</div>
</div>
</el-card>
<el-card
shadow="never"
class="mb-8 w-full"
style="line-height: 22px"
v-if="detail?.type === 2"
>
<div class="flex align-center">
<el-avatar shape="square" :size="32" style="background: none">
<img src="@/assets/knowledge/logo_lark.svg" style="width: 100%" alt="" />
</el-avatar>
<div>
<p>
<el-text>{{ $t('views.knowledge.knowledgeType.larkKnowledge') }}</el-text>
</p>
<el-text type="info"
>{{ $t('views.knowledge.knowledgeType.larkInfo') }}
</el-text>
</div>
</div>
</el-card>
</el-form-item>
<el-form-item
:label="$t('views.knowledge.form.source_url.label')"
prop="source_url"
v-if="detail.type === 1"
>
<el-input
v-model="form.source_url"
:placeholder="$t('views.knowledge.form.source_url.placeholder')"
@blur="form.source_url = form.source_url.trim()"
/>
</el-form-item>
<el-form-item
:label="$t('views.knowledge.form.selector.label')"
v-if="detail.type === 1"
>
<el-input
v-model="form.selector"
:placeholder="$t('views.knowledge.form.selector.placeholder')"
@blur="form.selector = form.selector.trim()"
/>
</el-form-item>
<el-form-item label="App ID" prop="app_id" v-if="detail.type === 2">
<el-input
v-model="form.app_id"
:placeholder="
$t('views.application.applicationAccess.larkSetting.appIdPlaceholder')
"
/>
</el-form-item>
<el-form-item label="App Secret" prop="app_id" v-if="detail.type === 2">
<el-input
v-model="form.app_secret"
type="password"
show-password
:placeholder="
$t('views.application.applicationAccess.larkSetting.appSecretPlaceholder')
"
/>
</el-form-item>
<el-form-item label="Folder Token" prop="folder_token" v-if="detail.type === 2">
<el-input
v-model="form.folder_token"
:placeholder="
$t('views.application.applicationAccess.larkSetting.folderTokenPlaceholder')
"
/>
</el-form-item>
<div v-if="detail.type === 0">
<h4 class="title-decoration-1 mb-16">
{{ $t('common.otherSetting') }}
</h4>
</div>
<el-form-item :label="$t('上传的每个文档最大限制')">
<el-slider
v-model="form.file_count_limit"
show-input
:show-input-controls="false"
:min="1"
:max="1000"
class="custom-slider"
/>
</el-form-item>
</el-form>
<div class="text-right">
<el-button @click="submit" type="primary"> {{ $t('common.save') }}</el-button>
</div>
</div>
</el-scrollbar>
</div>
</el-card>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, reactive } from 'vue'
import { useRoute } from 'vue-router'
import BaseForm from '@/views/resource-management/knowledge/component/BaseForm.vue'
import KnowledgeApi from '@/api/resource-management/knowledge'
import type { ApplicationFormType } from '@/api/type/application'
import { MsgSuccess, MsgConfirm } from '@/utils/message'
import { isAppIcon } from '@/utils/common'
import useStore from '@/stores/modules-resource-management'
import { t } from '@/locales'
const route = useRoute()
const {
params: { id },
} = route as any
const { knowledge } = useStore()
const webFormRef = ref()
const BaseFormRef = ref()
const loading = ref(false)
const detail = ref<any>({})
const cloneModelId = ref('')
const form = ref<any>({
source_url: '',
selector: '',
app_id: '',
app_secret: '',
folder_token: '',
file_count_limit: 100,
})
const rules = reactive({
source_url: [
{
required: true,
message: t('views.knowledge.form.source_url.requiredMessage'),
trigger: 'blur',
},
],
app_id: [
{
required: true,
message: t('views.application.applicationAccess.larkSetting.appIdPlaceholder'),
trigger: 'blur',
},
],
app_secret: [
{
required: true,
message: t('views.application.applicationAccess.larkSetting.appSecretPlaceholder'),
trigger: 'blur',
},
],
folder_token: [
{
required: true,
message: t('views.application.applicationAccess.larkSetting.folderTokenPlaceholder'),
trigger: 'blur',
},
],
})
async function submit() {
if (await BaseFormRef.value?.validate()) {
await webFormRef.value.validate((valid: any) => {
if (valid) {
const obj =
detail.value.type === 1 || detail.value.type === 2
? {
meta: form.value,
...BaseFormRef.value.form,
}
: {
...BaseFormRef.value.form,
}
if (cloneModelId.value !== BaseFormRef.value.form.embedding_mode_id) {
MsgConfirm(t('common.tip'), t('views.knowledge.tip.updateModeMessage'), {
confirmButtonText: t('views.knowledge.setting.vectorization'),
})
.then(() => {
if (detail.value.type === 2) {
// KnowledgeApi.putLarkKnowledge(id, obj, loading).then((res) => {
// KnowledgeApi.putReEmbeddingKnowledge(id).then(() => {
// MsgSuccess(t('common.saveSuccess'))
// })
// })
} else {
KnowledgeApi.putKnowledge(id, obj, loading).then((res) => {
KnowledgeApi.putReEmbeddingKnowledge(id).then(() => {
MsgSuccess(t('common.saveSuccess'))
})
})
}
})
.catch(() => {})
} else {
if (detail.value.type === 2) {
// KnowledgeApi.putLarkKnowledge(id, obj, loading).then((res) => {
// KnowledgeApi.putReEmbeddingKnowledge(id).then(() => {
// MsgSuccess(t('common.saveSuccess'))
// })
// })
} else {
KnowledgeApi.putKnowledge(id, obj, loading).then((res) => {
MsgSuccess(t('common.saveSuccess'))
})
}
}
}
})
}
}
function getDetail() {
knowledge.asyncGetKnowledgeDetail(id, loading).then((res: any) => {
detail.value = res.data
cloneModelId.value = res.data?.embedding_mode_id
if (detail.value.type === '1' || detail.value.type === '2') {
form.value = res.data.meta
}
})
}
onMounted(() => {
getDetail()
})
</script>
<style lang="scss" scoped>
.knowledge-setting {
width: 70%;
margin: 0 auto;
}
</style>

View File

@ -1,147 +0,0 @@
<template>
<el-form
ref="FormRef"
:model="form"
:rules="rules"
label-position="top"
require-asterisk-position="right"
v-loading="loading"
>
<el-form-item :label="$t('views.knowledge.form.knowledgeName.label')" prop="name">
<el-input
v-model="form.name"
:placeholder="$t('views.knowledge.form.knowledgeName.placeholder')"
maxlength="64"
show-word-limit
@blur="form.name = form.name.trim()"
/>
</el-form-item>
<el-form-item :label="$t('views.knowledge.form.knowledgeDescription.label')" prop="desc">
<el-input
v-model="form.desc"
type="textarea"
:placeholder="$t('views.knowledge.form.knowledgeDescription.placeholder')"
maxlength="256"
show-word-limit
:autosize="{ minRows: 3 }"
@blur="form.desc = form.desc.trim()"
/>
</el-form-item>
<el-form-item
:label="$t('views.knowledge.form.EmbeddingModel.label')"
prop="embedding_model_id"
>
<ModelSelect
v-model="form.embedding_model_id"
:placeholder="$t('views.knowledge.form.EmbeddingModel.placeholder')"
:options="modelOptions"
:model-type="'EMBEDDING'"
showFooter
></ModelSelect>
</el-form-item>
</el-form>
</template>
<script setup lang="ts">
import {ref, reactive, onMounted, onUnmounted, computed, watch} from 'vue'
import {groupBy} from 'lodash'
import useStore from '@/stores/modules-resource-management'
import type {knowledgeData} from '@/api/type/knowledge'
import {t} from '@/locales'
const props = defineProps({
data: {
type: Object,
default: () => {
},
},
})
const {model} = useStore()
const form = ref<knowledgeData>({
name: '',
desc: '',
embedding_model_id: '',
})
const rules = reactive({
name: [
{
required: true,
message: t('views.knowledge.form.knowledgeName.requiredMessage'),
trigger: 'blur',
},
],
desc: [
{
required: true,
message: t('views.knowledge.form.knowledgeDescription.requiredMessage'),
trigger: 'blur',
},
],
embedding_model_id: [
{
required: true,
message: t('views.knowledge.form.EmbeddingModel.requiredMessage'),
trigger: 'change',
},
],
})
const FormRef = ref()
const loading = ref(false)
const modelOptions = ref<any>([])
watch(
() => props.data,
(value) => {
if (value && JSON.stringify(value) !== '{}') {
form.value.name = value.name
form.value.desc = value.desc
form.value.embedding_model_id = value.embedding_model_id
}
},
{
immediate: true,
},
)
/*
表单校验
*/
function validate() {
if (!FormRef.value) return
return FormRef.value.validate((valid: any) => {
return valid
})
}
function getSelectModel() {
loading.value = true
model
.asyncGetSelectModel({model_type: 'EMBEDDING'})
.then((res: any) => {
modelOptions.value = groupBy(res?.data, 'provider')
loading.value = false
})
.catch(() => {
loading.value = false
})
}
onMounted(() => {
getSelectModel()
})
onUnmounted(() => {
form.value = {
name: '',
desc: '',
embedding_model_id: '',
}
FormRef.value?.clearValidate()
})
defineExpose({
validate,
form,
})
</script>
<style scoped lang="scss"></style>

View File

@ -1,135 +0,0 @@
<template>
<el-dialog
:title="$t('views.paragraph.editParagraph')"
v-model="dialogVisible"
width="80%"
destroy-on-close
class="paragraph-dialog"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<el-row v-if="isConnect">
<el-col :span="18" class="p-24">
<ParagraphForm ref="paragraphFormRef" :data="detail" :isEdit="true" />
</el-col>
<el-col :span="6" class="border-l" style="width: 300px">
<p class="bold title p-24" style="padding-bottom: 0">
<span class="flex align-center">
<span>{{ $t('views.paragraph.relatedProblem.title') }}</span>
<el-divider direction="vertical" class="mr-4" />
<el-button text @click="addProblem">
<el-icon><Plus /></el-icon>
</el-button>
</span>
</p>
<el-scrollbar height="500px">
<div class="p-24" style="padding-top: 16px">
<el-input
v-if="isAddProblem"
v-model="problemValue"
:placeholder="$t('views.paragraph.relatedProblem.placeholder')"
@change="addProblemHandle"
@blur="isAddProblem = false"
ref="inputRef"
class="mb-8"
/>
<template v-for="(item, index) in detail.problem_list" :key="index">
<TagEllipsis
@close="delProblemHandle(item, index)"
class="question-tag"
type="info"
effect="plain"
closable
>
<auto-tooltip :content="item.content">
{{ item.content }}
</auto-tooltip>
</TagEllipsis>
</template>
</div>
</el-scrollbar>
</el-col>
</el-row>
<div v-else class="p-24">
<ParagraphForm ref="paragraphFormRef" :data="detail" :isEdit="true" />
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
<el-button type="primary" @click="submitHandle"> {{ $t('common.save') }} </el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, watch, nextTick } from 'vue'
import { cloneDeep } from 'lodash'
import ParagraphForm from '@/views/resource-management/paragraph/component/ParagraphForm.vue'
const props = defineProps({
isConnect: Boolean
})
const emit = defineEmits(['updateContent'])
const dialogVisible = ref<boolean>(false)
const detail = ref<any>({})
const paragraphFormRef = ref()
const inputRef = ref()
const isAddProblem = ref(false)
const problemValue = ref('')
watch(dialogVisible, (bool) => {
if (!bool) {
detail.value = {}
}
})
const open = (data: any) => {
detail.value = cloneDeep(data)
dialogVisible.value = true
}
function delProblemHandle(item: any, index: number) {
detail.value.problem_list.splice(index, 1)
}
function addProblemHandle() {
if (problemValue.value.trim()) {
if (
!detail.value?.problem_list.some((item: any) => item.content === problemValue.value.trim())
) {
detail.value?.problem_list?.push({
content: problemValue.value.trim()
})
}
problemValue.value = ''
isAddProblem.value = false
}
}
function addProblem() {
isAddProblem.value = true
nextTick(() => {
inputRef.value?.focus()
})
}
const submitHandle = async () => {
if (await paragraphFormRef.value?.validate()) {
emit('updateContent', {
problem_list: detail.value.problem_list,
...paragraphFormRef.value?.form
})
dialogVisible.value = false
}
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@ -1,109 +0,0 @@
<template>
<div>
<InfiniteScroll
:size="paragraph_list.length"
:total="modelValue.length"
:page_size="page_size"
v-model:current_page="current_page"
@load="next()"
:loading="loading"
>
<el-card
v-for="(child, cIndex) in paragraph_list"
:key="cIndex"
shadow="never"
class="card-never mb-16"
>
<div class="flex-between">
<span>{{ child.title || '-' }}</span>
<div>
<!-- 编辑分段按钮 -->
<el-button link @click="editHandle(child, cIndex)">
<el-icon><EditPen /></el-icon>
</el-button>
<!-- 删除分段按钮 -->
<el-button link @click="deleteHandle(child, cIndex)">
<el-icon><Delete /></el-icon>
</el-button>
</div>
</div>
<div class="lighter mt-12">
{{ child.content }}
</div>
<div class="lighter mt-12">
<el-text type="info">
{{ child.content.length }} {{ $t('views.paragraph.character_count') }}
</el-text>
</div>
</el-card>
</InfiniteScroll>
<EditParagraphDialog
ref="EditParagraphDialogRef"
@updateContent="updateContent"
:isConnect="isConnect"
/>
</div>
</template>
<script setup lang="ts">
import { cloneDeep } from 'lodash'
import { ref, computed } from 'vue'
import EditParagraphDialog from './EditParagraphDialog.vue'
import { MsgConfirm } from '@/utils/message'
import { t } from '@/locales'
const page_size = ref<number>(30)
const current_page = ref<number>(1)
const currentCIndex = ref<number>(0)
const EditParagraphDialogRef = ref()
const emit = defineEmits(['update:modelValue'])
const loading = ref<boolean>(false)
const editHandle = (item: any, cIndex: number) => {
currentCIndex.value = cIndex
EditParagraphDialogRef.value.open(item)
}
const props = defineProps<{ modelValue: Array<any>; isConnect: boolean }>()
const paragraph_list = computed(() => {
return props.modelValue.slice(0, page_size.value * (current_page.value - 1) + page_size.value)
})
const next = () => {
loading.value = true
current_page.value += 1
loading.value = false
}
const updateContent = (data: any) => {
const new_value = [...props.modelValue]
if (
props.isConnect &&
data.title &&
!data?.problem_list.some((item: any) => item.content === data.title.trim())
) {
data['problem_list'].push({
content: data.title.trim()
})
}
new_value[currentCIndex.value] = cloneDeep(data)
emit('update:modelValue', new_value)
}
const deleteHandle = (item: any, cIndex: number) => {
MsgConfirm(
`${t('views.paragraph.delete.confirmTitle')}${item.title || '-'} ?`,
t('views.paragraph.delete.confirmMessage'),
{
confirmButtonText: t('common.confirm'),
confirmButtonClass: 'color-danger'
}
)
.then(() => {
const new_value = [...props.modelValue]
new_value.splice(cIndex, 1)
emit('update:modelValue', new_value)
})
.catch(() => {})
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,70 +0,0 @@
<template>
<el-tabs v-model="activeName" class="paragraph-tabs">
<template v-for="(item, index) in data" :key="index">
<el-tab-pane :label="item.name" :name="index">
<template #label>
<div class="flex-center">
<img :src="getImgUrl(item && item?.name)" alt="" height="16" />
<span class="ml-4">{{ item?.name }}</span>
</div>
</template>
<div class="mb-16">
<el-text type="info"
>{{ item.content.length }} {{ $t('views.paragraph.title') }}</el-text
>
</div>
<div class="paragraph-list" v-if="activeName == index">
<el-scrollbar>
<ParagraphList v-model="item.content" :isConnect="isConnect"> </ParagraphList>
</el-scrollbar>
</div>
</el-tab-pane>
</template>
</el-tabs>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { getImgUrl } from '@/utils/utils'
import ParagraphList from './ParagraphList.vue'
defineProps({
data: {
type: Array<any>,
default: () => []
},
isConnect: Boolean
})
const activeName = ref(0)
</script>
<style scoped lang="scss">
.paragraph-tabs {
:deep(.el-tabs__item) {
background: var(--app-text-color-light-1);
margin: 4px;
border-radius: 4px;
padding: 5px 10px 5px 8px !important;
height: auto;
&:nth-child(2) {
margin-left: 0;
}
&:last-child {
margin-right: 0;
}
&.is-active {
border: 1px solid var(--el-color-primary);
background: var(--el-color-primary-light-9);
color: var(--el-text-color-primary);
}
}
:deep(.el-tabs__nav-wrap::after) {
display: none;
}
:deep(.el-tabs__active-bar) {
display: none;
}
}
.paragraph-list {
height: calc(var(--create-dataset-height) - 101px);
}
</style>

View File

@ -1,87 +0,0 @@
<template>
<el-dialog
:title="$t('views.knowledge.syncWeb.title')"
v-model="dialogVisible"
width="600px"
:close-on-click-modal="false"
:close-on-press-escape="false"
:destroy-on-close="true"
>
<p class="mb-8">{{ $t('views.knowledge.syncWeb.syncMethod') }}</p>
<el-radio-group v-model="method" class="card__radio">
<el-card shadow="never" class="mb-16" :class="method === 'replace' ? 'active' : ''">
<el-radio value="replace" size="large">
<p class="mb-4">{{ $t('views.knowledge.syncWeb.replace') }}</p>
<el-text type="info">{{ $t('views.knowledge.syncWeb.replaceText') }}</el-text>
</el-radio>
</el-card>
<el-card shadow="never" class="mb-16" :class="method === 'complete' ? 'active' : ''">
<el-radio value="complete" size="large">
<p class="mb-4">{{ $t('views.knowledge.syncWeb.complete') }}</p>
<el-text type="info">{{ $t('views.knowledge.syncWeb.completeText') }}</el-text>
</el-radio>
</el-card>
</el-radio-group>
<p class="color-danger">{{ $t('views.knowledge.syncWeb.tip') }}</p>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
<el-button type="primary" @click="submit" :loading="loading">
{{ $t('common.confirm') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import useStore from '@/stores/modules-resource-management'
const { knowledge } = useStore()
const emit = defineEmits(['refresh'])
const loading = ref<boolean>(false)
const method = ref('replace')
const knowledgeId = ref('')
const dialogVisible = ref<boolean>(false)
watch(dialogVisible, (bool) => {
if (!bool) {
method.value = 'replace'
}
})
const open = (id: string) => {
knowledgeId.value = id
dialogVisible.value = true
}
const submit = () => {
knowledge.asyncSyncKnowledge(knowledgeId.value, method.value, loading).then((res: any) => {
emit('refresh', res.data)
dialogVisible.value = false
})
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
.select-provider {
font-size: 16px;
color: rgba(100, 106, 115, 1);
font-weight: 400;
line-height: 24px;
cursor: pointer;
&:hover {
color: var(--el-color-primary);
}
}
.active-breadcrumb {
font-size: 16px;
color: rgba(31, 35, 41, 1);
font-weight: 500;
line-height: 24px;
}
</style>

View File

@ -1,70 +0,0 @@
<template>
<el-dialog
:title="$t('views.knowledge.knowledgeType.createGeneralKnowledge')"
v-model="dialogVisible"
width="720"
append-to-body
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<!-- 基本信息 -->
<BaseForm ref="BaseFormRef" v-if="dialogVisible" />
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false" :loading="loading">
{{ $t('common.cancel') }}
</el-button>
<el-button type="primary" @click="submitHandle" :loading="loading">
{{ $t('common.create') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, watch, reactive } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import BaseForm from '@/views/resource-management/knowledge/component/BaseForm.vue'
import KnowledgeApi from '@/api/resource-management/knowledge'
import { MsgSuccess, MsgAlert } from '@/utils/message'
import { t } from '@/locales'
const emit = defineEmits(['refresh'])
const router = useRouter()
const BaseFormRef = ref()
const loading = ref(false)
const dialogVisible = ref<boolean>(false)
const currentFolder = ref<any>(null)
watch(dialogVisible, (bool) => {
if (!bool) {
currentFolder.value = null
}
})
const open = (folder: string) => {
currentFolder.value = folder
dialogVisible.value = true
}
const submitHandle = async () => {
if (await BaseFormRef.value?.validate()) {
const obj = {
folder_id: currentFolder.value?.id,
...BaseFormRef.value.form,
}
KnowledgeApi.postKnowledge(obj, loading).then((res) => {
MsgSuccess(t('common.createSuccess'))
// router.push({ path: `/knowledge/${res.data.id}/${currentFolder.value.id}/document` })
emit('refresh')
})
} else {
return false
}
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@ -1,161 +0,0 @@
<template>
<el-dialog
:title="$t('views.knowledge.knowledgeType.createLarkKnowledge')"
v-model="dialogVisible"
width="720"
append-to-body
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<!-- 基本信息 -->
<BaseForm ref="BaseFormRef" v-if="dialogVisible" />
<el-form
ref="DatasetFormRef"
:rules="rules"
:model="datasetForm"
label-position="top"
require-asterisk-position="right"
>
<el-form-item label="App ID" prop="app_id">
<el-input
v-model="datasetForm.app_id"
:placeholder="$t('views.application.applicationAccess.larkSetting.appIdPlaceholder')"
/>
</el-form-item>
<el-form-item label="App Secret" prop="app_secret">
<el-input
v-model="datasetForm.app_secret"
type="password"
show-password
:placeholder="$t('views.application.applicationAccess.larkSetting.appSecretPlaceholder')"
/>
</el-form-item>
<el-form-item label="Folder Token" prop="folder_token">
<el-input
v-model="datasetForm.folder_token"
:placeholder="
$t('views.application.applicationAccess.larkSetting.folderTokenPlaceholder')
"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false" :loading="loading">
{{ $t('common.cancel') }}
</el-button>
<el-button type="primary" @click="submitHandle" :loading="loading">
{{ $t('common.create') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, watch, reactive } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import BaseForm from '@/views/resource-management/knowledge/component/BaseForm.vue'
import KnowledgeApi from '@/api/resource-management/knowledge'
import { MsgSuccess, MsgAlert } from '@/utils/message'
import { t } from '@/locales'
import { ComplexPermission } from '@/utils/permission/type'
const emit = defineEmits(['refresh'])
const router = useRouter()
const BaseFormRef = ref()
const DatasetFormRef = ref()
const loading = ref(false)
const dialogVisible = ref<boolean>(false)
const datasetForm = ref<any>({
type: '0',
source_url: '',
selector: '',
app_id: '',
app_secret: '',
folder_token: '',
})
const rules = reactive({
source_url: [
{
required: true,
message: t('views.knowledge.form.source_url.requiredMessage'),
trigger: 'blur',
},
],
app_id: [
{
required: true,
message: t('views.application.applicationAccess.larkSetting.appIdPlaceholder'),
trigger: 'blur',
},
],
app_secret: [
{
required: true,
message: t('views.application.applicationAccess.larkSetting.appSecretPlaceholder'),
trigger: 'blur',
},
],
folder_token: [
{
required: true,
message: t('views.application.applicationAccess.larkSetting.folderTokenPlaceholder'),
trigger: 'blur',
},
],
user_id: [
{
required: true,
message: t('views.knowledge.form.user_id.requiredMessage'),
trigger: 'blur',
},
],
token: [
{
required: true,
message: t('views.knowledge.form.token.requiredMessage'),
trigger: 'blur',
},
],
})
watch(dialogVisible, (bool) => {
if (!bool) {
datasetForm.value = {
type: '0',
source_url: '',
selector: '',
}
DatasetFormRef.value?.clearValidate()
}
})
const open = () => {
dialogVisible.value = true
}
const submitHandle = async () => {
if (await BaseFormRef.value?.validate()) {
await DatasetFormRef.value.validate((valid: any) => {
if (valid) {
const obj = { ...BaseFormRef.value.form, ...datasetForm.value }
// KnowledgeApi.postLarkKnowledge(obj, loading).then((res) => {
// MsgSuccess(t('common.createSuccess'))
// router.push({ path: `/knowledge/${res.data.id}/document` })
// emit('refresh')
// })
} else {
return false
}
})
} else {
return false
}
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@ -1,120 +0,0 @@
<template>
<el-dialog
:title="$t('views.knowledge.knowledgeType.createGeneralKnowledge')"
v-model="dialogVisible"
width="720"
append-to-body
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<!-- 基本信息 -->
<BaseForm ref="BaseFormRef" v-if="dialogVisible" />
<el-form
ref="KnowledgeFormRef"
:rules="rules"
:model="knowledgeForm"
label-position="top"
require-asterisk-position="right"
>
<el-form-item :label="$t('views.knowledge.form.source_url.label')" prop="source_url">
<el-input
v-model="knowledgeForm.source_url"
:placeholder="$t('views.knowledge.form.source_url.placeholder')"
@blur="knowledgeForm.source_url = knowledgeForm.source_url.trim()"
/>
</el-form-item>
<el-form-item :label="$t('views.knowledge.form.selector.label')">
<el-input
v-model="knowledgeForm.selector"
:placeholder="$t('views.knowledge.form.selector.placeholder')"
@blur="knowledgeForm.selector = knowledgeForm.selector.trim()"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false" :loading="loading">
{{ $t('common.cancel') }}
</el-button>
<el-button type="primary" @click="submitHandle" :loading="loading">
{{ $t('common.create') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, watch, reactive } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import BaseForm from '@/views/resource-management/knowledge/component/BaseForm.vue'
import KnowledgeApi from '@/api/resource-management/knowledge'
import { MsgSuccess, MsgAlert } from '@/utils/message'
import { t } from '@/locales'
const emit = defineEmits(['refresh'])
const router = useRouter()
const BaseFormRef = ref()
const KnowledgeFormRef = ref()
const loading = ref(false)
const dialogVisible = ref<boolean>(false)
const knowledgeForm = ref<any>({
source_url: '',
selector: '',
})
const rules = reactive({
source_url: [
{
required: true,
message: t('views.knowledge.form.source_url.requiredMessage'),
trigger: 'blur',
},
],
})
const currentFolder = ref<any>(null)
watch(dialogVisible, (bool) => {
if (!bool) {
currentFolder.value = null
knowledgeForm.value = {
source_url: '',
selector: '',
}
KnowledgeFormRef.value?.clearValidate()
}
})
const open = (folder: string) => {
currentFolder.value = folder
dialogVisible.value = true
}
const submitHandle = async () => {
if (await BaseFormRef.value?.validate()) {
await KnowledgeFormRef.value.validate((valid: any) => {
if (valid) {
const obj = {
folder_id: currentFolder.value?.id,
...BaseFormRef.value.form,
...knowledgeForm.value,
}
KnowledgeApi.postWebKnowledge(obj, loading).then((res) => {
MsgSuccess(t('common.createSuccess'))
router.push({ path: `/knowledge/resource/${res.data.id}/documentResource` })
emit('refresh')
})
} else {
return false
}
})
} else {
return false
}
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@ -1,450 +0,0 @@
<template>
<div class="resource-manage_knowledge">
<div class="shared-header">
<span class="title">{{ t('views.system.resource_management.label') }}</span>
<el-icon size="12">
<rightOutlined></rightOutlined>
</el-icon>
<span class="sub-title">{{ t('views.knowledge.title') }}</span>
</div>
<div class="table-content">
<div class="flex-between complex-search">
<el-select
class="complex-search__left"
v-model="search_type"
style="width: 120px"
@change="search_type_change"
>
<el-option :label="$t('common.creator')" value="create_user" />
<el-option :label="$t('common.name')" value="name" />
</el-select>
<el-input
v-if="search_type === 'name'"
v-model="search_form.name"
@change="getList"
:placeholder="$t('common.searchBar.placeholder')"
style="width: 220px"
clearable
/>
<el-select
v-else-if="search_type === 'create_user'"
v-model="search_form.create_user"
@change="getList"
clearable
style="width: 220px"
>
<el-option v-for="u in user_options" :key="u.id" :value="u.id" :label="u.username" />
</el-select>
</div>
<div class="table-knowledge">
<el-table height="100%" :data="knowledgeList" style="width: 100%">
<el-table-column type="selection" width="55" />
<el-table-column width="220" :label="$t('common.name')">
<template #default="scope">
<div class="table-name flex align-center">
<el-icon size="24">
<KnowledgeIcon size="24" :type="scope.row.type" />
</el-icon>
{{ scope.row.name }}
</div>
</template>
</el-table-column>
<el-table-column
property="type"
:label="$t('views.application.form.appType.label')"
width="120"
/>
<el-table-column width="100" property="workspace_name">
<template #header>
<div class="flex align-center">
{{ $t('views.role.member.workspace') }}
<el-popover placement="bottom">
<template #reference
><el-icon style="margin-left: 4px; cursor: pointer" size="16">
<AppIcon iconName="app-filter_outlined"></AppIcon> </el-icon
></template>
<div>
<el-checkbox
v-model="checkAll"
:indeterminate="isIndeterminate"
@change="handleCheckAllChange"
>
{{ $t('views.document.feishu.allCheck') }}
</el-checkbox>
<el-checkbox-group
v-model="checkedWorkspaces"
@change="handleCheckedWorkspacesChange"
>
<el-checkbox
v-for="workspace in workspaces"
:key="workspace"
:label="workspace"
:value="workspace"
>
{{ workspace }}
</el-checkbox>
</el-checkbox-group>
</div>
</el-popover>
</div>
</template>
</el-table-column>
<el-table-column property="nick_name" :label="$t('common.creator')" />
<el-table-column
property="update_time"
sortable
width="180"
:formatter="formatter"
:label="$t('views.document.table.updateTime')"
/>
<el-table-column
width="180"
property="create_time"
sortable
:formatter="formatter"
:label="$t('common.createTime')"
/>
<el-table-column
class-name="operation-column_text"
width="120"
fixed="right"
:label="$t('common.operation')"
>
<template #default="scope">
<el-button
@click="
router.push({
path: `/knowledge/resource/${scope.row.id}/documentResource`,
})
"
text
type="primary"
>
<el-icon size="16">
<AppIcon iconName="app-icon-blue"></AppIcon>
</el-icon>
</el-button>
<el-button @click="reEmbeddingKnowledge(scope.row)" text type="primary">
<el-icon size="16">
<AppIcon iconName="app-vectorization"></AppIcon>
</el-icon>
</el-button>
<el-dropdown trigger="click">
<el-button text @click.stop>
<el-icon size="16">
<MoreFilled />
</el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
icon="Refresh"
@click.stop="syncKnowledge(scope.row)"
v-if="scope.row.type === 1"
>{{ $t('views.knowledge.setting.sync') }}
</el-dropdown-item>
<el-dropdown-item
icon="Connection"
@click.stop="openGenerateDialog(scope.row)"
>{{ $t('views.document.generateQuestion.title') }}</el-dropdown-item
>
<el-dropdown-item @click.stop="exportKnowledge(scope.row)">
<AppIcon iconName="app-export"></AppIcon
>{{ $t('views.document.setting.export') }} Excel</el-dropdown-item
>
<el-dropdown-item @click.stop="exportZipKnowledge(scope.row)">
<AppIcon iconName="app-export"></AppIcon
>{{ $t('views.document.setting.export') }} ZIP</el-dropdown-item
>
<el-dropdown-item icon="Delete" @click.stop="deleteKnowledge(scope.row)">{{
$t('common.delete')
}}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-table-column>
</el-table>
</div>
<div class="table__pagination mt-16">
<el-pagination
v-model:current-page="paginationConfig.current_page"
v-model:page-size="paginationConfig.page_size"
:page-sizes="pageSizes"
:total="paginationConfig.total"
layout="total, prev, pager, next, sizes"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</div>
<component :is="currentCreateDialog" ref="CreateKnowledgeDialogRef" />
<CreateFolderDialog ref="CreateFolderDialogRef" @refresh="refreshFolder" />
<GenerateRelatedDialog ref="GenerateRelatedDialogRef" />
</template>
<script lang="ts" setup>
import { onMounted, ref, reactive, shallowRef, nextTick } from 'vue'
import CreateKnowledgeDialog from './create-component/CreateKnowledgeDialog.vue'
import CreateWebKnowledgeDialog from './create-component/CreateWebKnowledgeDialog.vue'
import CreateLarkKnowledgeDialog from './create-component/CreateLarkKnowledgeDialog.vue'
import CreateFolderDialog from '@/components/folder-tree/CreateFolderDialog.vue'
import GenerateRelatedDialog from '@/components/generate-related-dialog/index.vue'
import KnowledgeApi from '@/api/resource-management/knowledge'
import { MsgSuccess, MsgConfirm } from '@/utils/message'
import useStore from '@/stores/modules-resource-management'
import { numberFormat } from '@/utils/common'
import iconMap from '@/components/app-icon/icons/common'
import { t } from '@/locales'
import { useRouter } from 'vue-router'
import type { CheckboxValueType } from 'element-plus'
const router = useRouter()
const { folder } = useStore()
let knowledgeListbp = []
const loading = ref(false)
const search_type = ref('name')
const search_form = ref<any>({
name: '',
create_user: '',
})
const user_options = ref<any[]>([])
const paginationConfig = reactive({
current_page: 1,
page_size: 30,
total: 0,
})
const pageSizes = [10, 20, 50, 100]
const folderList = ref<any[]>([])
const knowledgeList = ref<any[]>([])
const currentFolder = ref<any>({})
const rightOutlined = iconMap['right-outlined'].iconReader()
const CreateKnowledgeDialogRef = ref()
const currentCreateDialog = shallowRef<any>(null)
const checkAll = ref(false)
const isIndeterminate = ref(true)
const checkedWorkspaces = ref([])
let workspaces = []
const handleCheckAllChange = (val: CheckboxValueType) => {
checkedWorkspaces.value = val ? workspaces : []
isIndeterminate.value = false
knowledgeList.value = val ? [...knowledgeListbp] : []
}
const handleCheckedWorkspacesChange = (value: CheckboxValueType[]) => {
const checkedCount = value.length
checkAll.value = checkedCount === workspaces.length
isIndeterminate.value = checkedCount > 0 && checkedCount < workspaces.length
knowledgeList.value = knowledgeListbp.filter((ele) => value.includes(ele.workspace_id))
}
const handleSizeChange = (val) => {
console.log(val)
}
const handleCurrentChange = (val) => {
console.log(val)
}
function openCreateDialog(data: any) {
currentCreateDialog.value = data
nextTick(() => {
CreateKnowledgeDialogRef.value.open(currentFolder.value)
})
// common.asyncGetValid(ValidType.Dataset, ValidCount.Dataset, loading).then(async (res: any) => {
// if (res?.data) {
// CreateDatasetDialogRef.value.open()
// } else if (res?.code === 400) {
// MsgConfirm(t('common.tip'), t('views.knowledge.tip.professionalMessage'), {
// cancelButtonText: t('common.confirm'),
// confirmButtonText: t('common.professional'),
// })
// .then(() => {
// window.open('https://maxkb.cn/pricing.html', '_blank')
// })
// .catch(() => {})
// }
// })
}
function reEmbeddingKnowledge(row: any) {
KnowledgeApi.putReEmbeddingKnowledge(row.id).then(() => {
MsgSuccess(t('common.submitSuccess'))
})
}
const SyncWebDialogRef = ref()
function syncKnowledge(row: any) {
SyncWebDialogRef.value.open(row.id)
}
const search_type_change = () => {
search_form.value = { name: '', create_user: '' }
}
function getList() {
console.log(currentFolder.value?.id)
const params = {
folder_id: currentFolder.value?.id || localStorage.getItem('workspace_id'),
[search_type.value]: search_form.value[search_type.value],
}
KnowledgeApi.getKnowledgeListPage(paginationConfig, params, loading).then((res) => {
paginationConfig.total = res.data.total
knowledgeListbp = [...res.data.records]
workspaces = [...new Set(knowledgeListbp.map((ele) => ele.workspace_id))]
checkedWorkspaces.value = [...workspaces]
checkAll.value = true
handleCheckAllChange(true)
})
}
function folderClickHandel(row: any) {
currentFolder.value = row
knowledgeList.value = []
if (currentFolder.value.id === 'share') return
getList()
}
function clickFolder(item: any) {
currentFolder.value.id = item.id
knowledgeList.value = []
getList()
}
const CreateFolderDialogRef = ref()
function openCreateFolder() {
CreateFolderDialogRef.value.open('KNOWLEDGE', currentFolder.value.id)
}
const GenerateRelatedDialogRef = ref<InstanceType<typeof GenerateRelatedDialog>>()
function openGenerateDialog(row: any) {
if (GenerateRelatedDialogRef.value) {
GenerateRelatedDialogRef.value.open([], 'knowledge', row.id)
}
}
const formatter = (_, __, value) => {
return value ? new Date(value).toLocaleString() : '-'
}
const exportKnowledge = (item: any) => {
KnowledgeApi.exportKnowledge(item.name, item.id, loading).then((ok) => {
MsgSuccess(t('common.exportSuccess'))
})
}
const exportZipKnowledge = (item: any) => {
KnowledgeApi.exportZipKnowledge(item.name, item.id, loading).then((ok) => {
MsgSuccess(t('common.exportSuccess'))
})
}
function deleteKnowledge(row: any) {
MsgConfirm(
`${t('views.knowledge.delete.confirmTitle')}${row.name} ?`,
`${t('views.knowledge.delete.confirmMessage1')} ${row.application_mapping_count} ${t('views.knowledge.delete.confirmMessage2')}`,
{
confirmButtonText: t('common.confirm'),
confirmButtonClass: 'color-danger',
},
)
.then(() => {
KnowledgeApi.delKnowledge(row.id, loading).then(() => {
const index = knowledgeList.value.findIndex((v) => v.id === row.id)
knowledgeList.value.splice(index, 1)
MsgSuccess(t('common.deleteSuccess'))
})
})
.catch(() => {})
}
function refreshFolder() {
knowledgeList.value = []
getList()
}
onMounted(() => {
getList()
})
</script>
<style lang="scss" scoped>
.resource-manage_knowledge {
padding: 16px 24px;
.complex-search {
width: 280px;
}
.complex-search__left {
width: 75px;
}
.el-avatar {
--el-avatar-size: 24px;
}
.table-content {
padding: 24px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0px 2px 4px 0px #1f23291f;
margin-top: 16px;
height: calc(100vh - 180px);
.table-knowledge {
height: calc(100% - 100px);
margin-top: 16px;
.table-name {
.el-icon {
margin-right: 8px;
}
}
.operation-column_text {
.el-button.is-text {
--el-button-text-color: #3370ff;
}
.el-button.is-text:not(.is-disabled):hover {
background-color: #3370ff1a;
}
.el-button + .el-button,
.el-button + .el-dropdown {
margin-left: 4px;
}
}
}
.table__pagination {
display: flex;
align-items: center;
justify-content: flex-end;
}
}
.shared-header {
color: #646a73;
font-weight: 400;
font-size: 14px;
line-height: 22px;
display: flex;
align-items: center;
:deep(.el-icon i) {
height: 12px;
}
.sub-title {
color: #1f2329;
}
}
}
</style>

View File

@ -1,195 +0,0 @@
<template>
<el-card
shadow="hover"
class="paragraph-box cursor"
@mouseenter="cardEnter()"
@mouseleave="cardLeave()"
@click.stop="editParagraph(data)"
>
<h2 class="mb-16">{{ data.title || '-' }}</h2>
<div v-show="show" class="mk-sticky">
<el-card
class="paragraph-box-operation mt-8 mr-8"
shadow="always"
style="--el-card-padding: 8px 12px; --el-card-border-radius: 8px"
@click.stop
>
<el-switch
:loading="changeStateloading"
v-model="data.is_active"
:before-change="() => changeState(data)"
size="small"
/>
<el-divider direction="vertical" />
<span class="mr-8">
<el-button link @click="editParagraph(data)">
<el-icon :size="16" :title="$t('views.applicationWorkflow.control.zoomOut')">
<EditPen />
</el-icon>
</el-button>
</span>
<span class="mr-8">
<el-button link>
<el-icon :size="16" :title="$t('views.applicationWorkflow.control.zoomOut')">
<el-icon><CirclePlus /></el-icon>
</el-icon>
</el-button>
</span>
<el-dropdown trigger="click" :teleported="false">
<el-button text>
<el-icon><MoreFilled /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="openGenerateDialog(data)">
<el-icon><Connection /></el-icon>
{{ $t('views.document.generateQuestion.title') }}</el-dropdown-item
>
<el-dropdown-item @click="openSelectDocumentDialog(data)">
<AppIcon iconName="app-migrate"></AppIcon>
{{ $t('views.document.setting.migration') }}</el-dropdown-item
>
<el-dropdown-item icon="Delete" @click.stop="deleteParagraph(data)">{{
$t('common.delete')
}}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-card>
</div>
<MdPreview
ref="editorRef"
editorId="preview-only"
:modelValue="data.content"
class="maxkb-md"
/>
<ParagraphDialog ref="ParagraphDialogRef" :title="title" @refresh="refresh" />
<SelectDocumentDialog ref="SelectDocumentDialogRef" @refresh="refreshMigrateParagraph" />
<GenerateRelatedDialog ref="GenerateRelatedDialogRef" @refresh="refresh" />
</el-card>
</template>
<script setup lang="ts">
import { ref, useSlots } from 'vue'
import { useRoute } from 'vue-router'
import { t } from '@/locales'
import useStore from '@/stores/modules-resource-management'
import GenerateRelatedDialog from '@/components/generate-related-dialog/index.vue'
import ParagraphDialog from '@/views/resource-management/paragraph/component/ParagraphDialog.vue'
import SelectDocumentDialog from '@/views/resource-management/paragraph/component/SelectDocumentDialog.vue'
import { MsgSuccess, MsgConfirm } from '@/utils/message'
const { paragraph } = useStore()
const route = useRoute()
const {
params: { id, documentId },
} = route as any
const props = defineProps<{
data: any
}>()
const emit = defineEmits(['changeState', 'deleteParagraph'])
const loading = ref(false)
const changeStateloading = ref(false)
const show = ref(false)
// carddropdown
const subHovered = ref(false)
function cardEnter() {
show.value = true
subHovered.value = false
}
function cardLeave() {
show.value = subHovered.value
}
function changeState(row: any) {
const obj = {
is_active: !row.is_active,
}
paragraph
.asyncPutParagraph(id, documentId, row.id, obj, changeStateloading)
.then((res) => {
emit('changeState', row.id)
return true
})
.catch(() => {
return false
})
}
const GenerateRelatedDialogRef = ref<InstanceType<typeof GenerateRelatedDialog>>()
function openGenerateDialog(row: any) {
if (GenerateRelatedDialogRef.value) {
GenerateRelatedDialogRef.value.open([], 'paragraph', row.id)
}
}
function openSelectDocumentDialog(row?: any) {
// if (row) {
// multipleSelection.value = [row.id]
// }
// SelectDocumentDialogRef.value.open(multipleSelection.value)
}
function deleteParagraph(row: any) {
MsgConfirm(
`${t('views.paragraph.delete.confirmTitle')} ${row.title || '-'} ?`,
t('views.paragraph.delete.confirmMessage'),
{
confirmButtonText: t('common.confirm'),
confirmButtonClass: 'danger',
},
)
.then(() => {
paragraph.asyncDelParagraph(id, documentId, row.id, loading).then(() => {
emit('deleteParagraph', row.id)
MsgSuccess(t('common.deleteSuccess'))
})
})
.catch(() => {})
}
const SelectDocumentDialogRef = ref()
const ParagraphDialogRef = ref()
const title = ref('')
function editParagraph(row: any) {
title.value = t('views.paragraph.paragraphDetail')
ParagraphDialogRef.value.open(row)
}
function refresh() {}
function refreshMigrateParagraph() {}
</script>
<style lang="scss" scoped>
.paragraph-box {
background: var(--app-layout-bg-color);
border: 1px solid #ffffff;
box-shadow: none !important;
position: relative;
overflow: inherit;
&:hover {
background: rgba(31, 35, 41, 0.1);
border: 1px solid #dee0e3;
}
.paragraph-box-operation {
position: absolute;
right: 0;
top: 0;
overflow: inherit;
border: 1px solid #dee0e3;
z-index: 10;
float: right;
}
.mk-sticky {
height: 0;
position: sticky;
right: 0;
top: 0;
overflow: inherit;
z-index: 10;
}
}
</style>

View File

@ -1,152 +0,0 @@
<template>
<el-dialog
:title="title"
v-model="dialogVisible"
width="80%"
class="paragraph-dialog"
destroy-on-close
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<el-row v-loading="loading">
<el-col :span="18">
<el-scrollbar height="500" wrap-class="paragraph-scrollbar">
<div class="p-24" style="padding-bottom: 8px">
<div style="position: absolute; right: 20px; top: 20px; ">
<el-button text @click="isEdit = true" v-if="problemId && !isEdit">
<el-icon><EditPen /></el-icon>
</el-button>
</div>
<ParagraphForm ref="paragraphFormRef" :data="detail" :isEdit="isEdit" />
</div>
</el-scrollbar>
<div class="text-right p-24 pt-0" v-if="problemId && isEdit">
<el-button @click.prevent="cancelEdit"> {{$t('common.cancel')}} </el-button>
<el-button type="primary" :disabled="loading" @click="handleDebounceClick">
{{$t('common.save')}}
</el-button>
</div>
</el-col>
<el-col :span="6" class="border-l" style="width: 300px">
<!-- 关联问题 -->
<ProblemComponent
:problemId="problemId"
:docId="document_id"
:knowledgeId="dataset_id"
ref="ProblemRef"
/>
</el-col>
</el-row>
<template #footer v-if="!problemId">
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> {{$t('common.cancel')}} </el-button>
<el-button :disabled="loading" type="primary" @click="handleDebounceClick">
{{$t('common.submit')}}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, watch, nextTick } from 'vue'
import { useRoute } from 'vue-router'
import { cloneDeep, debounce } from 'lodash'
import ParagraphForm from '@/views/resource-management/paragraph/component/ParagraphForm.vue'
import ProblemComponent from '@/views/resource-management/paragraph/component/ProblemComponent.vue'
import paragraphApi from '@/api/resource-management/paragraph'
import useStore from '@/stores/modules-resource-management'
const props = defineProps({
title: String
})
const { paragraph } = useStore()
const route = useRoute()
const {
params: { id, documentId }
} = route as any
const emit = defineEmits(['refresh'])
const ProblemRef = ref()
const paragraphFormRef = ref<any>()
const dialogVisible = ref<boolean>(false)
const loading = ref(false)
const problemId = ref('')
const detail = ref<any>({})
const isEdit = ref(false)
const document_id = ref('')
const dataset_id = ref('')
const cloneData = ref(null)
watch(dialogVisible, (bool) => {
if (!bool) {
problemId.value = ''
detail.value = {}
isEdit.value = false
document_id.value = ''
dataset_id.value = ''
cloneData.value = null
}
})
const cancelEdit = () => {
isEdit.value = false
detail.value = cloneDeep(cloneData.value)
}
const open = (data: any) => {
if (data) {
detail.value.title = data.title
detail.value.content = data.content
cloneData.value = cloneDeep(detail.value)
problemId.value = data.id
document_id.value = data.document_id
dataset_id.value = data.dataset_id || id
} else {
isEdit.value = true
}
dialogVisible.value = true
}
const submitHandle = async () => {
if (await paragraphFormRef.value?.validate()) {
loading.value = true
if (problemId.value) {
paragraph
.asyncPutParagraph(
dataset_id.value,
documentId || document_id.value,
problemId.value,
paragraphFormRef.value?.form,
loading
)
.then((res: any) => {
isEdit.value = false
emit('refresh', res.data)
})
} else {
const obj =
ProblemRef.value.problemList.length > 0
? {
problem_list: ProblemRef.value.problemList,
...paragraphFormRef.value?.form
}
: paragraphFormRef.value?.form
paragraphApi.postParagraph(id, documentId, obj, loading).then((res) => {
dialogVisible.value = false
emit('refresh')
})
}
}
}
const handleDebounceClick = debounce(() => {
submitHandle()
}, 200)
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@ -1,174 +0,0 @@
<template>
<el-form
ref="paragraphFormRef"
:model="form"
label-position="top"
require-asterisk-position="right"
:rules="rules"
@submit.prevent
>
<el-form-item :label="$t('views.paragraph.form.paragraphTitle.label')">
<el-input
v-if="isEdit"
v-model="form.title"
:placeholder="$t('views.paragraph.form.paragraphTitle.placeholder')"
maxlength="256"
show-word-limit
>
</el-input>
<span class="lighter" v-else>{{ form.title || '-' }}</span>
</el-form-item>
<el-form-item :label="$t('views.paragraph.form.content.label')" prop="content">
<MdEditor
v-if="isEdit"
v-model="form.content"
:placeholder="$t('views.paragraph.form.content.placeholder')"
:maxLength="100000"
:preview="false"
:toolbars="toolbars"
style="height: 300px"
@onUploadImg="onUploadImg"
:footers="footers"
>
<template #defFooters>
<span style="margin-left: -6px">/ 100000</span>
</template>
</MdEditor>
<MdPreview
v-else
ref="editorRef"
editorId="preview-only"
:modelValue="form.content"
class="maxkb-md"
/>
</el-form-item>
</el-form>
</template>
<script setup lang="ts">
import { ref, reactive, onUnmounted, watch } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
import imageApi from '@/api/image'
import { t } from '@/locales'
const props = defineProps({
data: {
type: Object,
default: () => {}
},
isEdit: Boolean
})
const toolbars = [
'bold',
'underline',
'italic',
'-',
'title',
'strikeThrough',
'sub',
'sup',
'quote',
'unorderedList',
'orderedList',
'task',
'-',
'codeRow',
'code',
'link',
'image',
'table',
'mermaid',
'katex',
'-',
'revoke',
'next',
'=',
'pageFullscreen',
'preview',
'htmlPreview'
] as any[]
const footers = ['markdownTotal', 0, '=', 1, 'scrollSwitch']
const editorRef = ref()
const form = ref<any>({
title: '',
content: ''
})
const rules = reactive<FormRules>({
content: [
{ required: true, message: t('views.paragraph.form.content.requiredMessage1'), trigger: 'blur' },
{ max: 100000, message: t('views.paragraph.form.content.requiredMessage2'), trigger: 'blur' }
]
})
const paragraphFormRef = ref<FormInstance>()
watch(
() => props.data,
(value) => {
if (value && JSON.stringify(value) !== '{}') {
form.value.title = value.title
form.value.content = value.content
}
},
{
immediate: true
}
)
watch(
() => props.isEdit,
(value) => {
if (!value) {
paragraphFormRef.value?.clearValidate()
}
},
{
immediate: true
}
)
/*
表单校验
*/
function validate() {
if (!paragraphFormRef.value) return
return paragraphFormRef.value.validate((valid: any) => {
return valid
})
}
const onUploadImg = async (files: any, callback: any) => {
const res = await Promise.all(
files.map((file: any) => {
return new Promise((rev, rej) => {
const fd = new FormData()
fd.append('file', file)
imageApi
.postImage(fd)
.then((res: any) => {
rev(res)
})
.catch((error) => rej(error))
})
})
)
callback(res.map((item) => item.data))
}
onUnmounted(() => {
form.value = {
title: '',
content: ''
}
})
defineExpose({
validate,
form
})
</script>
<style scoped lang="scss"></style>

View File

@ -1,200 +0,0 @@
<template>
<p class="bold title p-24" style="padding-bottom: 0">
<span class="flex align-center">
<span>{{ $t('views.paragraph.relatedProblem.title') }}</span>
<el-divider direction="vertical" class="mr-4" />
<el-button text @click="addProblem">
<el-icon><Plus /></el-icon>
</el-button>
</span>
</p>
<div v-loading="loading">
<el-scrollbar height="500px">
<div class="p-24" style="padding-top: 16px">
<el-select
v-if="isAddProblem"
v-model="problemValue"
filterable
allow-create
default-first-option
:reserve-keyword="false"
:placeholder="$t('views.paragraph.relatedProblem.placeholder')"
remote
:remote-method="remoteMethod"
:loading="optionLoading"
@change="addProblemHandle"
@blur="isAddProblem = false"
class="mb-16"
popper-class="select-popper"
:popper-append-to-body="false"
>
<el-option
v-for="item in problemOptions"
:key="item.id"
:label="item.content"
:value="item.id"
>
{{ item.content }}
</el-option>
</el-select>
<template v-for="(item, index) in problemList" :key="index">
<TagEllipsis
@close="delProblemHandle(item, index)"
class="question-tag"
type="info"
effect="plain"
closable
>
<auto-tooltip :content="item.content">
{{ item.content }}
</auto-tooltip>
</TagEllipsis>
</template>
</div>
</el-scrollbar>
</div>
</template>
<script setup lang="ts">
import { ref, nextTick, onMounted, onUnmounted, watch } from 'vue'
import { useRoute } from 'vue-router'
import paragraphApi from '@/api/resource-management/paragraph'
import useStore from '@/stores/modules-resource-management'
const props = defineProps({
problemId: String,
docId: String,
knowledgeId: String,
})
const route = useRoute()
const {
params: { id, documentId }, // idknowledgeId
} = route as any
const { problem, paragraph } = useStore()
const inputRef = ref()
const loading = ref(false)
const isAddProblem = ref(false)
const problemValue = ref('')
const problemList = ref<any[]>([])
const problemOptions = ref<any[]>([])
const optionLoading = ref(false)
watch(
() => props.problemId,
(value) => {
if (value) {
getProblemList()
}
},
{
immediate: true,
},
)
function delProblemHandle(item: any, index: number) {
if (item.id) {
paragraph
.asyncDisassociationProblem(
props.knowledgeId || id,
documentId || props.docId,
props.problemId || '',
item.id,
loading,
)
.then((res: any) => {
getProblemList()
})
} else {
problemList.value.splice(index, 1)
}
}
function getProblemList() {
loading.value = true
paragraphApi
.getParagraphProblem(props.knowledgeId || id, documentId || props.docId, props.problemId || '')
.then((res) => {
problemList.value = res.data
loading.value = false
})
.catch(() => {
loading.value = false
})
}
function addProblem() {
isAddProblem.value = true
nextTick(() => {
inputRef.value?.focus()
})
}
function addProblemHandle(val: string) {
if (props.problemId) {
const api = problemOptions.value.some((option) => option.id === val)
? paragraph.asyncAssociationProblem(
props.knowledgeId || id,
documentId || props.docId,
props.problemId,
val,
loading,
)
: paragraphApi.postParagraphProblem(
props.knowledgeId || id,
documentId || props.docId,
props.problemId,
{
content: val,
},
loading,
)
api.then(() => {
getProblemList()
problemValue.value = ''
isAddProblem.value = false
})
} else {
const problem = problemOptions.value.find((option) => option.id === val)
const content = problem ? problem.content : val
if (!problemList.value.some((item) => item.content === content)) {
problemList.value.push({ content: content })
}
problemValue.value = ''
isAddProblem.value = false
}
}
const remoteMethod = (query: string) => {
getProblemOption(query)
}
function getProblemOption(filterText?: string) {
return problem
.asyncGetProblem(
props.knowledgeId || (id as string),
{ current_page: 1, page_size: 100 },
filterText && { content: filterText },
optionLoading,
)
.then((res: any) => {
problemOptions.value = res.data.records
})
}
onMounted(() => {
getProblemOption()
})
onUnmounted(() => {
problemList.value = []
problemValue.value = ''
isAddProblem.value = false
})
defineExpose({
problemList,
})
</script>
<style scoped lang="scss"></style>

View File

@ -1,158 +0,0 @@
<template>
<el-dialog
:title="`${$t('views.chatLog.selectKnowledge')}/${$t('common.fileUpload.document')}`"
v-model="dialogVisible"
width="500"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<el-form
ref="formRef"
:model="form"
label-position="top"
require-asterisk-position="right"
:rules="rules"
@submit.prevent
>
<el-form-item :label="$t('views.chatLog.selectKnowledge')" prop="dataset_id">
<el-select
v-model="form.dataset_id"
filterable
:placeholder="$t('views.chatLog.selectKnowledgePlaceholder')"
:loading="optionLoading"
@change="changeDataset"
>
<el-option v-for="item in datasetList" :key="item.id" :label="item.name" :value="item.id">
<span class="flex align-center">
<KnowledgeIcon v-if="!item.dataset_id" :type="item.type" />
{{ item.name }}
</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('views.chatLog.saveToDocument')" prop="document_id">
<el-select
v-model="form.document_id"
filterable
:placeholder="$t('views.chatLog.documentPlaceholder')"
:loading="optionLoading"
>
<el-option
v-for="item in documentList"
:key="item.id"
:label="item.name"
:value="item.id"
>
{{ item.name }}
</el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
<el-button type="primary" @click="submitForm(formRef)" :loading="loading">
{{ $t('views.document.setting.migration') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, watch, reactive } from 'vue'
import { useRoute } from 'vue-router'
import type { FormInstance, FormRules } from 'element-plus'
import paragraphApi from '@/api/resource-management/paragraph'
import useStore from '@/stores/modules-resource-management'
import { t } from '@/locales'
const { knowledge, document } = useStore()
const route = useRoute()
const {
params: { id, documentId },
} = route as any
const emit = defineEmits(['refresh'])
const formRef = ref()
const dialogVisible = ref<boolean>(false)
const loading = ref(false)
const form = ref<any>({
dataset_id: '',
document_id: '',
})
const rules = reactive<FormRules>({
dataset_id: [
{ required: true, message: t('views.chatLog.selectKnowledgePlaceholder'), trigger: 'change' },
],
document_id: [{ required: true, message: t('views.chatLog.documentPlaceholder'), trigger: 'change' }],
})
const datasetList = ref<any[]>([])
const documentList = ref<any[]>([])
const optionLoading = ref(false)
const paragraphList = ref<string[]>([])
watch(dialogVisible, (bool) => {
if (!bool) {
form.value = {
dataset_id: '',
document_id: '',
}
datasetList.value = []
documentList.value = []
paragraphList.value = []
formRef.value?.clearValidate()
}
})
function changeDataset(id: string) {
form.value.document_id = ''
getDocument(id)
}
function getDocument(id: string) {
document.asyncGetAllDocument(id, loading).then((res: any) => {
documentList.value = res.data?.filter((v: any) => v.id !== documentId)
})
}
function getDataset() {
knowledge.asyncGetFolderKnowledge(loading).then((res: any) => {
datasetList.value = res.data
})
}
const open = (list: any) => {
paragraphList.value = list
getDataset()
formRef.value?.clearValidate()
dialogVisible.value = true
}
const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
paragraphApi
.putMigrateMulParagraph(
id,
documentId,
form.value.dataset_id,
form.value.document_id,
paragraphList.value,
loading,
)
.then(() => {
emit('refresh')
dialogVisible.value = false
})
}
})
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@ -1,375 +0,0 @@
<template>
<div class="paragraph p-12-24">
<div class="flex align-center" style="width: 78%">
<back-button to="-1" style="margin-left: -4px"></back-button>
<h3 style="display: inline-block">{{ documentDetail?.name }}</h3>
<el-text type="info" v-if="documentDetail?.type === '1'"
>{{ $t('views.document.form.source_url.label') }}<el-link
:href="documentDetail?.meta?.source_url"
target="_blank"
>
<span class="break-all">{{ documentDetail?.meta?.source_url }} </span></el-link
>
</el-text>
</div>
<div class="header-button">
<el-button @click="batchSelectedHandle(true)" v-if="isBatch === false">
{{ $t('views.paragraph.setting.batchSelected') }}
</el-button>
<el-button @click="batchSelectedHandle(false)" v-if="isBatch === true">
{{ $t('views.paragraph.setting.cancelSelected') }}
</el-button>
<el-button @click="addParagraph" type="primary" :disabled="loading" v-if="isBatch === false">
{{ $t('views.paragraph.addParagraph') }}
</el-button>
</div>
<el-card
style="--el-card-padding: 0"
class="paragraph__main mt-16"
v-loading="(paginationConfig.current_page === 1 && loading) || changeStateloading"
>
<div class="flex-between p-12-16 border-b">
<span>{{ paginationConfig.total }} {{ $t('views.paragraph.paragraph_count') }}</span>
<el-input
v-model="search"
:placeholder="$t('common.search')"
class="input-with-select"
style="width: 260px"
@change="searchHandle"
clearable
>
<template #prepend>
<el-select v-model="searchType" placeholder="Select" style="width: 80px">
<el-option :label="$t('common.title')" value="title" />
<el-option :label="$t('common.content')" value="content" />
</el-select>
</template>
</el-input>
</div>
<div class="flex">
<div class="paragraph-sidebar p-16 border-r">
<el-anchor
direction="vertical"
type="default"
:offset="130"
container=".paragraph-scollbar"
@click="handleClick"
>
<template v-for="(item, index) in paragraphDetail" :key="item.id">
<el-anchor-link :href="`#m${item.id}`" :title="item.title" v-if="item.title" />
</template>
</el-anchor>
</div>
<div class="w-full">
<el-empty v-if="paragraphDetail.length == 0" :description="$t('common.noData')" />
<div v-else>
<el-scrollbar class="paragraph-scollbar">
<div class="paragraph-detail">
<el-checkbox-group v-model="multipleSelection">
<InfiniteScroll
:size="paragraphDetail.length"
:total="paginationConfig.total"
:page_size="paginationConfig.page_size"
v-model:current_page="paginationConfig.current_page"
@load="getParagraphList"
:loading="loading"
>
<VueDraggable
ref="el"
v-model="paragraphDetail"
:disabled="isBatch === true"
handle=".handle"
:animation="150"
ghostClass="ghost"
>
<template v-for="(item, index) in paragraphDetail" :key="item.id">
<div :id="`m${item.id}`" style="display: flex; margin-bottom: 16px">
<!-- 批量操作 -->
<div class="paragraph-card flex" v-if="isBatch === true">
<el-checkbox :value="item.id" />
<ParagraphCard :data="item" class="mb-8 w-full" />
</div>
<!-- 非批量操作 -->
<div class="handle paragraph-card flex" :id="item.id" v-else>
<img
src="@/assets/sort.svg"
alt=""
height="15"
class="handle-img mr-8 mt-24 cursor"
/>
</div>
<ParagraphCard
:data="item"
class="mb-8 w-full"
@changeState="changeState"
@deleteParagraph="deleteParagraph"
/>
</div>
</template>
</VueDraggable>
</InfiniteScroll>
</el-checkbox-group>
</div>
</el-scrollbar>
</div>
</div>
</div>
<div class="mul-operation border-t w-full" v-if="isBatch === true">
<el-button :disabled="multipleSelection.length === 0" @click="openGenerateDialog()">
{{ $t('views.document.generateQuestion.title') }}
</el-button>
<el-button :disabled="multipleSelection.length === 0" @click="openSelectDocumentDialog()">
{{ $t('views.document.setting.migration') }}
</el-button>
<el-button :disabled="multipleSelection.length === 0" @click="deleteMulParagraph">
{{ $t('common.delete') }}
</el-button>
<span class="ml-8">
{{ $t('views.document.selected') }} {{ multipleSelection.length }}
{{ $t('views.document.items') }}
</span>
</div>
</el-card>
<ParagraphDialog ref="ParagraphDialogRef" :title="title" @refresh="refresh" />
<SelectDocumentDialog ref="SelectDocumentDialogRef" @refresh="refreshMigrateParagraph" />
<GenerateRelatedDialog ref="GenerateRelatedDialogRef" @refresh="refresh" :apiType="apiType" />
</div>
</template>
<script setup lang="ts">
import { reactive, ref, onMounted, computed } from 'vue'
import { useRoute } from 'vue-router'
import { cloneDeep } from 'lodash'
import paragraphApi from '@/api/resource-management/paragraph'
import ParagraphDialog from './component/ParagraphDialog.vue'
import ParagraphCard from './component/ParagraphCard.vue'
import SelectDocumentDialog from './component/SelectDocumentDialog.vue'
import GenerateRelatedDialog from '@/components/generate-related-dialog/index.vue'
import { VueDraggable } from 'vue-draggable-plus'
import { MsgSuccess, MsgConfirm } from '@/utils/message'
import { t } from '@/locales'
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
const route = useRoute()
const {
params: { id, documentId },
query: { type },
} = route as any
const apiType = computed(() => {
return type as 'systemShare' | 'workspace' | 'systemManage'
})
const SelectDocumentDialogRef = ref()
const ParagraphDialogRef = ref()
const loading = ref(false)
const changeStateloading = ref(false)
const documentDetail = ref<any>({})
const paragraphDetail = ref<any[]>([])
const title = ref('')
const search = ref('')
const searchType = ref('title')
const handleClick = (e: MouseEvent, ele: any) => {
e.preventDefault()
document.querySelector(`${ele}`).scrollIntoView({ behavior: 'smooth', block: 'start' })
}
//
const isBatch = ref(false)
const multipleSelection = ref<any[]>([])
const paginationConfig = reactive({
current_page: 1,
page_size: 30,
total: 0,
})
function deleteParagraph(id: string) {
const index = paragraphDetail.value.findIndex((v) => v.id === id)
paragraphDetail.value.splice(index, 1)
}
function changeState(id: string) {
const index = paragraphDetail.value.findIndex((v) => v.id === id)
paragraphDetail.value[index].is_active = !paragraphDetail.value[index].is_active
}
function refreshMigrateParagraph() {
paragraphDetail.value = paragraphDetail.value.filter(
(v) => !multipleSelection.value.includes(v.id),
)
multipleSelection.value = []
MsgSuccess(t('views.document.tip.migrationSuccess'))
}
function openSelectDocumentDialog(row?: any) {
if (row) {
multipleSelection.value = [row.id]
}
SelectDocumentDialogRef.value.open(multipleSelection.value)
}
function deleteMulParagraph() {
MsgConfirm(
`${t('views.document.delete.confirmTitle1')} ${multipleSelection.value.length} ${t('views.document.delete.confirmTitle2')}`,
t('views.paragraph.delete.confirmMessage'),
{
confirmButtonText: t('common.confirm'),
confirmButtonClass: 'danger',
},
)
.then(() => {
paragraphApi
.putMulParagraph(id, documentId, multipleSelection.value, changeStateloading)
.then(() => {
paragraphDetail.value = paragraphDetail.value.filter(
(v) => !multipleSelection.value.includes(v.id),
)
multipleSelection.value = []
MsgSuccess(t('views.document.delete.successMessage'))
})
})
.catch(() => {})
}
function batchSelectedHandle(bool: boolean) {
isBatch.value = bool
multipleSelection.value = []
}
function selectHandle(id: string) {
if (multipleSelection.value.includes(id)) {
multipleSelection.value.splice(multipleSelection.value.indexOf(id), 1)
} else {
multipleSelection.value.push(id)
}
}
function searchHandle() {
paginationConfig.current_page = 1
paragraphDetail.value = []
getParagraphList()
}
function addParagraph() {
title.value = t('views.paragraph.addParagraph')
ParagraphDialogRef.value.open()
}
function getDetail() {
loadSharedApi({ type: 'document', systemType: apiType.value })
.getDocumentDetail(id, documentId, loading)
.then((res) => {
documentDetail.value = res.data
})
}
function getParagraphList() {
paragraphApi
.getParagraph(
id,
documentId,
paginationConfig,
search.value && { [searchType.value]: search.value },
loading,
)
.then((res) => {
paragraphDetail.value = [...paragraphDetail.value, ...res.data.records]
paginationConfig.total = res.data.total
})
}
function refresh(data: any) {
if (data) {
const index = paragraphDetail.value.findIndex((v) => v.id === data.id)
paragraphDetail.value.splice(index, 1, data)
} else {
paginationConfig.current_page = 1
paragraphDetail.value = []
getParagraphList()
}
}
const GenerateRelatedDialogRef = ref()
function openGenerateDialog(row?: any) {
const arr: string[] = []
if (row) {
arr.push(row.id)
} else {
multipleSelection.value.map((v) => {
if (v) {
arr.push(v)
}
})
}
GenerateRelatedDialogRef.value.open(arr, 'paragraph')
}
function onEnd(event?: any) {
const { oldIndex, newIndex } = event
if (oldIndex === undefined || newIndex === undefined) return
const list = cloneDeep(paragraphDetail.value)
if (oldIndex === list.length - 1 || newIndex === list.length - 1) {
return
}
const newInstance = { ...list[oldIndex], type: list[newIndex].type, id: list[newIndex].id }
const oldInstance = { ...list[newIndex], type: list[oldIndex].type, id: list[oldIndex].id }
list[newIndex] = newInstance
list[oldIndex] = oldInstance
paragraphDetail.value = list
}
onMounted(() => {
getDetail()
getParagraphList()
})
</script>
<style lang="scss" scoped>
.paragraph {
position: relative;
.header-button {
position: absolute;
right: calc(var(--app-base-px) * 3);
top: calc(var(--app-base-px) + 4px);
}
.paragraph-sidebar {
width: 240px;
}
.paragraph-detail {
height: calc(100vh - 215px);
max-width: 1000px;
margin: 16px auto;
// .el-checkbox-group {
// display: flex;
// }
}
&__main {
position: relative;
box-sizing: border-box;
.mul-operation {
position: absolute;
bottom: 0;
left: 0;
padding: 16px 24px;
box-sizing: border-box;
background: #ffffff;
}
}
.paragraph-card {
&.handle {
.handle-img {
visibility: hidden;
}
&:hover {
.handle-img {
visibility: visible;
}
}
}
}
}
</style>

View File

@ -1,92 +0,0 @@
<template>
<el-dialog
:title="$t('views.problem.createProblem')"
v-model="dialogVisible"
:close-on-click-modal="false"
:close-on-press-escape="false"
:destroy-on-close="true"
>
<el-form
label-position="top"
ref="problemFormRef"
:rules="rules"
:model="form"
require-asterisk-position="right"
>
<el-form-item :label="$t('views.problem.title')" prop="data">
<el-input
v-model="form.data"
:placeholder="$t('views.problem.tip.placeholder')"
:rows="10"
type="textarea"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
<el-button type="primary" @click="submit(problemFormRef)" :loading="loading">
{{ $t('common.confirm') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
import { useRoute } from 'vue-router'
import type { FormInstance, FormRules } from 'element-plus'
import { MsgSuccess } from '@/utils/message'
import useStore from '@/stores/modules-resource-management'
import { t } from '@/locales'
const route = useRoute()
const {
params: { id }
} = route as any
const { problem } = useStore()
const emit = defineEmits(['refresh'])
const problemFormRef = ref()
const loading = ref<boolean>(false)
const form = ref<any>({
data: ''
})
const rules = reactive({
data: [{ required: true, message: t('views.problem.tip.requiredMessage'), trigger: 'blur' }]
})
const dialogVisible = ref<boolean>(false)
watch(dialogVisible, (bool) => {
if (!bool) {
form.value = {
data: ''
}
}
})
const open = () => {
dialogVisible.value = true
}
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
const arr = form.value.data.split('\n').filter(function (item: string) {
return item !== ''
})
problem.asyncPostProblem(id, arr, loading).then((res: any) => {
MsgSuccess(t('common.createSuccess'))
emit('refresh')
dialogVisible.value = false
})
}
})
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@ -1,206 +0,0 @@
<template>
<el-drawer v-model="visible" size="60%" @close="closeHandle">
<template #header>
<h4>{{ $t('views.problem.detailProblem') }}</h4>
</template>
<div>
<el-scrollbar>
<div class="p-8">
<el-form label-position="top" v-loading="loading" @submit.prevent>
<el-form-item :label="$t('views.problem.title')">
<ReadWrite
@change="editName"
:data="currentContent"
:showEditIcon="true"
:maxlength="256"
/>
</el-form-item>
<el-form-item :label="$t('views.problem.relateParagraph.title')">
<template v-for="(item, index) in paragraphList" :key="index">
<CardBox
:title="item.title || '-'"
class="paragraph-source-card cursor mb-8"
:showIcon="false"
@click.stop="editParagraph(item)"
>
<div class="active-button">
<span class="mr-4">
<el-tooltip
effect="dark"
:content="$t('views.problem.setting.cancelRelated')"
placement="top"
>
<el-button type="primary" text @click.stop="disassociation(item)">
<AppIcon iconName="app-quxiaoguanlian"></AppIcon>
</el-button>
</el-tooltip>
</span>
</div>
<template #description>
<el-scrollbar height="80">
{{ item.content }}
</el-scrollbar>
</template>
<template #footer>
<div class="footer-content flex-between">
<el-text>
<el-icon>
<Document />
</el-icon>
{{ item?.document_name }}
</el-text>
</div>
</template>
</CardBox>
</template>
</el-form-item>
</el-form>
</div>
</el-scrollbar>
<ParagraphDialog
ref="ParagraphDialogRef"
:title="$t('views.paragraph.editParagraph')"
@refresh="refresh"
/>
<RelateProblemDialog ref="RelateProblemDialogRef" @refresh="refresh" />
</div>
<template #footer>
<div>
<el-button @click="relateProblem">{{
$t('views.problem.relateParagraph.title')
}}</el-button>
<el-button @click="pre" :disabled="pre_disable || loading">{{
$t('views.chatLog.buttons.prev')
}}</el-button>
<el-button @click="next" :disabled="next_disable || loading">{{
$t('views.chatLog.buttons.next')
}}</el-button>
</div>
</template>
</el-drawer>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
import { useRoute } from 'vue-router'
import problemApi from '@/api/resource-management/problem'
import ParagraphDialog from '@/views/resource-management/paragraph/component/ParagraphDialog.vue'
import RelateProblemDialog from './RelateProblemDialog.vue'
import { MsgSuccess, MsgConfirm, MsgError } from '@/utils/message'
import useStore from '@/stores/modules-resource-management'
import { t } from '@/locales'
const props = withDefaults(
defineProps<{
/**
* 当前的id
*/
currentId: string
currentContent: string
/**
* 下一条
*/
next: () => void
/**
* 上一条
*/
pre: () => void
pre_disable: boolean
next_disable: boolean
}>(),
{},
)
const emit = defineEmits(['update:currentId', 'update:currentContent', 'refresh'])
const route = useRoute()
const {
params: { id },
} = route
const { paragraph } = useStore()
const RelateProblemDialogRef = ref()
const ParagraphDialogRef = ref()
const loading = ref(false)
const visible = ref(false)
const paragraphList = ref<any[]>([])
function disassociation(item: any) {
paragraph
.asyncDisassociationProblem(
item.knowledge_id,
item.document_id,
item.id,
props.currentId,
loading,
)
.then(() => {
getRecord()
})
}
function relateProblem() {
RelateProblemDialogRef.value.open([props.currentId])
}
function editParagraph(row: any) {
ParagraphDialogRef.value.open(row)
}
function editName(val: string) {
if (val) {
const obj = {
content: val,
}
problemApi.putProblems(id as string, props.currentId, obj, loading).then(() => {
emit('update:currentContent', val)
MsgSuccess(t('common.modifySuccess'))
})
} else {
MsgError(t('views.problem.tip.errorMessage'))
}
}
function closeHandle() {
paragraphList.value = []
}
function getRecord() {
if (props.currentId && visible.value) {
problemApi.getDetailProblems(id as string, props.currentId, loading).then((res) => {
paragraphList.value = res.data
})
}
}
function refresh() {
getRecord()
}
watch(
() => props.currentId,
() => {
paragraphList.value = []
getRecord()
},
)
watch(visible, (bool) => {
if (!bool) {
emit('update:currentId', '')
emit('update:currentContent', '')
emit('refresh')
}
})
const open = () => {
getRecord()
visible.value = true
}
defineExpose({
open,
})
</script>
<style lang="scss"></style>

View File

@ -1,330 +0,0 @@
<template>
<el-dialog
:title="$t('views.problem.relateParagraph.title')"
v-model="dialogVisible"
width="80%"
class="paragraph-dialog"
destroy-on-close
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<el-row v-loading="loading">
<el-col :span="6">
<el-scrollbar height="500" wrap-class="paragraph-scrollbar">
<div class="bold title align-center p-24 pb-0">
{{ $t('views.problem.relateParagraph.selectDocument') }}
</div>
<div class="p-8" style="padding-bottom: 8px">
<el-input
v-model="filterDoc"
:placeholder="$t('views.problem.relateParagraph.placeholder')"
prefix-icon="Search"
clearable
/>
<common-list
:data="documentList"
class="mt-8"
@click="clickDocumentHandle"
:default-active="currentDocument"
>
<template #default="{ row }">
<span class="flex lighter align-center">
<auto-tooltip :content="row.name">
{{ row.name }}
</auto-tooltip>
<el-badge
:value="associationCount(row.id)"
type="primary"
v-if="associationCount(row.id)"
class="paragraph-badge ml-4"
/>
</span>
</template>
</common-list>
</div>
</el-scrollbar>
</el-col>
<el-col :span="18" class="border-l">
<el-scrollbar height="500" wrap-class="paragraph-scrollbar">
<div class="p-24" style="padding-bottom: 8px; padding-top: 16px">
<div class="flex-between mb-16">
<div class="bold title align-center">
{{ $t('components.selectParagraph.title') }}
<el-text>
{{ $t('views.problem.relateParagraph.selectedParagraph') }}{{
associationCount(currentDocument)
}}
{{ $t('views.problem.relateParagraph.count') }}
</el-text>
</div>
<el-input
v-model="search"
:placeholder="$t('common.search')"
class="input-with-select"
style="width: 260px"
@change="searchHandle"
>
<template #prepend>
<el-select v-model="searchType" placeholder="Select" style="width: 80px">
<el-option :label="$t('common.title')" value="title" />
<el-option :label="$t('common.content')" value="content" />
</el-select>
</template>
</el-input>
</div>
<el-empty v-if="paragraphList.length == 0" :description="$t('common.noData')" />
<InfiniteScroll
v-else
:size="paragraphList.length"
:total="paginationConfig.total"
:page_size="paginationConfig.page_size"
v-model:current_page="paginationConfig.current_page"
@load="getParagraphList"
:loading="loading"
>
<template v-for="(item, index) in paragraphList" :key="index">
<CardBox
shadow="hover"
:title="item.title || '-'"
:description="item.content"
class="paragraph-card cursor mb-16"
:class="isAssociation(item.id) ? 'selected' : ''"
:showIcon="false"
@click="associationClick(item)"
>
</CardBox>
</template>
</InfiniteScroll>
</div>
</el-scrollbar>
</el-col>
</el-row>
<template #footer v-if="isMul">
<div class="dialog-footer">
<el-button @click="dialogVisible = false"> {{ $t('common.cancel') }}</el-button>
<el-button type="primary" @click="mulAssociation"> {{ $t('common.confirm') }} </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, watch, reactive } from 'vue'
import { useRoute } from 'vue-router'
import problemApi from '@/api/resource-management/problem'
import paragraphApi from '@/api/resource-management/paragraph'
import useStore from '@/stores/modules-resource-management'
import { MsgSuccess } from '@/utils/message'
import { t } from '@/locales'
const { problem, document, paragraph } = useStore()
const route = useRoute()
const {
params: { id }, // knowledgeId
} = route as any
const emit = defineEmits(['refresh'])
const dialogVisible = ref<boolean>(false)
const loading = ref(false)
const documentList = ref<any[]>([])
const cloneDocumentList = ref<any[]>([])
const paragraphList = ref<any[]>([])
const currentProblemId = ref<string>('')
const currentMulProblemId = ref<string[]>([])
//
const associationParagraph = ref<any[]>([])
const currentDocument = ref<string>('')
const search = ref('')
const searchType = ref('title')
const filterDoc = ref('')
//
const isMul = ref(false)
const paginationConfig = reactive({
current_page: 1,
page_size: 50,
total: 0,
})
function mulAssociation() {
const data = {
problem_id_list: currentMulProblemId.value,
paragraph_list: associationParagraph.value.map((item) => ({
paragraph_id: item.id,
document_id: item.document_id,
})),
}
problemApi.putMulAssociationProblem(id, data, loading).then(() => {
MsgSuccess(t('views.problem.tip.relatedSuccess'))
dialogVisible.value = false
})
}
function associationClick(item: any) {
if (isMul.value) {
if (isAssociation(item.id)) {
associationParagraph.value.splice(associationParagraph.value.indexOf(item.id), 1)
} else {
associationParagraph.value.push(item)
}
} else {
if (isAssociation(item.id)) {
paragraph
.asyncDisassociationProblem(
id,
item.document_id,
item.id,
currentProblemId.value as string,
loading,
)
.then(() => {
getRecord(currentProblemId.value)
})
} else {
paragraph
.asyncAssociationProblem(
id,
item.document_id,
item.id,
currentProblemId.value as string,
loading,
)
.then(() => {
getRecord(currentProblemId.value)
})
}
}
}
function searchHandle() {
paginationConfig.current_page = 1
paragraphList.value = []
currentDocument.value && getParagraphList(currentDocument.value)
}
function clickDocumentHandle(item: any) {
paginationConfig.current_page = 1
paragraphList.value = []
currentDocument.value = item.id
getParagraphList(item.id)
}
function getDocument() {
document.asyncGetAllDocument(id, loading).then((res: any) => {
cloneDocumentList.value = res.data
documentList.value = res.data
currentDocument.value = cloneDocumentList.value?.length > 0 ? cloneDocumentList.value[0].id : ''
currentDocument.value && getParagraphList(currentDocument.value)
})
}
function getParagraphList(documentId: string) {
paragraphApi
.getParagraph(
id,
(documentId || currentDocument.value) as string,
paginationConfig,
search.value && { [searchType.value]: search.value },
loading,
)
.then((res) => {
paragraphList.value = [...paragraphList.value, ...res.data.records]
paginationConfig.total = res.data.total
})
}
//
function getRecord(problemId: string) {
problemApi.getDetailProblems(id as string, problemId as string, loading).then((res) => {
associationParagraph.value = res.data
})
}
function associationCount(documentId: string) {
return associationParagraph.value.filter((item) => item.document_id === documentId).length
}
function isAssociation(paragraphId: string) {
return associationParagraph.value.some((option) => option.id === paragraphId)
}
watch(dialogVisible, (bool) => {
if (!bool) {
documentList.value = []
cloneDocumentList.value = []
paragraphList.value = []
associationParagraph.value = []
isMul.value = false
currentDocument.value = ''
search.value = ''
searchType.value = 'title'
emit('refresh')
}
})
watch(filterDoc, (val) => {
paragraphList.value = []
documentList.value = val
? cloneDocumentList.value.filter((item) => item.name.includes(val))
: cloneDocumentList.value
currentDocument.value = documentList.value?.length > 0 ? documentList.value[0].id : ''
})
const open = (problemId: any) => {
getDocument()
if (problemId.length == 1) {
currentProblemId.value = problemId[0]
getRecord(problemId)
} else if (problemId.length > 1) {
currentMulProblemId.value = problemId
isMul.value = true
}
dialogVisible.value = true
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
.paragraph-card {
position: relative;
// card
&.selected {
border: 1px solid var(--el-color-primary) !important;
&:before {
content: '';
position: absolute;
right: 0;
top: 0;
border: 14px solid var(--el-color-primary);
border-bottom-color: transparent;
border-left-color: transparent;
}
&:after {
content: '';
width: 3px;
height: 6px;
position: absolute;
right: 5px;
top: 2px;
border: 2px solid #fff;
border-top-color: transparent;
border-left-color: transparent;
transform: rotate(35deg);
}
&:hover {
border: 1px solid var(--el-color-primary);
}
}
}
.paragraph-badge {
.el-badge__content {
height: auto;
display: table;
}
}
</style>

View File

@ -1,388 +0,0 @@
<template>
<div class="document p-16-24">
<h2 class="mb-16">{{ $t('views.problem.title') }}</h2>
<el-card style="--el-card-padding: 0">
<div class="main-calc-height">
<div class="p-24">
<div class="flex-between">
<div>
<el-button type="primary" @click="createProblem"
>{{ $t('views.problem.createProblem') }}
</el-button>
<el-button @click="relateProblem()" :disabled="multipleSelection.length === 0"
>{{ $t('views.problem.relateParagraph.title') }}
</el-button>
<el-button @click="deleteMulDocument" :disabled="multipleSelection.length === 0"
>{{ $t('views.problem.setting.batchDelete') }}
</el-button>
</div>
<el-input
v-model="filterText"
:placeholder="$t('views.problem.searchBar.placeholder')"
prefix-icon="Search"
class="w-240"
@change="getList"
clearable
/>
</div>
<app-table
ref="multipleTableRef"
class="mt-16"
:data="problemData"
:pagination-config="paginationConfig"
quick-create
:quickCreateName="$t('views.problem.quickCreateName')"
:quickCreatePlaceholder="$t('views.problem.quickCreateProblem')"
:quickCreateMaxlength="256"
@sizeChange="handleSizeChange"
@changePage="getList"
@cell-mouse-enter="cellMouseEnter"
@cell-mouse-leave="cellMouseLeave"
@creatQuick="creatQuickHandle"
@row-click="rowClickHandle"
@selection-change="handleSelectionChange"
:row-class-name="setRowClass"
v-loading="loading"
:row-key="(row: any) => row.id"
>
<el-table-column type="selection" width="55" :reserve-selection="true" />
<el-table-column prop="content" :label="$t('views.problem.title')" min-width="280">
<template #default="{ row }">
<ReadWrite
@change="editName($event, row.id)"
:data="row.content"
:showEditIcon="row.id === currentMouseId"
:maxlength="256"
/>
</template>
</el-table-column>
<el-table-column
prop="paragraph_count"
:label="$t('views.problem.table.paragraph_count')"
align="right"
min-width="100"
>
<template #default="{ row }">
<el-link
type="primary"
@click.stop="rowClickHandle(row)"
v-if="row.paragraph_count"
>
{{ row.paragraph_count }}
</el-link>
<span v-else>
{{ row.paragraph_count }}
</span>
</template>
</el-table-column>
<el-table-column prop="create_time" :label="$t('common.createTime')" width="170">
<template #default="{ row }">
{{ datetimeFormat(row.create_time) }}
</template>
</el-table-column>
<el-table-column
prop="update_time"
:label="$t('views.problem.table.updateTime')"
width="170"
>
<template #default="{ row }">
{{ datetimeFormat(row.update_time) }}
</template>
</el-table-column>
<el-table-column :label="$t('common.operation')" align="left" fixed="right">
<template #default="{ row }">
<div>
<span class="mr-4">
<el-tooltip
effect="dark"
:content="$t('views.problem.relateParagraph.title')"
placement="top"
>
<el-button type="primary" text @click.stop="relateProblem(row)">
<el-icon><Connection /></el-icon>
</el-button>
</el-tooltip>
</span>
<span>
<el-tooltip effect="dark" :content="$t('common.delete')" placement="top">
<el-button type="primary" text @click.stop="deleteProblem(row)">
<el-icon><Delete /></el-icon>
</el-button>
</el-tooltip>
</span>
</div>
</template>
</el-table-column>
</app-table>
</div>
</div>
</el-card>
<CreateProblemDialog ref="CreateProblemDialogRef" @refresh="refresh" />
<DetailProblemDrawer
:next="nextChatRecord"
:pre="preChatRecord"
ref="DetailProblemRef"
v-model:currentId="currentClickId"
v-model:currentContent="currentContent"
:pre_disable="pre_disable"
:next_disable="next_disable"
@refresh="refreshRelate"
/>
<RelateProblemDialog ref="RelateProblemDialogRef" @refresh="refreshRelate" />
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, reactive, onBeforeUnmount, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { ElTable } from 'element-plus'
import problemApi from '@/api/resource-management/problem'
import CreateProblemDialog from './component/CreateProblemDialog.vue'
import DetailProblemDrawer from './component/DetailProblemDrawer.vue'
import RelateProblemDialog from './component/RelateProblemDialog.vue'
import { datetimeFormat } from '@/utils/time'
import { MsgSuccess, MsgConfirm, MsgError } from '@/utils/message'
import type { Dict } from '@/api/type/common'
import useStore from '@/stores/modules-resource-management'
import { t } from '@/locales'
const route = useRoute()
const {
params: { id }, // id
} = route as any
const { problem } = useStore()
const RelateProblemDialogRef = ref()
const DetailProblemRef = ref()
const CreateProblemDialogRef = ref()
const loading = ref(false)
// id
const currentMouseId = ref('')
// drawerid
const currentClickId = ref('')
const currentContent = ref('')
const paginationConfig = reactive({
current_page: 1,
page_size: 10,
total: 0,
})
const filterText = ref('')
const problemData = ref<any[]>([])
const problemIndexMap = computed<Dict<number>>(() => {
return problemData.value
.map((row, index) => ({
[row.id]: index,
}))
.reduce((pre, next) => ({ ...pre, ...next }), {})
})
const multipleTableRef = ref<InstanceType<typeof ElTable>>()
const multipleSelection = ref<any[]>([])
function relateProblem(row?: any) {
const arr: string[] = []
if (row) {
arr.push(row.id)
} else {
multipleSelection.value.map((v) => {
if (v) {
arr.push(v.id)
}
})
}
RelateProblemDialogRef.value.open(arr)
}
function createProblem() {
CreateProblemDialogRef.value.open()
}
const handleSelectionChange = (val: any[]) => {
multipleSelection.value = val
}
/*
快速创建空白文档
*/
function creatQuickHandle(val: string) {
loading.value = true
const obj = [val]
problem
.asyncPostProblem(id, obj)
.then((res) => {
getList()
MsgSuccess(t('common.createSuccess'))
})
.catch(() => {
loading.value = false
})
}
function deleteMulDocument() {
const arr: string[] = []
multipleSelection.value.map((v) => {
if (v) {
arr.push(v.id)
}
})
problemApi.putMulProblem(id, arr, loading).then(() => {
MsgSuccess(t('views.document.delete.successMessage'))
multipleTableRef.value?.clearSelection()
getList()
})
}
function deleteProblem(row: any) {
MsgConfirm(
`${t('views.problem.delete.confirmTitle')} ${row.content} ?`,
`${t('views.problem.delete.confirmMessage1')} ${row.paragraph_count} ${t('views.problem.delete.confirmMessage2')}`,
{
confirmButtonText: t('common.confirm'),
confirmButtonClass: 'danger',
},
)
.then(() => {
problemApi.delProblems(id, row.id, loading).then(() => {
MsgSuccess(t('common.deleteSuccess'))
getList()
})
})
.catch(() => {})
}
function editName(val: string, problemId: string) {
if (val) {
const obj = {
content: val,
}
problemApi.putProblems(id, problemId, obj, loading).then(() => {
getList()
MsgSuccess(t('common.modifySuccess'))
})
} else {
MsgError(t('views.problem.tip.errorMessage'))
}
}
function cellMouseEnter(row: any) {
currentMouseId.value = row.id
}
function cellMouseLeave() {
currentMouseId.value = ''
}
/**
* 下一页
*/
const nextChatRecord = () => {
let index = problemIndexMap.value[currentClickId.value] + 1
if (index >= problemData.value.length) {
if (
index + (paginationConfig.current_page - 1) * paginationConfig.page_size >=
paginationConfig.total - 1
) {
return
}
paginationConfig.current_page = paginationConfig.current_page + 1
getList().then(() => {
index = 0
currentClickId.value = problemData.value[index].id
currentContent.value = problemData.value[index].content
})
} else {
currentClickId.value = problemData.value[index].id
currentContent.value = problemData.value[index].content
}
}
const pre_disable = computed(() => {
const index = problemIndexMap.value[currentClickId.value] - 1
return index < 0 && paginationConfig.current_page <= 1
})
const next_disable = computed(() => {
const index = problemIndexMap.value[currentClickId.value] + 1
return (
index >= problemData.value.length &&
index + (paginationConfig.current_page - 1) * paginationConfig.page_size >=
paginationConfig.total - 1
)
})
/**
* 上一页
*/
const preChatRecord = () => {
let index = problemIndexMap.value[currentClickId.value] - 1
if (index < 0) {
if (paginationConfig.current_page <= 1) {
return
}
paginationConfig.current_page = paginationConfig.current_page - 1
getList().then((ok) => {
index = paginationConfig.page_size - 1
currentClickId.value = problemData.value[index].id
currentContent.value = problemData.value[index].content
})
} else {
currentClickId.value = problemData.value[index].id
currentContent.value = problemData.value[index].content
}
}
function rowClickHandle(row: any, column?: any) {
if (column && column.type === 'selection') {
return
}
if (row.paragraph_count) {
currentClickId.value = row.id
currentContent.value = row.content
DetailProblemRef.value.open()
}
}
const setRowClass = ({ row }: any) => {
return currentClickId.value === row?.id ? 'highlight' : ''
}
function handleSizeChange() {
paginationConfig.current_page = 1
getList()
}
function getList() {
return problem
.asyncGetProblem(
id as string,
paginationConfig,
filterText.value && { content: filterText.value },
loading,
)
.then((res: any) => {
problemData.value = res.data.records
paginationConfig.total = res.data.total
})
}
function refreshRelate() {
getList()
multipleTableRef.value?.clearSelection()
}
function refresh() {
paginationConfig.current_page = 1
getList()
}
onMounted(() => {
getList()
})
onBeforeUnmount(() => {})
</script>
<style lang="scss" scoped></style>

View File

@ -1,184 +0,0 @@
<template>
<el-drawer v-model="debugVisible" size="60%" :append-to-body="true">
<template #header>
<div class="flex align-center" style="margin-left: -8px">
<el-button class="cursor mr-4" link @click.prevent="debugVisible = false">
<el-icon :size="20">
<Back />
</el-icon>
</el-button>
<h4>{{ $t('common.debug') }}</h4>
</div>
</template>
<div>
<div v-if="form.init_field_list.length > 0" class="mb-16">
<h4 class="title-decoration-1 mb-16">
{{ $t('common.param.initParam') }}
</h4>
<el-card shadow="never" class="card-never" style="--el-card-padding: 12px">
<DynamicsForm
v-model="form.init_params"
:model="form.init_params"
label-position="top"
require-asterisk-position="right"
:render_data="form.init_field_list"
ref="dynamicsFormRef"
>
</DynamicsForm>
</el-card>
</div>
<div v-if="form.debug_field_list.length > 0" class="mb-16">
<h4 class="title-decoration-1 mb-16">
{{ $t('common.param.inputParam') }}
</h4>
<el-card shadow="never" class="card-never" style="--el-card-padding: 12px">
<el-form
ref="FormRef"
:model="form"
label-position="top"
require-asterisk-position="right"
hide-required-asterisk
v-loading="loading"
@submit.prevent
>
<template v-for="(item, index) in form.debug_field_list" :key="index">
<el-form-item
:label="item.name"
:prop="'debug_field_list.' + index + '.value'"
:rules="{
required: item.is_required,
message: $t('views.tool.form.param.inputPlaceholder'),
trigger: 'blur',
}"
>
<template #label>
<div class="flex">
<span
>{{ item.name }} <span class="danger" v-if="item.is_required">*</span></span
>
<el-tag type="info" class="info-tag ml-4">{{ item.type }}</el-tag>
</div>
</template>
<el-input
v-model="item.value"
:placeholder="$t('views.tool.form.param.inputPlaceholder')"
/>
</el-form-item>
</template>
</el-form>
</el-card>
</div>
<el-button type="primary" @click="submit(FormRef)" :loading="loading">
{{ $t('views.tool.form.debug.run') }}
</el-button>
<div v-if="showResult" class="mt-8">
<h4 class="title-decoration-1 mb-16 mt-16">
{{ $t('views.tool.form.debug.runResult') }}
</h4>
<div class="mb-16">
<el-alert
v-if="isSuccess"
:title="$t('views.tool.form.debug.runSuccess')"
type="success"
show-icon
:closable="false"
/>
<el-alert
v-else
:title="$t('views.tool.form.debug.runFailed')"
type="error"
show-icon
:closable="false"
/>
</div>
<p class="lighter mb-8">{{ $t('views.tool.form.debug.output') }}</p>
<el-card
:class="isSuccess ? '' : 'danger'"
class="pre-wrap"
shadow="never"
style="max-height: 350px; overflow: scroll"
>
{{ String(result) == '0' ? 0 : result || '-' }}
</el-card>
</div>
</div>
</el-drawer>
</template>
<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
import ToolApi from '@/api/system-shared/tool'
import type { FormInstance } from 'element-plus'
import DynamicsForm from '@/components/dynamics-form/index.vue'
const FormRef = ref()
const dynamicsFormRef = ref()
const loading = ref(false)
const debugVisible = ref(false)
const showResult = ref(false)
const isSuccess = ref(false)
const result = ref('')
const form = ref<any>({
debug_field_list: [],
code: '',
input_field_list: [],
init_field_list: [],
init_params: {},
})
watch(debugVisible, (bool) => {
if (!bool) {
showResult.value = false
isSuccess.value = false
result.value = ''
form.value = {
debug_field_list: [],
code: '',
input_field_list: [],
init_field_list: [],
init_params: {},
}
}
})
const submit = async (formEl: FormInstance | undefined) => {
const validate = formEl ? formEl.validate() : Promise.resolve()
Promise.all([dynamicsFormRef.value?.validate(), validate]).then(() => {
ToolApi.postToolDebug(form.value, loading).then((res) => {
if (res.code === 500) {
showResult.value = true
isSuccess.value = false
result.value = res.message
} else {
showResult.value = true
isSuccess.value = true
result.value = res.data
}
})
})
}
const open = (data: any) => {
if (data.input_field_list.length > 0) {
data.input_field_list.forEach((item: any) => {
form.value.debug_field_list.push({
value: '',
...item,
})
})
}
form.value.code = data.code
form.value.input_field_list = data.input_field_list
form.value.init_field_list = data.init_field_list
debugVisible.value = true
}
defineExpose({
open,
})
</script>
<style lang="scss"></style>

View File

@ -1,449 +0,0 @@
<template>
<el-drawer v-model="visible" size="60%" :before-close="close">
<template #header>
<h4>{{ title }}</h4>
</template>
<div>
<h4 class="title-decoration-1 mb-16">
{{ $t('views.tool.form.title.baseInfo') }}
</h4>
<el-form
ref="FormRef"
:model="form"
:rules="rules"
label-position="top"
require-asterisk-position="right"
v-loading="loading"
@submit.prevent
>
<el-form-item :label="$t('views.tool.form.toolName.label')" prop="name">
<div class="flex w-full">
<div
v-if="form.id"
class="edit-avatar mr-12"
@mouseenter="showEditIcon = true"
@mouseleave="showEditIcon = false"
>
<el-Avatar
v-if="isAppIcon(form.icon)"
:id="form.id"
shape="square"
:size="32"
style="background: none"
>
<img :src="String(form.icon)" alt=""/>
</el-Avatar>
<el-avatar v-else class="avatar-green" shape="square" :size="32">
<img src="@/assets/node/icon_tool.svg" style="width: 58%" alt=""/>
</el-avatar>
<el-Avatar
v-if="showEditIcon"
:id="form.id"
shape="square"
class="edit-mask"
:size="32"
@click="openEditAvatar"
>
<el-icon>
<EditPen/>
</el-icon>
</el-Avatar>
</div>
<el-avatar v-else class="avatar-green" shape="square" :size="32">
<img src="@/assets/node/icon_tool.svg" style="width: 58%" alt=""/>
</el-avatar>
<el-input
v-model="form.name"
:placeholder="$t('views.tool.form.toolName.placeholder')"
maxlength="64"
show-word-limit
@blur="form.name = form.name?.trim()"
/>
</div>
</el-form-item>
<el-form-item :label="$t('views.tool.form.toolDescription.label')">
<el-input
v-model="form.desc"
type="textarea"
:placeholder="$t('views.tool.form.toolDescription.placeholder')"
maxlength="128"
show-word-limit
:autosize="{ minRows: 3 }"
@blur="form.desc = form.desc?.trim()"
/>
</el-form-item>
</el-form>
<div class="flex-between">
<h4 class="title-decoration-1 mb-16">
{{ $t('common.param.initParam') }}
</h4>
<el-button link type="primary" @click="openAddInitDialog()">
<el-icon class="mr-4">
<Plus/>
</el-icon>
{{ $t('common.add') }}
</el-button>
</div>
<el-table ref="initFieldTableRef" :data="form.init_field_list" class="mb-16">
<el-table-column prop="field" :label="$t('dynamicsForm.paramForm.field.label')">
<template #default="{ row }">
<span :title="row.field" class="ellipsis-1">{{ row.field }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('dynamicsForm.paramForm.input_type.label')">
<template #default="{ row }">
<el-tag type="info" class="info-tag" v-if="row.input_type === 'TextInput'">{{
$t('dynamicsForm.input_type_list.TextInput')
}}
</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'PasswordInput'">{{
$t('dynamicsForm.input_type_list.PasswordInput')
}}
</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'Slider'">{{
$t('dynamicsForm.input_type_list.Slider')
}}
</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'SwitchInput'">{{
$t('dynamicsForm.input_type_list.SwitchInput')
}}
</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'SingleSelect'">{{
$t('dynamicsForm.input_type_list.SingleSelect')
}}
</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'MultiSelect'">{{
$t('dynamicsForm.input_type_list.MultiSelect')
}}
</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'RadioCard'">{{
$t('dynamicsForm.input_type_list.RadioCard')
}}
</el-tag>
<el-tag type="info" class="info-tag" v-if="row.input_type === 'DatePicker'">{{
$t('dynamicsForm.input_type_list.DatePicker')
}}
</el-tag>
</template>
</el-table-column>
<el-table-column :label="$t('common.required')">
<template #default="{ row }">
<div @click.stop>
<el-switch disabled size="small" v-model="row.required"/>
</div>
</template>
</el-table-column>
<el-table-column :label="$t('common.operation')" align="left" width="90">
<template #default="{ row, $index }">
<span class="mr-4">
<el-tooltip effect="dark" :content="$t('common.modify')" placement="top">
<el-button type="primary" text @click.stop="openAddInitDialog(row, $index)">
<el-icon><EditPen/></el-icon>
</el-button>
</el-tooltip>
</span>
<el-tooltip effect="dark" :content="$t('common.delete')" placement="top">
<el-button type="primary" text @click="deleteInitField($index)">
<el-icon>
<Delete/>
</el-icon>
</el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<div class="flex-between">
<h4 class="title-decoration-1 mb-16">
{{ $t('common.param.inputParam') }}
<el-text type="info" class="color-secondary">
{{ $t('views.tool.form.param.paramInfo1') }}
</el-text>
</h4>
<el-button link type="primary" @click="openAddDialog()">
<el-icon class="mr-4">
<Plus/>
</el-icon>
{{ $t('common.add') }}
</el-button>
</div>
<el-table ref="inputFieldTableRef" :data="form.input_field_list" class="mb-16">
<el-table-column prop="name" :label="$t('views.tool.form.paramName.label')"/>
<el-table-column :label="$t('views.tool.form.dataType.label')">
<template #default="{ row }">
<el-tag type="info" class="info-tag">{{ row.type }}</el-tag>
</template>
</el-table-column>
<el-table-column :label="$t('common.required')">
<template #default="{ row }">
<div @click.stop>
<el-switch size="small" v-model="row.is_required"/>
</div>
</template>
</el-table-column>
<el-table-column prop="source" :label="$t('views.tool.form.source.label')">
<template #default="{ row }">
{{
row.source === 'custom'
? $t('views.tool.form.source.custom')
: $t('views.tool.form.source.reference')
}}
</template>
</el-table-column>
<el-table-column :label="$t('common.operation')" align="left" width="90">
<template #default="{ row, $index }">
<span class="mr-4">
<el-tooltip effect="dark" :content="$t('common.modify')" placement="top">
<el-button type="primary" text @click.stop="openAddDialog(row, $index)">
<el-icon><EditPen/></el-icon>
</el-button>
</el-tooltip>
</span>
<el-tooltip effect="dark" :content="$t('common.delete')" placement="top">
<el-button type="primary" text @click="deleteField($index)">
<el-icon>
<Delete/>
</el-icon>
</el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<h4 class="title-decoration-1 mb-16">
{{ $t('views.tool.form.param.code') }}
<span style="color: red; margin-left: -10px">*</span>
<el-text type="info" class="color-secondary">
{{ $t('views.tool.form.param.paramInfo2') }}
</el-text>
</h4>
<div class="mb-8" v-if="showEditor">
<CodemirrorEditor
:title="$t('views.tool.form.param.code')"
v-model="form.code"
@submitDialog="submitCodemirrorEditor"
/>
</div>
<h4 class="title-decoration-1 mb-16 mt-16">
{{ $t('common.param.outputParam') }}
<el-text type="info" class="color-secondary">
{{ $t('views.tool.form.param.paramInfo1') }}
</el-text>
</h4>
<div class="flex-between border-r-4 p-8-12 mb-8 layout-bg lighter">
<span>{{ $t('common.result') }} {result}</span>
</div>
</div>
<template #footer>
<div>
<el-button :loading="loading" @click="visible = false">{{ $t('common.cancel') }}</el-button>
<el-button :loading="loading" @click="openDebug">{{ $t('common.debug') }}</el-button>
<el-button type="primary" @click="submit(FormRef)" :loading="loading">
{{ isEdit ? $t('common.save') : $t('common.create') }}
</el-button
>
</div>
</template>
<ToolDebugDrawer ref="ToolDebugDrawerRef"/>
<FieldFormDialog ref="FieldFormDialogRef" @refresh="refreshFieldList"/>
<UserFieldFormDialog ref="UserFieldFormDialogRef" @refresh="refreshInitFieldList"/>
<EditAvatarDialog ref="EditAvatarDialogRef" @refresh="refreshTool"/>
</el-drawer>
</template>
<script setup lang="ts">
import {ref, reactive, watch, nextTick} from 'vue'
import FieldFormDialog from '@/views/resource-management/tool/component/FieldFormDialog.vue'
import ToolDebugDrawer from './ToolDebugDrawer.vue'
import UserFieldFormDialog from '@/views/resource-management/tool/component/UserFieldFormDialog.vue'
import EditAvatarDialog from '@/views/resource-management/tool/component/EditAvatarDialog.vue'
import type {toolData} from '@/api/type/tool'
import ToolApi from '@/api/system-shared/tool'
import type {FormInstance} from 'element-plus'
import {MsgSuccess, MsgConfirm} from '@/utils/message'
import {cloneDeep} from 'lodash'
import {PermissionType, PermissionDesc} from '@/enums/model'
import {t} from '@/locales'
import {isAppIcon} from '@/utils/common'
const props = defineProps({
title: String,
})
const emit = defineEmits(['refresh'])
const FieldFormDialogRef = ref()
const ToolDebugDrawerRef = ref()
const UserFieldFormDialogRef = ref()
const EditAvatarDialogRef = ref()
const initFieldTableRef = ref()
const inputFieldTableRef = ref()
const FormRef = ref()
const isEdit = ref(false)
const loading = ref(false)
const visible = ref(false)
const showEditor = ref(false)
const currentIndex = ref<any>(null)
const showEditIcon = ref(false)
const form = ref<toolData>({
name: '',
desc: '',
code: '',
icon: '',
input_field_list: [],
init_field_list: [],
})
watch(visible, (bool) => {
if (!bool) {
isEdit.value = false
showEditor.value = false
currentIndex.value = null
form.value = {
name: '',
desc: '',
code: '',
icon: '',
input_field_list: [],
init_field_list: [],
}
FormRef.value?.clearValidate()
}
})
const rules = reactive({
name: [
{
required: true,
message: t('views.tool.form.toolName.requiredMessage'),
trigger: 'blur',
},
],
})
function submitCodemirrorEditor(val: string) {
form.value.code = val
}
function close() {
if (isEdit.value || !areAllValuesNonEmpty(form.value)) {
visible.value = false
} else {
MsgConfirm(t('common.tip'), t('views.tool.tip.saveMessage'), {
confirmButtonText: t('common.confirm'),
type: 'warning',
})
.then(() => {
visible.value = false
})
.catch(() => {
})
}
}
function areAllValuesNonEmpty(obj: any) {
return Object.values(obj).some((value) => {
return Array.isArray(value)
? value.length !== 0
: value !== null && value !== undefined && value !== ''
})
}
function openDebug() {
ToolDebugDrawerRef.value.open(form.value)
}
function deleteField(index: any) {
form.value.input_field_list?.splice(index, 1)
}
function openAddDialog(data?: any, index?: any) {
if (typeof index !== 'undefined') {
currentIndex.value = index
}
FieldFormDialogRef.value.open(data)
}
function refreshFieldList(data: any) {
if (currentIndex.value !== null) {
form.value.input_field_list?.splice(currentIndex.value, 1, data)
} else {
form.value.input_field_list?.push(data)
}
currentIndex.value = null
}
function openAddInitDialog(data?: any, index?: any) {
if (typeof index !== 'undefined') {
currentIndex.value = index
}
UserFieldFormDialogRef.value.open(data)
}
function refreshInitFieldList(data: any) {
if (currentIndex.value !== null) {
form.value.init_field_list?.splice(currentIndex.value, 1, data)
} else {
form.value.init_field_list?.push(data)
}
currentIndex.value = null
UserFieldFormDialogRef.value.close()
}
function refreshTool(data: any) {
form.value.icon = data
}
function deleteInitField(index: any) {
form.value.init_field_list?.splice(index, 1)
}
function openEditAvatar() {
EditAvatarDialogRef.value.open(form.value)
}
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid: any) => {
if (valid) {
if (isEdit.value) {
ToolApi.putTool(form.value?.id as string, form.value, loading).then((res) => {
MsgSuccess(t('common.editSuccess'))
emit('refresh', res.data)
visible.value = false
})
} else {
ToolApi.postTool(form.value, loading).then((res) => {
MsgSuccess(t('common.createSuccess'))
emit('refresh')
visible.value = false
})
}
}
})
}
const open = (data: any) => {
if (data) {
isEdit.value = data?.id ? true : false
form.value = cloneDeep(data)
}
visible.value = true
setTimeout(() => {
showEditor.value = true
}, 100)
}
defineExpose({
open,
})
</script>
<style lang="scss" scoped></style>

View File

@ -1,88 +0,0 @@
<template>
<el-dialog
:title="$t('views.tool.form.toolName.name')"
v-model="dialogVisible"
:close-on-click-modal="false"
:close-on-press-escape="false"
:destroy-on-close="true"
append-to-body
width="450"
>
<el-form
label-position="top"
ref="fieldFormRef"
:rules="rules"
:model="form"
require-asterisk-position="right"
>
<el-form-item prop="name">
<el-input v-model="form.name" maxlength="64" show-word-limit></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
<el-button type="primary" @click="submit(fieldFormRef)" :loading="loading">
{{ isEdit ? $t('common.save') : $t('common.add') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { reactive, ref, watch } from 'vue'
import type { FormInstance } from 'element-plus'
import { cloneDeep } from 'lodash'
import { t } from '@/locales'
const emit = defineEmits(['refresh'])
const fieldFormRef = ref()
const loading = ref<boolean>(false)
const isEdit = ref<boolean>(false)
const form = ref<any>({
name: ''
})
const rules = reactive({
name: [
{
required: true,
message: t('views.tool.form.toolName.placeholder'),
trigger: 'blur'
}
]
})
const dialogVisible = ref<boolean>(false)
watch(dialogVisible, (bool) => {
if (!bool) {
form.value = {
name: ''
}
}
})
const open = (row: any, edit: boolean) => {
if (row) {
form.value = cloneDeep(row)
}
isEdit.value = edit || false
dialogVisible.value = true
}
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid) => {
if (valid) {
emit('refresh', form.value, isEdit.value)
dialogVisible.value = false
}
})
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@ -1,120 +0,0 @@
<template>
<el-dialog
:title="`Logo ${$t('common.setting')}`"
v-model="dialogVisible"
:close-on-click-modal="false"
:close-on-press-escape="false"
width="550"
>
<el-radio-group v-model="radioType" class="radio-block mb-16">
<el-radio value="default">
<p>{{ $t('common.EditAvatarDialog.default') }}</p>
<el-avatar class="avatar-green" shape="square" :size="32">
<img src="@/assets/node/icon_tool.svg" style="width: 58%" alt="" />
</el-avatar>
</el-radio>
<el-radio value="custom">
<p>{{ $t('common.EditAvatarDialog.customizeUpload') }}</p>
<div class="flex mt-8">
<el-avatar
v-if="fileURL"
shape="square"
:size="32"
style="background: none"
class="mr-16"
>
<img :src="fileURL" alt="" />
</el-avatar>
<el-upload
ref="uploadRef"
action="#"
:auto-upload="false"
:show-file-list="false"
accept="image/jpeg, image/png, image/gif"
:on-change="onChange"
>
<el-button icon="Upload" :disabled="radioType !== 'custom'"
>{{ $t('common.EditAvatarDialog.upload') }}
</el-button>
</el-upload>
</div>
<div class="el-upload__tip info mt-8">
{{ $t('common.EditAvatarDialog.sizeTip') }}
</div>
</el-radio>
</el-radio-group>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }}</el-button>
<el-button type="primary" @click="submit" :loading="loading">
{{ $t('common.save') }}</el-button
>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import ToolApi from '@/api/system-shared/tool'
import { cloneDeep } from 'lodash'
import { MsgError, MsgSuccess } from '@/utils/message'
import { defaultIcon, isAppIcon } from '@/utils/common'
import { t } from '@/locales'
const emit = defineEmits(['refresh'])
const iconFile = ref<any>(null)
const fileURL = ref<any>(null)
const dialogVisible = ref<boolean>(false)
const loading = ref(false)
const detail = ref<any>(null)
const radioType = ref('default')
watch(dialogVisible, (bool) => {
if (!bool) {
iconFile.value = null
fileURL.value = null
}
})
const open = (data: any) => {
radioType.value = isAppIcon(data.icon) ? 'custom' : 'default'
fileURL.value = isAppIcon(data.icon) ? data.icon : null
detail.value = cloneDeep(data)
dialogVisible.value = true
}
const onChange = (file: any) => {
//110MB
const isLimit = file?.size / 1024 / 1024 < 10
if (!isLimit) {
// @ts-ignore
MsgError(t('common.EditAvatarDialog.fileSizeExceeded'))
return false
} else {
iconFile.value = file
fileURL.value = URL.createObjectURL(file.raw)
}
}
function submit() {
if (radioType.value === 'default') {
emit('refresh', '/ui/favicon.ico')
dialogVisible.value = false
} else if (radioType.value === 'custom' && iconFile.value) {
const fd = new FormData()
fd.append('file', iconFile.value.raw)
ToolApi.putToolIcon(detail.value.id, fd, loading).then((res: any) => {
emit('refresh', res.data)
dialogVisible.value = false
})
} else {
MsgError(t('common.EditAvatarDialog.uploadImagePrompt'))
}
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@ -1,116 +0,0 @@
<template>
<el-dialog
:title="isEdit ? $t('common.param.editParam') : $t('common.param.addParam')"
v-model="dialogVisible"
:close-on-click-modal="false"
:close-on-press-escape="false"
:destroy-on-close="true"
append-to-body
>
<el-form
label-position="top"
ref="fieldFormRef"
:rules="rules"
:model="form"
require-asterisk-position="right"
>
<el-form-item :label="$t('views.tool.form.paramName.label')" prop="name">
<el-input
v-model="form.name"
:placeholder="$t('views.tool.form.paramName.placeholder')"
maxlength="64"
show-word-limit
@blur="form.name = form.name.trim()"
/>
</el-form-item>
<el-form-item :label="$t('views.tool.form.dataType.label')">
<el-select v-model="form.type">
<el-option v-for="item in typeOptions" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
<el-form-item :label="$t('views.tool.form.source.label')">
<el-select v-model="form.source">
<el-option :label="$t('views.tool.form.source.reference')" value="reference" />
<el-option :label="$t('views.tool.form.source.custom')" value="custom" />
</el-select>
</el-form-item>
<el-form-item :label="$t('views.tool.form.required.label')" @click.prevent>
<el-switch size="small" v-model="form.is_required"></el-switch>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click.prevent="dialogVisible = false"> {{ $t('common.cancel') }} </el-button>
<el-button type="primary" @click="submit(fieldFormRef)" :loading="loading">
{{ isEdit ? $t('common.save') : $t('common.add') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
import type { FormInstance } from 'element-plus'
import { cloneDeep } from 'lodash'
import { t } from '@/locales'
const typeOptions = ['string', 'int', 'dict', 'array', 'float']
const emit = defineEmits(['refresh'])
const fieldFormRef = ref()
const loading = ref<boolean>(false)
const isEdit = ref(false)
const form = ref<any>({
name: '',
type: typeOptions[0],
source: 'reference',
is_required: true,
})
const rules = reactive({
name: [
{
required: true,
message: t('views.tool.form.paramName.placeholder'),
trigger: 'blur',
},
],
})
const dialogVisible = ref<boolean>(false)
watch(dialogVisible, (bool) => {
if (!bool) {
form.value = {
name: '',
type: typeOptions[0],
source: 'reference',
is_required: true,
}
isEdit.value = false
}
})
const open = (row: any) => {
if (row) {
form.value = cloneDeep(row)
isEdit.value = true
}
dialogVisible.value = true
}
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid) => {
if (valid) {
emit('refresh', form.value)
dialogVisible.value = false
}
})
}
defineExpose({ open })
</script>
<style lang="scss" scoped></style>

View File

@ -1,87 +0,0 @@
<template>
<el-drawer v-model="debugVisible" size="60%" :append-to-body="true">
<template #header>
<h4>{{ $t('common.param.initParam') }}</h4>
</template>
<div>
<div v-if="form.init_field_list?.length > 0">
<DynamicsForm
v-model="form.init_params"
:model="form.init_params"
label-position="top"
require-asterisk-position="right"
:render_data="form.init_field_list"
ref="dynamicsFormRef"
>
</DynamicsForm>
</div>
</div>
<template #footer>
<div>
<el-button type="primary" @click="submit()" :loading="loading">
{{ $t('common.save') }}
</el-button>
</div>
</template>
</el-drawer>
</template>
<script setup lang="ts">
import {ref, watch} from 'vue'
import ToolApi from '@/api/system-shared/tool'
import DynamicsForm from '@/components/dynamics-form/index.vue'
import {MsgSuccess} from '@/utils/message'
import {t} from '@/locales'
import {cloneDeep} from 'lodash'
const emit = defineEmits(['refresh'])
const dynamicsFormRef = ref()
const loading = ref(false)
const debugVisible = ref(false)
const form = ref<any>({
init_params: {},
})
watch(debugVisible, (bool) => {
if (!bool) {
form.value = {
init_params: {},
is_active: false,
}
}
})
const submit = async () => {
dynamicsFormRef.value.validate().then(() => {
ToolApi.putTool(form.value?.id as string, form.value, loading).then((res) => {
MsgSuccess(t('common.editSuccess'))
emit('refresh')
debugVisible.value = false
})
})
}
const open = (data: any, is_active: boolean) => {
if (data) {
form.value = cloneDeep(data)
form.value.is_active = is_active
}
const init_params = form.value.init_field_list
.map((item: any) => {
if (item.show_default_value === false) {
return {[item.field]: undefined}
}
return {[item.field]: item.default_value}
})
.reduce((x: any, y: any) => ({...x, ...y}), {})
form.value.init_params = {...init_params, ...form.value.init_params}
debugVisible.value = true
}
defineExpose({
open,
})
</script>
<style lang="scss"></style>

Some files were not shown because too many files have changed in this diff Show More