Browse Source

1222

yangrongze
hanyuqing 4 months ago
parent
commit
5237941155
  1. 165
      1111.py
  2. 100
      import.py
  3. 4
      test.py
  4. 39
      test1.py
  5. 173
      test1217.py
  6. 54
      util/neo4j_utils.py
  7. 208
      vue/node_modules/.package-lock.json
  8. 357
      vue/package-lock.json
  9. 1
      vue/package.json
  10. 343474
      vue/public/icd10.json
  11. 9
      vue/src/api/graph.js
  12. 6
      vue/src/main.js
  13. 591
      vue/src/system/GraphDemo.vue

165
1111.py

@ -0,0 +1,165 @@
import json
import re
import os
from neo4j import GraphDatabase
# === 配置 ===
NEO4J_URI = "bolt://localhost:7687"
NEO4J_USER = "neo4j"
NEO4J_PASSWORD = "12345678" # 👈 请确保密码正确
RELATIONSHIP_FOLDER = r"D:\temp\669"
BATCH_SIZE = 100
def sanitize_relationship_type(rel_type: str) -> str:
"""清理关系类型,确保合法"""
if not isinstance(rel_type, str):
rel_type = str(rel_type)
sanitized = re.sub(r"[^a-zA-Z0-9_]", "", rel_type)
if not sanitized or sanitized[0].isdigit():
sanitized = "REL_" + sanitized
return sanitized or "RELATED"
def extract_start_end(rel: dict):
"""兼容多种字段名提取 start/end"""
for s_key, e_key in [("start", "end"), ("source", "target"), ("from", "to")]:
s = rel.get(s_key)
e = rel.get(e_key)
if s is not None and e is not None:
return s, e
return None, None
def load_relationships_from_file(filepath):
"""从单个 JSON 文件加载 relationships"""
with open(filepath, "r", encoding="utf-8-sig") as f:
data = json.load(f)
relationships = []
if isinstance(data, list):
for item in data:
if isinstance(item, dict) and "relationships" in item:
relationships.extend(item["relationships"])
elif isinstance(item, dict):
relationships.append(item)
elif isinstance(data, dict) and "relationships" in data:
relationships = data["relationships"]
else:
relationships = data if isinstance(data, list) else []
return relationships
def process_relationships(relationships):
"""清洗并验证关系列表"""
valid_rels = []
for rel in relationships:
start_id, end_id = extract_start_end(rel)
rel_type = rel.get("type", "RELATED")
props = rel.get("properties", {}) or {}
if start_id is None or end_id is None:
continue
try:
start_id = int(float(start_id))
end_id = int(float(end_id))
except (TypeError, ValueError):
continue
valid_rels.append({
"start": start_id,
"end": end_id,
"type": sanitize_relationship_type(rel_type),
"props": props
})
return valid_rels
def import_relationships_in_batches(tx, rels, batch_size):
total = len(rels)
created_total = 0
for i in range(0, total, batch_size):
batch = rels[i:i + batch_size]
rel_groups = {}
for rel in batch:
rel_groups.setdefault(rel["type"], []).append({
"start": rel["start"],
"end": rel["end"],
"props": rel["props"]
})
created_this_batch = 0
for rel_type, group in rel_groups.items():
cypher = f"""
UNWIND $rels AS r
MATCH (a {{nodeId: r.start}})
MATCH (b {{nodeId: r.end}})
WITH a, b, r
WHERE a IS NOT NULL AND b IS NOT NULL
MERGE (a)-[rel:`{rel_type}`]->(b)
SET rel += r.props
RETURN count(rel) AS c
"""
result = tx.run(cypher, rels=group).single()
created_this_batch += result["c"]
created_total += created_this_batch
print(f" ➤ 本批创建关系: {created_this_batch}")
return created_total
def main():
driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD))
# 获取所有 JSON 文件,并按文件名排序(确保 relations_001.json 先于 002)
json_files = [f for f in os.listdir(RELATIONSHIP_FOLDER) if f.startswith("relations_") and f.endswith(".json")]
json_files.sort() # 按字典序排序,适用于 001, 002... 格式
if not json_files:
print("❌ 文件夹中没有找到 relations_*.json 文件")
return
total_global_created = 0
total_global_processed = 0
print(f"📁 找到 {len(json_files)} 个关系文件,开始逐个导入...\n")
for idx, filename in enumerate(json_files, 1):
filepath = os.path.join(RELATIONSHIP_FOLDER, filename)
print(f"\n📄 [{idx}/{len(json_files)}] 正在处理: {filename}")
try:
raw_rels = load_relationships_from_file(filepath)
print(f" ➤ 原始关系数: {len(raw_rels)}")
valid_rels = process_relationships(raw_rels)
print(f" ➤ 有效关系数: {len(valid_rels)}")
if not valid_rels:
print(" ⚠️ 跳过:无有效关系")
continue
with driver.session() as session:
created = session.execute_write(import_relationships_in_batches, valid_rels, BATCH_SIZE)
total_global_created += created
total_global_processed += len(valid_rels)
print(f" ✅ 文件 {filename} 导入完成,创建 {created} 条关系")
except Exception as e:
print(f" ❌ 处理 {filename} 时出错: {e}")
continue # 继续处理下一个文件
print("\n" + "="*60)
print(f"🎉 全部导入完成!")
print(f"📊 总共处理有效关系: {total_global_processed}")
print(f"✅ 总共成功创建关系: {total_global_created}")
driver.close()
if __name__ == "__main__":
main()

100
import.py

@ -0,0 +1,100 @@
import pandas as pd
from neo4j import GraphDatabase
import numpy as np
# === 配置 ===
EXCEL_PATH = r"C:\Users\hanyuqing\Desktop\最新国家医保ICD编码\最新国家医保ICD编码\ICD-10医保版数据.xlsx"
NEO4J_URI = "bolt://localhost:7687"
NEO4J_USER = "neo4j"
NEO4J_PASSWORD = "12345678"
# === 读取 Excel ===
df = pd.read_excel(
EXCEL_PATH,
header=1,
dtype=str, # 关键:防止 A00.0 变成 A00
engine='openpyxl'
)
# 清理列名
df.columns = df.columns.astype(str).str.strip()
# 必需列
required_cols = [
"条目(诊断)名称", "条目(诊断)代码",
"亚目名称", "亚目代码",
"章代码范围", "节代码范围", "类目代码"
]
# 检查列是否存在
missing = [col for col in required_cols if col not in df.columns]
if missing:
raise ValueError(f"缺少必要列: {missing}")
# 替换 NaN 为 None(便于后续判断)
df = df.replace({np.nan: None})
# === 构造 name 和 code 字段(按你的逻辑)===
def get_disease_name(row):
diag_name = row["条目(诊断)名称"]
subcat_name = row["亚目名称"]
# 如果诊断名称为空(None 或 空白),用亚目名称
if not diag_name or str(diag_name).strip() == "":
return str(subcat_name).strip() if subcat_name else None
return str(diag_name).strip()
def get_diagnosis_code(row):
code = row["条目(诊断)代码"]
# 如果为空,返回空字符串 ""
if not code or str(code).strip() == "":
return ""
return str(code).strip()
# 应用逻辑
df["_disease_name"] = df.apply(get_disease_name, axis=1)
df["_diagnosis_code"] = df.apply(get_diagnosis_code, axis=1)
# 过滤掉 name 仍为 None 的行(即 诊断名 + 亚目名 都为空)
df = df[df["_disease_name"].notna() & (df["_disease_name"] != "")]
print(f"✅ 共准备 {len(df)} 条疾病记录用于导入")
# === Neo4j 连接 ===
driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD))
def upsert_disease(tx, record):
cypher = """
MERGE (d:Disease {name: $name})
ON CREATE SET
d.diagnosisCode = $diagnosisCode,
d.chapterRange = $chapterRange,
d.sectionRange = $sectionRange,
d.categoryCode = $categoryCode,
d.subcategoryCode = $subcategoryCode
ON MATCH SET
d.diagnosisCode = $diagnosisCode,
d.chapterRange = $chapterRange,
d.sectionRange = $sectionRange,
d.categoryCode = $categoryCode,
d.subcategoryCode = $subcategoryCode
"""
tx.run(cypher, {
"name": record["_disease_name"],
"diagnosisCode": record["_diagnosis_code"],
"chapterRange": record.get("章代码范围") or "",
"sectionRange": record.get("节代码范围") or "",
"categoryCode": record.get("类目代码") or "",
"subcategoryCode": record.get("亚目代码") or ""
})
# === 批量导入 ===
with driver.session() as session:
for idx, row in df.iterrows():
try:
session.execute_write(upsert_disease, row.to_dict())
except Exception as e:
print(f"❌ 第 {idx + 2} 行失败: {e}")
continue
print("✅ 数据导入完成!")
driver.close()

