519 lines
20 KiB
HTML
519 lines
20 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>工作流编辑器 - 微博舆情分析系统</title>
|
|
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/css/bootstrap.min.css" rel="stylesheet">
|
|
<link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.2.0/css/all.min.css" rel="stylesheet">
|
|
<link href="https://cdn.jsdelivr.net/npm/jsoneditor@9.5.0/dist/jsoneditor.min.css" rel="stylesheet">
|
|
<style>
|
|
:root {
|
|
--primary-color: #1890ff;
|
|
--success-color: #52c41a;
|
|
--warning-color: #faad14;
|
|
--error-color: #f5222d;
|
|
--bg-color: #f0f2f5;
|
|
--component-bg: #fafafa;
|
|
--border-color: #d9d9d9;
|
|
}
|
|
|
|
body {
|
|
background-color: var(--bg-color);
|
|
font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
}
|
|
|
|
.navbar-brand {
|
|
font-weight: 600;
|
|
}
|
|
|
|
.sidebar {
|
|
position: fixed;
|
|
top: 56px;
|
|
bottom: 0;
|
|
left: 0;
|
|
z-index: 100;
|
|
padding: 20px 0;
|
|
width: 280px;
|
|
overflow-x: hidden;
|
|
overflow-y: auto;
|
|
background-color: white;
|
|
border-right: 1px solid var(--border-color);
|
|
}
|
|
|
|
.main-content {
|
|
margin-left: 280px;
|
|
padding: 20px;
|
|
}
|
|
|
|
.workflow-canvas {
|
|
background-color: white;
|
|
min-height: calc(100vh - 150px);
|
|
border-radius: 8px;
|
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.component-container {
|
|
padding: 15px;
|
|
border-radius: 6px;
|
|
border: 1px solid var(--border-color);
|
|
margin-bottom: 15px;
|
|
background-color: var(--component-bg);
|
|
}
|
|
|
|
.component-item {
|
|
background-color: white;
|
|
padding: 8px 12px;
|
|
border-radius: 4px;
|
|
margin: 8px 0;
|
|
border: 1px solid var(--border-color);
|
|
cursor: move;
|
|
user-select: none;
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.component-item:hover {
|
|
border-color: var(--primary-color);
|
|
box-shadow: 0 2px 5px rgba(24, 144, 255, 0.15);
|
|
}
|
|
|
|
.workflow-node {
|
|
position: absolute;
|
|
width: 200px;
|
|
min-height: 100px;
|
|
background-color: white;
|
|
border-radius: 6px;
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
padding: 12px;
|
|
cursor: move;
|
|
z-index: 10;
|
|
}
|
|
|
|
.workflow-node .node-header {
|
|
border-bottom: 1px solid #eee;
|
|
padding-bottom: 8px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.workflow-node .node-title {
|
|
font-weight: 600;
|
|
font-size: 14px;
|
|
display: block;
|
|
text-overflow: ellipsis;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.workflow-node .node-type {
|
|
font-size: 12px;
|
|
color: #666;
|
|
}
|
|
|
|
.workflow-node .node-ports {
|
|
position: relative;
|
|
height: 20px;
|
|
margin-top: 15px;
|
|
}
|
|
|
|
.port {
|
|
position: absolute;
|
|
width: 12px;
|
|
height: 12px;
|
|
border-radius: 50%;
|
|
background-color: var(--primary-color);
|
|
cursor: crosshair;
|
|
}
|
|
|
|
.port-in {
|
|
top: 4px;
|
|
left: -6px;
|
|
}
|
|
|
|
.port-out {
|
|
top: 4px;
|
|
right: -6px;
|
|
}
|
|
|
|
.connection-path {
|
|
stroke: var(--primary-color);
|
|
stroke-width: 2px;
|
|
fill: none;
|
|
}
|
|
|
|
.template-item {
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 6px;
|
|
padding: 15px;
|
|
margin-bottom: 15px;
|
|
cursor: pointer;
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.template-item:hover {
|
|
border-color: var(--primary-color);
|
|
box-shadow: 0 2px 8px rgba(24, 144, 255, 0.15);
|
|
}
|
|
|
|
.template-item .template-title {
|
|
font-weight: 600;
|
|
color: #333;
|
|
}
|
|
|
|
.template-item .template-desc {
|
|
color: #666;
|
|
font-size: 13px;
|
|
margin-top: 5px;
|
|
}
|
|
|
|
.active-tab {
|
|
border-bottom: 2px solid var(--primary-color);
|
|
color: var(--primary-color);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.tab-content {
|
|
padding-top: 20px;
|
|
}
|
|
|
|
.task-item {
|
|
background-color: white;
|
|
border-radius: 6px;
|
|
padding: 15px;
|
|
margin-bottom: 15px;
|
|
border-left: 4px solid var(--primary-color);
|
|
}
|
|
|
|
.task-item.running {
|
|
border-left-color: var(--primary-color);
|
|
}
|
|
|
|
.task-item.completed {
|
|
border-left-color: var(--success-color);
|
|
}
|
|
|
|
.task-item.failed {
|
|
border-left-color: var(--error-color);
|
|
}
|
|
|
|
.properties-panel {
|
|
position: fixed;
|
|
top: 76px;
|
|
right: 20px;
|
|
width: 320px;
|
|
background-color: white;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
padding: 15px;
|
|
max-height: calc(100vh - 120px);
|
|
overflow-y: auto;
|
|
z-index: 100;
|
|
transform: translateX(360px);
|
|
transition: transform 0.3s;
|
|
}
|
|
|
|
.properties-panel.open {
|
|
transform: translateX(0);
|
|
}
|
|
|
|
.form-label {
|
|
font-weight: 500;
|
|
font-size: 13px;
|
|
}
|
|
|
|
/* 媒体查询用于响应式设计 */
|
|
@media (max-width: 768px) {
|
|
.sidebar {
|
|
width: 100%;
|
|
position: static;
|
|
height: auto;
|
|
padding-bottom: 0;
|
|
}
|
|
|
|
.main-content {
|
|
margin-left: 0;
|
|
}
|
|
|
|
.properties-panel {
|
|
width: 100%;
|
|
position: fixed;
|
|
top: auto;
|
|
bottom: 0;
|
|
right: 0;
|
|
transform: translateY(100%);
|
|
border-radius: 8px 8px 0 0;
|
|
max-height: 70vh;
|
|
}
|
|
|
|
.properties-panel.open {
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
|
<div class="container-fluid">
|
|
<a class="navbar-brand" href="#">
|
|
<i class="fas fa-project-diagram me-2"></i>工作流编辑器
|
|
</a>
|
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
|
<span class="navbar-toggler-icon"></span>
|
|
</button>
|
|
<div class="collapse navbar-collapse" id="navbarNav">
|
|
<ul class="navbar-nav me-auto">
|
|
<li class="nav-item">
|
|
<a class="nav-link active" href="#">可视化编辑</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="#">模板管理</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="#">任务列表</a>
|
|
</li>
|
|
</ul>
|
|
<div class="d-flex">
|
|
<button id="saveWorkflowBtn" class="btn btn-success me-2">
|
|
<i class="fas fa-save me-1"></i>保存
|
|
</button>
|
|
<button id="runWorkflowBtn" class="btn btn-primary">
|
|
<i class="fas fa-play me-1"></i>运行
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<!-- 侧边栏 -->
|
|
<div class="col-md-3 col-lg-2 d-md-block sidebar">
|
|
<div class="d-flex justify-content-center mb-4">
|
|
<div class="btn-group">
|
|
<button class="btn btn-outline-primary active" id="componentsTabBtn">组件</button>
|
|
<button class="btn btn-outline-primary" id="templatesTabBtn">模板</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 组件面板 -->
|
|
<div id="componentsPanel">
|
|
<div class="component-container">
|
|
<h6><i class="fas fa-database me-2"></i>数据源</h6>
|
|
<div class="component-list">
|
|
<div class="component-item" data-type="data_source" data-subtype="database">
|
|
<i class="fas fa-table me-2"></i>数据库
|
|
</div>
|
|
<div class="component-item" data-type="data_source" data-subtype="file">
|
|
<i class="fas fa-file-alt me-2"></i>文件
|
|
</div>
|
|
<div class="component-item" data-type="data_source" data-subtype="crawler">
|
|
<i class="fas fa-spider me-2"></i>爬虫
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="component-container">
|
|
<h6><i class="fas fa-filter me-2"></i>数据处理</h6>
|
|
<div class="component-list">
|
|
<div class="component-item" data-type="preprocessing" data-subtype="filter">
|
|
<i class="fas fa-filter me-2"></i>过滤
|
|
</div>
|
|
<div class="component-item" data-type="preprocessing" data-subtype="sort">
|
|
<i class="fas fa-sort me-2"></i>排序
|
|
</div>
|
|
<div class="component-item" data-type="preprocessing" data-subtype="aggregate">
|
|
<i class="fas fa-layer-group me-2"></i>聚合
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="component-container">
|
|
<h6><i class="fas fa-brain me-2"></i>模型分析</h6>
|
|
<div class="component-list">
|
|
<div class="component-item" data-type="model" data-subtype="sentiment">
|
|
<i class="fas fa-smile me-2"></i>情感分析
|
|
</div>
|
|
<div class="component-item" data-type="model" data-subtype="topic">
|
|
<i class="fas fa-tags me-2"></i>话题分类
|
|
</div>
|
|
<div class="component-item" data-type="model" data-subtype="keywords">
|
|
<i class="fas fa-key me-2"></i>关键词提取
|
|
</div>
|
|
<div class="component-item" data-type="model" data-subtype="summarize">
|
|
<i class="fas fa-compress-alt me-2"></i>文本摘要
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="component-container">
|
|
<h6><i class="fas fa-chart-bar me-2"></i>可视化</h6>
|
|
<div class="component-list">
|
|
<div class="component-item" data-type="visualization" data-subtype="chart">
|
|
<i class="fas fa-chart-line me-2"></i>图表
|
|
</div>
|
|
<div class="component-item" data-type="visualization" data-subtype="table">
|
|
<i class="fas fa-table me-2"></i>表格
|
|
</div>
|
|
<div class="component-item" data-type="visualization" data-subtype="wordcloud">
|
|
<i class="fas fa-cloud me-2"></i>词云
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 模板面板 -->
|
|
<div id="templatesPanel" style="display: none;">
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<h6 class="mb-0">爬虫模板</h6>
|
|
<button class="btn btn-sm btn-outline-primary">
|
|
<i class="fas fa-plus"></i> 新建
|
|
</button>
|
|
</div>
|
|
<div id="crawlerTemplatesList">
|
|
<!-- 爬虫模板列表将动态加载 -->
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-between align-items-center mb-3 mt-4">
|
|
<h6 class="mb-0">分析流程模板</h6>
|
|
<button class="btn btn-sm btn-outline-primary">
|
|
<i class="fas fa-plus"></i> 新建
|
|
</button>
|
|
</div>
|
|
<div id="analysisTemplatesList">
|
|
<!-- 分析流程模板列表将动态加载 -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 主要内容 -->
|
|
<div class="col-md-9 col-lg-10 main-content">
|
|
<div class="workflow-canvas" id="workflowCanvas">
|
|
<!-- 工作流节点和连接将在这里动态创建 -->
|
|
<svg id="connectionsSvg" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none;">
|
|
<!-- 连接线将在这里动态创建 -->
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 属性面板 -->
|
|
<div class="properties-panel" id="propertiesPanel">
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<h5 class="mb-0">组件属性</h5>
|
|
<button class="btn-close" id="closePropertiesBtn"></button>
|
|
</div>
|
|
<div id="propertiesContent">
|
|
<!-- 属性内容将动态加载 -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 模态框 -->
|
|
<div class="modal fade" id="saveTemplateModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">保存为模板</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form id="saveTemplateForm">
|
|
<div class="mb-3">
|
|
<label for="templateName" class="form-label">模板名称</label>
|
|
<input type="text" class="form-control" id="templateName" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="templateDescription" class="form-label">描述</label>
|
|
<textarea class="form-control" id="templateDescription" rows="3"></textarea>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="templateIcon" class="form-label">图标</label>
|
|
<select class="form-select" id="templateIcon">
|
|
<option value="chart-line">📊 图表</option>
|
|
<option value="filter">🔍 过滤</option>
|
|
<option value="spider">🕸️ 爬虫</option>
|
|
<option value="brain">🧠 AI分析</option>
|
|
<option value="database">💾 数据库</option>
|
|
<option value="cloud">☁️ 词云</option>
|
|
</select>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
|
<button type="button" class="btn btn-primary" id="saveTemplateBtn">保存</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal fade" id="runWorkflowModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">运行工作流</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p>确认要运行当前工作流吗?</p>
|
|
<div class="form-check mb-3">
|
|
<input class="form-check-input" type="checkbox" id="saveBeforeRun" checked>
|
|
<label class="form-check-label" for="saveBeforeRun">
|
|
运行前保存工作流
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
|
<button type="button" class="btn btn-primary" id="confirmRunBtn">运行</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal fade" id="taskStatusModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">任务执行状态</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<h6>进度</h6>
|
|
<div class="progress">
|
|
<div id="taskProgressBar" class="progress-bar" role="progressbar" style="width: 0%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<h6>状态信息</h6>
|
|
<div id="taskStatusInfo" class="p-3 bg-light rounded">
|
|
<p class="mb-1">任务ID: <span id="taskIdDisplay">-</span></p>
|
|
<p class="mb-1">状态: <span id="taskStatusDisplay">-</span></p>
|
|
<p class="mb-1">开始时间: <span id="taskStartTimeDisplay">-</span></p>
|
|
<p class="mb-0">完成时间: <span id="taskCompleteTimeDisplay">-</span></p>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<h6>结果预览</h6>
|
|
<div id="taskResultPreview" class="p-3 bg-light rounded" style="max-height: 300px; overflow: auto;">
|
|
<p class="text-muted">任务完成后将显示结果预览...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
|
|
<button type="button" class="btn btn-danger" id="cancelTaskBtn">取消任务</button>
|
|
<button type="button" class="btn btn-primary" id="viewResultBtn">查看完整结果</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
|
|
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/js/bootstrap.bundle.min.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/jsoneditor@9.5.0/dist/jsoneditor.min.js"></script>
|
|
<script src="C:\Users\67093\Desktop\开源安全奖励计划\网安小学期-微博舆情预测系统\Weibo_PublicOpinion_AnalysisSystem\static\js\workflow_editor.js"></script>
|
|
</body>
|
|
</html> |