抓变化

This commit is contained in:
jiang 2025-05-29 17:08:47 +08:00
parent 90245dbb80
commit 7d839712ca
6 changed files with 905 additions and 592 deletions

109
main.js
View File

@ -1,4 +1,4 @@
const { app, BrowserWindow, ipcMain, dialog, Menu } = require('electron'); const {app, BrowserWindow, ipcMain, dialog, Menu} = require('electron');
const path = require('path'); const path = require('path');
const fs = require('fs-extra'); const fs = require('fs-extra');
let isDev; let isDev;
@ -131,6 +131,19 @@ function initDatabase() {
risk_tips TEXT, -- 隐患提示/工作要求 risk_tips TEXT, -- 隐患提示/工作要求
completion_time TEXT, -- 完成时间 completion_time TEXT, -- 完成时间
next_review_time TEXT, -- 下次梳理时间 next_review_time TEXT, -- 下次梳理时间
new_team INTEGER, --新进班组数量
new_members INTEGER, --新进班组骨干数量
new_high_altitude INTEGER, --新进高空人员数量
new_hired_general INTEGER, --新进一般人员数量
new_homework_content TEXT, --新的作业内容
change_homework_method TEXT, --改变作业方法
changes_geographical TEXT, --地理环境的变化
changes_meteorological TEXT, --气象环境的变化
changes_social TEXT, --社会环境的变化
changes_management TEXT, --管理要求的变化
changes_homework_plan TEXT, --作业计划的变化
changes_management_personnel TEXT, --管理人员的变化
remarks TEXT -- 备注 remarks TEXT -- 备注
) )
`); `);
@ -161,43 +174,43 @@ const menuTemplate = [
{ {
label: '文件', label: '文件',
submenu: [ submenu: [
{ role: 'quit', label: '退出' } {role: 'quit', label: '退出'}
] ]
}, },
{ {
label: '编辑', label: '编辑',
submenu: [ submenu: [
{ role: 'undo', label: '撤销' }, {role: 'undo', label: '撤销'},
{ role: 'redo', label: '恢复' }, {role: 'redo', label: '恢复'},
{ type: 'separator' }, {type: 'separator'},
{ role: 'cut', label: '剪切' }, {role: 'cut', label: '剪切'},
{ role: 'copy', label: '复制' }, {role: 'copy', label: '复制'},
{ role: 'paste', label: '粘贴' }, {role: 'paste', label: '粘贴'},
{ role: 'delete', label: '删除' }, {role: 'delete', label: '删除'},
{ role: 'selectAll', label: '全选' } {role: 'selectAll', label: '全选'}
] ]
}, },
{ {
label: '视图', label: '视图',
submenu: [ submenu: [
{ role: 'reload', label: '重新加载' }, {role: 'reload', label: '重新加载'},
{ role: 'forceReload', label: '强制重新加载' }, {role: 'forceReload', label: '强制重新加载'},
{ role: 'toggleDevTools', label: '开发者工具' }, {role: 'toggleDevTools', label: '开发者工具'},
{ type: 'separator' }, {type: 'separator'},
{ role: 'resetZoom', label: '重置缩放' }, {role: 'resetZoom', label: '重置缩放'},
{ role: 'zoomIn', label: '放大' }, {role: 'zoomIn', label: '放大'},
{ role: 'zoomOut', label: '缩小' }, {role: 'zoomOut', label: '缩小'},
{ type: 'separator' }, {type: 'separator'},
{ role: 'togglefullscreen', label: '全屏' } {role: 'togglefullscreen', label: '全屏'}
] ]
}, },
{ {
label: '窗口', label: '窗口',
submenu: [ submenu: [
{ role: 'minimize', label: '最小化' }, {role: 'minimize', label: '最小化'},
{ role: 'zoom', label: '缩放' }, {role: 'zoom', label: '缩放'},
{ type: 'separator' }, {type: 'separator'},
{ role: 'front', label: '前置所有窗口' } {role: 'front', label: '前置所有窗口'}
] ]
}, },
{ {
@ -235,7 +248,7 @@ app.whenReady().then(() => {
return await excelService.importExcel(filePath); return await excelService.importExcel(filePath);
} catch (error) { } catch (error) {
console.error('导入Excel错误:', error); console.error('导入Excel错误:', error);
return { success: false, error: error.message }; return {success: false, error: error.message};
} }
}); });
@ -246,28 +259,28 @@ app.whenReady().then(() => {
console.log('处理清除数据请求...'); console.log('处理清除数据请求...');
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
db.serialize(() => { db.serialize(() => {
db.run('DELETE FROM projects', function(err) { db.run('DELETE FROM projects', function (err) {
if (err) { if (err) {
console.error('清除项目数据失败:', err); console.error('清除项目数据失败:', err);
reject({ success: false, error: err.message }); reject({success: false, error: err.message});
return; return;
} }
db.run('DELETE FROM tree_structure', function(err) { db.run('DELETE FROM tree_structure', function (err) {
if (err) { if (err) {
console.error('清除树状结构数据失败:', err); console.error('清除树状结构数据失败:', err);
reject({ success: false, error: err.message }); reject({success: false, error: err.message});
return; return;
} }
// 重置自增ID // 重置自增ID
db.run('DELETE FROM sqlite_sequence WHERE name IN (\'projects\', \'tree_structure\')', function(err) { db.run('DELETE FROM sqlite_sequence WHERE name IN (\'projects\', \'tree_structure\')', function (err) {
if (err) { if (err) {
console.error('重置自增ID失败:', err); console.error('重置自增ID失败:', err);
// 不影响主要功能,继续执行 // 不影响主要功能,继续执行
} }
resolve({ success: true, message: '所有数据已清除' }); resolve({success: true, message: '所有数据已清除'});
}); });
}); });
}); });
@ -275,7 +288,7 @@ app.whenReady().then(() => {
}); });
} catch (error) { } catch (error) {
console.error('清除数据错误:', error); console.error('清除数据错误:', error);
return { success: false, error: error.message }; return {success: false, error: error.message};
} }
}); });
@ -297,10 +310,10 @@ app.on('window-all-closed', () => {
// 处理Excel文件选择 // 处理Excel文件选择
ipcMain.handle('select-excel-file', async () => { ipcMain.handle('select-excel-file', async () => {
const { canceled, filePaths } = await dialog.showOpenDialog(mainWindow, { const {canceled, filePaths} = await dialog.showOpenDialog(mainWindow, {
properties: ['openFile'], properties: ['openFile'],
filters: [ filters: [
{ name: 'Excel Files', extensions: ['xlsx', 'xls'] } {name: 'Excel Files', extensions: ['xlsx', 'xls']}
] ]
}); });
@ -469,6 +482,20 @@ ipcMain.handle('update-project', (event, project) => {
risk_tips = ?, risk_tips = ?,
completion_time = ?, completion_time = ?,
next_review_time = ?, next_review_time = ?,
new_team = ?,
new_members = ?,
new_high_altitude = ?,
new_hired_general = ?,
new_homework_content= ?,
change_homework_method = ?,
changes_geographical = ?,
changes_meteorological = ?,
changes_social = ?,
changes_management = ?,
changes_homework_plan = ?,
changes_management_personnel = ?,
remarks = ? remarks = ?
WHERE id = ? WHERE id = ?
`; `;
@ -503,14 +530,26 @@ ipcMain.handle('update-project', (event, project) => {
project.risk_tips, project.risk_tips,
project.completion_time, project.completion_time,
project.next_review_time, project.next_review_time,
project.new_team,
project.new_members,
project.new_high_altitude,
project.new_hired_general,
project.new_homework_content,
project.change_homework_method,
project.changes_geographical,
project.changes_meteorological,
project.changes_social,
project.changes_management,
project.changes_homework_plan,
project.changes_management_personnel,
project.remarks, project.remarks,
project.id project.id
], function(err) { ], function (err) {
if (err) { if (err) {
console.error('更新项目数据失败:', err); console.error('更新项目数据失败:', err);
reject(err); reject(err);
} else { } else {
resolve({ success: true, changes: this.changes }); resolve({success: true, changes: this.changes});
} }
}); });
}); });

View File

@ -13,6 +13,7 @@ import Toolbar from './components/Toolbar';
import TreeView from './components/TreeView'; import TreeView from './components/TreeView';
import DataView from './components/DataView'; import DataView from './components/DataView';
import ProjectDetailForm from './components/ProjectDetailForm'; import ProjectDetailForm from './components/ProjectDetailForm';
import ProjectWarningView from "./components/ProjectWarningView";
function App() { function App() {
// 状态管理 // 状态管理
@ -393,6 +394,13 @@ function App() {
loading={loading} loading={loading}
/> />
{/* 树状结构区 */}
<ProjectWarningView
projects={projects}
loading={loading}
onClick={handleProjectClick} // 传入点击事件处理函数
/>
{/* 项目详情表单 */} {/* 项目详情表单 */}
<ProjectDetailForm <ProjectDetailForm
visible={detailModalVisible} visible={detailModalVisible}

View File

@ -1,17 +1,17 @@
import React, { useEffect } from 'react'; import React, {useEffect} from 'react';
import { Modal, Form, Input, Select, Switch, Button } from 'antd'; import {Modal, Form, Input, Select, Switch, Button} from 'antd';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
const { Option } = Select; const {Option} = Select;
const { TextArea } = Input; const {TextArea} = Input;
const ProjectDetailForm = ({ visible, project, onCancel, onSave }) => { const ProjectDetailForm = ({visible, project, onCancel, onSave}) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
useEffect(() => { useEffect(() => {
if (project && visible) { if (project && visible) {
// 格式化日期字段为字符串 // 格式化日期字段为字符串
const formattedProject = { ...project }; const formattedProject = {...project};
['actual_start_time', 'planned_completion_time', 'completion_time', 'next_review_time'].forEach(field => { ['actual_start_time', 'planned_completion_time', 'completion_time', 'next_review_time'].forEach(field => {
if (formattedProject[field]) { if (formattedProject[field]) {
formattedProject[field] = dayjs(formattedProject[field]).format('YYYY-MM-DD'); formattedProject[field] = dayjs(formattedProject[field]).format('YYYY-MM-DD');
@ -24,7 +24,7 @@ const ProjectDetailForm = ({ visible, project, onCancel, onSave }) => {
const handleSave = () => { const handleSave = () => {
form.validateFields() form.validateFields()
.then(values => { .then(values => {
onSave({ ...project, ...values }); onSave({...project, ...values});
}) })
.catch(info => { .catch(info => {
console.log('验证失败:', info); console.log('验证失败:', info);
@ -37,6 +37,12 @@ const ProjectDetailForm = ({ visible, project, onCancel, onSave }) => {
open={visible} open={visible}
width={800} width={800}
onCancel={onCancel} onCancel={onCancel}
bodyStyle={{
maxHeight: '60vh',
overflowY: 'scroll',
msOverflowStyle: 'none', // IE, Edge
scrollbarWidth: 'none' // Firefox
}}
footer={[ footer={[
<Button key="cancel" onClick={onCancel}> <Button key="cancel" onClick={onCancel}>
取消 取消
@ -51,76 +57,76 @@ const ProjectDetailForm = ({ visible, project, onCancel, onSave }) => {
layout="vertical" layout="vertical"
> >
<Form.Item label="单位" name="unit"> <Form.Item label="单位" name="unit">
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item label="项目编号" name="project_number"> <Form.Item label="项目编号" name="project_number">
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item label="安全编码" name="safety_code"> <Form.Item label="安全编码" name="safety_code">
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item label="大项工程名称" name="major_project_name"> <Form.Item label="大项工程名称" name="major_project_name">
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item label="单项工程名称" name="sub_project_name"> <Form.Item label="单项工程名称" name="sub_project_name">
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item label="在施工程作业范围" name="construction_scope"> <Form.Item label="在施工程作业范围" name="construction_scope">
<TextArea rows={2} /> <TextArea rows={2}/>
</Form.Item> </Form.Item>
<Form.Item label="工程规模" name="project_scale"> <Form.Item label="工程规模" name="project_scale">
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item label="安全总监" name="safety_director"> <Form.Item label="安全总监" name="safety_director">
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item label="建设单位" name="construction_unit"> <Form.Item label="建设单位" name="construction_unit">
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item label="监理单位" name="supervision_unit"> <Form.Item label="监理单位" name="supervision_unit">
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item label="施工单位" name="construction_company"> <Form.Item label="施工单位" name="construction_company">
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item label="工程位置" name="project_location"> <Form.Item label="工程位置" name="project_location">
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item label="实际开工时间" name="actual_start_time"> <Form.Item label="实际开工时间" name="actual_start_time">
<Input placeholder="YYYY-MM-DD" /> <Input placeholder="YYYY-MM-DD"/>
</Form.Item> </Form.Item>
<Form.Item label="计划竣工时间" name="planned_completion_time"> <Form.Item label="计划竣工时间" name="planned_completion_time">
<Input placeholder="YYYY-MM-DD" /> <Input placeholder="YYYY-MM-DD"/>
</Form.Item> </Form.Item>
<Form.Item label="完成时间" name="completion_time"> <Form.Item label="完成时间" name="completion_time">
<Input placeholder="YYYY-MM-DD" /> <Input placeholder="YYYY-MM-DD"/>
</Form.Item> </Form.Item>
<Form.Item label="下次梳理时间" name="next_review_time"> <Form.Item label="下次梳理时间" name="next_review_time">
<Input placeholder="YYYY-MM-DD" /> <Input placeholder="YYYY-MM-DD"/>
</Form.Item> </Form.Item>
<Form.Item label="参建人数" name="participants_count"> <Form.Item label="参建人数" name="participants_count">
<Input type="number" /> <Input type="number"/>
</Form.Item> </Form.Item>
<Form.Item label="新班组进场数量" name="new_team_count"> <Form.Item label="新班组进场数量" name="new_team_count">
<Input type="number" /> <Input type="number"/>
</Form.Item> </Form.Item>
<Form.Item label="新人进场数量" name="new_person_count"> <Form.Item label="新人进场数量" name="new_person_count">
<Input type="number" /> <Input type="number"/>
</Form.Item> </Form.Item>
<Form.Item label="带班人姓名、电话" name="leader_info"> <Form.Item label="带班人姓名、电话" name="leader_info">
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item label="下周作业计划" name="next_week_plan"> <Form.Item label="下周作业计划" name="next_week_plan">
<TextArea rows={2} /> <TextArea rows={2}/>
</Form.Item> </Form.Item>
<Form.Item label="下周8+2工况内容" name="next_week_condition"> <Form.Item label="下周8+2工况内容" name="next_week_condition">
<TextArea rows={2} /> <TextArea rows={2}/>
</Form.Item> </Form.Item>
<Form.Item label="工期是否紧张" name="is_schedule_tight" valuePropName="checked"> <Form.Item label="工期是否紧张" name="is_schedule_tight" valuePropName="checked">
<Switch /> <Switch/>
</Form.Item> </Form.Item>
<Form.Item label="是否存在账外事" name="has_off_book_matters" valuePropName="checked"> <Form.Item label="是否存在账外事" name="has_off_book_matters" valuePropName="checked">
<Switch /> <Switch/>
</Form.Item> </Form.Item>
<Form.Item label="当前风险等级" name="current_risk_level"> <Form.Item label="当前风险等级" name="current_risk_level">
<Select> <Select>
@ -130,13 +136,109 @@ const ProjectDetailForm = ({ visible, project, onCancel, onSave }) => {
</Select> </Select>
</Form.Item> </Form.Item>
<Form.Item label="当前风险判断理由" name="risk_judgment_reason"> <Form.Item label="当前风险判断理由" name="risk_judgment_reason">
<TextArea rows={2} /> <TextArea rows={2}/>
</Form.Item> </Form.Item>
<Form.Item label="隐患提示/工作要求" name="risk_tips"> <Form.Item label="隐患提示/工作要求" name="risk_tips">
<TextArea rows={2} /> <TextArea rows={2}/>
</Form.Item>
<Form.Item>
<div>
<p style={{fontSize: '20px', fontWeight: 'bold'}}>人的变化</p>
<Form.Item label="新进班组数量" name="new_team">
<Input type="number"/>
</Form.Item>
<Form.Item label="新进班组骨干数量" name="new_members">
<Input type="number"/>
</Form.Item>
<Form.Item label="新进高空人员数量" name="new_high_altitude">
<Input type="number"/>
</Form.Item>
<Form.Item label="新进一般人员数量" name="new_hired_general">
<Input type="number"/>
</Form.Item>
</div>
</Form.Item>
<Form.Item>
<div>
<p style={{fontSize: '20px', fontWeight: 'bold'}}>机的变化</p>
<Form.Item label="新的作业内容" name="new_homework_content">
<Select allowClear placeholder="请选择新的作业内容">
<Option value="同一班组作业类型调整">同一班组作业类型调整</Option>
<Option value="在运变电站新增作业">在运变电站新增作业</Option>
<Option value="工程转序">工程转序</Option>
</Select>
</Form.Item>
<Form.Item label="改变作业方法" name="change_homework_method">
<Select allowClear placeholder="请选择改变作业方法">
<Option value="同一部位基础开挖由机械变为人工">同一部位基础开挖由机械变为人工</Option>
<Option
value="同一部位铁塔组立由起重机变为抱杆">同一部位铁塔组立由起重机变为抱杆</Option>
<Option value="同一跨越物改变跨越方式">同一跨越物改变跨越方式</Option>
<Option value="同一放线段改变放线方式">同一放线段改变放线方式</Option>
</Select>
</Form.Item>
</div>
</Form.Item>
<Form.Item>
<div>
<p style={{fontSize: '20px', fontWeight: 'bold'}}>环境的变化</p>
<Form.Item label="地理环境的变化" name="changes_geographical">
<Select allowClear placeholder="请选择地理环境的变化">
<Option value="新增带电线路(引起近电作业)">新增带电线路引起近电作业</Option>
<Option value="新增带电线路(未引起近电作业)">新增带电线路未引起近电作业</Option>
<Option
value="新增跨越物(新投入使用铁路、高速、电力线等线性工程)">新增跨越物新投入使用铁路高速电力线等线性工程</Option>
</Select>
</Form.Item>
<Form.Item label="气象环境的变化" name="changes_meteorological">
<Select allowClear placeholder="请选择气象环境的变化">
<Option value="降雪预警">降雪预警</Option>
<Option value="降雨预警">降雨预警</Option>
<Option value="大风预警">大风预警</Option>
<Option value="高温预警">高温预警</Option>
<Option value="低温预警">低温预警</Option>
</Select>
</Form.Item>
<Form.Item label="社会环境的变化" name="changes_social">
<Select allowClear placeholder="请选择社会环境的变化">
<Option value="外部协调引起阻工(属地协调不畅)">外部协调引起阻工属地协调不畅</Option>
<Option value="物资供应滞后">物资供应滞后</Option>
</Select>
</Form.Item>
</div>
</Form.Item>
<Form.Item>
<div>
<p style={{fontSize: '20px', fontWeight: 'bold'}}>管理的变化</p>
<Form.Item label="管理要求的变化" name="changes_management">
<Select allowClear placeholder="请选择管理要求的变化">
<Option value="投产计划提前(工期紧张)">投产计划提前工期紧张</Option>
<Option value="特殊时段作业">特殊时段作业</Option>
<Option value="停电计划调整">停电计划调整</Option>
</Select>
</Form.Item>
<Form.Item label="作业计划的变化" name="changes_homework_plan">
<Select allowClear placeholder="请选择作业计划的变化">
<Option value="原作业计划未按期执行,顺延至今">原作业计划未按期执行顺延至今</Option>
<Option value="下周作业计划无法执行,临时变更">下周作业计划无法执行临时变更</Option>
</Select>
</Form.Item>
<Form.Item label="管理人员的变化" name="changes_management_personnel">
<Select allowClear placeholder="请选择管理人员变化">
<Option value="施工项目部关键人员变化">施工项目部关键人员变化</Option>
<Option value="监理项目部关键人员变化">监理项目部关键人员变化</Option>
<Option value="业主项目部关键人员变化">业主项目部关键人员变化</Option>
<Option value="施工单位主要负责人、分管领导调整">施工单位主要负责人分管领导调整</Option>
</Select>
</Form.Item>
</div>
</Form.Item> </Form.Item>
<Form.Item label="备注" name="remarks"> <Form.Item label="备注" name="remarks">
<TextArea rows={2} /> <TextArea rows={2}/>
</Form.Item> </Form.Item>
</Form> </Form>
</Modal> </Modal>

View File

@ -0,0 +1,157 @@
import React from 'react';
import { Spin } from 'antd';
const ProjectWarningView = ({ projects = [], loading = false,onClick}) => {
const warningFields = [
{ key: 'new_team', label: '新班组', message: '存在新班组,请做好班组入场管理。' },
{ key: 'new_homework_content', label: '新的作业内容', message: '存在新的作业内容,请加强现场管控。' },
{ key: 'change_homework_method', label: '改变作业方法', message: '存在改变作业方法,请及时核查施工方案编审、方案交底及人员、机具准备情况。' },
{ key: 'changes_geographical', label: '地理环境的变化', message: '存在作业环境的变化,请及时核查施工方案编审、方案交底及人员、机具准备情况。' },
{ key: 'changes_meteorological', label: '气象环境的变化', message: '存在气象预警,请关注天气变化,做好应对措施。' },
{ key: 'changes_social', label: '社会环境的变化', message: '存在社会环境变化,请合理安排作业计划,避免人员失控。' },
{ key: 'changes_management', label: '管理要求的变化', message: '存在管理要求的变化,请加强现场巡查力度,严防无计划作业。' },
{ key: 'changes_homework_plan', label: '作业计划的变化', message: '存在作业计划的变化,请做好施工力量配备。' },
{ key: 'changes_management_personnel', label: '管理人员的变化', message: '存在管理人员的变化,请加强现场管控。' },
];
const hasWarnings = (item) => {
if (typeof item !== 'object') return false;
if (item.new_members || item.new_high_altitude || item.new_hired_general) return true;
return warningFields.some(({ key }) => item[key]);
};
const filteredProjects = projects.filter(hasWarnings);
return (
<div
className="project-warning-view"
>
<div
style={{
padding: '16px 20px',
fontWeight: '700',
fontSize: '18px',
userSelect: 'none',
borderBottom: '1px solid var(--vscode-sidebar-border)'
}}
>
工程预警
</div>
<div
style={{
padding: '20px',
overflowY: 'auto',
flexGrow: 1,
maxHeight: '90%',
scrollbarWidth: 'thin',
scrollbarColor: '#c1c1c1 transparent',
}}
>
<Spin spinning={loading} tip="加载中...">
{!loading && (
<>
{filteredProjects.length > 0 ? (
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(320px, 1fr))',
gap: '24px',
}}
>
{filteredProjects.map((item, index) => (
<div
key={index}
style={{
border: '1px solid #ddd',
borderRadius: '12px',
padding: '20px',
boxShadow: '0 6px 15px rgba(0,0,0,0.07)',
transition: 'transform 0.3s ease, box-shadow 0.3s ease',
cursor: 'pointer',
display: 'flex',
flexDirection: 'column',
gap: '12px',
userSelect: 'none',
}}
onClick={() => onClick(item)}
onMouseEnter={(e) => {
e.currentTarget.style.transform = 'translateY(-6px) scale(1.02)';
e.currentTarget.style.boxShadow = '0 12px 24px rgba(0,0,0,0.15)';
}}
onMouseLeave={(e) => {
e.currentTarget.style.transform = 'translateY(0) scale(1)';
e.currentTarget.style.boxShadow = '0 6px 15px rgba(0,0,0,0.07)';
}}
title={typeof item === 'string' ? item : item.sub_project_name || '未命名项目'}
>
<div
style={{
fontWeight: '700',
fontSize: '16px',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
maxWidth: '100%',
}}
>
{typeof item === 'string' ? item : item.sub_project_name || '未命名项目'}
</div>
{(item.new_members || item.new_high_altitude || item.new_hired_general) && (
<div
style={{
fontSize: '14px',
color: '#e64c3c',
fontWeight: '600',
borderLeft: '4px solid #e64c3c',
paddingLeft: '10px',
}}
>
新人: 存在新人员请做好人员面对面核实
</div>
)}
{warningFields.map(({key, label, message}) =>
item[key] ? (
<div
key={key}
style={{
fontSize: '14px',
color: '#e64c3c',
fontWeight: '600',
borderLeft: '4px solid #e64c3c',
paddingLeft: '10px',
}}
>
{label}: {message}
</div>
) : null
)}
</div>
))}
</div>
) : (
<div
style={{
textAlign: 'center',
color: '#aaa',
fontSize: '15px',
marginTop: '50px',
userSelect: 'none',
}}
>
暂无项目预警
</div>
)}
</>
)}
</Spin>
</div>
</div>
);
};
export default ProjectWarningView;

View File

@ -1,8 +1,8 @@
import React, { useState, useEffect } from 'react'; import React, {useState, useEffect} from 'react';
import { Tree, Spin } from 'antd'; import {Tree, Spin} from 'antd';
import { FolderOutlined, ApartmentOutlined, HomeOutlined } from '@ant-design/icons'; import {FolderOutlined, ApartmentOutlined, HomeOutlined} from '@ant-design/icons';
const TreeView = ({ treeData, selectedNode, onSelect, loading }) => { const TreeView = ({treeData, selectedNode, onSelect, loading}) => {
const [expandedKeys, setExpandedKeys] = useState([]); const [expandedKeys, setExpandedKeys] = useState([]);
// 默认只展开一级目录 // 默认只展开一级目录
@ -16,11 +16,11 @@ const TreeView = ({ treeData, selectedNode, onSelect, loading }) => {
// 自定义树节点图标 // 自定义树节点图标
const getIcon = (node) => { const getIcon = (node) => {
if (node.level === 1) { if (node.level === 1) {
return <HomeOutlined />; return <HomeOutlined/>;
} else if (node.level === 2) { } else if (node.level === 2) {
return <ApartmentOutlined />; return <ApartmentOutlined/>;
} else { } else {
return <FolderOutlined />; return <FolderOutlined/>;
} }
}; };
@ -35,13 +35,13 @@ const TreeView = ({ treeData, selectedNode, onSelect, loading }) => {
return ( return (
<div className="tree-view"> <div className="tree-view">
<div style={{ padding: '10px', fontWeight: 'bold', borderBottom: '1px solid var(--vscode-sidebar-border)' }}> <div style={{padding: '10px', fontWeight: 'bold', borderBottom: '1px solid var(--vscode-sidebar-border)'}}>
项目结构 项目预警
</div> </div>
{loading ? ( {loading ? (
<div style={{ display: 'flex', justifyContent: 'center', padding: '20px' }}> <div style={{display: 'flex', justifyContent: 'center', padding: '20px'}}>
<Spin /> <Spin/>
</div> </div>
) : ( ) : (
<Tree <Tree

View File

@ -49,6 +49,13 @@ code {
overflow-y: auto; overflow-y: auto;
} }
.project-warning-view {
width: 400px;
background-color: var(--vscode-sidebar-bg);
border-right: 1px solid var(--vscode-sidebar-border);
}
.data-view { .data-view {
flex: 1; flex: 1;
background-color: var(--vscode-editor-bg); background-color: var(--vscode-editor-bg);