4
test.py

@ -82,10 +82,10 @@ from util.neo4j_utils import neo4j_client
# print("关系属性已更新") # print("关系属性已更新")
# neighbors = neo4j_client.find_neighbors_with_relationships( # neighbors = neo4j_client.find_neighbors_with_relationships(
# node_label="Disease", # node_label="Disease",
# node_properties={"name": "糖尿病"}, # node_properties={"name": "霍乱"},
# direction="both" # 或 "out"/"in" # direction="both" # 或 "out"/"in"
# ) # )
# # print(neighbors)
# for item in neighbors: # for item in neighbors:
# print(f"关系: {item['relationship']['type']}") # print(f"关系: {item['relationship']['type']}")
# print(f"目标节点: {item['target']['label']} - {item['target']}") # print(f"目标节点: {item['target']['label']} - {item['target']}")

39
test1.py

@ -1,3 +1,5 @@
from datetime import datetime
import robyn import robyn
from robyn import Robyn, jsonify, Response from robyn import Robyn, jsonify, Response
from typing import Optional, List, Any, Dict from typing import Optional, List, Any, Dict
@ -93,8 +95,8 @@ def build_g6_graph_data_from_results(
} }
def build_g6_subgraph_by_props( def build_g6_subgraph_by_props(
neo4j_util: Neo4jUtil, neo4j_util: Neo4jUtil,
node_label: str,
node_properties: Dict[str, Any], node_properties: Dict[str, Any],
node_label: Optional[str] = None,
direction: str = "both", direction: str = "both",
rel_type: Optional[str] = None rel_type: Optional[str] = None
) -> dict: ) -> dict:
@ -137,10 +139,11 @@ def get_data():
graph_data = build_g6_subgraph_by_props( graph_data = build_g6_subgraph_by_props(
neo4j_client, neo4j_client,
node_label="Disease", node_label="Disease",
node_properties={"name": "偏头痛"}, node_properties={"name": "埃尔托生物型霍乱"},
direction="both", direction="both",
rel_type=None rel_type=None
) )
return Response( return Response(
status_code=200, status_code=200,
description=jsonify(graph_data), description=jsonify(graph_data),
@ -150,7 +153,39 @@ def get_data():
return jsonify({"error": str(e)}), 500 return jsonify({"error": str(e)}), 500
@app.post("/getGraph")
def get_graph(req):
try:
# 1. 获取 JSON body(自动解析为 dict)
body = req.json()
# 2. 提取 label 字段(即疾病名称)
disease_name = body.get("label")
if not disease_name:
return jsonify({"error": "Missing 'label' in request body"}), 400
code = body.get("code")
level = body.get("level")
print("sssssssssss")
print(body.get("type"))
print(code)
print(level)
graph_data = build_g6_subgraph_by_props(
neo4j_client,
node_label=body.get("type"),
node_properties={"name": disease_name},
direction="both",
rel_type=None
)
return Response(
status_code=200,
description=jsonify(graph_data),
headers={"Content-Type": "text/plain; charset=utf-8"}
)
except Exception as e:
return jsonify({"error": str(e)}), 500
if __name__ == "__main__": if __name__ == "__main__":
app.start(host="0.0.0.0", port=8088) app.start(host="0.0.0.0", port=8088)

173
test1217.py

@ -0,0 +1,173 @@
import pandas as pd
import json
import numpy as np
import re
# === 配置 ===
EXCEL_PATH = r"C:\Users\hanyuqing\Desktop\最新国家医保ICD编码\最新国家医保ICD编码\ICD-10医保版数据.xlsx"
OUTPUT_JSON_PATH = "icd10_tree_with_level.json"
# === 章 code 格式化 ===
def extract_chapter_number(text):
if not text:
return None
text = str(text).strip()
match = re.search(r'第([一二三四五六七八九十百\d]+)章', text)
if match:
num_str = match.group(1)
chinese_num_map = {
'': 1, '': 2, '': 3, '': 4, '': 5,
'': 6, '': 7, '': 8, '': 9, '': 10,
'十一': 11, '十二': 12, '十三': 13, '十四': 14, '十五': 15,
'十六': 16, '十七': 17, '十八': 18, '十九': 19, '二十': 20,
'二十一': 21, '二十二': 22
}
if num_str in chinese_num_map:
return chinese_num_map[num_str]
elif num_str.isdigit():
return int(num_str)
if text.isdigit():
return int(text)
if text.endswith('.') and text[:-1].isdigit():
return int(text[:-1])
return None
def format_chapter_code(original):
num = extract_chapter_number(original)
if num is not None:
return f"{num}"
return str(original).strip() if original else ""
def get_clean(val):
if val is None or str(val).strip().lower() in ("", "nan", "none"):
return None
return str(val).strip()
def make_fields(code, name):
code_str = code or ""
label_str = name or ""
title_str = f"{code_str} {label_str}" if code_str and label_str else (code_str or label_str)
return code_str, label_str, title_str
# === 带 level 的树节点 ===
class TreeNode:
def __init__(self, code="", label="", title="", level=""):
self.code = code
self.label = label
self.title = title
self.level = level # 新增字段
self.children = []
self._child_key_set = set() # (code, label)
def add_or_get_child(self, code, label, title, level):
key = (code, label)
if key in self._child_key_set:
for child in self.children:
if child.code == code and child.label == label:
return child
else:
new_child = TreeNode(code=code, label=label, title=title, level=level)
self.children.append(new_child)
self._child_key_set.add(key)
return new_child
return None
# === 构建树 ===
root = TreeNode()
chapter_map = {}
df = pd.read_excel(
EXCEL_PATH,
header=1,
dtype=str,
engine='openpyxl'
)
df.columns = df.columns.astype(str).str.strip()
df = df.replace({np.nan: None})
for idx, row in df.iterrows():
raw_chapter = get_clean(row.get(""))
chapter_name = get_clean(row.get("章的名称"))
section_code = get_clean(row.get("节代码范围"))
section_name = get_clean(row.get("节名称"))
category_code = get_clean(row.get("类目代码"))
category_name = get_clean(row.get("类目名称"))
subcategory_code = get_clean(row.get("亚目代码"))
subcategory_name = get_clean(row.get("亚目名称"))
diagnosis_code = get_clean(row.get("条目(诊断)代码"))
diagnosis_name = get_clean(row.get("条目(诊断)名称"))
if not raw_chapter and not chapter_name:
continue
# === 章 ===
chapter_code = format_chapter_code(raw_chapter)
chap_label = chapter_name or chapter_code
chap_title = f"{chapter_code} {chapter_name}" if chapter_name else chapter_code
chap_key = (chapter_code, chap_label)
if chap_key not in chapter_map:
chapter_node = TreeNode(
code=chapter_code,
label=chap_label,
title=chap_title,
level="chapter"
)
root.children.append(chapter_node)
chapter_map[chap_key] = chapter_node
else:
chapter_node = chapter_map[chap_key]
current = chapter_node
# === 节 ===
if section_code or section_name:
sec_code, sec_label, sec_title = make_fields(section_code, section_name)
current = current.add_or_get_child(sec_code, sec_label, sec_title, "section")
# === 类目 ===
if category_code or category_name:
cat_code, cat_label, cat_title = make_fields(category_code, category_name)
current = current.add_or_get_child(cat_code, cat_label, cat_title, "category")
# === 亚目 ===
if subcategory_code or subcategory_name:
sub_code, sub_label, sub_title = make_fields(subcategory_code, subcategory_name)
current = current.add_or_get_child(sub_code, sub_label, sub_title, "subcategory")
# === 条目 ===
if diagnosis_code or diagnosis_name:
diag_code, diag_label, diag_title = make_fields(diagnosis_code, diagnosis_name)
current.add_or_get_child(diag_code, diag_label, diag_title, "diagnosis")
# === 转为带 id 的 dict ===
next_id = 1
def node_to_dict(node):
global next_id
item = {
"id": next_id,
"code": node.code,
"label": node.label,
"title": node.title,
"level": node.level # 新增
}
next_id += 1
if node.children:
item["children"] = [node_to_dict(child) for child in node.children]
return item
treeData = [node_to_dict(chap) for chap in root.children]
# === 保存 ===
with open(OUTPUT_JSON_PATH, 'w', encoding='utf-8') as f:
json.dump(treeData, f, ensure_ascii=False, indent=2)
print(f"✅ 树形结构已生成,共 {len(treeData)} 个章节点")
print(f"📄 输出文件: {OUTPUT_JSON_PATH}")

54
util/neo4j_utils.py

@ -1,4 +1,5 @@
# neo4j_util.py # neo4j_util.py
from datetime import datetime
import logging import logging
from typing import Dict, List, Optional, Any from typing import Dict, List, Optional, Any
from neo4j import GraphDatabase, Driver from neo4j import GraphDatabase, Driver
@ -100,15 +101,40 @@ class Neo4jUtil:
raw = self.execute_read(cypher) raw = self.execute_read(cypher)
return [self._merge_id_and_props(row) for row in raw] return [self._merge_id_and_props(row) for row in raw]
def find_nodes_with_element_id(self, label: str, properties: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]: from typing import Optional, Dict, Any, List
"""按属性查询节点"""
cypher = f"MATCH (n:`{label}`)" def find_nodes_with_element_id(
self,
label: Optional[str],
properties: Optional[Dict[str, Any]] = None
) -> List[Dict[str, Any]]:
"""
按属性查询节点支持指定标签或不指定标签
Args:
label (Optional[str]): 节点标签若为 None 则匹配任意标签的节点
properties (Optional[Dict[str, Any]]): 节点属性过滤条件
Returns:
List[Dict]: 节点列表每个节点包含 id 和所有属性
"""
# 构建节点模式
if label is not None:
node_pattern = f"(n:`{label}`)"
else:
node_pattern = "(n)"
cypher = f"MATCH {node_pattern}"
params = {} params = {}
if properties: if properties:
# 安全构建 WHERE 条件(使用参数化查询)
where_clause = " AND ".join([f"n.`{k}` = $prop_{k}" for k in properties]) where_clause = " AND ".join([f"n.`{k}` = $prop_{k}" for k in properties])
params = {f"prop_{k}": v for k, v in properties.items()} params = {f"prop_{k}": v for k, v in properties.items()}
cypher += f" WHERE {where_clause}" cypher += f" WHERE {where_clause}"
cypher += " RETURN elementId(n) AS id, n{.*} AS props" cypher += " RETURN elementId(n) AS id, n{.*} AS props"
raw = self.execute_read(cypher, params) raw = self.execute_read(cypher, params)
return [self._merge_id_and_props(row) for row in raw] return [self._merge_id_and_props(row) for row in raw]
@ -229,9 +255,11 @@ class Neo4jUtil:
raw = self.execute_read(cypher, params) raw = self.execute_read(cypher, params)
return [self._enrich_relationship(row) for row in raw] return [self._enrich_relationship(row) for row in raw]
from typing import Optional, Dict, Any, List
def find_neighbors_with_relationships( def find_neighbors_with_relationships(
self, self,
node_label: str, node_label: Optional[str],
node_properties: Dict[str, Any], node_properties: Dict[str, Any],
direction: str = "both", # 可选: "out", "in", "both" direction: str = "both", # 可选: "out", "in", "both"
rel_type: Optional[str] = None, rel_type: Optional[str] = None,
@ -240,7 +268,7 @@ class Neo4jUtil:
查询指定节点的所有邻居节点及其关系包括入边出边或双向 查询指定节点的所有邻居节点及其关系包括入边出边或双向
Args: Args:
node_label (str): 节点标签 node_label (Optional[str]): 节点标签若为 None 则匹配任意标签的节点
node_properties (Dict[str, Any]): 节点匹配属性必须能唯一或有效定位节点 node_properties (Dict[str, Any]): 节点匹配属性必须能唯一或有效定位节点
direction (str): 关系方向"out" 表示 (n)-[r]->(m)"in" 表示 (n)<-[r]-(m)"both" 表示无向 direction (str): 关系方向"out" 表示 (n)-[r]->(m)"in" 表示 (n)<-[r]-(m)"both" 表示无向
rel_type (Optional[str]): 可选的关系类型过滤 rel_type (Optional[str]): 可选的关系类型过滤
@ -253,14 +281,23 @@ class Neo4jUtil:
# 构建起始节点匹配条件 # 构建起始节点匹配条件
where_clause, params = self._build_where_conditions("n", node_properties, "node") where_clause, params = self._build_where_conditions("n", node_properties, "node")
# 构建关系类型过滤
rel_filter = f":`{rel_type}`" if rel_type else "" rel_filter = f":`{rel_type}`" if rel_type else ""
# ✅ 动态构建节点模式:支持 node_label=None
if node_label is not None:
node_pattern = f"(n:`{node_label}`)"
else:
node_pattern = "(n)"
# 构建完整 MATCH 模式
if direction == "out": if direction == "out":
pattern = f"(n:`{node_label}`)-[r{rel_filter}]->(m)" pattern = f"{node_pattern}-[r{rel_filter}]->(m)"
elif direction == "in": elif direction == "in":
pattern = f"(n:`{node_label}`)<-[r{rel_filter}]-(m)" pattern = f"{node_pattern}<[r{rel_filter}]-(m)"
elif direction == "both": elif direction == "both":
pattern = f"(n:`{node_label}`)-[r{rel_filter}]-(m)" pattern = f"{node_pattern}-[r{rel_filter}]-(m)"
else: else:
raise ValueError("direction 必须是 'out', 'in''both'") raise ValueError("direction 必须是 'out', 'in''both'")
@ -282,6 +319,7 @@ class Neo4jUtil:
raw_results = self.execute_read(cypher, params) raw_results = self.execute_read(cypher, params)
neighbors = [] neighbors = []
for row in raw_results: for row in raw_results:
source = dict(row["sourceProps"]) source = dict(row["sourceProps"])
source.update({"id": row["sourceId"], "label": row["sourceLabel"]}) source.update({"id": row["sourceId"], "label": row["sourceLabel"]})

208
vue/node_modules/.package-lock.json

@ -2114,6 +2114,14 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@ctrl/tinycolor": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
"integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==",
"engines": {
"node": ">=10"
}
},
"node_modules/@discoveryjs/json-ext": { "node_modules/@discoveryjs/json-ext": {
"version": "0.5.7", "version": "0.5.7",
"resolved": "https://registry.npmmirror.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", "resolved": "https://registry.npmmirror.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
@ -2123,6 +2131,14 @@
"node": ">=10.0.0" "node": ">=10.0.0"
} }
}, },
"node_modules/@element-plus/icons-vue": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz",
"integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==",
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/@eslint-community/eslint-utils": { "node_modules/@eslint-community/eslint-utils": {
"version": "4.9.0", "version": "4.9.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
@ -2221,6 +2237,28 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
} }
}, },
"node_modules/@floating-ui/core": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz",
"integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==",
"dependencies": {
"@floating-ui/utils": "^0.2.10"
}
},
"node_modules/@floating-ui/dom": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz",
"integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==",
"dependencies": {
"@floating-ui/core": "^1.7.3",
"@floating-ui/utils": "^0.2.10"
}
},
"node_modules/@floating-ui/utils": {
"version": "0.2.10",
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="
},
"node_modules/@hapi/hoek": { "node_modules/@hapi/hoek": {
"version": "9.3.0", "version": "9.3.0",
"resolved": "https://registry.npmmirror.com/@hapi/hoek/-/hoek-9.3.0.tgz", "resolved": "https://registry.npmmirror.com/@hapi/hoek/-/hoek-9.3.0.tgz",
@ -2387,6 +2425,16 @@
"integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==", "integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==",
"dev": true "dev": true
}, },
"node_modules/@popperjs/core": {
"name": "@sxzz/popperjs-es",
"version": "2.11.7",
"resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
"integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@sideway/address": { "node_modules/@sideway/address": {
"version": "4.1.5", "version": "4.1.5",
"resolved": "https://registry.npmmirror.com/@sideway/address/-/address-4.1.5.tgz", "resolved": "https://registry.npmmirror.com/@sideway/address/-/address-4.1.5.tgz",
@ -2734,6 +2782,19 @@
"resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz", "resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="
}, },
"node_modules/@types/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ=="
},
"node_modules/@types/lodash-es": {
"version": "4.17.12",
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
"dependencies": {
"@types/lodash": "*"
}
},
"node_modules/@types/mime": { "node_modules/@types/mime": {
"version": "1.3.5", "version": "1.3.5",
"resolved": "https://registry.npmmirror.com/@types/mime/-/mime-1.3.5.tgz", "resolved": "https://registry.npmmirror.com/@types/mime/-/mime-1.3.5.tgz",
@ -2838,6 +2899,11 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/web-bluetooth": {
"version": "0.0.16",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
},
"node_modules/@types/ws": { "node_modules/@types/ws": {
"version": "8.5.10", "version": "8.5.10",
"resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.5.10.tgz", "resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.5.10.tgz",
@ -4148,6 +4214,89 @@
"integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==", "integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==",
"dev": true "dev": true
}, },
"node_modules/@vueuse/core": {
"version": "9.13.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz",
"integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==",
"dependencies": {
"@types/web-bluetooth": "^0.0.16",
"@vueuse/metadata": "9.13.0",
"@vueuse/shared": "9.13.0",
"vue-demi": "*"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/core/node_modules/vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@vueuse/metadata": {
"version": "9.13.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz",
"integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared": {
"version": "9.13.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz",
"integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==",
"dependencies": {
"vue-demi": "*"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared/node_modules/vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@webassemblyjs/ast": { "node_modules/@webassemblyjs/ast": {
"version": "1.11.6", "version": "1.11.6",
"resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.6.tgz", "resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.6.tgz",
@ -4522,6 +4671,11 @@
"lodash": "^4.17.14" "lodash": "^4.17.14"
} }
}, },
"node_modules/async-validator": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
"integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
},
"node_modules/asynckit": { "node_modules/asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@ -6140,6 +6294,11 @@
"lodash": "^4.17.15" "lodash": "^4.17.15"
} }
}, },
"node_modules/dayjs": {
"version": "1.11.19",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="
},
"node_modules/debounce": { "node_modules/debounce": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmmirror.com/debounce/-/debounce-1.2.1.tgz", "resolved": "https://registry.npmmirror.com/debounce/-/debounce-1.2.1.tgz",
@ -6569,6 +6728,30 @@
"resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.694.tgz", "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.694.tgz",
"integrity": "sha512-kM3SwvGTYpBFJSc8jm4IYVMIOzDmAGd/Ry96O9elRiM6iEwHKNKhtXyFGzpfMMIGZD84W4/hyaULlMmNVvLQlQ==" "integrity": "sha512-kM3SwvGTYpBFJSc8jm4IYVMIOzDmAGd/Ry96O9elRiM6iEwHKNKhtXyFGzpfMMIGZD84W4/hyaULlMmNVvLQlQ=="
}, },
"node_modules/element-plus": {
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.12.0.tgz",
"integrity": "sha512-M9YLSn2np9OnqrSKWsiXvGe3qnF8pd94+TScsHj1aTMCD+nSEvucXermf807qNt6hOP040le0e5Aft7E9ZfHmA==",
"dependencies": {
"@ctrl/tinycolor": "^3.4.1",
"@element-plus/icons-vue": "^2.3.2",
"@floating-ui/dom": "^1.0.1",
"@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
"@types/lodash": "^4.17.20",
"@types/lodash-es": "^4.17.12",
"@vueuse/core": "^9.1.0",
"async-validator": "^4.2.5",
"dayjs": "^1.11.19",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"lodash-unified": "^1.0.3",
"memoize-one": "^6.0.0",
"normalize-wheel-es": "^1.2.0"
},
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/emoji-regex": { "node_modules/emoji-regex": {
"version": "8.0.0", "version": "8.0.0",
"resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz",
@ -8813,6 +8996,21 @@
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
}, },
"node_modules/lodash-es": {
"version": "4.17.22",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.22.tgz",
"integrity": "sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q=="
},
"node_modules/lodash-unified": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz",
"integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==",
"peerDependencies": {
"@types/lodash-es": "*",
"lodash": "*",
"lodash-es": "*"
}
},
"node_modules/lodash.debounce": { "node_modules/lodash.debounce": {
"version": "4.0.8", "version": "4.0.8",
"resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@ -9136,6 +9334,11 @@
"node": ">= 4.0.0" "node": ">= 4.0.0"
} }
}, },
"node_modules/memoize-one": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
},
"node_modules/merge-descriptors": { "node_modules/merge-descriptors": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@ -9575,6 +9778,11 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/normalize-wheel-es": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
"integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw=="
},
"node_modules/npm-run-path": { "node_modules/npm-run-path": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-2.0.2.tgz", "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-2.0.2.tgz",

357
vue/package-lock.json

@ -11,6 +11,7 @@
"@antv/g6": "^5.0.50", "@antv/g6": "^5.0.50",
"axios": "^1.13.2", "axios": "^1.13.2",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"element-plus": "^2.12.0",
"vue": "^3.2.13" "vue": "^3.2.13"
}, },
"devDependencies": { "devDependencies": {
@ -2140,6 +2141,14 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@ctrl/tinycolor": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
"integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==",
"engines": {
"node": ">=10"
}
},
"node_modules/@discoveryjs/json-ext": { "node_modules/@discoveryjs/json-ext": {
"version": "0.5.7", "version": "0.5.7",
"resolved": "https://registry.npmmirror.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", "resolved": "https://registry.npmmirror.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
@ -2149,6 +2158,14 @@
"node": ">=10.0.0" "node": ">=10.0.0"
} }
}, },
"node_modules/@element-plus/icons-vue": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz",
"integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==",
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/@eslint-community/eslint-utils": { "node_modules/@eslint-community/eslint-utils": {
"version": "4.9.0", "version": "4.9.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
@ -2247,6 +2264,28 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
} }
}, },
"node_modules/@floating-ui/core": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz",
"integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==",
"dependencies": {
"@floating-ui/utils": "^0.2.10"
}
},
"node_modules/@floating-ui/dom": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz",
"integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==",
"dependencies": {
"@floating-ui/core": "^1.7.3",
"@floating-ui/utils": "^0.2.10"
}
},
"node_modules/@floating-ui/utils": {
"version": "0.2.10",
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="
},
"node_modules/@hapi/hoek": { "node_modules/@hapi/hoek": {
"version": "9.3.0", "version": "9.3.0",
"resolved": "https://registry.npmmirror.com/@hapi/hoek/-/hoek-9.3.0.tgz", "resolved": "https://registry.npmmirror.com/@hapi/hoek/-/hoek-9.3.0.tgz",
@ -2413,6 +2452,16 @@
"integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==", "integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==",
"dev": true "dev": true
}, },
"node_modules/@popperjs/core": {
"name": "@sxzz/popperjs-es",
"version": "2.11.7",
"resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
"integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@sideway/address": { "node_modules/@sideway/address": {
"version": "4.1.5", "version": "4.1.5",
"resolved": "https://registry.npmmirror.com/@sideway/address/-/address-4.1.5.tgz", "resolved": "https://registry.npmmirror.com/@sideway/address/-/address-4.1.5.tgz",
@ -2760,6 +2809,19 @@
"resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz", "resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="
}, },
"node_modules/@types/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ=="
},
"node_modules/@types/lodash-es": {
"version": "4.17.12",
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
"dependencies": {
"@types/lodash": "*"
}
},
"node_modules/@types/mime": { "node_modules/@types/mime": {
"version": "1.3.5", "version": "1.3.5",
"resolved": "https://registry.npmmirror.com/@types/mime/-/mime-1.3.5.tgz", "resolved": "https://registry.npmmirror.com/@types/mime/-/mime-1.3.5.tgz",
@ -2864,6 +2926,11 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/web-bluetooth": {
"version": "0.0.16",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
},
"node_modules/@types/ws": { "node_modules/@types/ws": {
"version": "8.5.10", "version": "8.5.10",
"resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.5.10.tgz", "resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.5.10.tgz",
@ -4174,6 +4241,89 @@
"integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==", "integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==",
"dev": true "dev": true
}, },
"node_modules/@vueuse/core": {
"version": "9.13.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz",
"integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==",
"dependencies": {
"@types/web-bluetooth": "^0.0.16",
"@vueuse/metadata": "9.13.0",
"@vueuse/shared": "9.13.0",
"vue-demi": "*"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/core/node_modules/vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@vueuse/metadata": {
"version": "9.13.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz",
"integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared": {
"version": "9.13.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz",
"integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==",
"dependencies": {
"vue-demi": "*"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared/node_modules/vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@webassemblyjs/ast": { "node_modules/@webassemblyjs/ast": {
"version": "1.11.6", "version": "1.11.6",
"resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.6.tgz", "resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.6.tgz",
@ -4548,6 +4698,11 @@
"lodash": "^4.17.14" "lodash": "^4.17.14"
} }
}, },
"node_modules/async-validator": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
"integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
},
"node_modules/asynckit": { "node_modules/asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@ -6166,6 +6321,11 @@
"lodash": "^4.17.15" "lodash": "^4.17.15"
} }
}, },
"node_modules/dayjs": {
"version": "1.11.19",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="
},
"node_modules/debounce": { "node_modules/debounce": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmmirror.com/debounce/-/debounce-1.2.1.tgz", "resolved": "https://registry.npmmirror.com/debounce/-/debounce-1.2.1.tgz",
@ -6595,6 +6755,30 @@
"resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.694.tgz", "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.694.tgz",
"integrity": "sha512-kM3SwvGTYpBFJSc8jm4IYVMIOzDmAGd/Ry96O9elRiM6iEwHKNKhtXyFGzpfMMIGZD84W4/hyaULlMmNVvLQlQ==" "integrity": "sha512-kM3SwvGTYpBFJSc8jm4IYVMIOzDmAGd/Ry96O9elRiM6iEwHKNKhtXyFGzpfMMIGZD84W4/hyaULlMmNVvLQlQ=="
}, },
"node_modules/element-plus": {
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.12.0.tgz",
"integrity": "sha512-M9YLSn2np9OnqrSKWsiXvGe3qnF8pd94+TScsHj1aTMCD+nSEvucXermf807qNt6hOP040le0e5Aft7E9ZfHmA==",
"dependencies": {
"@ctrl/tinycolor": "^3.4.1",
"@element-plus/icons-vue": "^2.3.2",
"@floating-ui/dom": "^1.0.1",
"@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
"@types/lodash": "^4.17.20",
"@types/lodash-es": "^4.17.12",
"@vueuse/core": "^9.1.0",
"async-validator": "^4.2.5",
"dayjs": "^1.11.19",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"lodash-unified": "^1.0.3",
"memoize-one": "^6.0.0",
"normalize-wheel-es": "^1.2.0"
},
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/emoji-regex": { "node_modules/emoji-regex": {
"version": "8.0.0", "version": "8.0.0",
"resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz",
@ -8853,6 +9037,21 @@
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
}, },
"node_modules/lodash-es": {
"version": "4.17.22",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.22.tgz",
"integrity": "sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q=="
},
"node_modules/lodash-unified": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz",
"integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==",
"peerDependencies": {
"@types/lodash-es": "*",
"lodash": "*",
"lodash-es": "*"
}
},
"node_modules/lodash.debounce": { "node_modules/lodash.debounce": {
"version": "4.0.8", "version": "4.0.8",
"resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@ -9176,6 +9375,11 @@
"node": ">= 4.0.0" "node": ">= 4.0.0"
} }
}, },
"node_modules/memoize-one": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
},
"node_modules/merge-descriptors": { "node_modules/merge-descriptors": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@ -9615,6 +9819,11 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/normalize-wheel-es": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
"integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw=="
},
"node_modules/npm-run-path": { "node_modules/npm-run-path": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-2.0.2.tgz", "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-2.0.2.tgz",
@ -14665,12 +14874,23 @@
"@babel/helper-validator-identifier": "^7.28.5" "@babel/helper-validator-identifier": "^7.28.5"
} }
}, },
"@ctrl/tinycolor": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
"integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA=="
},
"@discoveryjs/json-ext": { "@discoveryjs/json-ext": {
"version": "0.5.7", "version": "0.5.7",
"resolved": "https://registry.npmmirror.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", "resolved": "https://registry.npmmirror.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
"integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
"dev": true "dev": true
}, },
"@element-plus/icons-vue": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz",
"integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==",
"requires": {}
},
"@eslint-community/eslint-utils": { "@eslint-community/eslint-utils": {
"version": "4.9.0", "version": "4.9.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
@ -14734,6 +14954,28 @@
"integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
"dev": true "dev": true
}, },
"@floating-ui/core": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz",
"integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==",
"requires": {
"@floating-ui/utils": "^0.2.10"
}
},
"@floating-ui/dom": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz",
"integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==",
"requires": {
"@floating-ui/core": "^1.7.3",
"@floating-ui/utils": "^0.2.10"
}
},
"@floating-ui/utils": {
"version": "0.2.10",
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="
},
"@hapi/hoek": { "@hapi/hoek": {
"version": "9.3.0", "version": "9.3.0",
"resolved": "https://registry.npmmirror.com/@hapi/hoek/-/hoek-9.3.0.tgz", "resolved": "https://registry.npmmirror.com/@hapi/hoek/-/hoek-9.3.0.tgz",
@ -14871,6 +15113,11 @@
"integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==", "integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==",
"dev": true "dev": true
}, },
"@popperjs/core": {
"version": "npm:@sxzz/popperjs-es@2.11.7",
"resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
"integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ=="
},
"@sideway/address": { "@sideway/address": {
"version": "4.1.5", "version": "4.1.5",
"resolved": "https://registry.npmmirror.com/@sideway/address/-/address-4.1.5.tgz", "resolved": "https://registry.npmmirror.com/@sideway/address/-/address-4.1.5.tgz",
@ -15193,6 +15440,19 @@
"resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz", "resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="
}, },
"@types/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ=="
},
"@types/lodash-es": {
"version": "4.17.12",
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
"requires": {
"@types/lodash": "*"
}
},
"@types/mime": { "@types/mime": {
"version": "1.3.5", "version": "1.3.5",
"resolved": "https://registry.npmmirror.com/@types/mime/-/mime-1.3.5.tgz", "resolved": "https://registry.npmmirror.com/@types/mime/-/mime-1.3.5.tgz",
@ -15297,6 +15557,11 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/web-bluetooth": {
"version": "0.0.16",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
},
"@types/ws": { "@types/ws": {
"version": "8.5.10", "version": "8.5.10",
"resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.5.10.tgz", "resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.5.10.tgz",
@ -16222,6 +16487,46 @@
"integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==", "integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==",
"dev": true "dev": true
}, },
"@vueuse/core": {
"version": "9.13.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz",
"integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==",
"requires": {
"@types/web-bluetooth": "^0.0.16",
"@vueuse/metadata": "9.13.0",
"@vueuse/shared": "9.13.0",
"vue-demi": "*"
},
"dependencies": {
"vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"requires": {}
}
}
},
"@vueuse/metadata": {
"version": "9.13.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz",
"integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ=="
},
"@vueuse/shared": {
"version": "9.13.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz",
"integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==",
"requires": {
"vue-demi": "*"
},
"dependencies": {
"vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"requires": {}
}
}
},
"@webassemblyjs/ast": { "@webassemblyjs/ast": {
"version": "1.11.6", "version": "1.11.6",
"resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.6.tgz", "resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.6.tgz",
@ -16525,6 +16830,11 @@
"lodash": "^4.17.14" "lodash": "^4.17.14"
} }
}, },
"async-validator": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
"integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
},
"asynckit": { "asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@ -17684,6 +17994,11 @@
"lodash": "^4.17.15" "lodash": "^4.17.15"
} }
}, },
"dayjs": {
"version": "1.11.19",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="
},
"debounce": { "debounce": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmmirror.com/debounce/-/debounce-1.2.1.tgz", "resolved": "https://registry.npmmirror.com/debounce/-/debounce-1.2.1.tgz",
@ -17997,6 +18312,27 @@
"resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.694.tgz", "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.694.tgz",
"integrity": "sha512-kM3SwvGTYpBFJSc8jm4IYVMIOzDmAGd/Ry96O9elRiM6iEwHKNKhtXyFGzpfMMIGZD84W4/hyaULlMmNVvLQlQ==" "integrity": "sha512-kM3SwvGTYpBFJSc8jm4IYVMIOzDmAGd/Ry96O9elRiM6iEwHKNKhtXyFGzpfMMIGZD84W4/hyaULlMmNVvLQlQ=="
}, },
"element-plus": {
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.12.0.tgz",
"integrity": "sha512-M9YLSn2np9OnqrSKWsiXvGe3qnF8pd94+TScsHj1aTMCD+nSEvucXermf807qNt6hOP040le0e5Aft7E9ZfHmA==",
"requires": {
"@ctrl/tinycolor": "^3.4.1",
"@element-plus/icons-vue": "^2.3.2",
"@floating-ui/dom": "^1.0.1",
"@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
"@types/lodash": "^4.17.20",
"@types/lodash-es": "^4.17.12",
"@vueuse/core": "^9.1.0",
"async-validator": "^4.2.5",
"dayjs": "^1.11.19",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"lodash-unified": "^1.0.3",
"memoize-one": "^6.0.0",
"normalize-wheel-es": "^1.2.0"
}
},
"emoji-regex": { "emoji-regex": {
"version": "8.0.0", "version": "8.0.0",
"resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz",
@ -19645,6 +19981,17 @@
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
}, },
"lodash-es": {
"version": "4.17.22",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.22.tgz",
"integrity": "sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q=="
},
"lodash-unified": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz",
"integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==",
"requires": {}
},
"lodash.debounce": { "lodash.debounce": {
"version": "4.0.8", "version": "4.0.8",
"resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "resolved": "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@ -19897,6 +20244,11 @@
"fs-monkey": "^1.0.4" "fs-monkey": "^1.0.4"
} }
}, },
"memoize-one": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
},
"merge-descriptors": { "merge-descriptors": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@ -20232,6 +20584,11 @@
"integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
"dev": true "dev": true
}, },
"normalize-wheel-es": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
"integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw=="
},
"npm-run-path": { "npm-run-path": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-2.0.2.tgz", "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-2.0.2.tgz",

1
vue/package.json

@ -11,6 +11,7 @@
"@antv/g6": "^5.0.50", "@antv/g6": "^5.0.50",
"axios": "^1.13.2", "axios": "^1.13.2",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"element-plus": "^2.12.0",
"vue": "^3.2.13" "vue": "^3.2.13"
}, },
"devDependencies": { "devDependencies": {

343474
vue/public/icd10.json

File diff suppressed because it is too large

9
vue/src/api/graph.js

@ -12,4 +12,13 @@ export function getTestGraphData() {
method: 'get' method: 'get'
// 注意:不传 params!因为后端不接收也不需要 // 注意:不传 params!因为后端不接收也不需要
}); });
}
export function getGraph(data) {
return request({
url: '/getGraph',
method: 'post',
data
// 注意:不传 params!因为后端不接收也不需要
});
} }

