feat(knowledgebase): 添加知识库头像功能

- 在知识库详情中增加头像字段
- 实现知识库头像的上传和显示功能
- 优化知识库编辑界面,支持头像修改
- 调整后端 API 和数据库以支持头像存储
This commit is contained in:
zstar 2025-06-13 18:28:49 +08:00
parent bee2ed1625
commit 86256b3399
5 changed files with 245 additions and 127 deletions

View File

@ -1,19 +1,22 @@
import traceback import traceback
from flask import request from flask import request
from services.knowledgebases.service import KnowledgebaseService from services.knowledgebases.service import KnowledgebaseService
from utils import success_response, error_response from utils import error_response, success_response
from .. import knowledgebase_bp from .. import knowledgebase_bp
@knowledgebase_bp.route('', methods=['GET'])
@knowledgebase_bp.route("", methods=["GET"])
def get_knowledgebase_list(): def get_knowledgebase_list():
"""获取知识库列表""" """获取知识库列表"""
try: try:
params = { params = {
'page': int(request.args.get('currentPage', 1)), "page": int(request.args.get("currentPage", 1)),
'size': int(request.args.get('size', 10)), "size": int(request.args.get("size", 10)),
'name': request.args.get('name', ''), "name": request.args.get("name", ""),
'sort_by': request.args.get("sort_by", "create_time"), "sort_by": request.args.get("sort_by", "create_time"),
'sort_order': request.args.get("sort_order", "desc") "sort_order": request.args.get("sort_order", "desc"),
} }
result = KnowledgebaseService.get_knowledgebase_list(**params) result = KnowledgebaseService.get_knowledgebase_list(**params)
return success_response(result) return success_response(result)
@ -22,87 +25,84 @@ def get_knowledgebase_list():
except Exception as e: except Exception as e:
return error_response(str(e)) return error_response(str(e))
@knowledgebase_bp.route('/<string:kb_id>', methods=['GET'])
@knowledgebase_bp.route("/<string:kb_id>", methods=["GET"])
def get_knowledgebase_detail(kb_id): def get_knowledgebase_detail(kb_id):
"""获取知识库详情""" """获取知识库详情"""
try: try:
knowledgebase = KnowledgebaseService.get_knowledgebase_detail( knowledgebase = KnowledgebaseService.get_knowledgebase_detail(kb_id=kb_id)
kb_id=kb_id
)
if not knowledgebase: if not knowledgebase:
return error_response('知识库不存在', code=404) return error_response("知识库不存在", code=404)
return success_response(knowledgebase) return success_response(knowledgebase)
except Exception as e: except Exception as e:
return error_response(str(e)) return error_response(str(e))
@knowledgebase_bp.route('', methods=['POST'])
@knowledgebase_bp.route("", methods=["POST"])
def create_knowledgebase(): def create_knowledgebase():
"""创建知识库""" """创建知识库"""
try: try:
data = request.json data = request.json
if not data.get('name'): if not data.get("name"):
return error_response('知识库名称不能为空', code=400) return error_response("知识库名称不能为空", code=400)
# 移除 created_by 参数 # 移除 created_by 参数
kb = KnowledgebaseService.create_knowledgebase(**data) kb = KnowledgebaseService.create_knowledgebase(**data)
return success_response(kb, "创建成功", code=0) return success_response(kb, "创建成功", code=0)
except Exception as e: except Exception as e:
return error_response(str(e)) return error_response(str(e))
@knowledgebase_bp.route('/<string:kb_id>', methods=['PUT'])
@knowledgebase_bp.route("/<string:kb_id>", methods=["PUT"])
def update_knowledgebase(kb_id): def update_knowledgebase(kb_id):
"""更新知识库""" """更新知识库"""
try: try:
data = request.json data = request.json
kb = KnowledgebaseService.update_knowledgebase( kb = KnowledgebaseService.update_knowledgebase(kb_id=kb_id, **data)
kb_id=kb_id,
**data
)
if not kb: if not kb:
return error_response('知识库不存在', code=404) return error_response("知识库不存在", code=404)
return success_response(kb) return success_response(kb)
except Exception as e: except Exception as e:
return error_response(str(e)) return error_response(str(e))
@knowledgebase_bp.route('/<string:kb_id>', methods=['DELETE'])
@knowledgebase_bp.route("/<string:kb_id>", methods=["DELETE"])
def delete_knowledgebase(kb_id): def delete_knowledgebase(kb_id):
"""删除知识库""" """删除知识库"""
try: try:
result = KnowledgebaseService.delete_knowledgebase( result = KnowledgebaseService.delete_knowledgebase(kb_id=kb_id)
kb_id=kb_id
)
if not result: if not result:
return error_response('知识库不存在', code=404) return error_response("知识库不存在", code=404)
return success_response(message='删除成功') return success_response(message="删除成功")
except Exception as e: except Exception as e:
return error_response(str(e)) return error_response(str(e))
@knowledgebase_bp.route('/batch', methods=['DELETE'])
@knowledgebase_bp.route("/batch", methods=["DELETE"])
def batch_delete_knowledgebase(): def batch_delete_knowledgebase():
"""批量删除知识库""" """批量删除知识库"""
try: try:
data = request.json data = request.json
if not data or not data.get('ids'): if not data or not data.get("ids"):
return error_response('请选择要删除的知识库', code=400) return error_response("请选择要删除的知识库", code=400)
result = KnowledgebaseService.batch_delete_knowledgebase( result = KnowledgebaseService.batch_delete_knowledgebase(kb_ids=data["ids"])
kb_ids=data['ids'] return success_response(message=f"成功删除 {result} 个知识库")
)
return success_response(message=f'成功删除 {result} 个知识库')
except Exception as e: except Exception as e:
return error_response(str(e)) return error_response(str(e))
@knowledgebase_bp.route('/<string:kb_id>/documents', methods=['GET'])
@knowledgebase_bp.route("/<string:kb_id>/documents", methods=["GET"])
def get_knowledgebase_documents(kb_id): def get_knowledgebase_documents(kb_id):
"""获取知识库下的文档列表""" """获取知识库下的文档列表"""
try: try:
params = { params = {
'kb_id': kb_id, "kb_id": kb_id,
'page': int(request.args.get('currentPage', 1)), "page": int(request.args.get("currentPage", 1)),
'size': int(request.args.get('size', 10)), "size": int(request.args.get("size", 10)),
'name': request.args.get('name', ''), "name": request.args.get("name", ""),
'sort_by': request.args.get("sort_by", "create_time"), "sort_by": request.args.get("sort_by", "create_time"),
'sort_order': request.args.get("sort_order", "desc") "sort_order": request.args.get("sort_order", "desc"),
} }
result = KnowledgebaseService.get_knowledgebase_documents(**params) result = KnowledgebaseService.get_knowledgebase_documents(**params)
return success_response(result) return success_response(result)
@ -111,7 +111,8 @@ def get_knowledgebase_documents(kb_id):
except Exception as e: except Exception as e:
return error_response(str(e)) return error_response(str(e))
@knowledgebase_bp.route('/<string:kb_id>/documents', methods=['POST'])
@knowledgebase_bp.route("/<string:kb_id>/documents", methods=["POST"])
def add_documents_to_knowledgebase(kb_id): def add_documents_to_knowledgebase(kb_id):
"""添加文档到知识库""" """添加文档到知识库"""
try: try:
@ -119,89 +120,86 @@ def add_documents_to_knowledgebase(kb_id):
data = request.json data = request.json
if not data: if not data:
print("[ERROR] 请求数据为空") print("[ERROR] 请求数据为空")
return error_response('请求数据不能为空', code=400) return error_response("请求数据不能为空", code=400)
file_ids = data.get('file_ids', []) file_ids = data.get("file_ids", [])
print(f"[DEBUG] 接收到的file_ids: {file_ids}, 类型: {type(file_ids)}") print(f"[DEBUG] 接收到的file_ids: {file_ids}, 类型: {type(file_ids)}")
try: try:
result = KnowledgebaseService.add_documents_to_knowledgebase( result = KnowledgebaseService.add_documents_to_knowledgebase(kb_id=kb_id, file_ids=file_ids)
kb_id=kb_id,
file_ids=file_ids
)
print(f"[DEBUG] 服务层处理成功,结果: {result}") print(f"[DEBUG] 服务层处理成功,结果: {result}")
return success_response( return success_response(data=result, message="添加成功", code=201)
data=result,
message="添加成功",
code=201
)
except Exception as service_error: except Exception as service_error:
print(f"[ERROR] 服务层错误详情: {str(service_error)}") print(f"[ERROR] 服务层错误详情: {str(service_error)}")
traceback.print_exc() traceback.print_exc()
return error_response(str(service_error), code=500) return error_response(str(service_error), code=500)
except Exception as e: except Exception as e:
print(f"[ERROR] 路由层错误详情: {str(e)}") print(f"[ERROR] 路由层错误详情: {str(e)}")
traceback.print_exc() traceback.print_exc()
return error_response(str(e), code=500) return error_response(str(e), code=500)
@knowledgebase_bp.route('/documents/<string:doc_id>', methods=['DELETE', 'OPTIONS'])
@knowledgebase_bp.route("/documents/<string:doc_id>", methods=["DELETE", "OPTIONS"])
def delete_document(doc_id): def delete_document(doc_id):
"""删除文档""" """删除文档"""
# 处理 OPTIONS 预检请求 # 处理 OPTIONS 预检请求
if request.method == 'OPTIONS': if request.method == "OPTIONS":
response = success_response({}) response = success_response({})
# 添加 CORS 相关头 # 添加 CORS 相关头
response.headers.add('Access-Control-Allow-Methods', 'DELETE') response.headers.add("Access-Control-Allow-Methods", "DELETE")
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization') response.headers.add("Access-Control-Allow-Headers", "Content-Type,Authorization")
return response return response
try: try:
KnowledgebaseService.delete_document(doc_id) KnowledgebaseService.delete_document(doc_id)
return success_response(message="删除成功") return success_response(message="删除成功")
except Exception as e: except Exception as e:
return error_response(str(e)) return error_response(str(e))
@knowledgebase_bp.route('/documents/<doc_id>/parse', methods=['POST'])
@knowledgebase_bp.route("/documents/<doc_id>/parse", methods=["POST"])
def parse_document(doc_id): def parse_document(doc_id):
"""开始解析文档""" """开始解析文档"""
# 处理 OPTIONS 预检请求 # 处理 OPTIONS 预检请求
if request.method == 'OPTIONS': if request.method == "OPTIONS":
response = success_response({}) response = success_response({})
# 添加 CORS 相关头 # 添加 CORS 相关头
response.headers.add('Access-Control-Allow-Methods', 'POST') response.headers.add("Access-Control-Allow-Methods", "POST")
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization') response.headers.add("Access-Control-Allow-Headers", "Content-Type,Authorization")
return response return response
try: try:
result = KnowledgebaseService.async_parse_document(doc_id) result = KnowledgebaseService.async_parse_document(doc_id)
return success_response(data=result) return success_response(data=result)
except Exception as e: except Exception as e:
return error_response(str(e), code=500) return error_response(str(e), code=500)
@knowledgebase_bp.route('/documents/<doc_id>/parse/progress', methods=['GET'])
@knowledgebase_bp.route("/documents/<doc_id>/parse/progress", methods=["GET"])
def get_parse_progress(doc_id): def get_parse_progress(doc_id):
"""获取文档解析进度""" """获取文档解析进度"""
# 处理 OPTIONS 预检请求 # 处理 OPTIONS 预检请求
if request.method == 'OPTIONS': if request.method == "OPTIONS":
response = success_response({}) response = success_response({})
# 添加 CORS 相关头 # 添加 CORS 相关头
response.headers.add('Access-Control-Allow-Methods', 'GET') response.headers.add("Access-Control-Allow-Methods", "GET")
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization') response.headers.add("Access-Control-Allow-Headers", "Content-Type,Authorization")
return response return response
try: try:
result = KnowledgebaseService.get_document_parse_progress(doc_id) result = KnowledgebaseService.get_document_parse_progress(doc_id)
if isinstance(result, dict) and 'error' in result: if isinstance(result, dict) and "error" in result:
return error_response(result['error'], code=404) return error_response(result["error"], code=404)
return success_response(data=result) return success_response(data=result)
except Exception as e: except Exception as e:
print(f"获取解析进度失败: {str(e)}") print(f"获取解析进度失败: {str(e)}")
return error_response("解析进行中,请稍后重试", code=202) return error_response("解析进行中,请稍后重试", code=202)
# 获取系统 Embedding 配置路由 # 获取系统 Embedding 配置路由
@knowledgebase_bp.route('/system_embedding_config', methods=['GET']) @knowledgebase_bp.route("/system_embedding_config", methods=["GET"])
def get_system_embedding_config_route(): def get_system_embedding_config_route():
"""获取系统级 Embedding 配置的API端点""" """获取系统级 Embedding 配置的API端点"""
try: try:
@ -209,69 +207,68 @@ def get_system_embedding_config_route():
return success_response(data=config_data) return success_response(data=config_data)
except Exception as e: except Exception as e:
print(f"获取系统 Embedding 配置失败: {str(e)}") print(f"获取系统 Embedding 配置失败: {str(e)}")
return error_response(message=f"获取配置失败: {str(e)}", code=500) # 返回通用错误信息 return error_response(message=f"获取配置失败: {str(e)}", code=500) # 返回通用错误信息
# 设置系统 Embedding 配置路由 # 设置系统 Embedding 配置路由
@knowledgebase_bp.route('/system_embedding_config', methods=['POST']) @knowledgebase_bp.route("/system_embedding_config", methods=["POST"])
def set_system_embedding_config_route(): def set_system_embedding_config_route():
"""设置系统级 Embedding 配置的API端点""" """设置系统级 Embedding 配置的API端点"""
try: try:
data = request.json data = request.json
if not data: if not data:
return error_response('请求数据不能为空', code=400) return error_response("请求数据不能为空", code=400)
llm_name = data.get('llm_name', '').strip() llm_name = data.get("llm_name", "").strip()
api_base = data.get('api_base', '').strip() api_base = data.get("api_base", "").strip()
api_key = data.get('api_key', '').strip() # 允许空 api_key = data.get("api_key", "").strip() # 允许空
if not llm_name or not api_base: if not llm_name or not api_base:
return error_response('模型名称和 API 地址不能为空', code=400) return error_response("模型名称和 API 地址不能为空", code=400)
# 调用服务层进行处理(包括连接测试和数据库操作) # 调用服务层进行处理(包括连接测试和数据库操作)
success, message = KnowledgebaseService.set_system_embedding_config( success, message = KnowledgebaseService.set_system_embedding_config(llm_name=llm_name, api_base=api_base, api_key=api_key)
llm_name=llm_name,
api_base=api_base,
api_key=api_key
)
if success: if success:
return success_response(message=message) return success_response(message=message)
else: else:
# 如果服务层返回失败(例如连接测试失败或数据库错误),将消息返回给前端 # 如果服务层返回失败(例如连接测试失败或数据库错误),将消息返回给前端
return error_response(message=message, code=400) # 使用 400 表示操作失败 return error_response(message=message, code=400) # 使用 400 表示操作失败
except Exception as e: except Exception as e:
# 捕获路由层或未预料的服务层异常 # 捕获路由层或未预料的服务层异常
print(f"设置系统 Embedding 配置失败: {str(e)}") print(f"设置系统 Embedding 配置失败: {str(e)}")
return error_response(message=f"设置配置时发生内部错误: {str(e)}", code=500) return error_response(message=f"设置配置时发生内部错误: {str(e)}", code=500)
@knowledgebase_bp.route('/documents/<doc_id>/parse', methods=['POST'])
def parse_document_async(doc_id): # 函数名改为 async 以区分 @knowledgebase_bp.route("/documents/<doc_id>/parse", methods=["POST"])
def parse_document_async(doc_id): # 函数名改为 async 以区分
"""开始异步解析单个文档""" """开始异步解析单个文档"""
if request.method == 'OPTIONS': if request.method == "OPTIONS":
response = success_response({}) response = success_response({})
response.headers.add('Access-Control-Allow-Methods', 'POST') response.headers.add("Access-Control-Allow-Methods", "POST")
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization') response.headers.add("Access-Control-Allow-Headers", "Content-Type,Authorization")
return response return response
try: try:
result = KnowledgebaseService.parse_document(doc_id) # 调用同步版本 result = KnowledgebaseService.parse_document(doc_id) # 调用同步版本
if result.get("success"): if result.get("success"):
return success_response(data={"message": f"文档 {doc_id} 同步解析完成。", "details": result}) return success_response(data={"message": f"文档 {doc_id} 同步解析完成。", "details": result})
else: else:
return error_response(result.get("message", "解析失败"), code=500) return error_response(result.get("message", "解析失败"), code=500)
except Exception as e: except Exception as e:
return error_response(str(e), code=500) return error_response(str(e), code=500)
# 启动顺序批量解析路由 # 启动顺序批量解析路由
@knowledgebase_bp.route('/<string:kb_id>/batch_parse_sequential/start', methods=['POST']) @knowledgebase_bp.route("/<string:kb_id>/batch_parse_sequential/start", methods=["POST"])
def start_sequential_batch_parse_route(kb_id): def start_sequential_batch_parse_route(kb_id):
"""异步启动知识库的顺序批量解析任务""" """异步启动知识库的顺序批量解析任务"""
if request.method == 'OPTIONS': if request.method == "OPTIONS":
response = success_response({}) response = success_response({})
response.headers.add('Access-Control-Allow-Methods', 'POST') response.headers.add("Access-Control-Allow-Methods", "POST")
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization') response.headers.add("Access-Control-Allow-Headers", "Content-Type,Authorization")
return response return response
try: try:
@ -286,14 +283,15 @@ def start_sequential_batch_parse_route(kb_id):
traceback.print_exc() traceback.print_exc()
return error_response(f"启动顺序批量解析失败: {str(e)}", code=500) return error_response(f"启动顺序批量解析失败: {str(e)}", code=500)
# 获取顺序批量解析进度路由 # 获取顺序批量解析进度路由
@knowledgebase_bp.route('/<string:kb_id>/batch_parse_sequential/progress', methods=['GET']) @knowledgebase_bp.route("/<string:kb_id>/batch_parse_sequential/progress", methods=["GET"])
def get_sequential_batch_parse_progress_route(kb_id): def get_sequential_batch_parse_progress_route(kb_id):
"""获取知识库的顺序批量解析任务进度""" """获取知识库的顺序批量解析任务进度"""
if request.method == 'OPTIONS': if request.method == "OPTIONS":
response = success_response({}) response = success_response({})
response.headers.add('Access-Control-Allow-Methods', 'GET') response.headers.add("Access-Control-Allow-Methods", "GET")
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization') response.headers.add("Access-Control-Allow-Headers", "Content-Type,Authorization")
return response return response
try: try:
@ -303,4 +301,4 @@ def get_sequential_batch_parse_progress_route(kb_id):
except Exception as e: except Exception as e:
print(f"获取顺序批量解析进度路由处理失败 (KB ID: {kb_id}): {str(e)}") print(f"获取顺序批量解析进度路由处理失败 (KB ID: {kb_id}): {str(e)}")
traceback.print_exc() traceback.print_exc()
return error_response(f"获取进度失败: {str(e)}", code=500) return error_response(f"获取进度失败: {str(e)}", code=500)

