Browse Source

Merge branch 'mh' of http://124.70.32.114:3100/hanyuqing/KGPython into hanyuqing

hanyuqing
hanyuqing 3 months ago
parent
commit
1c142d3567
  1. 85
      service/OperationService.py
  2. 101
      vue/src/system/GraphStyle.vue

85
service/OperationService.py

@ -390,3 +390,88 @@ class OperationService:
return {"success": True, "msg": "删除成功"} if result else {"success": False, "msg": "关系不存在"} return {"success": True, "msg": "删除成功"} if result else {"success": False, "msg": "关系不存在"}
except Exception as e: except Exception as e:
return {"success": False, "msg": f"删除失败: {str(e)}"} return {"success": False, "msg": f"删除失败: {str(e)}"}
# --- 7. 导出功能 ---
def export_nodes_to_json(self, label=None, name=None):
"""
按照条件导出节点确保包含 identity, elementId, labels, properties 等所有原始字段
"""
try:
conditions = []
params = {}
# 构建过滤条件(复用查询逻辑,但去掉分页)
if name:
params["name"] = unquote(str(name)).strip()
conditions.append("n.name CONTAINS $name")
lb_clause = ""
if label and label not in ["全部", ""]:
# 为了保证原生对象的完整性,这里直接 MATCH 标签
lb_clause = f":`{label}`"
where_clause = "WHERE " + " AND ".join(conditions) if conditions else ""
# 注意:这里 RETURN n,返回的是整个节点对象
cypher = f"MATCH (n{lb_clause}) {where_clause} RETURN n"
raw_data = self.db.execute_read(cypher, params)
export_items = []
for row in raw_data:
node = row['n']
# 核心逻辑:提取 Neo4j 节点对象的所有原生属性
node_data = {
"identity": node.id, # 对应你截图中的 identity (旧版 ID)
"elementId": node.element_id, # 对应你截图中的 elementId (新版 ID)
"labels": list(node.labels),
"properties": dict(node.items())
}
export_items.append(node_data)
return {"success": True, "data": export_items}
except Exception as e:
traceback.print_exc()
return {"success": False, "msg": f"导出节点失败: {str(e)}"}
def export_relationships_to_json(self, source=None, target=None, rel_type=None):
"""
按照条件导出关系确保包含起始/结束节点信息及完整属性
"""
try:
conditions = []
params = {}
if source:
params["source"] = unquote(str(source)).strip()
conditions.append("a.name CONTAINS $source")
if target:
params["target"] = unquote(str(target)).strip()
conditions.append("b.name CONTAINS $target")
if rel_type and rel_type not in ["全部", ""]:
conditions.append(f"type(r) = $rel_type")
params["rel_type"] = rel_type
where_clause = "WHERE " + " AND ".join(conditions) if conditions else ""
# 返回关系对象 r 以及起止节点的 elementId 以便追溯
cypher = f"MATCH (a)-[r]->(b) {where_clause} RETURN r, elementId(a) as startNode, elementId(b) as endNode"
raw_data = self.db.execute_read(cypher, params)
export_items = []
for row in raw_data:
rel = row['r']
rel_data = {
"identity": rel.id,
"elementId": rel.element_id,
"type": rel.type,
"startNodeElementId": row['startNode'],
"endNodeElementId": row['endNode'],
"properties": dict(rel.items())
}
export_items.append(rel_data)
return {"success": True, "data": export_items}
except Exception as e:
traceback.print_exc()
return {"success": False, "msg": f"导出关系失败: {str(e)}"}

101
vue/src/system/GraphStyle.vue

