feat(data): 业务数据与系统数据分离的导入导出
数据迁移不再整体替换 trade.db —— 那条路会把账号、权限组、组织、设置(含大模型密钥)、 登录会话与审计日志一起搬到目标部署。改为按类别搬运业务数据,系统数据永远是目标部署自己那份。 - backend/lib/dataTransfer:表目录(30 张业务表,依赖顺序)、gzip JSONL 数据包(每表 sha256)、导入内核 - 归属统一给导入人;冲突跳过不覆盖;父记录按 __refs 自然键快照补壳 - 流水表(price_history)按整行内容判重:用 (sku, changed_at) 当键实测 643 行丢 186 行 - 预览在库副本上真跑一遍导入,报告与真导同源;导入前 VACUUM INTO 备份,单事务写入 - 新权限点 data.transfer(仅超管组),导出/导入均写审计 - 前端「数据迁移」页:按类别勾选导出、上传后预览逐表明细、确认导入;移除设置里的静态占位「数据交换」 - 测试:单测 7 项(含目录外键顺序、BLOB、重复导入、包被改坏)、API 端到端 1 项(两个真实实例互传) - 用真实库副本彩排:3854 行 0 失败,29 张业务表行数全部一致,包 1.22 MB
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect, useRef, Suspense } from 'react'
|
||||
import axios from 'axios'
|
||||
import { MoonStarsIcon, SunIcon, TuneIcon, CheckIcon, CloseIcon, ExchangeIcon, SparkIcon, RefreshIcon, BuildingIcon } from './Icons'
|
||||
import { MoonStarsIcon, SunIcon, TuneIcon, CheckIcon, CloseIcon, SparkIcon, RefreshIcon, BuildingIcon } from './Icons'
|
||||
import { useAuth, hasPermission } from '../auth'
|
||||
import { useBranding } from '../branding'
|
||||
|
||||
@@ -10,11 +10,12 @@ const AIConfigSettings = React.lazy(() => import('./AIConfigSettings'))
|
||||
const OrgBrandingSettings = React.lazy(() => import('./OrgBrandingSettings'))
|
||||
|
||||
/* 设置分类。带 permission 的项只对有该权限点的人显示 ——
|
||||
智能配置里有接口地址与密钥,组织品牌是系统管理动作,都不该摆在业务员眼前。 */
|
||||
智能配置里有接口地址与密钥,组织品牌是系统管理动作,都不该摆在业务员眼前。
|
||||
数据导入导出已从设置里移出,做成独立页面「数据迁移」(侧栏 · 系统管理),
|
||||
因为那里要放类别勾选和逐表明细,塞进这个 1000px 的模态框里看不清。 */
|
||||
const CATEGORIES = [
|
||||
{ key: 'appearance', label: '外观与主题', icon: TuneIcon },
|
||||
{ key: 'organization', label: '组织与品牌', icon: BuildingIcon, permission: 'branding.manage' },
|
||||
{ key: 'import-export', label: '数据交换', icon: ExchangeIcon },
|
||||
{ key: 'ai-config', label: '智能配置', icon: SparkIcon, permission: 'ai.manage' },
|
||||
{ key: 'system-update', label: '系统与更新', icon: RefreshIcon }
|
||||
]
|
||||
@@ -89,7 +90,6 @@ function Settings({ isOpen, onClose, theme, onThemeChange, reducedMotion, onRedu
|
||||
<Suspense fallback={<div className="settings-section"><p className="settings-description">正在载入…</p></div>}>
|
||||
{current === 'appearance' && <AppearanceSettings theme={theme} onThemeChange={onThemeChange} reducedMotion={reducedMotion} onReducedMotionChange={onReducedMotionChange} />}
|
||||
{current === 'organization' && <OrgBrandingSettings />}
|
||||
{current === 'import-export' && <ImportExportSettings />}
|
||||
{current === 'ai-config' && <AIConfigSettings />}
|
||||
{current === 'system-update' && <SystemUpdateSettings />}
|
||||
</Suspense>
|
||||
@@ -128,17 +128,7 @@ function AppearanceSettings({ theme, onThemeChange, reducedMotion, onReducedMoti
|
||||
)
|
||||
}
|
||||
|
||||
function ImportExportSettings() {
|
||||
return (
|
||||
<div className="settings-section">
|
||||
<h3>导入 / 导出</h3>
|
||||
<p className="settings-description">管理业务数据的导入、导出与本地备份。</p>
|
||||
<div className="settings-group"><h4>导出数据</h4><div className="settings-actions"><button className="btn btn-secondary">导出供应商数据</button><button className="btn btn-secondary">导出产品数据</button><button className="btn btn-secondary">导出客户数据</button><button className="btn btn-secondary">导出订单数据</button></div></div>
|
||||
<div className="settings-group"><h4>导入数据</h4><div className="settings-actions"><label className="btn btn-secondary file-label">导入供应商数据<input type="file" accept=".csv,.xlsx" /></label><label className="btn btn-secondary file-label">导入产品数据<input type="file" accept=".csv,.xlsx" /></label><label className="btn btn-secondary file-label">导入客户数据<input type="file" accept=".csv,.xlsx" /></label></div><p className="help-text">支持 CSV 和 Excel 格式文件</p></div>
|
||||
<div className="settings-group"><h4>备份与恢复</h4><div className="settings-actions"><button className="btn btn-primary">创建完整备份</button><label className="btn btn-secondary file-label">恢复备份<input type="file" accept=".db,.backup" /></label></div><p className="help-text">建议定期备份数据库</p></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
/* 数据导入导出已移出设置:见 pages/DataTransfer.jsx(侧栏 · 系统管理 · 数据迁移) */
|
||||
|
||||
/* 智能配置已拆到 ./AIConfigSettings(多模型接入 + 用途分配)与 ./OrgBrandingSettings(组织与品牌) */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user