View File

@ -8,7 +8,6 @@ import shutil
import tempfile import tempfile
import time import time
from datetime import datetime from datetime import datetime
from io import BytesIO
from urllib.parse import urlparse from urllib.parse import urlparse
import requests import requests
@ -61,7 +60,7 @@ def perform_parse(doc_id, doc_info, file_info, embedding_config, kb_info):
if embedding_model_name == "netease-youdao/bce-embedding-base_v1": if embedding_model_name == "netease-youdao/bce-embedding-base_v1":
embedding_model_name = "BAAI/bge-m3" embedding_model_name = "BAAI/bge-m3"
embedding_api_base = embedding_config.get("api_base") if embedding_config and embedding_config.get("api_base") else "http://localhost:8000" # 默认基础 URL embedding_api_base = embedding_config.get("api_base") if embedding_config and embedding_config.get("api_base") else "http://localhost:11434" # 默认基础 URL
# 如果 API 基础地址为空字符串,设置为硅基流动的 API 地址 # 如果 API 基础地址为空字符串,设置为硅基流动的 API 地址
if embedding_api_base == "": if embedding_api_base == "":

View File

@ -105,7 +105,8 @@ class KnowledgebaseService:
k.description, k.description,
k.create_date, k.create_date,
k.update_date, k.update_date,
k.doc_num k.doc_num,
k.avatar
FROM knowledgebase k FROM knowledgebase k
WHERE k.id = %s WHERE k.id = %s
""" """
@ -334,6 +335,13 @@ class KnowledgebaseService:
update_fields.append("permission = %s") update_fields.append("permission = %s")
params.append(data["permission"]) params.append(data["permission"])
if "avatar" in data and data["avatar"]:
avatar_base64 = data["avatar"]
# 拼接上前缀
full_avatar_url = f"data:image/png;base64,{avatar_base64}"
update_fields.append("avatar = %s")
params.append(full_avatar_url)
# 更新时间 # 更新时间
current_time = datetime.now() current_time = datetime.now()
update_date = current_time.strftime("%Y-%m-%d %H:%M:%S") update_date = current_time.strftime("%Y-%m-%d %H:%M:%S")

