From 0b24bd36f429c8ab59652a9b9e5f5c14423efc7b Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Sun, 18 May 2025 17:18:29 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=BB=84=E4=BB=B6=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/components/ChatComponent.vue | 85 +- .../components/ModelProvidersComponent.vue | 686 +++++++++++ web/src/components/ModelSelectorComponent.vue | 117 ++ .../components/UserManagementComponent.vue | 372 ++++++ web/src/views/SettingView.vue | 1033 +---------------- 5 files changed, 1192 insertions(+), 1101 deletions(-) create mode 100644 web/src/components/ModelProvidersComponent.vue create mode 100644 web/src/components/ModelSelectorComponent.vue create mode 100644 web/src/components/UserManagementComponent.vue diff --git a/web/src/components/ChatComponent.vue b/web/src/components/ChatComponent.vue index 6bba07d9..298411e9 100644 --- a/web/src/components/ChatComponent.vue +++ b/web/src/components/ChatComponent.vue @@ -17,29 +17,7 @@ - - - - - {{ configStore.config?.model_name }} - - {{ configStore.config?.model_provider }} - - - +
- - - -
@@ -362,120 +112,26 @@ import { ReloadOutlined, SettingOutlined, CodeOutlined, - ExceptionOutlined, FolderOutlined, - DeleteOutlined, - EditOutlined, - InfoCircleOutlined, - DownOutlined, - UpOutlined, - LoadingOutlined, - UpCircleOutlined, - DownCircleOutlined, - UserOutlined, - PlusOutlined + UserOutlined } from '@ant-design/icons-vue'; import HeaderComponent from '@/components/HeaderComponent.vue'; import TableConfigComponent from '@/components/TableConfigComponent.vue'; +import ModelProvidersComponent from '@/components/ModelProvidersComponent.vue'; +import UserManagementComponent from '@/components/UserManagementComponent.vue'; import { notification, Button } from 'ant-design-vue'; -import { modelIcons } from '@/utils/modelIcon' import { systemConfigApi } from '@/apis/admin_api' -import { chatApi } from '@/apis/auth_api' - const configStore = useConfigStore() const userStore = useUserStore() const items = computed(() => configStore.config._config_items) -const modelNames = computed(() => configStore.config?.model_names) -const modelStatus = computed(() => configStore.config?.model_provider_status) -const modelProvider = computed(() => configStore.config?.model_provider) const isNeedRestart = ref(false) -const customModel = reactive({ - modelTitle: '添加自定义模型', - visible: false, - custom_id: '', - name: '', - api_key: '', - api_base: '', - edit_type: 'add', -}) -const providerConfig = reactive({ - visible: false, - provider: '', - providerName: '', - models: [], - allModels: [], // 所有可用的模型 - selectedModels: [], // 用户选择的模型 - loading: false, -}) const state = reactive({ loading: false, section: 'base', windowWidth: window?.innerWidth || 0 }) -// 用户管理相关状态 -const userManagement = reactive({ - loading: false, - users: [], - error: null, - modalVisible: false, - modalTitle: '添加用户', - editMode: false, - editUserId: null, - form: { - username: '', - password: '', - confirmPassword: '', - role: 'user' // 默认角色 - }, - displayPasswordFields: true, // 编辑时是否显示密码字段 -}) - -// 筛选 modelStatus 中为真的key -const modelKeys = computed(() => { - return Object.keys(modelStatus.value || {}).filter(key => modelStatus.value?.[key]) -}) - -// 监听密码字段显示状态变化 -watch(() => userManagement.displayPasswordFields, (newVal) => { - // 当取消显示密码字段时,清空密码输入 - if (!newVal) { - userManagement.form.password = '' - userManagement.form.confirmPassword = '' - } -}) - -const notModelKeys = computed(() => { - return Object.keys(modelStatus.value || {}).filter(key => !modelStatus.value?.[key]) -}) - -// 模型展开状态管理 -const expandedModels = reactive({}) - -// 监听 modelKeys 变化,确保新添加的模型也是默认展开状态 -watch(modelKeys, (newKeys) => { - newKeys.forEach(key => { - if (expandedModels[key] === undefined) { - expandedModels[key] = true - } - }) -}, { immediate: true }) - -// 切换展开状态的方法 -const toggleExpand = (item) => { - expandedModels[item] = !expandedModels[item] -} - -const generateRandomHash = (length) => { - let chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; - let hash = ''; - for (let i = 0; i < length; i++) { - hash += chars.charAt(Math.floor(Math.random() * chars.length)); - } - return hash; -} - const handleModelLocalPathsUpdate = (config) => { handleChange('model_local_paths', config) } @@ -525,71 +181,6 @@ const handleChanges = (items) => { configStore.setConfigValues(items) } -const handleAddOrEditCustomModel = async () => { - if (!customModel.name || !customModel.api_base) { - message.error('请填写完整的模型名称和API Base信息。') - return - } - - let custom_models = configStore.config.custom_models || []; - - const model_info = { - custom_id: customModel.custom_id || `${customModel.name}-${generateRandomHash(4)}`, - name: customModel.name, - api_key: customModel.api_key, - api_base: customModel.api_base, - } - - if (customModel.edit_type === 'add') { - if (custom_models.find(item => item.custom_id === customModel.custom_id)) { - message.error('模型ID已存在') - return - } - custom_models.push(model_info) - } else { - // 如果 custom_id 相同,则更新 - custom_models = custom_models.map(item => item.custom_id === customModel.custom_id ? model_info : item); - } - - customModel.visible = false; - await configStore.setConfigValue('custom_models', custom_models); - message.success(customModel.edit_type === 'add' ? '模型添加成功' : '模型修改成功'); -} - -const handleDeleteCustomModel = (custom_id) => { - const updatedModels = configStore.config.custom_models.filter(item => item.custom_id !== custom_id); - configStore.setConfigValue('custom_models', updatedModels); -} - -const prepareToEditCustomModel = (item) => { - customModel.modelTitle = '编辑自定义模型' - customModel.custom_id = item.custom_id - customModel.visible = true - customModel.edit_type = 'edit' - customModel.name = item.name - customModel.api_key = item.api_key - customModel.api_base = item.api_base -} - -const prepareToAddCustomModel = () => { - customModel.modelTitle = '添加自定义模型' - customModel.edit_type = 'add' - customModel.visible = true - clearCustomModel() -} - -const clearCustomModel = () => { - customModel.custom_id = '' - customModel.name = '' - customModel.api_key = '' - customModel.api_base = '' -} - -const handleCancelCustomModel = () => { - clearCustomModel() - customModel.visible = false -} - const updateWindowWidth = () => { state.windowWidth = window?.innerWidth || 0 } @@ -620,310 +211,6 @@ const sendRestart = () => { message.error({ content: `重启失败: ${error.message}`, key: "restart", duration: 2 }); }); } - -// 获取模型提供商的模型列表 -const fetchProviderModels = (provider) => { - providerConfig.loading = true; - chatApi.getProviderModels(provider) - .then(data => { - console.log(`${provider} 模型列表:`, data); - - // 处理各种可能的API返回格式 - let modelsList = []; - - // 情况1: { data: [...] } - if (data.data && Array.isArray(data.data)) { - modelsList = data.data; - } - // 情况2: { models: [...] } (字符串数组) - else if (data.models && Array.isArray(data.models)) { - modelsList = data.models.map(model => typeof model === 'string' ? { id: model } : model); - } - // 情况3: { models: { data: [...] } } - else if (data.models && data.models.data && Array.isArray(data.models.data)) { - modelsList = data.models.data; - } - - console.log("处理后的模型列表:", modelsList); - providerConfig.allModels = modelsList; - providerConfig.loading = false; - }) - .catch(error => { - console.error(`获取${provider}模型列表失败:`, error); - message.error({ content: `获取${modelNames.value[provider].name}模型列表失败`, duration: 2 }); - providerConfig.loading = false; - }); -} - -const openProviderConfig = (provider) => { - providerConfig.provider = provider; - providerConfig.providerName = modelNames.value[provider].name; - providerConfig.allModels = []; - providerConfig.visible = true; - providerConfig.loading = true; - - // 获取当前选择的模型作为初始选中值 - const currentModels = modelNames.value[provider]?.models || []; - providerConfig.selectedModels = [...currentModels]; - - // 获取所有可用模型 - fetchProviderModels(provider); -} - -const saveProviderConfig = async () => { - if (!modelStatus.value[providerConfig.provider]) { - message.error('请在 src/.env 中配置对应的 APIKEY,并重新启动服务') - return - } - - message.loading({ content: '保存配置中...', key: 'save-config', duration: 0 }); - - try { - // 发送选择的模型列表到后端 - const data = await chatApi.updateProviderModels(providerConfig.provider, providerConfig.selectedModels); - console.log('更新后的模型列表:', data.models); - - message.success({ content: '模型配置已保存!', key: 'save-config', duration: 2 }); - - // 关闭弹窗 - providerConfig.visible = false; - - // 刷新配置 - configStore.refreshConfig(); - - } catch (error) { - console.error('保存配置失败:', error); - message.error({ content: '保存配置失败: ' + error.message, key: 'save-config', duration: 2 }); - } -} - -const cancelProviderConfig = () => { - providerConfig.visible = false; -} - -// 获取用户列表 -const fetchUsers = async () => { - try { - userManagement.loading = true - const users = await userStore.getUsers() - userManagement.users = users - userManagement.error = null - } catch (error) { - console.error('获取用户列表失败:', error) - userManagement.error = '获取用户列表失败' - } finally { - userManagement.loading = false - } -} - -// 打开添加用户模态框 -const showAddUserModal = () => { - userManagement.modalTitle = '添加用户' - userManagement.editMode = false - userManagement.editUserId = null - userManagement.form = { - username: '', - password: '', - confirmPassword: '', - role: 'user' // 默认角色为普通用户 - } - userManagement.displayPasswordFields = true - userManagement.modalVisible = true -} - -// 打开编辑用户模态框 -const showEditUserModal = (user) => { - userManagement.modalTitle = '编辑用户' - userManagement.editMode = true - userManagement.editUserId = user.id - userManagement.form = { - username: user.username, - password: '', - confirmPassword: '', - role: user.role - } - userManagement.displayPasswordFields = true // 默认显示密码字段 - userManagement.modalVisible = true -} - -// 处理用户表单提交 -const handleUserFormSubmit = async () => { - try { - // 简单验证 - if (!userManagement.form.username) { - notification.error({ message: '用户名不能为空' }) - return - } - - if (userManagement.displayPasswordFields) { - if (!userManagement.form.password) { - notification.error({ message: '密码不能为空' }) - return - } - - if (userManagement.form.password !== userManagement.form.confirmPassword) { - notification.error({ message: '两次输入的密码不一致' }) - return - } - } - - userManagement.loading = true - - // 根据模式决定创建还是更新用户 - if (userManagement.editMode) { - // 创建更新数据对象 - const updateData = { - username: userManagement.form.username, - role: userManagement.form.role - } - - // 如果显示了密码字段并且填写了密码,才更新密码 - if (userManagement.displayPasswordFields && userManagement.form.password) { - updateData.password = userManagement.form.password - } - - await userStore.updateUser(userManagement.editUserId, updateData) - notification.success({ message: '用户更新成功' }) - } else { - await userStore.createUser({ - username: userManagement.form.username, - password: userManagement.form.password, - role: userManagement.form.role - }) - notification.success({ message: '用户创建成功' }) - } - - // 重新获取用户列表 - await fetchUsers() - userManagement.modalVisible = false - } catch (error) { - console.error('用户操作失败:', error) - notification.error({ - message: '操作失败', - description: error.message || '请稍后重试' - }) - } finally { - userManagement.loading = false - } -} - -// 切换是否显示密码字段(编辑用户时使用) -const togglePasswordFields = () => { - userManagement.displayPasswordFields = !userManagement.displayPasswordFields - if (!userManagement.displayPasswordFields) { - userManagement.form.password = '' - userManagement.form.confirmPassword = '' - } -} - -// 删除用户 -const confirmDeleteUser = (user) => { - // 自己不能删除自己 - if (user.id === userStore.userId) { - notification.error({ message: '不能删除自己的账户' }) - return - } - - // 确认对话框 - const { modal } = notification - - modal.confirm({ - title: '确认删除用户', - content: `确定要删除用户 "${user.username}" 吗?此操作不可撤销。`, - okText: '删除', - okType: 'danger', - cancelText: '取消', - async onOk() { - try { - userManagement.loading = true - await userStore.deleteUser(user.id) - notification.success({ message: '用户删除成功' }) - // 重新获取用户列表 - await fetchUsers() - } catch (error) { - console.error('删除用户失败:', error) - notification.error({ - message: '删除失败', - description: error.message || '请稍后重试' - }) - } finally { - userManagement.loading = false - } - } - }) -} - -// 在组件挂载时,如果选择了用户管理部分,则获取用户列表 -const loadUserManagement = async () => { - if (state.section === 'user') { - await fetchUsers() - } -} - -// 监听部分切换 -watch(() => state.section, async (newSection) => { - if (newSection === 'user') { - await fetchUsers() - } -}) - -// 用户表格列定义 -const userColumns = [ - { - title: 'ID', - dataIndex: 'id', - key: 'id', - width: 80 - }, - { - title: '用户名', - dataIndex: 'username', - key: 'username' - }, - { - title: '角色', - dataIndex: 'role', - key: 'role', - width: 120 - }, - { - title: '创建时间', - dataIndex: 'created_at', - key: 'created_at', - width: 180 - }, - { - title: '最后登录', - dataIndex: 'last_login', - key: 'last_login', - width: 180 - }, - { - title: '操作', - key: 'action', - width: 120 - } -] - -// 角色显示辅助函数 -const getRoleLabel = (role) => { - switch (role) { - case 'superadmin': return '超级管理员' - case 'admin': return '管理员' - case 'user': return '普通用户' - default: return role - } -} - -// 角色标签颜色 -const getRoleColor = (role) => { - switch (role) { - case 'superadmin': return 'red' - case 'admin': return 'blue' - case 'user': return 'green' - default: return 'default' - } -}