6
vue/src/main.js

@ -1,4 +1,8 @@
import { createApp } from 'vue' import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
createApp(App).mount('#app') const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')

591
vue/src/system/GraphDemo.vue

@ -1,151 +1,181 @@
<template> <template>
<div class="knowledge-graph-container"> <div class="knowledge-graph-container">
<!-- 控制面板 --> <!-- 控制面板 -->
<div class="control-panel"> <!-- <div class="control-panel">-->
<!-- 节点控制 --> <!-- &lt;!&ndash; 节点控制 &ndash;&gt;-->
<div class="section"> <!-- <div class="section">-->
<h5>节点控制</h5> <!-- <h5>节点控制</h5>-->
<label style="text-align: left;margin: 10px 0;display: flex;align-items: center;font-size: 12px;"> <!-- <label style="text-align: left;margin: 10px 0;display: flex;align-items: center;font-size: 12px;">-->
<input v-model="nodeShowLabel" type="checkbox" /> <!-- <input v-model="nodeShowLabel" type="checkbox" />-->
显示节点标签 <!-- 显示节点标签-->
</label> <!-- </label>-->
<div class="form-group"> <!-- <div class="form-group">-->
<label>字体名称:</label> <!-- <label>字体名称:</label>-->
<select v-model="nodeFontFamily"> <!-- <select v-model="nodeFontFamily">-->
<!-- 中文常用字体 --> <!-- &lt;!&ndash; 中文常用字体 &ndash;&gt;-->
<option value="Microsoft YaHei, sans-serif">微软雅黑</option> <!-- <option value="Microsoft YaHei, sans-serif">微软雅黑</option>-->
<option value="SimSun, serif">宋体SimSun</option> <!-- <option value="SimSun, serif">宋体SimSun</option>-->
<option value="SimHei, sans-serif">黑体SimHei</option> <!-- <option value="SimHei, sans-serif">黑体SimHei</option>-->
<option value="KaiTi, serif">楷体KaiTi</option> <!-- <option value="KaiTi, serif">楷体KaiTi</option>-->
<option value="FangSong, serif">仿宋FangSong</option> <!-- <option value="FangSong, serif">仿宋FangSong</option>-->
<option value="PingFang SC, Helvetica Neue, sans-serif">苹方PingFang SC</option> <!-- <option value="PingFang SC, Helvetica Neue, sans-serif">苹方PingFang SC</option>-->
<!-- 英文/通用字体 --> <!-- &lt;!&ndash; 英文/通用字体 &ndash;&gt;-->
<option value="Arial, sans-serif">Arial</option> <!-- <option value="Arial, sans-serif">Arial</option>-->
<option value="Helvetica, sans-serif">Helvetica</option> <!-- <option value="Helvetica, sans-serif">Helvetica</option>-->
<option value="Times New Roman, serif">Times New Roman</option> <!-- <option value="Times New Roman, serif">Times New Roman</option>-->
<option value="Georgia, serif">Georgia</option> <!-- <option value="Georgia, serif">Georgia</option>-->
<option value="Courier New, monospace">Courier New等宽</option> <!-- <option value="Courier New, monospace">Courier New等宽</option>-->
<option value="Verdana, sans-serif">Verdana</option> <!-- <option value="Verdana, sans-serif">Verdana</option>-->
<option value="Tahoma, sans-serif">Tahoma</option> <!-- <option value="Tahoma, sans-serif">Tahoma</option>-->
<option value="Impact, sans-serif">Impact</option> <!-- <option value="Impact, sans-serif">Impact</option>-->
</select> <!-- </select>-->
</div> <!-- </div>-->
<div class="slider-group"> <!-- <div class="slider-group">-->
<span>字体大小: {{ nodeFontSize }}px</span> <!-- <span>字体大小: {{ nodeFontSize }}px</span>-->
<input <!-- <input-->
v-model.number="nodeFontSize" <!-- v-model.number="nodeFontSize"-->
type="range" <!-- type="range"-->
min="10" <!-- min="10"-->
max="24" <!-- max="24"-->
step="1" <!-- step="1"-->
/> <!-- />-->
</div> <!-- </div>-->
<div class="color-picker"> <!-- <div class="color-picker">-->
<label>字体颜色:</label> <!-- <label>字体颜色:</label>-->
<input v-model="nodeFontColor" type="color" /> <!-- <input v-model="nodeFontColor" type="color" />-->
</div> <!-- </div>-->
<div class="form-group"> <!-- <div class="form-group">-->
<label>图形:</label> <!-- <label>图形:</label>-->
<select v-model="nodeShape"> <!-- <select v-model="nodeShape">-->
<option value="circle">圆形</option> <!-- <option value="circle">圆形</option>-->
<option value="diamond">菱形</option> <!-- <option value="diamond">菱形</option>-->
<option value="triangle">三角形</option> <!-- <option value="triangle">三角形</option>-->
<option value="rect">矩形</option> <!-- <option value="rect">矩形</option>-->
<option value="star">星形</option> <!-- <option value="star">星形</option>-->
<option value="hexagon">六边形</option> <!-- <option value="hexagon">六边形</option>-->
</select> <!-- </select>-->
</div> <!-- </div>-->
<div class="form-group"> <!-- <div class="form-group">-->
<label>尺寸:</label> <!-- <label>尺寸:</label>-->
<input v-model.number="nodeSize" type="number" min="30" max="100" /> <!-- <input v-model.number="nodeSize" type="number" min="30" max="100" />-->
</div> <!-- </div>-->
<div class="color-picker"> <!-- <div class="color-picker">-->
<label>填充颜色:</label> <!-- <label>填充颜色:</label>-->
<input v-model="nodeFill" type="color" /> <!-- <input v-model="nodeFill" type="color" />-->
</div> <!-- </div>-->
<div class="color-picker"> <!-- <div class="color-picker">-->
<label>边框颜色:</label> <!-- <label>边框颜色:</label>-->
<input v-model="nodeStroke" type="color" /> <!-- <input v-model="nodeStroke" type="color" />-->
</div> <!-- </div>-->
<div class="form-group"> <!-- <div class="form-group">-->
<label>边框尺寸:</label> <!-- <label>边框尺寸:</label>-->
<input v-model.number="nodeLineWidth" type="number" min="1" max="5" /> <!-- <input v-model.number="nodeLineWidth" type="number" min="1" max="5" />-->
</div> <!-- </div>-->
</div> <!-- </div>-->
<!-- 连边控制 --> <!-- &lt;!&ndash; 连边控制 &ndash;&gt;-->
<div class="section"> <!-- <div class="section">-->
<h5>连边控制</h5> <!-- <h5>连边控制</h5>-->
<label style="text-align: left;margin: 10px 0;display: flex;align-items: center;font-size: 12px;"> <!-- <label style="text-align: left;margin: 10px 0;display: flex;align-items: center;font-size: 12px;">-->
<input v-model="edgeShowLabel" type="checkbox" /> <!-- <input v-model="edgeShowLabel" type="checkbox" />-->
显示连边标签 <!-- 显示连边标签-->
<input v-model="edgeEndArrow" type="checkbox" style="margin-left: 10px"/> <!-- <input v-model="edgeEndArrow" type="checkbox" style="margin-left: 10px"/>-->
显示端点箭头
</label>
<div class="form-group">
<label>字体名称:</label>
<select v-model="edgeFontFamily">
<option value="Microsoft YaHei, sans-serif">微软雅黑</option>
<option value="SimSun, serif">宋体</option>
<option value="SimHei, sans-serif">黑体</option>
<option value="Arial, sans-serif">Arial</option>
<option value="sans-serif">无衬线默认</option>
</select>
</div>
<div class="slider-group">
<span>字体大小: {{ edgeFontSize }}px</span>
<input
v-model.number="edgeFontSize"
type="range"
min="8"
max="16"
step="1"
/>
</div>
<div class="color-picker">
<label>字体颜色:</label>
<input v-model="edgeFontColor" type="color" />
</div>
<div class="form-group">
<label>连边类型:</label>
<select v-model="edgeType">
<option value="line">直线</option>
<option value="polyline">折线边</option>
<option value="cubic">三次贝塞尔曲线边</option>
<option value="cubic-horizontal">水平三次贝塞尔曲线边</option>
<option value="cubic-vertical">垂直三次贝塞尔曲线边</option>
<option value="quadratic">二次贝塞尔曲线边</option>
</select>
</div>
<div class="form-group">
<label>线粗细:</label>
<input v-model.number="edgeLineWidth" type="number" min="1" max="5" />
</div>
<div class="color-picker">
<label>线条颜色:</label>
<input v-model="edgeStroke" type="color" />
</div>
<!-- <label>-->
<!-- <input v-model="edgeEndArrow" type="checkbox" />-->
<!-- 显示端点箭头--> <!-- 显示端点箭头-->
<!-- </label>--> <!-- </label>-->
<!-- <div class="form-group">-->
<!-- <label>字体名称:</label>-->
<!-- <select v-model="edgeFontFamily">-->
<!-- <option value="Microsoft YaHei, sans-serif">微软雅黑</option>-->
<!-- <option value="SimSun, serif">宋体</option>-->
<!-- <option value="SimHei, sans-serif">黑体</option>-->
<!-- <option value="Arial, sans-serif">Arial</option>-->
<!-- <option value="sans-serif">无衬线默认</option>-->
<!-- </select>-->
<!-- </div>-->
<!-- <div class="slider-group">-->
<!-- <span>字体大小: {{ edgeFontSize }}px</span>-->
<!-- <input-->
<!-- v-model.number="edgeFontSize"-->
<!-- type="range"-->
<!-- min="8"-->
<!-- max="16"-->
<!-- step="1"-->
<!-- />-->
<!-- </div>-->
<!-- <div class="color-picker">-->
<!-- <label>字体颜色:</label>-->
<!-- <input v-model="edgeFontColor" type="color" />-->
<!-- </div>-->
<!-- <div class="form-group">-->
<!-- <label>连边类型:</label>-->
<!-- <select v-model="edgeType">-->
<!-- <option value="line">直线</option>-->
<!-- <option value="polyline">折线边</option>-->
<!-- <option value="cubic">三次贝塞尔曲线边</option>-->
<!-- <option value="cubic-horizontal">水平三次贝塞尔曲线边</option>-->
<!-- <option value="cubic-vertical">垂直三次贝塞尔曲线边</option>-->
<!-- <option value="quadratic">二次贝塞尔曲线边</option>-->
<!-- </select>-->
<!-- </div>-->
<!-- <div class="form-group">-->
<!-- <label>线粗细:</label>-->
<!-- <input v-model.number="edgeLineWidth" type="number" min="1" max="5" />-->
<!-- </div>-->
<!-- <div class="color-picker">-->
<!-- <label>线条颜色:</label>-->
<!-- <input v-model="edgeStroke" type="color" />-->
<!-- </div>-->
<!--&lt;!&ndash; <label>&ndash;&gt;-->
<!--&lt;!&ndash; <input v-model="edgeEndArrow" type="checkbox" />&ndash;&gt;-->
<!--&lt;!&ndash; 显示端点箭头&ndash;&gt;-->
<!--&lt;!&ndash; </label>&ndash;&gt;-->
<!-- </div>-->
<!-- <button @click="resetView">重置视图</button>-->
<!-- <button @click="resetStyle">重置样式</button>-->
<!-- &lt;!&ndash; 操作按钮 &ndash;&gt;-->
<!-- </div>-->
<div class="icd10-tree-container">
<div>
<el-radio-group v-model="typeRadio" @change="changeTree">
<el-radio value="Disease">疾病</el-radio>
<el-radio label="Drug">药品</el-radio>
<el-radio label="Check">检查</el-radio>
</el-radio-group>
</div>
<div v-if="typeRadio='Disease'">
<el-tree
:data="treeData"
:props="treeProps"
:expand-on-click-node="false"
@node-click="handleNodeClick"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<el-tag size="small" :type="getTagType(data.level)" class="level-tag">
{{ getLevelLabel(data.level) }}
</el-tag>
<span class="code">{{ data.code }}</span>
<span class="label">{{ data.label }}</span>
</span>
</template>
</el-tree>
</div> </div>
<button @click="resetView">重置视图</button>
<button @click="resetStyle">重置样式</button>
<!-- 操作按钮 -->
</div> </div>
<!-- 图谱容器 --> <!-- 图谱容器 -->
<div ref="graphContainer" class="graph-container" id="container"></div> <div ref="graphContainer" class="graph-container" id="container"></div>
</div> </div>
</template> </template>
<script> <script>
import { getTestGraphData } from "@/api/graph" import {getGraph, getTestGraphData} from "@/api/graph"
import { Graph } from '@antv/g6'; import { Graph } from '@antv/g6';
export default { export default {
@ -156,9 +186,9 @@ export default {
// //
nodeShowLabel: true, nodeShowLabel: true,
nodeFontSize: 12, nodeFontSize: 12,
nodeFontColor: '#000000', nodeFontColor: '#fff',
nodeShape: 'circle', nodeShape: 'circle',
nodeSize: 60, nodeSize: 50,
nodeFill: '#9FD5FF', nodeFill: '#9FD5FF',
nodeStroke: '#5B8FF9', nodeStroke: '#5B8FF9',
nodeLineWidth: 2, nodeLineWidth: 2,
@ -168,9 +198,9 @@ export default {
edgeShowLabel: true, edgeShowLabel: true,
edgeFontSize: 10, edgeFontSize: 10,
edgeFontColor: '#666666', edgeFontColor: '#666666',
edgeType: 'line', edgeType: 'quadratic',
edgeLineWidth: 2, edgeLineWidth: 2,
edgeStroke: '#F00', edgeStroke: '#b6b2b2',
edgeEndArrow: true, edgeEndArrow: true,
edgeFontFamily: 'Microsoft YaHei, sans-serif', edgeFontFamily: 'Microsoft YaHei, sans-serif',
@ -184,11 +214,19 @@ export default {
{source: 'A', target: 'B', label: '包含'}, {source: 'A', target: 'B', label: '包含'},
{source: 'B', target: 'C', label: '子领域'} {source: 'B', target: 'C', label: '子领域'}
] ]
} },
treeData: [],
treeProps: {
children: 'children',
label: 'title' // el-tree
},
typeRadio:"Disease"
} }
}, },
async mounted() { async mounted() {
this.loadTreeData()
await this.$nextTick(); await this.$nextTick();
try { try {
const response = await getTestGraphData(); // Promise const response = await getTestGraphData(); // Promise
@ -203,10 +241,9 @@ export default {
label: this.nodeShowLabel, label: this.nodeShowLabel,
labelFontSize: this.nodeFontSize, labelFontSize: this.nodeFontSize,
labelFontFamily: this.nodeFontFamily, labelFontFamily: this.nodeFontFamily,
labelFontColor: this.nodeFontColor, labelFill: this.nodeFontColor,
} }
})) }))
const updatedEdges = response.edges.map(edge => ({ const updatedEdges = response.edges.map(edge => ({
...edge, ...edge,
type: this.edgeType, type: this.edgeType,
@ -262,14 +299,124 @@ export default {
edgeFontFamily: 'updateAllEdges', edgeFontFamily: 'updateAllEdges',
}, },
methods: { methods: {
changeTree(){
},
async loadTreeData() {
try {
const res = await fetch('/icd10.json')
if (!res.ok) throw new Error('Failed to load JSON')
this.treeData = await res.json()
console.log(this.treeData)
} catch (error) {
console.error('加载 ICD-10 数据失败:', error)
this.$message.error('加载编码数据失败,请检查文件路径')
}
},
async handleNodeClick(data) {
console.log('点击节点:', data)
// code
if(data.level=="category"||
data.level=="subcategory"||
data.level=="diagnosis"){
data.type="Disease"
const response = await getGraph(data); // Promise
this.formatData(response)
}
this.$message.info(`已选中: ${data.title}`)
},
buildNodeLabelMap(nodes) {
this._nodeLabelMap = new Map();
nodes.forEach(node => {
this._nodeLabelMap.set(node.id, node.data?.label || 'default');
});
},
clearGraphState() {
if (!this._graph) return;
// 1.
this._graph.getNodeData().forEach(node => {
this._graph.setElementState(node.id,[]);
});
this._graph.getEdgeData().forEach(edge => {
this._graph.setElementState(edge.id,[]);
});
// 2. pending
// clearTimeout
},
formatData(data){
this._graph.stopLayout();
this.clearGraphState();
// data.nodes = data.nodes.slice(0, 1000);
// data.edges = data.edges.slice(0, 0);
const updatedEdges = data.edges.map(edge => ({
...edge,
type: this.edgeType,
style: {
endArrow: this.edgeEndArrow,
stroke: this.edgeStroke,
lineWidth: this.edgeLineWidth,
label: this.edgeShowLabel,
labelFontSize: this.edgeFontSize,
labelFontFamily: this.edgeFontFamily,
labelFill: this.edgeFontColor,
},
}))
const updatedNodes = data.nodes.map(node => ({
...node,
type: this.nodeShape,
style:{
size: this.nodeSize,
lineWidth: this.nodeLineWidth,
label: this.nodeShowLabel,
labelFontSize: this.nodeFontSize,
labelFontFamily: this.nodeFontFamily,
labelFill: this.nodeFontColor,
opacity: 1,
}
}))
const updatedData = {
nodes: updatedNodes,
edges: updatedEdges
}
this.buildNodeLabelMap(updatedNodes);
this.updateGraph(updatedData)
},
getLevelLabel(level) {
const map = {
chapter: '章',
section: '节',
category: '类目',
subcategory: '亚目',
diagnosis: '条目'
}
return map[level] || level
},
getTagType(level) {
const map = {
chapter: 'primary',
section: 'success',
category: 'warning',
subcategory: 'info',
diagnosis: 'info'
}
return map[level] || ''
},
initGraph() { initGraph() {
if (this._graph!=null){ if (this._graph!=null){
this._graph.destroy() this._graph.destroy()
this._graph = null; this._graph = null;
} }
if (!this._nodeLabelMap) {
this.buildNodeLabelMap(this.defaultData.nodes);
}
console.log(this.defaultData)
console.log(this._nodeLabelMap)
const container = this.$refs.graphContainer; const container = this.$refs.graphContainer;
const width = container.clientWidth || 800; const width = container.clientWidth || 800;
const height = container.clientHeight || 600; const height = container.clientHeight || 600;
@ -279,15 +426,24 @@ export default {
width, width,
height, height,
layout: { layout: {
type: 'radial', // type: 'force', //
nodeSize: 32, // gravity: 0.3, //
unitRadius: 100, // repulsion: 500, //
linkDistance: 200, // attraction: 20, //
// preventOverlap: true //
// type: 'radial',
// preventOverlap: true,
// unitRadius: 200,
// maxPreventOverlapIteration:100
type: 'force-atlas2',
preventOverlap: true,
kr: 50,
center: [250, 250],
}, },
behaviors: [ 'zoom-canvas', 'drag-element','click-select','focus-element', behaviors: [ 'zoom-canvas', 'drag-element',
{ 'click-select','focus-element', {
type: 'hover-activate', type: 'hover-activate',
degree: 1, // 👈🏻 Activate relations. degree: 1,
}, },
{ {
type: 'drag-canvas', type: 'drag-canvas',
@ -300,37 +456,69 @@ export default {
node: { node: {
style: { style: {
fill: (d) => {
const label = d.data?.label;
if (label === 'Disease') return '#EF4444'; //
if (label === 'Drug') return '#91cc75'; // 绿
if (label === 'Symptom') return '#fac858'; //
return '#336eee'; //
},
stroke: (d) => {
const label = d.data?.label;
if (label === 'Disease') return '#B91C1C';
if (label === 'Drug') return '#047857';
if (label === 'Symptom') return '#B45309';
return '#1D4ED8';
},
labelText: (d) => d.data.name, labelText: (d) => d.data.name,
labelPlacement: 'center', labelPlacement: 'center',
labelWordWrap: true, labelWordWrap: true,
labelMaxWidth: '150%', labelMaxWidth: '150%',
labelMaxLines: 3, labelMaxLines: 3,
labelTextOverflow: 'ellipsis', labelTextOverflow: 'ellipsis',
labelTextAlign: 'center', labelTextAlign: 'center',
opacity: 1
}, },
state: { state: {
active: { active: {
fill: '#95D6FB',
stroke: '#1890FF',
lineWidth: 2, lineWidth: 2,
shadowColor: '#1890FF', shadowColor: '#1890FF',
shadowBlur: 10, shadowBlur: 10,
opacity: 1
}, },
highlight: { inactive: {
stroke: '#FF6A00', opacity: 0.3
lineWidth: 3,
},
disabled: {
fill: '#ECECEC',
stroke: '#BFBFBF',
opacity: 0.5,
}, },
normal:{
opacity: 1
}
}, },
}, },
edge: { edge: {
style: { style: {
labelText: (d) => d.data.relationship.type, labelText: (d) => d.data.relationship.type,
stroke: (d) => {
// target label
const targetLabel = this._nodeLabelMap.get(d.target); // d.target ID
// target
if (targetLabel === 'Disease') return '#f8d2d2';
if (targetLabel === 'Drug') return '#c0efe2';
if (targetLabel === 'Symptom') return '#f5cebf';
return '#c9d3ee'; // default
},
labelFill: (d) => {
// target label
const targetLabel = this._nodeLabelMap.get(d.target); // d.target ID
// target
if (targetLabel === 'Disease') return '#ff4444';
if (targetLabel === 'Drug') return '#2f9b70';
if (targetLabel === 'Symptom') return '#f89775';
return '#6b91ff'; // default
}
}, },
state: { state: {
selected: { selected: {
@ -338,22 +526,100 @@ export default {
lineWidth: 2, lineWidth: 2,
}, },
highlight: { highlight: {
stroke: '#FF6A00', halo: true,
haloStroke: '#1890FF',
haloLineWidth: 6,
haloStrokeOpacity: 0.3,
lineWidth: 3, lineWidth: 3,
opacity: 1
},
inactive: {
opacity: 0.3
}, },
normal:{
opacity: 1
}
}, },
}, },
data:this.defaultData data:this.defaultData,
}); });
graph.render(); graph.render();
// graph.on('node:pointerover', (evt) => {
// const nodeItem = evt.target; //
// const relatedEdges = graph.getRelatedEdgesData(nodeItem.id);
// const relatedEdgeIds = relatedEdges.map(edge => edge.id);
//
// // 3. 'highlight'
// relatedEdgeIds.forEach(edgeId => {
// graph.setElementState(edgeId, 'highlight', true);
// });
// graph.setElementState(nodeItem.id, 'active',true);
//
// // 2. ID
// const neighborNodeIds = new Set();
// relatedEdges.forEach(edge => {
// if (edge.source !== nodeItem.id) neighborNodeIds.add(edge.source);
// if (edge.target !== nodeItem.id) neighborNodeIds.add(edge.target);
// });
//
// neighborNodeIds.forEach(id => {
// graph.setElementState(id, 'active', true);
// });
//
// graph.getEdgeData().forEach(edge => {
// if (!relatedEdgeIds.includes(edge.id)) {
// graph.setElementState(edge.id, 'inactive', true);
// }
// });
// graph.getNodeData().forEach(node => {
// if (node.id !== nodeItem.id && !neighborNodeIds.has(node.id)) {
// graph.setElementState(node.id, 'inactive',true);
// }
// });
// });
// graph.on('node:pointerleave', (evt) => {
// graph.getEdgeData().forEach(edge => {
// graph.setElementState(edge.id, 'highlight', false);
// graph.setElementState(edge.id, 'inactive', false);
// graph.setElementState(edge.id, 'normal', true);
// });
// graph.getNodeData().forEach(node => {
// graph.setElementState(node.id, 'active', false);
// graph.setElementState(node.id, 'inactive', false);
// graph.setElementState(node.id, 'normal', true);
// });
// });
graph.on('node:click', (evt) => {
const nodeItem = evt.target.id; //
let node=graph.getNodeData(nodeItem).data
let data={
label:node.name,
type:node.label
}
getGraph(data).then(response=>{
console.log(response)
this.formatData(response)
}); // Promise
});
this._graph = graph this._graph = graph
this._graph?.fitView() this._graph?.fitView()
}, },
updateGraph(data) { updateGraph(data) {
if (!this._graph) return if (!this._graph) return
this._graph.setData(data) this._graph.setData(data)
this._graph.render() this._graph.render()
}, },
@ -538,7 +804,6 @@ export default {
button { button {
width: 45%; width: 45%;
padding: 10px; padding: 10px;
//margin: 10px 0;
background: #007bff; background: #007bff;
color: white; color: white;
border: none; border: none;

Loading…
Cancel
Save