删除分页和结果分析功能,优化了表格导入的功能

This commit is contained in:
吕继龙 2025-04-09 17:43:19 +08:00
parent f045fc0d37
commit 879ee40f82
11 changed files with 1764 additions and 230 deletions

3
.gitignore vendored
View File

@ -1 +1,4 @@
node_modules
build
dist
release

View File

@ -0,0 +1,22 @@
{
"appId": "com.datatools.app",
"productName": "DataTools",
"files": [
"build/**/*",
"node_modules/**/*",
"main.js",
"preload.js"
],
"directories": {
"buildResources": "assets",
"output": "release"
},
"win": {
"target": "dir"
},
"npmRebuild": false,
"asar": false,
"extraMetadata": {
"main": "main.js"
}
}

43
main.js
View File

@ -30,6 +30,9 @@ function createWindow() {
}
});
// 将mainWindow设为全局变量以便其他模块可以访问
global.mainWindow = mainWindow;
// 加载应用
const loadAppUrl = () => {
const devUrl = 'http://localhost:3000';
@ -236,6 +239,46 @@ app.whenReady().then(() => {
}
});
// 注册clear-all-data事件处理器
ipcMain.removeHandler('clear-all-data'); // 先移除已有的处理器
ipcMain.handle('clear-all-data', async () => {
try {
console.log('处理清除数据请求...');
return new Promise((resolve, reject) => {
db.serialize(() => {
db.run('DELETE FROM projects', function(err) {
if (err) {
console.error('清除项目数据失败:', err);
reject({ success: false, error: err.message });
return;
}
db.run('DELETE FROM tree_structure', function(err) {
if (err) {
console.error('清除树状结构数据失败:', err);
reject({ success: false, error: err.message });
return;
}
// 重置自增ID
db.run('DELETE FROM sqlite_sequence WHERE name IN (\'projects\', \'tree_structure\')', function(err) {
if (err) {
console.error('重置自增ID失败:', err);
// 不影响主要功能,继续执行
}
resolve({ success: true, message: '所有数据已清除' });
});
});
});
});
});
} catch (error) {
console.error('清除数据错误:', error);
return { success: false, error: error.message };
}
});
app.on('activate', () => {
// 在macOS上当点击dock图标并且没有其他窗口打开时通常在应用程序中重新创建一个窗口
if (BrowserWindow.getAllWindows().length === 0) {

1083
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,9 @@
"dev": "concurrently \"npm run start\" \"cross-env BROWSER=none npm run react-start\"",
"react-start": "react-scripts start",
"react-build": "react-scripts build",
"build": "electron-builder",
"rebuild": "electron-rebuild",
"build": "electron-builder --publish never",
"package": "npm run react-build && npm run rebuild && npm run build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
@ -32,26 +34,36 @@
"preload.js"
],
"directories": {
"buildResources": "assets"
"buildResources": "assets",
"output": "release"
},
"win": {
"target": "nsis"
}
"target": "nsis",
"sign": null
},
"npmRebuild": false,
"extraMetadata": {
"main": "main.js"
},
"asar": true,
"forceCodeSigning": false
},
"dependencies": {
"antd": "^5.7.1",
"sqlite3": "^5.1.6",
"electron-is-dev": "^2.0.0",
"exceljs": "^4.3.0",
"fs-extra": "^11.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"sqlite3": "^5.1.6"
},
"devDependencies": {
"concurrently": "^8.2.0",
"cross-env": "^7.0.3",
"electron": "^27.3.8",
"electron-builder": "^24.6.3",
"electron-packager": "^17.1.2",
"electron-rebuild": "^3.2.9",
"react-scripts": "5.0.1"
},
"browserslist": {

View File

@ -10,7 +10,19 @@ contextBridge.exposeInMainWorld('electronAPI', {
getTreeStructure: () => ipcRenderer.invoke('get-tree-structure'),
filterProjects: (filters) => ipcRenderer.invoke('filter-projects', filters),
updateProject: (project) => ipcRenderer.invoke('update-project', project),
deleteProject: (projectId) => ipcRenderer.invoke('delete-project', projectId),
// Excel处理
importExcel: (filePath) => ipcRenderer.invoke('import-excel', filePath),
// 数据清除
clearAllData: () => ipcRenderer.invoke('clear-all-data'),
// 事件监听
onImportProgress: (callback) => {
// 移除之前的监听器,避免重复
ipcRenderer.removeAllListeners('import-progress');
// 添加新的监听器
ipcRenderer.on('import-progress', (event, data) => callback(data));
}
});

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { ConfigProvider, theme, Switch, Space } from 'antd';
import { ConfigProvider, theme, Switch, Space, Modal, Progress, message } from 'antd';
import zhCN from 'antd/locale/zh_CN';
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
@ -12,7 +12,6 @@ dayjs.locale('zh-cn');
import Toolbar from './components/Toolbar';
import TreeView from './components/TreeView';
import DataView from './components/DataView';
import AnalysisView from './components/AnalysisView';
import ProjectDetailForm from './components/ProjectDetailForm';
function App() {
@ -206,21 +205,123 @@ function App() {
if (filePath) {
setLoading(true);
// 创建进度对话框
const progressModal = Modal.info({
title: '导入Excel',
content: (
<div>
<p id="import-progress-message">正在准备导入...</p>
<Progress id="import-progress-bar" percent={0} status="active" />
</div>
),
icon: null,
okButtonProps: { style: { display: 'none' } },
maskClosable: false,
closable: false,
});
// 监听导入进度
window.electronAPI.onImportProgress((data) => {
// 更新进度条和消息
const progressBar = document.getElementById('import-progress-bar');
const progressMessage = document.getElementById('import-progress-message');
if (progressBar && progressMessage) {
// 更新进度条
const antProgress = progressBar.querySelector('.ant-progress-bg');
if (antProgress) {
antProgress.style.width = `${data.progress}%`;
antProgress.setAttribute('aria-valuenow', data.progress);
}
// 更新文本
progressMessage.textContent = data.message;
// 如果导入完成,关闭对话框并重新加载数据
if (data.status === 'complete') {
setTimeout(() => {
progressModal.destroy();
message.success('Excel导入成功');
// 重新加载数据
loadData();
setLoading(false);
}, 1000);
} else if (data.status === 'error') {
setTimeout(() => {
progressModal.destroy();
message.error(`导入失败: ${data.message}`);
setLoading(false);
}, 1000);
}
}
});
// 导入Excel文件
const result = await window.electronAPI.importExcel(filePath);
if (result.success) {
// 导入成功,重新加载数据
loadData();
} else {
// 如果导入失败且没有进度事件处理,则显示错误消息
if (!result.success) {
progressModal.destroy();
message.error(`导入失败: ${result.error}`);
console.error('导入Excel文件失败:', result.error);
setLoading(false);
}
}
} catch (error) {
console.error('导入Excel文件失败:', error);
message.error(`导入失败: ${error.message}`);
setLoading(false);
}
};
// 处理清除数据
const handleClearData = async () => {
// 显示确认对话框
Modal.confirm({
title: '确认清除数据',
content: '此操作将清除所有项目数据,无法恢复。确定要继续吗?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk: async () => {
setLoading(true);
try {
// 调用API清除数据
const result = await window.electronAPI.clearAllData();
if (result.success) {
// 清除成功,重置状态
setProjects([]);
setTreeData([]);
setSelectedNode(null);
setSelectedProjects([]);
setActiveFilter(null);
setSearchText('');
// 显示成功提示
Modal.success({
title: '操作成功',
content: '所有数据已清除'
});
} else {
// 显示错误提示
Modal.error({
title: '操作失败',
content: result.error || '清除数据时发生错误'
});
}
} catch (error) {
console.error('清除数据失败:', error);
// 显示错误提示
Modal.error({
title: '操作失败',
content: '清除数据时发生错误'
});
} finally {
setLoading(false);
}
}
});
};
return (
@ -239,6 +340,7 @@ function App() {
activeFilter={activeFilter}
onFilterChange={handleToolbarFilter}
onImportExcel={handleImportExcel}
onClearData={handleClearData}
/>
{/* 树状结构区 */}
@ -260,11 +362,6 @@ function App() {
loading={loading}
/>
{/* 分析结果区 */}
<AnalysisView
selectedProjects={projects.filter(p => selectedProjects.includes(p.id))}
/>
{/* 项目详情表单 */}
<ProjectDetailForm
visible={detailModalVisible}

View File

@ -40,6 +40,13 @@ const DataView = ({
key: 'current_progress',
width: 120,
ellipsis: true,
render: (text) => {
// 如果进度文本过长只显示前15个字符加省略号
if (text && text.length > 15) {
return <span title={text}>{text.substring(0, 15)}...</span>;
}
return text;
},
},
{
title: '当前工程状态',
@ -115,17 +122,15 @@ const DataView = ({
selectedRowKeys: selectedProjects,
onChange: onSelect,
}}
pagination={{
pageSize: 20,
showSizeChanger: true,
showTotal: (total) => `${total} 条数据`,
}}
pagination={false}
scroll={{ y: 'calc(100vh - 150px)', x: 'max-content' }}
size="small"
bordered
onRow={(record) => ({
onClick: () => onClick(record), // 点击行时调用传入的onClick函数
style: { cursor: 'pointer' } // 鼠标悬停时显示指针样式
})}
style={{ margin: '10px' }}
/>
)}
</div>

View File

@ -5,10 +5,11 @@ import {
WarningOutlined,
SearchOutlined,
ImportOutlined,
SettingOutlined
SettingOutlined,
ClearOutlined
} from '@ant-design/icons';
const Toolbar = ({ activeFilter, onFilterChange, onImportExcel }) => {
const Toolbar = ({ activeFilter, onFilterChange, onImportExcel, onClearData }) => {
// 显示"正在开发中"的提示
const showDevelopingMessage = () => {
Modal.info({
@ -48,6 +49,12 @@ const Toolbar = ({ activeFilter, onFilterChange, onImportExcel }) => {
icon: <SettingOutlined />,
title: '设置',
onClick: showDevelopingMessage
},
{
key: 'clear',
icon: <ClearOutlined />,
title: '清除数据',
onClick: onClearData
}
];

View File

@ -20,12 +20,22 @@ class ExcelService {
throw new Error('文件路径不能为空');
}
// 发送开始导入进度事件
if (global.mainWindow) {
global.mainWindow.webContents.send('import-progress', {
status: 'reading',
progress: 0,
message: '正在读取Excel文件...'
});
}
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.readFile(filePath);
// 读取第一个工作表
const worksheet = workbook.getWorksheet(1);
const data = [];
const totalRows = worksheet.rowCount - 1; // 减去表头行
// 读取表头
const headers = [];
@ -33,7 +43,17 @@ class ExcelService {
headers[colNumber - 1] = cell.value;
});
// 发送读取表头完成进度事件
if (global.mainWindow) {
global.mainWindow.webContents.send('import-progress', {
status: 'reading',
progress: 10,
message: '表头读取完成,正在读取数据...'
});
}
// 读取数据
let processedRows = 0;
worksheet.eachRow((row, rowNumber) => {
if (rowNumber > 1) { // 跳过表头
const rowData = {};
@ -41,12 +61,64 @@ class ExcelService {
rowData[headers[colNumber - 1]] = cell.value;
});
data.push(rowData);
// 计算并发送进度
processedRows++;
if (processedRows % 10 === 0 || processedRows === totalRows) { // 每10行或最后一行发送一次进度
const progress = Math.floor(10 + (processedRows / totalRows) * 40); // 10%-50%的进度
if (global.mainWindow) {
global.mainWindow.webContents.send('import-progress', {
status: 'reading',
progress: progress,
message: `正在读取数据...${processedRows}/${totalRows}`
});
}
}
}
});
// 发送数据读取完成进度事件
if (global.mainWindow) {
global.mainWindow.webContents.send('import-progress', {
status: 'saving',
progress: 50,
message: `数据读取完成,正在保存到数据库...`
});
}
// 将数据保存到数据库(这里可以根据实际需求修改)
if (data.length > 0 && this.db) {
this.saveDataToDatabase(data);
await this.saveDataToDatabase(data);
// 发送数据保存完成进度事件
if (global.mainWindow) {
global.mainWindow.webContents.send('import-progress', {
status: 'building',
progress: 70,
message: `数据保存完成,正在构建树状结构...`
});
}
// 构建树状结构
await this.buildTreeStructure(data);
// 发送导入完成进度事件
if (global.mainWindow) {
global.mainWindow.webContents.send('import-progress', {
status: 'complete',
progress: 100,
message: `导入完成,共导入 ${data.length} 条数据`
});
}
} else {
// 如果没有数据,直接发送完成事件
if (global.mainWindow) {
global.mainWindow.webContents.send('import-progress', {
status: 'complete',
progress: 100,
message: `导入完成,没有数据需要导入`
});
}
}
return {
@ -56,6 +128,16 @@ class ExcelService {
};
} catch (error) {
console.error('Excel导入错误:', error);
// 发送导入错误进度事件
if (global.mainWindow) {
global.mainWindow.webContents.send('import-progress', {
status: 'error',
progress: 0,
message: `导入失败: ${error.message}`
});
}
return {
success: false,
error: error.message
@ -65,10 +147,12 @@ class ExcelService {
// 将数据保存到数据库
saveDataToDatabase(data) {
return new Promise((resolve, reject) => {
// 清空现有数据
this.db.run('DELETE FROM projects', (err) => {
if (err) {
console.error('清空项目数据失败:', err);
reject(err);
return;
}
@ -112,49 +196,97 @@ class ExcelService {
this.db.serialize(() => {
this.db.run('BEGIN TRANSACTION');
// 发送进度更新
let processedRows = 0;
const totalRows = data.length;
for (const row of data) {
// 处理字段值,确保所有字段都能正确导入
const getValue = (fieldName, defaultValue = null) => {
// 检查字段是否存在,并处理空值
const value = row[fieldName];
if (value === undefined || value === null || value === '') {
return defaultValue;
}
return value;
};
// 处理布尔值字段
const getBooleanValue = (fieldName) => {
const value = row[fieldName];
if (value === '是' || value === 'true' || value === true || value === 1) {
return 1;
}
return 0;
};
// 处理数字字段
const getNumberValue = (fieldName, defaultValue = 0) => {
const value = row[fieldName];
if (value === undefined || value === null || value === '') {
return defaultValue;
}
// 尝试将值转换为数字
const num = Number(value);
return isNaN(num) ? defaultValue : num;
};
// 使用处理函数获取字段值
stmt.run(
row['单位'] || null,
row['项目编号'] || null,
row['安全编码'] || null,
row['大项工程名称'] || null,
row['单项工程名称'] || null,
row['在施工程作业范围'] || null,
row['工程规模'] || null,
row['安全总监'] || null,
row['建设单位'] || null,
row['监理单位'] || null,
row['施工单位'] || null,
row['工程位置'] || null,
row['实际开工时间'] || null,
row['计划竣工时间'] || null,
row['当前工程进度'] || null,
row['当前工程状态'] || null,
row['参建人数'] || 0,
row['新班组进场数量'] || 0,
row['新人进场数量'] || 0,
row['带班人姓名、电话'] || null,
row['下周作业计划'] || null,
row['下周8+2工况内容'] || null,
row['工期是否紧张'] === '是' ? 1 : 0,
row['是否存在"账外事"'] === '是' ? 1 : 0,
row['当前风险等级'] || null,
row['当前风险判断理由'] || null,
row['隐患提示/工作要求'] || null,
row['完成时间'] || null,
row['下次梳理时间'] || null,
row['备注'] || null
getValue('单位'),
getValue('项目编号'),
getValue('安全编码'),
getValue('大项工程名称'),
getValue('单项工程名称'),
getValue('在施工程作业范围'),
getValue('工程规模'),
getValue('安全总监'),
getValue('建设单位'),
getValue('监理单位'),
getValue('施工单位'),
getValue('工程位置'),
getValue('实际开工时间'),
getValue('计划竣工时间'),
getValue('当前工程进度'),
getValue('当前工程状态'),
getNumberValue('参建人数'),
getNumberValue('新班组进场数量'),
getNumberValue('新人进场数量'),
getValue('带班人姓名、电话'),
getValue('下周作业计划'),
getValue('下周8+2工况内容'),
getBooleanValue('工期是否紧张'),
getBooleanValue('是否存在"账外事"'),
getValue('当前风险等级'),
getValue('当前风险判断理由'),
getValue('隐患提示/工作要求'),
getValue('完成时间'),
getValue('下次梳理时间'),
getValue('备注')
);
// 更新进度
processedRows++;
if (processedRows % 10 === 0 || processedRows === totalRows) {
const progress = Math.floor(50 + (processedRows / totalRows) * 20); // 50%-70%的进度
if (global.mainWindow) {
global.mainWindow.webContents.send('import-progress', {
status: 'saving',
progress: progress,
message: `正在保存数据到数据库...${processedRows}/${totalRows}`
});
}
}
}
this.db.run('COMMIT', (err) => {
if (err) {
console.error('提交事务失败:', err);
this.db.run('ROLLBACK');
reject(err);
} else {
console.log(`成功导入 ${data.length} 条数据到数据库`);
// 构建树状结构
this.buildTreeStructure(data);
resolve();
}
});
});
@ -162,55 +294,98 @@ class ExcelService {
// 完成后关闭准备好的语句
stmt.finalize();
});
});
}
// 构建树状结构
buildTreeStructure(data) {
return new Promise((resolve, reject) => {
// 清空现有树状结构
this.db.run('DELETE FROM tree_structure', (err) => {
if (err) {
console.error('清空树状结构失败:', err);
reject(err);
return;
}
// 创建总部节点
// 使用Promise和事务来确保操作的原子性和顺序性
const headquarters = '总部';
const insertHeadquarters = this.db.prepare(`
INSERT INTO tree_structure (
headquarters,
unit,
construction_unit,
parent_id,
node_level
) VALUES (?, ?, ?, ?, ?)
`);
// 开始事务
this.db.run('BEGIN TRANSACTION', (err) => {
if (err) {
console.error('开始事务失败:', err);
reject(err);
return;
}
// 发送进度更新 - 开始创建树状结构
if (global.mainWindow) {
global.mainWindow.webContents.send('import-progress', {
status: 'building',
progress: 75,
message: `正在创建总部节点...`
});
}
// 插入总部节点
insertHeadquarters.run(headquarters, null, null, null, 1, function(err) {
this.db.run(
`INSERT INTO tree_structure (headquarters, unit, construction_unit, parent_id, node_level)
VALUES (?, ?, ?, ?, ?)`,
[headquarters, null, null, null, 1],
(err) => {
if (err) {
console.error('插入总部节点失败:', err);
this.db.run('ROLLBACK');
reject(err);
return;
}
const headquartersId = this.lastID;
// 获取总部节点ID
this.db.get('SELECT last_insert_rowid() as id', (err, row) => {
if (err) {
console.error('获取总部节点ID失败:', err);
this.db.run('ROLLBACK');
reject(err);
return;
}
const headquartersId = row.id;
console.log(`创建总部节点成功, ID: ${headquartersId}`);
// 单位映射
const unitMap = {};
// 遍历数据,构建树状结构
for (const row of data) {
const unit = row['单位'];
const constructionUnit = row['建设单位'];
// 首先处理所有单位节点
const uniqueUnits = [...new Set(data.filter(row => row['单位']).map(row => row['单位']))];
// 检查单位是否为空
if (!unit) continue;
// 发送进度更新 - 开始创建单位节点
if (global.mainWindow) {
global.mainWindow.webContents.send('import-progress', {
status: 'building',
progress: 80,
message: `正在创建单位节点...`
});
}
// 如果单位不存在,则创建单位节点
if (!unitMap[unit]) {
insertHeadquarters.run(headquarters, unit, null, headquartersId, 2, function(err) {
const processUnits = () => {
return new Promise((resolve, reject) => {
let unitProcessed = 0;
if (uniqueUnits.length === 0) {
resolve();
return;
}
uniqueUnits.forEach(unit => {
this.db.run(
`INSERT INTO tree_structure (headquarters, unit, construction_unit, parent_id, node_level)
VALUES (?, ?, ?, ?, ?)`,
[headquarters, unit, null, headquartersId, 2],
function(err) {
if (err) {
console.error(`创建单位节点失败: ${unit}`, err);
reject(err);
return;
}
@ -218,34 +393,127 @@ class ExcelService {
unitMap[unit] = { id: unitId, constructionUnits: {} };
console.log(`创建单位节点: ${unit}, ID: ${unitId}`);
// 如果建设单位不为空且不存在,则添加建设单位节点
if (constructionUnit && !unitMap[unit].constructionUnits[constructionUnit]) {
insertHeadquarters.run(headquarters, unit, constructionUnit, unitId, 3, function(err) {
if (err) {
console.error(`创建建设单位节点失败: ${constructionUnit}`, err);
} else {
unitMap[unit].constructionUnits[constructionUnit] = true;
console.log(`创建建设单位节点: ${constructionUnit}, 父节点: ${unit}`);
}
});
}
});
} else if (constructionUnit && !unitMap[unit].constructionUnits[constructionUnit]) {
// 如果单位已存在但建设单位不存在,则添加建设单位节点
insertHeadquarters.run(headquarters, unit, constructionUnit, unitMap[unit].id, 3, function(err) {
if (err) {
console.error(`创建建设单位节点失败: ${constructionUnit}`, err);
} else {
unitMap[unit].constructionUnits[constructionUnit] = true;
console.log(`创建建设单位节点: ${constructionUnit}, 父节点: ${unit}`);
}
unitProcessed++;
// 更新进度
if (unitProcessed % 5 === 0 || unitProcessed === uniqueUnits.length) {
const progress = Math.floor(80 + (unitProcessed / uniqueUnits.length) * 10); // 80%-90%的进度
if (global.mainWindow) {
global.mainWindow.webContents.send('import-progress', {
status: 'building',
progress: progress,
message: `正在创建单位节点...${unitProcessed}/${uniqueUnits.length}`
});
}
}
// 完成后关闭准备好的语句
insertHeadquarters.finalize();
if (unitProcessed === uniqueUnits.length) {
resolve();
}
}
);
});
});
};
// 然后处理所有建设单位节点
const processConstructionUnits = () => {
return new Promise((resolve, reject) => {
// 收集所有有效的建设单位数据
const constructionUnitData = [];
data.forEach(row => {
const unit = row['单位'];
const constructionUnit = row['建设单位'];
if (unit && constructionUnit && unitMap[unit] &&
!unitMap[unit].constructionUnits[constructionUnit]) {
constructionUnitData.push({
unit,
constructionUnit,
unitId: unitMap[unit].id
});
unitMap[unit].constructionUnits[constructionUnit] = true;
}
});
// 发送进度更新 - 开始创建建设单位节点
if (global.mainWindow) {
global.mainWindow.webContents.send('import-progress', {
status: 'building',
progress: 90,
message: `正在创建建设单位节点...`
});
}
if (constructionUnitData.length === 0) {
resolve();
return;
}
let processed = 0;
constructionUnitData.forEach(item => {
this.db.run(
`INSERT INTO tree_structure (headquarters, unit, construction_unit, parent_id, node_level)
VALUES (?, ?, ?, ?, ?)`,
[headquarters, item.unit, item.constructionUnit, item.unitId, 3],
function(err) {
if (err) {
console.error(`创建建设单位节点失败: ${item.constructionUnit}`, err);
// 不中断整个过程,继续处理其他节点
} else {
console.log(`创建建设单位节点: ${item.constructionUnit}, 父节点: ${item.unit}`);
}
processed++;
// 更新进度
if (processed % 10 === 0 || processed === constructionUnitData.length) {
const progress = Math.floor(90 + (processed / constructionUnitData.length) * 10); // 90%-100%的进度
if (global.mainWindow) {
global.mainWindow.webContents.send('import-progress', {
status: 'building',
progress: progress,
message: `正在创建建设单位节点...${processed}/${constructionUnitData.length}`
});
}
}
if (processed === constructionUnitData.length) {
resolve();
}
}
);
});
});
};
// 按顺序执行:先处理单位,再处理建设单位
processUnits()
.then(() => processConstructionUnits())
.then(() => {
// 提交事务
this.db.run('COMMIT', (err) => {
if (err) {
console.error('提交事务失败:', err);
this.db.run('ROLLBACK');
reject(err);
} else {
console.log('树状结构构建完成');
resolve();
}
});
})
.catch(err => {
console.error('构建树状结构失败:', err);
this.db.run('ROLLBACK');
reject(err);
});
});
}
);
});
});
});
}

View File

@ -55,14 +55,6 @@ code {
overflow-y: auto;
}
.analysis-view {
width: 300px;
background-color: var(--vscode-sidebar-bg);
border-left: 1px solid var(--vscode-sidebar-border);
overflow-y: auto;
padding: 10px;
}
/* 工具栏图标样式 */
.toolbar-icon {
width: 32px;
@ -163,3 +155,61 @@ code {
border-color: #40a9ff !important;
color: white !important;
}
/* 自定义滚动条样式 */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: var(--vscode-sidebar-bg);
border-radius: 4px;
}
::-webkit-scrollbar-thumb {
background: #555;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #777;
}
/* 表格滚动条样式 */
.ant-table-body::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.ant-table-body::-webkit-scrollbar-track {
background: var(--vscode-sidebar-bg);
border-radius: 4px;
}
.ant-table-body::-webkit-scrollbar-thumb {
background: #555;
border-radius: 4px;
}
.ant-table-body::-webkit-scrollbar-thumb:hover {
background: #777;
}
/* 树状结构滚动条样式 */
.tree-view::-webkit-scrollbar {
width: 8px;
}
.tree-view::-webkit-scrollbar-track {
background: var(--vscode-sidebar-bg);
}
.tree-view::-webkit-scrollbar-thumb {
background: #555;
border-radius: 4px;
}
.tree-view::-webkit-scrollbar-thumb:hover {
background: #777;
}