View File

@ -1,5 +1,19 @@
import { request } from "@/http/axios" import { request } from "@/http/axios"
// 定义修改数据库界面中显示的信息
interface KbDetailData {
id: string
name: string
permission: string
avatar?: string
}
interface ApiDetailResponse {
data: KbDetailData
code: number
message: string
}
// 获取知识库列表 // 获取知识库列表
export function getKnowledgeBaseListApi(params: { export function getKnowledgeBaseListApi(params: {
currentPage: number currentPage: number
@ -16,7 +30,7 @@ export function getKnowledgeBaseListApi(params: {
} }
// 获取知识库详情 // 获取知识库详情
export function getKnowledgeBaseDetailApi(id: string) { export function getKbDetailApi(id: string): Promise<ApiDetailResponse> {
return request({ return request({
url: `/api/v1/knowledgebases/${id}`, url: `/api/v1/knowledgebases/${id}`,
method: "get" method: "get"
@ -44,6 +58,7 @@ export function updateKnowledgeBaseApi(id: string, data: {
description?: string description?: string
language?: string language?: string
permission?: string permission?: string
avatar?: string
}) { }) {
return request({ return request({
url: `/api/v1/knowledgebases/${id}`, url: `/api/v1/knowledgebases/${id}`,

View File

@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { SequentialBatchTaskProgress } from "@@/apis/kbs/document" import type { SequentialBatchTaskProgress } from "@@/apis/kbs/document"
import type { FormInstance } from "element-plus" import type { FormInstance, UploadFile, UploadProps } from "element-plus"
import DocumentParseProgress from "@/layouts/components/DocumentParseProgress/index.vue" import DocumentParseProgress from "@/layouts/components/DocumentParseProgress/index.vue"
import { import {
deleteDocumentApi, deleteDocumentApi,
@ -14,9 +14,11 @@ import {
batchDeleteKnowledgeBaseApi, batchDeleteKnowledgeBaseApi,
createKnowledgeBaseApi, createKnowledgeBaseApi,
deleteKnowledgeBaseApi, deleteKnowledgeBaseApi,
getKbDetailApi,
getKnowledgeBaseListApi, getKnowledgeBaseListApi,
getSystemEmbeddingConfigApi, getSystemEmbeddingConfigApi,
setSystemEmbeddingConfigApi setSystemEmbeddingConfigApi,
updateKnowledgeBaseApi
} from "@@/apis/kbs/knowledgebase" } from "@@/apis/kbs/knowledgebase"
import { getTableDataApi } from "@@/apis/tables" import { getTableDataApi } from "@@/apis/tables"
import { usePagination } from "@@/composables/usePagination" import { usePagination } from "@@/composables/usePagination"
@ -157,39 +159,91 @@ const editDialogVisible = ref(false)
const editForm = reactive({ const editForm = reactive({
id: "", id: "",
name: "", name: "",
permission: "me" permission: "me",
avatar: ""
}) })
const editLoading = ref(false) const editLoading = ref(false)
// // //
function handleEdit(row: KnowledgeBaseData) { // function handleEdit(row: KnowledgeBaseData) {
// editDialogVisible.value = true
// editForm.id = row.id
// editForm.name = row.name
// editForm.permission = row.permission
// }
//
async function handleEdit(row: KnowledgeBaseData) {
editDialogVisible.value = true editDialogVisible.value = true
editForm.id = row.id editLoading.value = true
editForm.name = row.name try {
editForm.permission = row.permission const { data } = await getKbDetailApi(row.id)
editForm.id = data.id
editForm.name = data.name
editForm.permission = row.permission
// base64
if (data.avatar && !data.avatar.startsWith("data:image")) {
editForm.avatar = `data:image/jpeg;base64,${data.avatar}`
} else {
editForm.avatar = data.avatar || ""
}
} catch (error: any) {
ElMessage.error(`获取知识库详情失败: ${error?.message || "未知错误"}`)
editDialogVisible.value = false //
} finally {
editLoading.value = false
}
} }
// //
function submitEdit() { function submitEdit() {
editLoading.value = true editLoading.value = true
// API
axios.put(`/api/v1/knowledgebases/${editForm.id}`, { //
const payload: { permission: string, avatar?: string } = {
permission: editForm.permission permission: editForm.permission
}) }
// Base64
if (editForm.avatar && editForm.avatar.startsWith("data:image")) {
payload.avatar = editForm.avatar.split(",")[1]
}
// 使 API
updateKnowledgeBaseApi(editForm.id, payload)
.then(() => { .then(() => {
ElMessage.success("知识库权限修改成功") ElMessage.success("知识库信息修改成功")
editDialogVisible.value = false editDialogVisible.value = false
// getTableData() //
getTableData()
}) })
.catch((error) => { .catch((error: any) => {
ElMessage.error(`修改知识库权限失败: ${error?.message || "未知错误"}`) ElMessage.error(`修改知识库失败: ${error?.message || "未知错误"}`)
}) })
.finally(() => { .finally(() => {
editLoading.value = false editLoading.value = false
}) })
} }
const handleAvatarChange: UploadProps["onChange"] = (uploadFile: UploadFile) => {
if (!uploadFile.raw) return
if (!uploadFile.raw.type.includes("image")) {
ElMessage.error("请上传图片格式文件!")
return false
}
//
const isLt2M = uploadFile.raw.size / 1024 / 1024 < 2
if (!isLt2M) {
ElMessage.error("上传头像图片大小不能超过 2MB!")
return false
}
const reader = new FileReader()
reader.readAsDataURL(uploadFile.raw)
reader.onload = () => {
editForm.avatar = reader.result as string
}
}
// //
const multipleSelection = ref<KnowledgeBaseData[]>([]) const multipleSelection = ref<KnowledgeBaseData[]>([])
@ -1404,6 +1458,21 @@ const userLoading = ref(false)
<el-form-item label="知识库名称"> <el-form-item label="知识库名称">
<span>{{ editForm.name }}</span> <span>{{ editForm.name }}</span>
</el-form-item> </el-form-item>
<el-form-item label="知识库头像">
<el-upload
class="avatar-uploader"
action="#"
:show-file-list="false"
:on-change="handleAvatarChange"
:auto-upload="false"
accept="image/png, image/jpeg, image/gif, image/webp"
>
<img v-if="editForm.avatar" :src="editForm.avatar" class="avatar" alt="avatar">
<el-icon v-else class="avatar-uploader-icon">
<Plus />
</el-icon>
</el-upload>
</el-form-item>
<el-form-item label="权限设置"> <el-form-item label="权限设置">
<el-select v-model="editForm.permission" placeholder="请选择权限"> <el-select v-model="editForm.permission" placeholder="请选择权限">
<el-option label="个人" value="me" /> <el-option label="个人" value="me" />
@ -1697,4 +1766,33 @@ const userLoading = ref(false)
vertical-align: middle; vertical-align: middle;
animation: rotating 2s linear infinite; animation: rotating 2s linear infinite;
} }
.avatar-uploader .el-upload {
border: 1px dashed var(--el-border-color);
border-radius: 50%; /* 圆形 */
cursor: pointer;
position: relative;
overflow: hidden;
transition: var(--el-transition-duration-fast);
}
.avatar-uploader .el-upload:hover {
border-color: var(--el-color-primary);
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 120px;
height: 120px;
text-align: center;
line-height: 120px; /* 垂直居中图标 */
}
.avatar {
width: 120px;
height: 120px;
display: block;
object-fit: cover; /* 保证图片不变形 */
}
</style> </style>