mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-28 13:39:28 +07:00
✨ feat: 实现配置导出功能
This commit is contained in:
@@ -13,11 +13,14 @@ import Router from 'next/router';
|
||||
import { ReactNode, memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useExportConfig } from '@/hooks/useExportConfig';
|
||||
|
||||
import pkg from '../../../package.json';
|
||||
|
||||
const BottomAction = memo<{ children: ReactNode }>(({ children }) => {
|
||||
const { t } = useTranslation('common');
|
||||
|
||||
const { exportSessions, exportSettings, exportAll, exportAgents } = useExportConfig();
|
||||
const items: MenuProps['items'] = useMemo(
|
||||
() => [
|
||||
{
|
||||
@@ -30,14 +33,17 @@ const BottomAction = memo<{ children: ReactNode }>(({ children }) => {
|
||||
{
|
||||
key: 'allAgent',
|
||||
label: <div>{t('exportType.allAgent')}</div>,
|
||||
onClick: exportAgents,
|
||||
},
|
||||
{
|
||||
key: 'allAgentWithMessage',
|
||||
label: <div>{t('exportType.allAgentWithMessage')}</div>,
|
||||
onClick: exportSessions,
|
||||
},
|
||||
{
|
||||
key: 'globalSetting',
|
||||
label: <div>{t('exportType.globalSetting')}</div>,
|
||||
onClick: exportSettings,
|
||||
},
|
||||
{
|
||||
type: 'divider',
|
||||
@@ -45,6 +51,7 @@ const BottomAction = memo<{ children: ReactNode }>(({ children }) => {
|
||||
{
|
||||
key: 'all',
|
||||
label: <div>{t('exportType.all')}</div>,
|
||||
onClick: exportAll,
|
||||
},
|
||||
],
|
||||
icon: <Icon icon={FolderOutput} />,
|
||||
|
||||
69
src/hooks/useExportConfig.ts
Normal file
69
src/hooks/useExportConfig.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { transform } from 'lodash-es';
|
||||
import { useMemo } from 'react';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
import { Migration } from '@/migrations';
|
||||
import { useSessionStore } from '@/store/session';
|
||||
import { useSettings } from '@/store/settings';
|
||||
import {
|
||||
ConfigFileAgents,
|
||||
ConfigFileAll,
|
||||
ConfigFileSessions,
|
||||
ConfigFileSettings,
|
||||
} from '@/types/exportConfig';
|
||||
import { exportConfigFile } from '@/utils/config';
|
||||
|
||||
export const useExportConfig = () => {
|
||||
const [sessions] = useSessionStore((s) => [s.sessions], shallow);
|
||||
|
||||
const [settings] = useSettings((s) => [s.settings, s.importSettings], shallow);
|
||||
|
||||
const exportAgents = () => {
|
||||
const config: ConfigFileAgents = {
|
||||
exportType: 'agents',
|
||||
state: {
|
||||
sessions: transform(sessions, (result, value, key) => {
|
||||
result[key] = { ...value, chats: {}, topics: {} };
|
||||
}),
|
||||
},
|
||||
version: Migration.targetVersion,
|
||||
};
|
||||
|
||||
exportConfigFile(config, 'agents');
|
||||
};
|
||||
|
||||
const exportSessions = () => {
|
||||
const config: ConfigFileSessions = {
|
||||
exportType: 'sessions',
|
||||
state: { sessions },
|
||||
version: Migration.targetVersion,
|
||||
};
|
||||
|
||||
exportConfigFile(config, 'sessions');
|
||||
};
|
||||
|
||||
const exportSettings = () => {
|
||||
const config: ConfigFileSettings = {
|
||||
exportType: 'settings',
|
||||
state: { settings },
|
||||
version: Migration.targetVersion,
|
||||
};
|
||||
|
||||
exportConfigFile(config, 'settings');
|
||||
};
|
||||
|
||||
const exportAll = () => {
|
||||
// 将 入参转换为 配置文件格式
|
||||
const config: ConfigFileAll = {
|
||||
exportType: 'all',
|
||||
state: { sessions, settings },
|
||||
version: Migration.targetVersion,
|
||||
};
|
||||
exportConfigFile(config, 'config');
|
||||
};
|
||||
|
||||
return useMemo(
|
||||
() => ({ exportAgents, exportAll, exportSessions, exportSettings }),
|
||||
[sessions, settings],
|
||||
);
|
||||
};
|
||||
@@ -6,10 +6,36 @@ export interface ConfigState {
|
||||
settings: GlobalSettings;
|
||||
}
|
||||
|
||||
export interface ConfigFile {
|
||||
state: ConfigState;
|
||||
/**
|
||||
* 配置文件的版本号
|
||||
*/
|
||||
export interface SettingsConfigState {
|
||||
settings: GlobalSettings;
|
||||
}
|
||||
export interface SessionsConfigState {
|
||||
sessions: LobeSessions;
|
||||
}
|
||||
|
||||
export type ExportType = 'agents' | 'sessions' | 'settings' | 'all';
|
||||
|
||||
export type ConfigFile = ConfigFileSettings | ConfigFileSessions | ConfigFileAll | ConfigFileAgents;
|
||||
|
||||
export interface ConfigFileSettings {
|
||||
exportType: 'settings';
|
||||
state: SettingsConfigState;
|
||||
version: number;
|
||||
}
|
||||
export interface ConfigFileSessions {
|
||||
exportType: 'sessions';
|
||||
state: SessionsConfigState;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface ConfigFileAgents {
|
||||
exportType: 'agents';
|
||||
state: SessionsConfigState;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface ConfigFileAll {
|
||||
exportType: 'all';
|
||||
state: ConfigState;
|
||||
version: number;
|
||||
}
|
||||
|
||||
49
src/utils/config.ts
Normal file
49
src/utils/config.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { notification } from 'antd';
|
||||
|
||||
import { CURRENT_CONFIG_VERSION, Migration } from '@/migrations';
|
||||
import { ConfigState } from '@/types/exportConfig';
|
||||
|
||||
export const exportConfigFile = (config: object, fileName?: string) => {
|
||||
const file = `LobeChat-${fileName || '-config'}-v${CURRENT_CONFIG_VERSION}.json`;
|
||||
|
||||
// 创建一个 Blob 对象
|
||||
const blob = new Blob([JSON.stringify(config)], { type: 'application/json' });
|
||||
|
||||
// 创建一个 URL 对象,用于下载
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
// 创建一个 <a> 元素,设置下载链接和文件名
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = file;
|
||||
|
||||
// 触发 <a> 元素的点击事件,开始下载
|
||||
document.body.append(a);
|
||||
a.click();
|
||||
|
||||
// 下载完成后,清除 URL 对象
|
||||
URL.revokeObjectURL(url);
|
||||
a.remove();
|
||||
};
|
||||
|
||||
export const handleImport = (info: any, onConfigImport: (config: ConfigState) => void) => {
|
||||
const reader = new FileReader();
|
||||
//读取完文件之后的回调函数
|
||||
reader.onloadend = function (evt) {
|
||||
const fileString = evt.target?.result;
|
||||
const fileJson = fileString as string;
|
||||
|
||||
try {
|
||||
const { state } = Migration.migrate(JSON.parse(fileJson));
|
||||
|
||||
onConfigImport(state);
|
||||
} catch (error) {
|
||||
notification.error({
|
||||
description: `出错原因: ${(error as Error).message}`,
|
||||
message: '导入失败',
|
||||
});
|
||||
}
|
||||
};
|
||||
//@ts-ignore file 类型不明确
|
||||
reader.readAsText(info.file.originFileObj, 'utf8');
|
||||
};
|
||||
Reference in New Issue
Block a user