@ -684,19 +684,15 @@ export default {
this.saveDialogVisible = true; this.saveDialogVisible = true;
}, },
async confirmSave() { async confirmSave() {
if (!this.saveForm.group_name || !this if (!this.saveForm.group_name || !this.saveForm.group_name.trim()) {
.saveForm.group_name.trim()) { return ElMessage.warning("请选择或输入方案名称");
return this.$message.warning("请选择或输入方案名称"
);
} }
if (!this.saveForm.canvas_name || !this if (!this.saveForm.canvas_name || !this.saveForm.canvas_name.trim()) {
.saveForm.canvas_name.trim()) { return ElMessage.warning("请输入配置名称");
return this.$message.warning("请输入配置名称"
);
} }
const payload = { const payload = {
canvas_name: this.saveForm.canvas_name, canvas_name: this.saveForm.canvas_name.trim(),
group_name: this.saveForm.group_name, group_name: this.saveForm.group_name.trim(),
current_label: this.activeTags, current_label: this.activeTags,
styles: {...this.tagStyles[tagToLabelMap[this.activeTags]]} styles: {...this.tagStyles[tagToLabelMap[this.activeTags]]}
}; };
@ -704,6 +700,8 @@ export default {
if (res.code === 200) { if (res.code === 200) {
ElMessage.success("保存成功"); ElMessage.success("保存成功");
this.saveDialogVisible = false; this.saveDialogVisible = false;
this.saveForm.canvas_name = '';
this.saveForm.group_name = '';
this.resetAllTagsToDefault(); this.resetAllTagsToDefault();
this.fetchConfigs(); this.fetchConfigs();
} }
@ -725,51 +723,114 @@ export default {
this.updateAllElements(); this.updateAllElements();
ElMessage.info(`已重置【${this.activeTags}】样式`); ElMessage.info(`已重置【${this.activeTags}】样式`);
}, },
// --- ---
async deleteSingleConfig(id) { async deleteSingleConfig(id) {
if (this.usingConfigIds.includes(id)) {
return ElMessage.error("该配置正在应用中,请取消应用或切换方案后再删除");
}
try { try {
await ElMessageBox.confirm('确定删除此配置吗?', '提示'); await ElMessageBox.confirm('确定删除此配置吗?', '提示');
const res = await deleteGraphStyle(id); const res = await deleteGraphStyle(id);
if (res.code === 200) { if (res.code === 200) {
this.usingConfigIds = this.usingConfigIds.filter(cid => cid !== id); ElMessage.success("删除成功");
this.fetchConfigs(); this.fetchConfigs();
this.updateAllElements();
} }
} catch (err) {} } catch (err) {}
}, },
// --- ---
async deleteGroup(groupId) { async deleteGroup(groupId) {
const group = this.styleGroups.find(g => g.id === groupId);
if (!group) return;
// 1.
const isGroupUsing = group.configs.some(c => this.usingConfigIds.includes(c.id));
if (isGroupUsing || group.is_active) {
return ElMessage.error("该方案中包含正在应用的配置,无法删除");
}
// 2.
if (this.styleGroups.length <= 1) {
return ElMessage.error("系统至少需保留一个方案,无法全部删除");
}
try { try {
await ElMessageBox.confirm('确定删除整个方案吗?', '提示'); await ElMessageBox.confirm('确定删除整个方案吗?', '提示');
const res = await deleteGraphStyleGroup(groupId); const res = await deleteGraphStyleGroup(groupId);
if (res.code === 200) { if (res.code === 200) {
ElMessage.success("方案已删除");
this.fetchConfigs(); this.fetchConfigs();
this.updateAllElements();
} }
} catch (err) {} } catch (err) {}
}, },
// --- ---
async handleUnifiedBatchDelete() { async handleUnifiedBatchDelete() {
// 1.
if (this.checkedConfigIds.length === 0 && this.checkedGroupIds.length === 0) {
return ElMessage.warning("请先勾选要删除的项目");
}
// 2.
const isAnyCheckedConfigUsing = this.checkedConfigIds.some(id => this.usingConfigIds.includes(id));
const isAnyCheckedGroupUsing = this.styleGroups
.filter(g => this.checkedGroupIds.includes(g.id))
.some(g => g.configs.some(c => this.usingConfigIds.includes(c.id)));
if (isAnyCheckedConfigUsing || isAnyCheckedGroupUsing) {
return ElMessageBox.alert(
'选中的项目中包含“正在应用”的配置,请先取消应用后再执行删除操作。',
'无法执行删除',
{ type: 'error', confirmButtonText: '我知道了' }
);
}
// 3. ()
if (this.checkedGroupIds.length >= this.styleGroups.length && this.styleGroups.length > 0) {
return ElMessage.error("系统至少需要保留一个方案,请勿全部勾选删除");
}
try { try {
await ElMessageBox.confirm( await ElMessageBox.confirm(
'确定执行批量删除吗?', '确定执行批量删除吗?此操作不可恢复。',
'批量删除', '批量删除确认',
{ {
confirmButtonText: '确定', confirmButtonText: '确定删除',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
} }
); );
for (const gid of this.checkedGroupIds) await deleteGraphStyleGroup(gid);
if (this.checkedConfigIds.length > 0) await batchDeleteGraphStyle({ids: this.checkedConfigIds}); //
if (this.checkedGroupIds.length > 0) {
for (const gid of this.checkedGroupIds) {
await deleteGraphStyleGroup(gid);
}
}
if (this.checkedConfigIds.length > 0) {
await batchDeleteGraphStyle({ids: this.checkedConfigIds});
}
ElMessage.success("批量删除成功");
this.clearSelection(); this.clearSelection();
this.fetchConfigs(); this.fetchConfigs();
this.updateAllElements(); this.updateAllElements();
} catch (e) {} } catch (e) {
console.log("用户取消或删除失败", e);
}
}, },
clearSelection() { clearSelection() {
this.checkedConfigIds = []; this.checkedConfigIds = [];
this.checkedGroupIds = []; this.checkedGroupIds = [];
}, },
handleResize() { handleResize() {
if (this._graph && this.$refs.graphContainer) this._graph.setSize(this.$refs.graphContainer.clientWidth, this.$refs.graphContainer.clientHeight); if (this._graph && this.$refs.graphContainer) {
this._graph.setSize(this.$refs.graphContainer.clientWidth, this.$refs.graphContainer.clientHeight);
}
} }
} }
} }

Loading…
Cancel
Save