refactor: 清理 LOW 问题 — 样式去重、死代码删除、命名修正

- 抽取 buttons.ts 共享按钮样式,消除 3 个组件的重复定义
- store 删除未调用的 canUndo/canRedo 方法
- importFromContent 变量 ext→lower 修正确性
- CSV 导出修复 BOM 重复(exportToCsv 自带 BOM)
- Rust error.rs 添加 allow(dead_code) 消除编译警告

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-26 08:13:17 +08:00
parent d28861ff9c
commit bdbb399ddc
8 changed files with 27 additions and 45 deletions
+2 -1
View File
@@ -1,6 +1,7 @@
use serde::Serialize;
/// 传给前端的统一错误类型(保留供未来使用,当前命令返回 Result<T, String>
/// 传给前端的统一错误类型(保留供未来迁移使用,届时所有命令改为返回 Result<T, AppError>
#[allow(dead_code)]
#[derive(Debug, Serialize)]
pub struct AppError {
pub message: String,
+1 -8
View File
@@ -1,5 +1,6 @@
import { useTranslation } from 'react-i18next';
import { useAppStore } from '@/store/app-store';
import { btnClass, btnStyle } from '@/components/ui/buttons';
interface ActionButtonsProps {
onNew: () => void;
@@ -24,14 +25,6 @@ export function ActionButtons({
const isAdmin = useAppStore((s) => s.isAdmin);
const disabled = !isAdmin;
const btnClass =
'px-3 py-1 text-sm rounded border transition-colors disabled:opacity-40 disabled:cursor-not-allowed';
const btnStyle = {
backgroundColor: 'var(--app-bg)',
color: 'var(--app-fg)',
borderColor: 'var(--app-border)',
};
return (
<div className="flex gap-1 flex-wrap">
<button className={btnClass} style={btnStyle} disabled={disabled} onClick={onNew}>
+12 -19
View File
@@ -1,5 +1,6 @@
import { useTranslation } from 'react-i18next';
import { useAppStore } from '@/store/app-store';
import { btnClass, btnStyle } from '@/components/ui/buttons';
import { SearchInput } from './SearchInput';
import { ActionButtons } from './ActionButtons';
import { UndoRedoButtons } from './UndoRedoButtons';
@@ -26,14 +27,6 @@ export function ToolBar(props: ToolBarProps) {
const isAdmin = useAppStore((s) => s.isAdmin);
const isModified = useAppStore((s) => s.isModified);
const sysBtnClass =
'px-3 py-1 text-sm rounded border transition-colors disabled:opacity-40 disabled:cursor-not-allowed';
const sysBtnStyle = {
backgroundColor: 'var(--app-bg)',
color: 'var(--app-fg)',
borderColor: 'var(--app-border)',
};
return (
<div className="space-y-2 pb-2 border-b" style={{ borderColor: 'var(--app-border)' }}>
{/* 第一行: 搜索 + 系统按钮 */}
@@ -42,38 +35,38 @@ export function ToolBar(props: ToolBarProps) {
<div className="flex-1" />
<UndoRedoButtons />
<button
className={sysBtnClass}
style={sysBtnStyle}
className={btnClass}
style={btnStyle}
disabled={!isAdmin}
onClick={props.onImport}
>
{t('button.import')}
</button>
<button className={sysBtnClass} style={sysBtnStyle} onClick={props.onExport}>
<button className={btnClass} style={btnStyle} onClick={props.onExport}>
{t('button.export')}
</button>
<button
className={sysBtnClass}
className={btnClass}
style={{
...sysBtnStyle,
backgroundColor: isModified ? '#2563eb' : sysBtnStyle.backgroundColor,
color: isModified ? '#fff' : sysBtnStyle.color,
...btnStyle,
backgroundColor: isModified ? '#2563eb' : btnStyle.backgroundColor,
color: isModified ? '#fff' : btnStyle.color,
}}
disabled={!isAdmin}
onClick={props.onSave}
>
{t('button.save')}
</button>
<button className={sysBtnClass} style={sysBtnStyle} onClick={props.onCancel}>
<button className={btnClass} style={btnStyle} onClick={props.onCancel}>
{t('button.cancel')}
</button>
<button className={sysBtnClass} style={sysBtnStyle} onClick={props.onHelp}>
<button className={btnClass} style={btnStyle} onClick={props.onHelp}>
{t('button.help')}
</button>
<button className={sysBtnClass} style={sysBtnStyle} onClick={props.onLanguage}>
<button className={btnClass} style={btnStyle} onClick={props.onLanguage}>
{t('button.language')}
</button>
<button className={sysBtnClass} style={sysBtnStyle} onClick={props.onDarkMode}>
<button className={btnClass} style={btnStyle} onClick={props.onDarkMode}>
{t('button.darkMode')}
</button>
</div>
+1 -8
View File
@@ -1,5 +1,6 @@
import { useTranslation } from 'react-i18next';
import { useAppStore } from '@/store/app-store';
import { btnClass, btnStyle } from '@/components/ui/buttons';
export function UndoRedoButtons() {
const { t } = useTranslation();
@@ -8,14 +9,6 @@ export function UndoRedoButtons() {
const undo = useAppStore((s) => s.undo);
const redo = useAppStore((s) => s.redo);
const btnClass =
'px-3 py-1 text-sm rounded border transition-colors disabled:opacity-40 disabled:cursor-not-allowed';
const btnStyle = {
backgroundColor: 'var(--app-bg)',
color: 'var(--app-fg)',
borderColor: 'var(--app-border)',
};
return (
<div className="flex gap-1">
<button
+7
View File
@@ -0,0 +1,7 @@
export const btnClass = 'px-3 py-1 text-sm rounded border transition-colors disabled:opacity-40 disabled:cursor-not-allowed';
export const btnStyle: React.CSSProperties = {
backgroundColor: 'var(--app-bg)',
color: 'var(--app-fg)',
borderColor: 'var(--app-border)',
};
+3 -3
View File
@@ -193,10 +193,10 @@ export function importFromContent(
content: string,
filepath: string,
): ImportResult {
const ext = filepath.toLowerCase();
if (ext.endsWith('.csv')) {
const lower = filepath.toLowerCase();
if (lower.endsWith('.csv')) {
return importFromCsv(content);
} else if (ext.endsWith('.json')) {
} else if (lower.endsWith('.json')) {
return importFromJson(content);
} else {
// TXT 文件:所有路径放入 system(用户后续可选择目标)
+1 -1
View File
@@ -108,7 +108,7 @@ export function useAppActions(activeTab: TabId, dialogs: DialogState) {
const content = isCsv ? exportToCsv(data) : exportToJson(data);
const mime = isCsv ? 'text/csv' : 'application/json';
const ext = isCsv ? '.csv' : '.json';
const blob = new Blob([isCsv ? '' : '', content], { type: mime });
const blob = new Blob([content], { type: mime });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
-5
View File
@@ -39,8 +39,6 @@ interface AppState {
undo: () => void;
redo: () => void;
canUndo: () => boolean;
canRedo: () => boolean;
loadPaths: () => Promise<void>;
savePaths: () => Promise<void>;
@@ -227,9 +225,6 @@ export const useAppStore = create<AppState>((set, get) => ({
set({ isModified: !(arraysEqual(sysPaths, _savedSys) && arraysEqual(userPaths, _savedUser)) });
},
canUndo: () => get().undoRedo.canUndo(),
canRedo: () => get().undoRedo.canRedo(),
loadPaths: async () => {
try {
set({ isLoading: true });