Compare commits

..

3 Commits
xu ... main

19
.gitignore vendored

@ -0,0 +1,19 @@
# Python
__pycache__/
*.pyc
*.pyo
# Node
node_modules/
dist/
# IDE
.vscode/
.idea/
# OS
.DS_Store
Thumbs.db
# Env
.env

@ -1,2 +1,108 @@
# minote66666
# DARPA 知识图谱系统
DARPA 项目知识图谱可视化分析平台,支持项目检索、趋势分析、机构合作网络、情报研判等功能。
## 技术栈
| 层级 | 技术 |
| --- | ------------------------------------------------ |
| 前端 | Vite + Tailwind CSS CDN + ECharts + Lucide Icons |
| 后端 | Python Flask (port 5001) |
| 数据库 | Neo4j 图数据库 |
| 认证 | AES-128-GCM (Web Crypto API + PBKDF2) |
## 目录结构
```
darpa/
├── frontend/ Vite 前端
│ ├── index.html
│ ├── vite.config.js
│ ├── package.json
│ └── src/
│ ├── js/ 12 个 JS 模块
│ ├── pages/ 8 个 HTML 页面片段
│ └── styles/ CSS 样式
├── backend/ Flask 后端
│ ├── app.py 主入口
│ ├── routes.py API 路由 (32 个端点)
│ ├── database.py Neo4j 连接
│ ├── import_data.py CSV 数据导入
│ ├── import_enrichment.py 富集数据导入
│ ├── data/ CSV 源数据
│ └── scripts/ 工具脚本
└── README.md
```
## 快速启动
### 1. 启动 Neo4j
确保 Neo4j 数据库已运行(默认 bolt://localhost:7687
### 2. 启动后端
```bash
cd backend
pip install -r requirements.txt
python app.py
# → http://localhost:5001
```
首次启动会自动导入 CSV 数据。强制重导:
```bash
python app.py --force-import
```
### 3. 启动前端
```bash
cd frontend
npm install
npm run dev
# → http://localhost:5173 (或其他可用端口)
```
### 4. 登录
- 管理员账号: `woker` / `Worker@2026`
- 新用户需在白名单中方可注册
## API 端点概览
| 端点 | 说明 |
| -------------------------------- | ----------- |
| `GET /` | 服务状态 |
| `GET /api/search` | 全文搜索(模糊/精准) |
| `GET /api/graph` | 知识图谱数据 |
| `GET /api/timeline` | 年代趋势 |
| `GET /api/domain_cluster` | 领域分布 |
| `GET /api/institution_network` | 机构合作网络 |
| `GET /api/centrality` | 节点中心度 |
| `GET /api/intelligence_report` | AI 情报研判 |
| `GET /api/project/<id>/detail` | 项目详情 |
| `GET /api/milestones` | 里程碑列表 |
| `GET /api/office_list` | 办公室列表 |
| `GET /api/manager_list` | 项目经理列表 |
| `GET/POST/PUT/DELETE /api/users` | 用户管理 |
| `GET/POST /api/whitelist` | 白名单管理 |
## 前端模块
| 文件 | 功能 |
| --------------- | ------------------ |
| `config.js` | 全局配置API 地址等) |
| `core.js` | 路由导航 |
| `auth.js` | 身份验证 (AES-128-GCM) |
| `dashboard.js` | 工作台仪表盘 |
| `search.js` | 智能检索 |
| `detail.js` | 项目详情 |
| `graph.js` | 知识图谱可视化 |
| `trend.js` | 趋势分析 |
| `wiki.js` | 情报百科 |
| `governance.js` | 数据治理 |
| `profile.js` | 个人资料/管理面板 |
| `main.js` | 模块入口汇总 |

@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
"""
DARPA 知识图谱 Flask 后端
- 启动时自动将 CSV 数据导入 Neo4jMERGE避免重复
- 提供全部前端所需 API
"""
import os
import traceback
from flask import Flask, request, jsonify
from flask_cors import CORS
# ─────────────────────────── 配置 ───────────────────────────
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
app = Flask(__name__, static_folder=BASE_DIR)
CORS(app)
# ── 全局错误处理 ────────────────────────────────────────────
@app.errorhandler(500)
def internal_error(e):
tb = traceback.format_exc()
print(f"[500] 服务器内部错误:\n{tb}", flush=True)
return jsonify({
"error": "服务器内部错误",
"detail": str(getattr(e, 'original_exception', e)),
}), 500
@app.errorhandler(404)
def not_found(e):
return jsonify({"error": "接口不存在"}), 404
@app.errorhandler(RuntimeError)
def handle_runtime_error(e):
print(f"[RuntimeError] {e}", flush=True)
return jsonify({"error": str(e)}), 500
# ── 根路由 ─────────────────────────────────────────────────
@app.route("/")
def serve_root():
return jsonify({"app": "DARPA 知识图谱 API", "status": "running"})
# ── 注册 API 路由 ──────────────────────────────────────────
from routes import bp
app.register_blueprint(bp)
# ═══════════════════════════════════════════════════════════════
# 主入口
# ═══════════════════════════════════════════════════════════════
if __name__ == "__main__":
import sys
from import_data import import_all
from database import driver
force_import = "--force-import" in sys.argv
data_already_exists = False
try:
from import_data import _has_existing_data
data_already_exists = _has_existing_data()
except Exception as exc:
print(f"[警告] 无法连接 Neo4j 检查数据: {exc}")
if force_import or not data_already_exists:
try:
import_all(force=force_import)
except Exception as exc:
print(f"[错误] 数据导入失败: {exc}")
else:
print("[启动] 数据库已有数据,跳过导入(--force-import 可强制重导)。")
print("[启动] Flask 运行于 http://localhost:5001")
app.run(host="0.0.0.0", port=5001, debug=False)

@ -0,0 +1,61 @@
# ============================================================
# Neo4j 知识图谱导入指南 - DARPA 项目数据
# ============================================================
# 1. 【推荐】neo4j-admin bulk import最快适合全量导入
neo4j-admin database import full neo4j --nodes=Project=nodes_project.csv --nodes=Office=nodes_office.csv --nodes=Technology=nodes_technology.csv --nodes=Manager=nodes_manager.csv --nodes=Institution=nodes_institution.csv --relationships=BELONGS_TO=rels_project_office.csv --relationships=MANAGED_BY=rels_project_manager.csv --relationships=USES_TECHNOLOGY=rels_project_technology.csv --relationships=PARTICIPATED_BY=rels_project_institution.csv --overwrite-destination=true
# 2. 【备选】Cypher LOAD CSV适合在线导入逐步执行
# ─── 创建约束 ───
CREATE CONSTRAINT FOR (p:Project) REQUIRE p.projectId IS UNIQUE;
CREATE CONSTRAINT FOR (o:Office) REQUIRE o.officeId IS UNIQUE;
CREATE CONSTRAINT FOR (t:Technology) REQUIRE t.techId IS UNIQUE;
CREATE CONSTRAINT FOR (m:Manager) REQUIRE m.managerId IS UNIQUE;
CREATE CONSTRAINT FOR (i:Institution) REQUIRE i.instId IS UNIQUE;
# ─── 导入节点 ───
LOAD CSV WITH HEADERS FROM 'file:///nodes_project.csv' AS row
CREATE (:Project {
projectId: row['projectId:ID(Project)'],
nameEn: row.nameEn,
nameCn: row.nameCn,
status: row.status,
startYear: toInteger(row['startYear:int']),
endYear: toInteger(row['endYear:int']),
budget: row.budget,
transferDomain: row.transferDomain
});
LOAD CSV WITH HEADERS FROM 'file:///nodes_office.csv' AS row
CREATE (:Office {officeId: row['officeId:ID(Office)'], name: row.name});
LOAD CSV WITH HEADERS FROM 'file:///nodes_technology.csv' AS row
CREATE (:Technology {techId: row['techId:ID(Technology)'], name: row.name});
LOAD CSV WITH HEADERS FROM 'file:///nodes_manager.csv' AS row
CREATE (:Manager {managerId: row['managerId:ID(Manager)'], name: row.name});
LOAD CSV WITH HEADERS FROM 'file:///nodes_institution.csv' AS row
CREATE (:Institution {instId: row['instId:ID(Institution)'], name: row.name});
# ─── 导入关系 ───
LOAD CSV WITH HEADERS FROM 'file:///rels_project_office.csv' AS row
MATCH (p:Project {projectId: row[':START_ID(Project)']}),
(o:Office {officeId: row[':END_ID(Office)']})
CREATE (p)-[:BELONGS_TO]->(o);
LOAD CSV WITH HEADERS FROM 'file:///rels_project_manager.csv' AS row
MATCH (p:Project {projectId: row[':START_ID(Project)']}),
(m:Manager {managerId: row[':END_ID(Manager)']})
CREATE (p)-[:MANAGED_BY]->(m);
LOAD CSV WITH HEADERS FROM 'file:///rels_project_technology.csv' AS row
MATCH (p:Project {projectId: row[':START_ID(Project)']}),
(t:Technology{techId: row[':END_ID(Technology)']})
CREATE (p)-[:USES_TECHNOLOGY]->(t);
LOAD CSV WITH HEADERS FROM 'file:///rels_project_institution.csv' AS row
MATCH (p:Project {projectId: row[':START_ID(Project)']}),
(i:Institution {instId: row[':END_ID(Institution)']})
CREATE (p)-[:PARTICIPATED_BY {relationType: row.relationType, remark: row.remark}]->(i);

@ -0,0 +1,37 @@
instId:ID(Institution),name,:LABEL
INST-AT_T,AT&T,Institution
INST-Bell_Labs,Bell Labs,Institution
INST-Burroughs,Burroughs,Institution
INST-Columbia,Columbia,Institution
INST-Columbia_University,Columbia University,Institution
INST-Cornell,Cornell,Institution
INST-Cray,Cray,Institution
INST-Cree_Wolfspeed,Cree/Wolfspeed,Institution
INST-DARPA,DARPA,Institution
INST-EG_G,EG&G,Institution
INST-GE,GE,Institution
INST-HP,HP,Institution
INST-HRL_Labs,HRL Labs,Institution
INST-Hughes,Hughes,Institution
INST-Hughes_Aircraft,Hughes Aircraft,Institution
INST-IBM,IBM,Institution
INST-Lockheed,Lockheed,Institution
INST-Lyric_Semiconductor,Lyric Semiconductor,Institution
INST-MIT,MIT,Institution
INST-MIT_Lincoln_Lab,MIT Lincoln Lab,Institution
INST-NREL,NREL,Institution
INST-Northrop,Northrop,Institution
INST-Purdue,Purdue,Institution
INST-RAND,RAND,Institution
INST-RF_Micro_Devices,RF Micro Devices,Institution
INST-Raytheon,Raytheon,Institution
INST-Rockwell,Rockwell,Institution
INST-SRI_International,SRI International,Institution
INST-Scripps_Institution,Scripps Institution,Institution
INST-Stanford,Stanford,Institution
INST-Sun,Sun,Institution
INST-TI,TI,Institution
INST-TRW,TRW,Institution
INST-UIUC,UIUC,Institution
INST-US_Army,US Army,Institution
INST-US_Navy,US Navy,Institution
1 instId:ID(Institution) name :LABEL
2 INST-AT_T AT&T Institution
3 INST-Bell_Labs Bell Labs Institution
4 INST-Burroughs Burroughs Institution
5 INST-Columbia Columbia Institution
6 INST-Columbia_University Columbia University Institution
7 INST-Cornell Cornell Institution
8 INST-Cray Cray Institution
9 INST-Cree_Wolfspeed Cree/Wolfspeed Institution
10 INST-DARPA DARPA Institution
11 INST-EG_G EG&G Institution
12 INST-GE GE Institution
13 INST-HP HP Institution
14 INST-HRL_Labs HRL Labs Institution
15 INST-Hughes Hughes Institution
16 INST-Hughes_Aircraft Hughes Aircraft Institution
17 INST-IBM IBM Institution
18 INST-Lockheed Lockheed Institution
19 INST-Lyric_Semiconductor Lyric Semiconductor Institution
20 INST-MIT MIT Institution
21 INST-MIT_Lincoln_Lab MIT Lincoln Lab Institution
22 INST-NREL NREL Institution
23 INST-Northrop Northrop Institution
24 INST-Purdue Purdue Institution
25 INST-RAND RAND Institution
26 INST-RF_Micro_Devices RF Micro Devices Institution
27 INST-Raytheon Raytheon Institution
28 INST-Rockwell Rockwell Institution
29 INST-SRI_International SRI International Institution
30 INST-Scripps_Institution Scripps Institution Institution
31 INST-Stanford Stanford Institution
32 INST-Sun Sun Institution
33 INST-TI TI Institution
34 INST-TRW TRW Institution
35 INST-UIUC UIUC Institution
36 INST-US_Army US Army Institution
37 INST-US_Navy US Navy Institution

@ -0,0 +1,29 @@
managerId:ID(Manager),name,:LABEL
MGR-20470728,Robert N. Noyce,Manager
MGR-88137902,Richard Kirschner,Manager
MGR-45095827,John M. Roland,Manager
MGR-56883573,Aristid V. Grosse,Manager
MGR-78216533,Jack L. Kerrebrock,Manager
MGR-58980650,J.C.R. Licklider / Robert E. Kahn,Manager
MGR-12117627,William Godel,Manager
MGR-62028279,Michael Arbib,Manager
MGR-43537160,Cordell Green,Manager
MGR-52944789,Robert W. Taylor,Manager
MGR-38011032,Lawrence G. Roberts,Manager
MGR-21572927,Raj Reddy,Manager
MGR-30572221,John J. Welsh,Manager
MGR-65101126,Lloyd G. Marts,Manager
MGR-29442483,DARPA战术技术办公室项目主管,Manager
MGR-89333365,DARPA信息创新办公室项目主管,Manager
MGR-50959738,DARPA微系统技术办公室项目主管,Manager
MGR-11959388,DARPA国防科学办公室项目主管,Manager
MGR-58272302,DARPA战略技术办公室项目主管,Manager
MGR-82307048,DARPA生物技术办公室项目主管,Manager
MGR-29103044,Robert Fano / Fernando Corbato,Manager
MGR-72808311,George Valley / Jay Forrester,Manager
MGR-44867089,Various Program Managers,Manager
MGR-79938277,Various MTO PMs,Manager
MGR-20235195,MTO Program Managers,Manager
MGR-86429568,DARPA I2O,Manager
MGR-85126670,Gill Pratt,Manager
MGR-48169304,MTO PM,Manager
1 managerId:ID(Manager) name :LABEL
2 MGR-20470728 Robert N. Noyce Manager
3 MGR-88137902 Richard Kirschner Manager
4 MGR-45095827 John M. Roland Manager
5 MGR-56883573 Aristid V. Grosse Manager
6 MGR-78216533 Jack L. Kerrebrock Manager
7 MGR-58980650 J.C.R. Licklider / Robert E. Kahn Manager
8 MGR-12117627 William Godel Manager
9 MGR-62028279 Michael Arbib Manager
10 MGR-43537160 Cordell Green Manager
11 MGR-52944789 Robert W. Taylor Manager
12 MGR-38011032 Lawrence G. Roberts Manager
13 MGR-21572927 Raj Reddy Manager
14 MGR-30572221 John J. Welsh Manager
15 MGR-65101126 Lloyd G. Marts Manager
16 MGR-29442483 DARPA战术技术办公室项目主管 Manager
17 MGR-89333365 DARPA信息创新办公室项目主管 Manager
18 MGR-50959738 DARPA微系统技术办公室项目主管 Manager
19 MGR-11959388 DARPA国防科学办公室项目主管 Manager
20 MGR-58272302 DARPA战略技术办公室项目主管 Manager
21 MGR-82307048 DARPA生物技术办公室项目主管 Manager
22 MGR-29103044 Robert Fano / Fernando Corbato Manager
23 MGR-72808311 George Valley / Jay Forrester Manager
24 MGR-44867089 Various Program Managers Manager
25 MGR-79938277 Various MTO PMs Manager
26 MGR-20235195 MTO Program Managers Manager
27 MGR-86429568 DARPA I2O Manager
28 MGR-85126670 Gill Pratt Manager
29 MGR-48169304 MTO PM Manager

@ -0,0 +1,7 @@
officeId:ID(Office),name,:LABEL
OFFICE-DSO,国防科学办公室,Office
OFFICE-STO,战略技术办公室,Office
OFFICE-MTO,微系统技术办公室,Office
OFFICE-I2O,信息创新办公室,Office
OFFICE-BTO,生物技术办公室,Office
OFFICE-TTO,战术技术办公室,Office
1 officeId:ID(Office) name :LABEL
2 OFFICE-DSO 国防科学办公室 Office
3 OFFICE-STO 战略技术办公室 Office
4 OFFICE-MTO 微系统技术办公室 Office
5 OFFICE-I2O 信息创新办公室 Office
6 OFFICE-BTO 生物技术办公室 Office
7 OFFICE-TTO 战术技术办公室 Office

@ -0,0 +1,163 @@
projectId:ID(Project),nameEn,nameCn,status,startYear:int,endYear:int,budget,transferDomain,:LABEL
DARPA-1958-CMP-001,Project Whirlwind,旋风计算机项目,结题,1958,1960,$500万,微电子,Project
DARPA-1959-GPS-001,Transit (NAVSTAR),子午仪卫星导航系统,结题,1959,1968,"$2,000万",太空技术,Project
DARPA-1959-SEN-001,Semiconductor Research,半导体研究,结题,1959,1965,$500万,微电子,Project
DARPA-1960-SEN-003,Project Vela,维拉计划,结题,1960,1966,$800万,材料科学,Project
DARPA-1961-ENG-001,Nuclear Rocket Program,核火箭计划,结题,1961,1973,"$2,000万",太空技术,Project
DARPA-1962-NET-001,ARPANET,阿帕网,结题,1962,1983,"$1,500万",通信网络,Project
DARPA-1963-MIL-002,Project AGILE,敏捷计划,结题,1963,1972,"$1,000万",无人系统,Project
DARPA-1964-AI-003,Perceptron Research,感知器研究,结题,1964,1970,$400万,人工智能,Project
DARPA-1965-AI-002,Interactive Theorem Proving,交互式定理证明,结题,1965,1975,$300万,人工智能,Project
DARPA-1965-CMP-003,Time-Sharing Systems,分时系统,结题,1965,1972,$500万,微电子,Project
DARPA-1966-NET-002,Network Control Program,网络控制程序,结题,1966,1970,$300万,通信网络,Project
DARPA-1967-CMP-001,Computer Vision Research,计算机视觉研究,结题,1967,1975,$400万,人工智能,Project
DARPA-1969-NET-003,ARPANET Initial Nodes,阿帕网首批节点,结题,1969,1973,$800万,通信网络,Project
DARPA-1970-AIR-003,D-21 Drone,D-21无人侦察机,结题,1970,1975,"$2,500万",无人系统,Project
DARPA-1970-SEN-002,Acoustic Research,声学研究,结题,1970,1978,$500万,微电子,Project
DARPA-1971-MIL-003,Project RED WING,红翼计划,结题,1971,1976,$800万,无人系统,Project
DARPA-1971-SPC-002,Survivable Communications,抗毁通信系统,结题,1971,1978,"$1,200万",通信网络,Project
DARPA-1972-NET-004,TCP/IP Protocol Suite,TCP/IP协议套件,结题,1972,1983,$600万,通信网络,Project
DARPA-1973-AI-001,Speech Understanding Research,语音理解研究,结题,1973,1976,"$1,500万",人工智能,Project
DARPA-1974-MIC-001,VLSI Project,超大规模集成电路项目,结题,1974,1984,"$2,000万",微电子,Project
DARPA-1975-AIR-001,Have Blue (Stealth),蓝色计划(隐身技术),结题,1975,1978,"$10,000万",无人系统,Project
DARPA-1976-NET-005,Packet Radio Network,分组无线电网,结题,1976,1984,$800万,通信网络,Project
DARPA-1978-AI-001,Artificial Intelligence Center,人工智能中心,结题,1978,1995,"$3,000万",人工智能,Project
DARPA-1979-MIL-027,Gorgon Stare,戈尔贡之眼,结题,1979,1990,"$2,000万",微电子,Project
DARPA-1980-ENG-007,Alternative Energy Systems,替代能源系统,结题,1980,1990,"$1,500万",能源技术,Project
DARPA-1981-SPC-003,Space Surveillance,太空监视,结题,1981,1995,"$2,500万",太空技术,Project
DARPA-1982-AI-002,Strategic Computing Program,战略计算计划,结题,1982,1993,"$10,000万",人工智能,Project
DARPA-1982-ENG-008,High Energy Laser Research,高能激光研究,结题,1982,1995,"$5,000万",能源技术,Project
DARPA-1983-NET-012,Defensive Comm,防御性通信系统,结题,1983,1989,"$1,500万",通信网络,Project
DARPA-1984-AI-003,Pilots Associate,飞行员助手,结题,1984,1991,"$2,500万",人工智能,Project
DARPA-1984-AIR-002,Have Blue II,蓝色计划II隐身,结题,1984,1990,"$8,000万",无人系统,Project
DARPA-1985-CMP-002,Parallel Computation,并行计算研究,结题,1985,1995,"$3,000万",微电子,Project
DARPA-1986-NET-010,AURORA (High Speed Networks),极光高速网络,结题,1986,1994,"$1,500万",通信网络,Project
DARPA-1987-MAT-001,Materials Research,先进材料研究,结题,1987,1998,"$2,500万",材料科学,Project
DARPA-1988-AI-004,Machine Learning,机器学习研究,结题,1988,1998,"$2,000万",人工智能,Project
DARPA-1988-CMP-009,HPCC (High Performance Computing),高性能计算,结题,1988,1995,"$10,000万",微电子,Project
DARPA-1989-MIL-030,Brilliant Eyes,慧眼计划,结题,1989,1995,"$3,000万",微电子,Project
DARPA-1990-ROB-001,Unmanned Ground Vehicle,无人地面车辆,结题,1993,2005,"$3,000万",无人系统,Project
DARPA-1990-ROB-002,ALV (Autonomous Land Vehicle),自主陆地车辆,结题,1990,1998,"$2,000万",无人系统,Project
DARPA-1992-CMP-010,Massively Parallel Computing,大规模并行计算,结题,1992,1998,"$2,500万",微电子,Project
DARPA-1993-ROB-003,Demo III,演示验证III,结题,1993,2000,"$1,500万",无人系统,Project
DARPA-1994-BIO-001,Bio-Inspired Systems,生物启发系统,结题,1994,2000,"$1,500万",生物技术,Project
DARPA-1995-SEC-004,Venetian Sands,威尼斯沙滩,结题,1995,1999,$800万,网络安全,Project
DARPA-1996-NET-011,Scalable Internet Routing,可扩展互联网路由,结题,1996,2002,"$1,500万",通信网络,Project
DARPA-1997-SEN-001,Sensor Webs,传感器网络,结题,1997,2005,"$2,500万",通信网络,Project
DARPA-1998-AI-005,Organic Computing,有机计算,结题,1998,2005,"$2,000万",人工智能,Project
DARPA-1998-BIO-009,Bio-Computation,生物计算,结题,1998,2003,"$1,000万",生物技术,Project
DARPA-1999-AI-015,PAL (Program for Language Learning),语言学习项目,结题,1999,2004,"$1,800万",人工智能,Project
DARPA-1999-NET-006,Next Generation Internet,下一代互联网,结题,1999,2005,"$10,000万",通信网络,Project
DARPA-2000-AI-006,Cognitive Technology,认知技术,结题,2000,2007,"$2,000万",人工智能,Project
DARPA-2000-MIL-016,Force Projection,力量投射,结题,2000,2006,"$4,000万",无人系统,Project
DARPA-2001-ENG-005,Adaptive Structures,自适应结构,结题,2001,2006,"$1,000万",材料科学,Project
DARPA-2001-NET-007,Tactical Internet,战术互联网,结题,2001,2008,"$5,000万",通信网络,Project
DARPA-2001-SEN-003,WASP (Wireless Aerial Sensor Platform),无线空中传感平台,结题,2001,2006,$900万,微电子,Project
DARPA-2002-ENG-001,Smart Dust (Mote),智能尘埃,结题,2002,2008,"$1,200万",微电子,Project
DARPA-2002-ENG-002,Mote (Smart Dust),智能尘埃节点,结题,2002,2008,"$1,200万",微电子,Project
DARPA-2002-MIL-031,Tactical Satellite,战术卫星,结题,2002,2008,"$2,000万",太空技术,Project
DARPA-2003-CMP-003,ProtoGEN,ProtoGEN项目,结题,2003,2007,$700万,微电子,Project
DARPA-2003-ENG-009,M-Warrior (Micro Air Vehicles),微型空中武器,结题,2003,2008,"$1,500万",无人系统,Project
DARPA-2003-MIL-001,Future Combat Systems,未来战斗系统,结题,2003,2009,"$20,000万",无人系统,Project
DARPA-2004-MIL-017,Project TALON,利爪计划,结题,2004,2008,"$2,500万",无人系统,Project
DARPA-2004-ROB-003,DARPA Grand Challenge,DARPA大挑战,结题,2004,2007,"$3,000万",无人系统,Project
DARPA-2004-SEC-005,Cyber Deterrence,网络威慑,结题,2004,2010,"$2,000万",网络安全,Project
DARPA-2005-AI-016,Integrated Warfighter Processing,综合战士处理,结题,2005,2010,"$1,500万",人工智能,Project
DARPA-2005-MIL-028,Project Vulture,秃鹰计划,结题,2005,2010,"$3,000万",无人系统,Project
DARPA-2005-ROB-004,DARPA Urban Challenge,DARPA城市挑战赛,结题,2007,2007,"$3,000万",无人系统,Project
DARPA-2006-BIO-001,Advanced Prosthetics,先进假肢,结题,2006,2015,"$3,000万",生物技术,Project
DARPA-2006-CMP-011,Cognitive Radio,认知无线电,结题,2006,2010,$800万,微电子,Project
DARPA-2006-ROB-014,M3 (Mechano-Micro),机械微型化,结题,2006,2012,"$1,800万",无人系统,Project
DARPA-2007-BIO-002,LUKE Arm (DEKA),卢克手臂DEKA,结题,2007,2014,"$4,000万",生物技术,Project
DARPA-2007-CMP-004,Universal Memory,通用内存,结题,2007,2014,"$2,000万",微电子,Project
DARPA-2008-BIO-010,In Vivo Nanotechnology,体内纳米技术,结题,2008,2013,"$2,000万",生物技术,Project
DARPA-2008-NET-008,Network Challenge,网络挑战,结题,2008,2009,$500万,通信网络,Project
DARPA-2008-ROB-005,EXACTO,精确制导自瞄子弹,结题,2008,2015,"$2,000万",无人系统,Project
DARPA-2009-BIO-005,RealNVC (Neural Vocabulary Coding),真实神经词汇编码,结题,2009,2014,"$1,000万",生物技术,Project
DARPA-2009-MIL-032,Double Eagle,双鹰计划,结题,2009,2015,"$2,500万",无人系统,Project
DARPA-2009-SEC-001,Vigilant Sentinels,警惕哨兵,结题,2009,2014,"$2,500万",网络安全,Project
DARPA-2009-SPC-005,Space Situational Awareness,太空态势感知,结题,2009,2015,"$3,000万",太空技术,Project
DARPA-2010-MIL-029,Active Confusion,主动迷惑,结题,2010,2014,"$1,000万",无人系统,Project
DARPA-2010-NET-009,RADICS (Rampant Attack Initiative),激增攻击应对,结题,2010,2017,"$4,000万",网络安全,Project
DARPA-2010-ROB-006,Robotics Challenge,机器人挑战赛DRC,结题,2010,2015,"$5,000万",无人系统,Project
DARPA-2011-AI-022,PPAML (Probabilistic Programming),概率编程,结题,2011,2016,"$3,000万",人工智能,Project
DARPA-2011-ENG-003,Air Force Energy Initiative,空军能源计划,结题,2011,2016,"$1,500万",能源技术,Project
DARPA-2011-SEC-002,Cyber Fast Track,网络快速跟进,结题,2011,2015,$500万,网络安全,Project
DARPA-2012-MIL-002,Adaptive Electronic Warfare,自适应电子战,结题,2012,2018,"$3,000万",无人系统,Project
DARPA-2012-MIL-018,Adaptive Radar Countermeasures,自适应雷达对抗,结题,2012,2018,"$2,000万",无人系统,Project
DARPA-2013-AI-007,Big Mechanism,大机制研究,结题,2013,2018,"$1,200万",人工智能,Project
DARPA-2013-ENG-004,Atmospheric Water Extraction,大气取水,结题,2013,2018,$800万,能源技术,Project
DARPA-2013-ENG-010,Mechantronics,机电一体化,结题,2013,2018,"$1,500万",材料科学,Project
DARPA-2013-SEC-006,Enhanced Cybersecurity,增强网络安全,结题,2013,2018,"$3,000万",网络安全,Project
DARPA-2014-CMP-012,UPSIDE (Unconventional Processing),非常规信号处理,结题,2014,2018,"$2,000万",微电子,Project
DARPA-2014-ROB-007,Cyber Grand Challenge,网络大挑战,结题,2014,2016,"$4,000万",网络安全,Project
DARPA-2014-ROB-009,Fast Lightweight Autonomy,快速轻量自主,结题,2014,2017,"$2,000万",无人系统,Project
DARPA-2015-AI-017,Verifiable AI,可验证AI,结题,2015,2020,"$1,500万",人工智能,Project
DARPA-2015-MIL-019,Long-Range Anti-Ship Missile,远程反舰导弹,结题,2015,2021,"$3,000万",无人系统,Project
DARPA-2015-ROB-008,OFFSET (Swarm),异构编队突击战术,结题,2015,2021,"$4,500万",无人系统,Project
DARPA-2016-AI-009,Explainable AI (XAI),可解释人工智能,结题,2016,2021,"$7,500万",人工智能,Project
DARPA-2016-CMP-005,DSO New Computing Architectures,DSO新计算架构,结题,2016,2022,"$5,000万",微电子,Project
DARPA-2016-MIL-020,Air Combat Evolution (ACE),空战进化,结题,2016,2024,"$10,000万",无人系统,Project
DARPA-2016-ROB-016,Fast Tools for Emerging Space,太空快速工具,结题,2016,2021,"$2,500万",太空技术,Project
DARPA-2017-AI-018,Explainable AI (Phase 2),可解释AI第二阶段,结题,2017,2021,"$4,000万",人工智能,Project
DARPA-2017-BIO-003,Living Foundries,生命体工厂,结题,2017,2025,"$7,700万",生物技术,Project
DARPA-2017-CMP-008,MANGROVE,森林计划,结题,2017,2023,"$2,500万",微电子,Project
DARPA-2017-ROB-010,Agile Team Tactics,敏捷团队战术,结题,2017,2022,"$3,000万",无人系统,Project
DARPA-2018-AI-010,AI Next Campaign,下一代AI运动,结题,2018,2025,"$20,000万",人工智能,Project
DARPA-2018-BIO-006,Detect It and GeOp (DIGO),检测与定位,结题,2018,2022,"$1,500万",生物技术,Project
DARPA-2018-CMP-001,Electronics Resurgence Initiative,电子复兴计划,结题,2018,2025,"$15,000万",微电子,Project
DARPA-2018-MIL-021,Ocean of Things,万物海洋,结题,2018,2024,"$2,500万",通信网络,Project
DARPA-2018-SEC-007,Cyber Hunting,网络狩猎,结题,2018,2022,"$1,500万",网络安全,Project
DARPA-2019-AI-023,AI for Data Curation,AI数据策展,结题,2019,2023,"$1,500万",人工智能,Project
DARPA-2019-BIO-009,Safe Genes,安全基因,结题,2019,2024,"$2,000万",生物技术,Project
DARPA-2019-ENG-005,Solaren (Space Solar),太空太阳能,结题,2019,2025,"$5,000万",能源技术,Project
DARPA-2019-QUT-001,Quantum Benchmarking,量子基准测试,结题,2019,2024,"$5,000万",量子科技,Project
DARPA-2019-ROB-011,No Ground Crew Required,无需地面人员,结题,2019,2023,"$2,000万",无人系统,Project
DARPA-2019-SPC-001,Black Address,黑址计划,结题,2019,2024,"$3,000万",太空技术,Project
DARPA-2020-AI-011,AI Quantum Initiative,AI量子倡议,结题,2020,2025,"$2,000万",量子科技,Project
DARPA-2020-BIO-011,Bio-Nanotechnology,生物纳米技术,结题,2020,2024,"$2,000万",生物技术,Project
DARPA-2020-CMP-006,Toolchains for Western Design,西方设计工具链,结题,2020,2024,"$3,000万",微电子,Project
DARPA-2020-MIL-022,Hypersonic Air-breathing Weapon,高超音速吸气式武器,研发中,2020,2026,"$8,000万",高超音速,Project
DARPA-2020-QUT-005,Quantum Enablement,量子赋能,结题,2020,2025,"$3,000万",量子科技,Project
DARPA-2021-AI-019,Automatic Machine Learning,自动机器学习,结题,2021,2025,"$3,000万",人工智能,Project
DARPA-2021-BIO-004,Neural Engineering System Design,神经工程系统设计,结题,2021,2025,"$6,500万",生物技术,Project
DARPA-2021-CMP-007,SPDC (Secure Processor Design),安全处理器设计,结题,2021,2025,"$2,500万",微电子,Project
DARPA-2021-MIL-003,Gremlins,小鬼计划,结题,2021,2025,"$3,500万",无人系统,Project
DARPA-2021-MIL-025,SIXTH SENSE,第六感,结题,2021,2025,"$2,500万",无人系统,Project
DARPA-2021-QUT-004,Optimization and Machine Learning,优化与机器学习,结题,2021,2025,"$2,500万",量子科技,Project
DARPA-2021-ROB-012,Subterranean (SubT) Challenge,地下挑战,结题,2021,2024,"$4,500万",无人系统,Project
DARPA-2022-AI-012,Semantic Forensics,语义取证,结题,2022,2027,"$2,000万",人工智能,Project
DARPA-2022-BIO-007,PREventing EMerging Pathogenic Threats,预防新发病原威胁,研发中,2022,2027,"$3,500万",生物技术,Project
DARPA-2022-CMP-002,CHIPS (Common Heterogeneous Integration),通用异构集成,结题,2022,2028,"$8,000万",微电子,Project
DARPA-2022-ENG-011,Clean Energy Initiative,清洁能源计划,结题,2022,2026,"$3,000万",能源技术,Project
DARPA-2022-MIL-023,MACE (Mid-Infrared Acquisition),中红外获取,研发中,2022,2026,"$2,000万",无人系统,Project
DARPA-2022-ROB-013,Avatar,阿凡达,研发中,2022,2026,"$5,000万",生物技术,Project
DARPA-2022-SEC-003,Zero Trust Architecture,零信任架构,结题,2022,2027,"$3,000万",网络安全,Project
DARPA-2023-AI-020,Adaptive Electronics,自适应电子,研发中,2023,2027,"$2,000万",人工智能,Project
DARPA-2023-ENG-006,AMMTO (Additive Manufacturing),增材制造,研发中,2023,2027,"$2,500万",材料科学,Project
DARPA-2023-HPM-001,Giant Leap,巨大飞跃,研发中,2023,2028,"$6,000万",高超音速,Project
DARPA-2023-MIL-026,Multi-Domain Ops,多域作战,研发中,2023,2027,"$3,500万",无人系统,Project
DARPA-2023-ROB-018,Squad Mission,班任务系统,研发中,2023,2027,"$4,000万",无人系统,Project
DARPA-2023-SPC-002,Space-BACN,太空BACN,研发中,2023,2027,"$4,000万",太空技术,Project
DARPA-2024-AI-013,AI-Assisted Science,AI辅助科学,研发中,2024,2028,"$5,000万",人工智能,Project
DARPA-2024-AI-024,Foundation Model Security,基础模型安全,研发中,2024,2028,"$4,000万",人工智能,Project
DARPA-2024-BIO-008,Pandemic Prevention Platform,大流行预防平台,研发中,2024,2028,"$5,000万",生物技术,Project
DARPA-2024-MIL-024,LongShank,长腿计划,研发中,2024,2028,"$3,000万",无人系统,Project
DARPA-2024-QUT-002,Quantum Networks,量子网络,研发中,2024,2028,"$5,500万",量子科技,Project
DARPA-2024-ROB-008,Atlas Next Gen,阿特拉斯下一代,研发中,2024,2028,"$3,000万",无人系统,Project
DARPA-2024-SEC-004,Secure Computation,安全计算,研发中,2024,2028,"$3,500万",网络安全,Project
DARPA-2025-AI-014,Trustworthy AI,可信AI,研发中,2025,2030,"$10,000万",人工智能,Project
DARPA-2025-BIO-012,Synthetic Human,合成人类,研发中,2025,2030,"$6,000万",生物技术,Project
DARPA-2025-MAT-002,Future Materials,未来材料,研发中,2025,2030,"$3,500万",材料科学,Project
DARPA-2025-QUT-003,Quantum Advantage,量子优势,研发中,2025,2030,"$8,000万",量子科技,Project
DARPA-2025-ROB-015,Mech Free,机械自由,研发中,2025,2029,"$4,000万",无人系统,Project
PROJ-044,Project MAC,MAC项目,已完成,1963,1974,"$1,500万",操作系统、云计算,Project
PROJ-045,SAGE System,赛奇防空系统,已完成,1954,1963,"$800,000万",防空系统、空中交通管制,Project
PROJ-046,AGILE Program,敏捷反叛乱项目,已完成,1961,1974,"$5,000万",特种作战、反恐技术,Project
PROJ-047,ASW Technology,反潜战技术,已完成,1960,1980,"$20,000万",海军装备、海洋监测,Project
PROJ-048,Gallium Arsenide,砷化镓半导体,已完成,1975,1990,"$10,000万",通信、雷达、光电子,Project
PROJ-049,MIMIC Program,微波单片集成电路,已完成,1987,1995,"$50,000万",雷达、通信、电子战,Project
PROJ-050,W/SEA Technology,宽禁带半导体,进行中,2001,进行中,"$20,000万",雷达、电力电子、电动车,Project
PROJ-051,High Productivity Computing,高生产率计算系统,已完成,2002,2012,"$10,000万",超级计算、科学计算,Project
PROJ-052,SyNAPSE,神经形态计算,已完成,2008,2016,"$10,000万",AI芯片、边缘计算,Project
PROJ-053,UPSIDE,不确定性处理处理器,已完成,2012,2017,"$3,500万",AI推理、传感器融合,Project
1 projectId:ID(Project) nameEn nameCn status startYear:int endYear:int budget transferDomain :LABEL
2 DARPA-1958-CMP-001 Project Whirlwind 旋风计算机项目 结题 1958 1960 $500万 微电子 Project
3 DARPA-1959-GPS-001 Transit (NAVSTAR) 子午仪卫星导航系统 结题 1959 1968 $2,000万 太空技术 Project
4 DARPA-1959-SEN-001 Semiconductor Research 半导体研究 结题 1959 1965 $500万 微电子 Project
5 DARPA-1960-SEN-003 Project Vela 维拉计划 结题 1960 1966 $800万 材料科学 Project
6 DARPA-1961-ENG-001 Nuclear Rocket Program 核火箭计划 结题 1961 1973 $2,000万 太空技术 Project
7 DARPA-1962-NET-001 ARPANET 阿帕网 结题 1962 1983 $1,500万 通信网络 Project
8 DARPA-1963-MIL-002 Project AGILE 敏捷计划 结题 1963 1972 $1,000万 无人系统 Project
9 DARPA-1964-AI-003 Perceptron Research 感知器研究 结题 1964 1970 $400万 人工智能 Project
10 DARPA-1965-AI-002 Interactive Theorem Proving 交互式定理证明 结题 1965 1975 $300万 人工智能 Project
11 DARPA-1965-CMP-003 Time-Sharing Systems 分时系统 结题 1965 1972 $500万 微电子 Project
12 DARPA-1966-NET-002 Network Control Program 网络控制程序 结题 1966 1970 $300万 通信网络 Project
13 DARPA-1967-CMP-001 Computer Vision Research 计算机视觉研究 结题 1967 1975 $400万 人工智能 Project
14 DARPA-1969-NET-003 ARPANET Initial Nodes 阿帕网首批节点 结题 1969 1973 $800万 通信网络 Project
15 DARPA-1970-AIR-003 D-21 Drone D-21无人侦察机 结题 1970 1975 $2,500万 无人系统 Project
16 DARPA-1970-SEN-002 Acoustic Research 声学研究 结题 1970 1978 $500万 微电子 Project
17 DARPA-1971-MIL-003 Project RED WING 红翼计划 结题 1971 1976 $800万 无人系统 Project
18 DARPA-1971-SPC-002 Survivable Communications 抗毁通信系统 结题 1971 1978 $1,200万 通信网络 Project
19 DARPA-1972-NET-004 TCP/IP Protocol Suite TCP/IP协议套件 结题 1972 1983 $600万 通信网络 Project
20 DARPA-1973-AI-001 Speech Understanding Research 语音理解研究 结题 1973 1976 $1,500万 人工智能 Project
21 DARPA-1974-MIC-001 VLSI Project 超大规模集成电路项目 结题 1974 1984 $2,000万 微电子 Project
22 DARPA-1975-AIR-001 Have Blue (Stealth) 蓝色计划(隐身技术) 结题 1975 1978 $10,000万 无人系统 Project
23 DARPA-1976-NET-005 Packet Radio Network 分组无线电网 结题 1976 1984 $800万 通信网络 Project
24 DARPA-1978-AI-001 Artificial Intelligence Center 人工智能中心 结题 1978 1995 $3,000万 人工智能 Project
25 DARPA-1979-MIL-027 Gorgon Stare 戈尔贡之眼 结题 1979 1990 $2,000万 微电子 Project
26 DARPA-1980-ENG-007 Alternative Energy Systems 替代能源系统 结题 1980 1990 $1,500万 能源技术 Project
27 DARPA-1981-SPC-003 Space Surveillance 太空监视 结题 1981 1995 $2,500万 太空技术 Project
28 DARPA-1982-AI-002 Strategic Computing Program 战略计算计划 结题 1982 1993 $10,000万 人工智能 Project
29 DARPA-1982-ENG-008 High Energy Laser Research 高能激光研究 结题 1982 1995 $5,000万 能源技术 Project
30 DARPA-1983-NET-012 Defensive Comm 防御性通信系统 结题 1983 1989 $1,500万 通信网络 Project
31 DARPA-1984-AI-003 Pilots Associate 飞行员助手 结题 1984 1991 $2,500万 人工智能 Project
32 DARPA-1984-AIR-002 Have Blue II 蓝色计划II(隐身) 结题 1984 1990 $8,000万 无人系统 Project
33 DARPA-1985-CMP-002 Parallel Computation 并行计算研究 结题 1985 1995 $3,000万 微电子 Project
34 DARPA-1986-NET-010 AURORA (High Speed Networks) 极光高速网络 结题 1986 1994 $1,500万 通信网络 Project
35 DARPA-1987-MAT-001 Materials Research 先进材料研究 结题 1987 1998 $2,500万 材料科学 Project
36 DARPA-1988-AI-004 Machine Learning 机器学习研究 结题 1988 1998 $2,000万 人工智能 Project
37 DARPA-1988-CMP-009 HPCC (High Performance Computing) 高性能计算 结题 1988 1995 $10,000万 微电子 Project
38 DARPA-1989-MIL-030 Brilliant Eyes 慧眼计划 结题 1989 1995 $3,000万 微电子 Project
39 DARPA-1990-ROB-001 Unmanned Ground Vehicle 无人地面车辆 结题 1993 2005 $3,000万 无人系统 Project
40 DARPA-1990-ROB-002 ALV (Autonomous Land Vehicle) 自主陆地车辆 结题 1990 1998 $2,000万 无人系统 Project
41 DARPA-1992-CMP-010 Massively Parallel Computing 大规模并行计算 结题 1992 1998 $2,500万 微电子 Project
42 DARPA-1993-ROB-003 Demo III 演示验证III 结题 1993 2000 $1,500万 无人系统 Project
43 DARPA-1994-BIO-001 Bio-Inspired Systems 生物启发系统 结题 1994 2000 $1,500万 生物技术 Project
44 DARPA-1995-SEC-004 Venetian Sands 威尼斯沙滩 结题 1995 1999 $800万 网络安全 Project
45 DARPA-1996-NET-011 Scalable Internet Routing 可扩展互联网路由 结题 1996 2002 $1,500万 通信网络 Project
46 DARPA-1997-SEN-001 Sensor Webs 传感器网络 结题 1997 2005 $2,500万 通信网络 Project
47 DARPA-1998-AI-005 Organic Computing 有机计算 结题 1998 2005 $2,000万 人工智能 Project
48 DARPA-1998-BIO-009 Bio-Computation 生物计算 结题 1998 2003 $1,000万 生物技术 Project
49 DARPA-1999-AI-015 PAL (Program for Language Learning) 语言学习项目 结题 1999 2004 $1,800万 人工智能 Project
50 DARPA-1999-NET-006 Next Generation Internet 下一代互联网 结题 1999 2005 $10,000万 通信网络 Project
51 DARPA-2000-AI-006 Cognitive Technology 认知技术 结题 2000 2007 $2,000万 人工智能 Project
52 DARPA-2000-MIL-016 Force Projection 力量投射 结题 2000 2006 $4,000万 无人系统 Project
53 DARPA-2001-ENG-005 Adaptive Structures 自适应结构 结题 2001 2006 $1,000万 材料科学 Project
54 DARPA-2001-NET-007 Tactical Internet 战术互联网 结题 2001 2008 $5,000万 通信网络 Project
55 DARPA-2001-SEN-003 WASP (Wireless Aerial Sensor Platform) 无线空中传感平台 结题 2001 2006 $900万 微电子 Project
56 DARPA-2002-ENG-001 Smart Dust (Mote) 智能尘埃 结题 2002 2008 $1,200万 微电子 Project
57 DARPA-2002-ENG-002 Mote (Smart Dust) 智能尘埃节点 结题 2002 2008 $1,200万 微电子 Project
58 DARPA-2002-MIL-031 Tactical Satellite 战术卫星 结题 2002 2008 $2,000万 太空技术 Project
59 DARPA-2003-CMP-003 ProtoGEN ProtoGEN项目 结题 2003 2007 $700万 微电子 Project
60 DARPA-2003-ENG-009 M-Warrior (Micro Air Vehicles) 微型空中武器 结题 2003 2008 $1,500万 无人系统 Project
61 DARPA-2003-MIL-001 Future Combat Systems 未来战斗系统 结题 2003 2009 $20,000万 无人系统 Project
62 DARPA-2004-MIL-017 Project TALON 利爪计划 结题 2004 2008 $2,500万 无人系统 Project
63 DARPA-2004-ROB-003 DARPA Grand Challenge DARPA大挑战 结题 2004 2007 $3,000万 无人系统 Project
64 DARPA-2004-SEC-005 Cyber Deterrence 网络威慑 结题 2004 2010 $2,000万 网络安全 Project
65 DARPA-2005-AI-016 Integrated Warfighter Processing 综合战士处理 结题 2005 2010 $1,500万 人工智能 Project
66 DARPA-2005-MIL-028 Project Vulture 秃鹰计划 结题 2005 2010 $3,000万 无人系统 Project
67 DARPA-2005-ROB-004 DARPA Urban Challenge DARPA城市挑战赛 结题 2007 2007 $3,000万 无人系统 Project
68 DARPA-2006-BIO-001 Advanced Prosthetics 先进假肢 结题 2006 2015 $3,000万 生物技术 Project
69 DARPA-2006-CMP-011 Cognitive Radio 认知无线电 结题 2006 2010 $800万 微电子 Project
70 DARPA-2006-ROB-014 M3 (Mechano-Micro) 机械微型化 结题 2006 2012 $1,800万 无人系统 Project
71 DARPA-2007-BIO-002 LUKE Arm (DEKA) 卢克手臂(DEKA) 结题 2007 2014 $4,000万 生物技术 Project
72 DARPA-2007-CMP-004 Universal Memory 通用内存 结题 2007 2014 $2,000万 微电子 Project
73 DARPA-2008-BIO-010 In Vivo Nanotechnology 体内纳米技术 结题 2008 2013 $2,000万 生物技术 Project
74 DARPA-2008-NET-008 Network Challenge 网络挑战 结题 2008 2009 $500万 通信网络 Project
75 DARPA-2008-ROB-005 EXACTO 精确制导自瞄子弹 结题 2008 2015 $2,000万 无人系统 Project
76 DARPA-2009-BIO-005 RealNVC (Neural Vocabulary Coding) 真实神经词汇编码 结题 2009 2014 $1,000万 生物技术 Project
77 DARPA-2009-MIL-032 Double Eagle 双鹰计划 结题 2009 2015 $2,500万 无人系统 Project
78 DARPA-2009-SEC-001 Vigilant Sentinels 警惕哨兵 结题 2009 2014 $2,500万 网络安全 Project
79 DARPA-2009-SPC-005 Space Situational Awareness 太空态势感知 结题 2009 2015 $3,000万 太空技术 Project
80 DARPA-2010-MIL-029 Active Confusion 主动迷惑 结题 2010 2014 $1,000万 无人系统 Project
81 DARPA-2010-NET-009 RADICS (Rampant Attack Initiative) 激增攻击应对 结题 2010 2017 $4,000万 网络安全 Project
82 DARPA-2010-ROB-006 Robotics Challenge 机器人挑战赛(DRC) 结题 2010 2015 $5,000万 无人系统 Project
83 DARPA-2011-AI-022 PPAML (Probabilistic Programming) 概率编程 结题 2011 2016 $3,000万 人工智能 Project
84 DARPA-2011-ENG-003 Air Force Energy Initiative 空军能源计划 结题 2011 2016 $1,500万 能源技术 Project
85 DARPA-2011-SEC-002 Cyber Fast Track 网络快速跟进 结题 2011 2015 $500万 网络安全 Project
86 DARPA-2012-MIL-002 Adaptive Electronic Warfare 自适应电子战 结题 2012 2018 $3,000万 无人系统 Project
87 DARPA-2012-MIL-018 Adaptive Radar Countermeasures 自适应雷达对抗 结题 2012 2018 $2,000万 无人系统 Project
88 DARPA-2013-AI-007 Big Mechanism 大机制研究 结题 2013 2018 $1,200万 人工智能 Project
89 DARPA-2013-ENG-004 Atmospheric Water Extraction 大气取水 结题 2013 2018 $800万 能源技术 Project
90 DARPA-2013-ENG-010 Mechantronics 机电一体化 结题 2013 2018 $1,500万 材料科学 Project
91 DARPA-2013-SEC-006 Enhanced Cybersecurity 增强网络安全 结题 2013 2018 $3,000万 网络安全 Project
92 DARPA-2014-CMP-012 UPSIDE (Unconventional Processing) 非常规信号处理 结题 2014 2018 $2,000万 微电子 Project
93 DARPA-2014-ROB-007 Cyber Grand Challenge 网络大挑战 结题 2014 2016 $4,000万 网络安全 Project
94 DARPA-2014-ROB-009 Fast Lightweight Autonomy 快速轻量自主 结题 2014 2017 $2,000万 无人系统 Project
95 DARPA-2015-AI-017 Verifiable AI 可验证AI 结题 2015 2020 $1,500万 人工智能 Project
96 DARPA-2015-MIL-019 Long-Range Anti-Ship Missile 远程反舰导弹 结题 2015 2021 $3,000万 无人系统 Project
97 DARPA-2015-ROB-008 OFFSET (Swarm) 异构编队突击战术 结题 2015 2021 $4,500万 无人系统 Project
98 DARPA-2016-AI-009 Explainable AI (XAI) 可解释人工智能 结题 2016 2021 $7,500万 人工智能 Project
99 DARPA-2016-CMP-005 DSO New Computing Architectures DSO新计算架构 结题 2016 2022 $5,000万 微电子 Project
100 DARPA-2016-MIL-020 Air Combat Evolution (ACE) 空战进化 结题 2016 2024 $10,000万 无人系统 Project
101 DARPA-2016-ROB-016 Fast Tools for Emerging Space 太空快速工具 结题 2016 2021 $2,500万 太空技术 Project
102 DARPA-2017-AI-018 Explainable AI (Phase 2) 可解释AI第二阶段 结题 2017 2021 $4,000万 人工智能 Project
103 DARPA-2017-BIO-003 Living Foundries 生命体工厂 结题 2017 2025 $7,700万 生物技术 Project
104 DARPA-2017-CMP-008 MANGROVE 森林计划 结题 2017 2023 $2,500万 微电子 Project
105 DARPA-2017-ROB-010 Agile Team Tactics 敏捷团队战术 结题 2017 2022 $3,000万 无人系统 Project
106 DARPA-2018-AI-010 AI Next Campaign 下一代AI运动 结题 2018 2025 $20,000万 人工智能 Project
107 DARPA-2018-BIO-006 Detect It and GeOp (DIGO) 检测与定位 结题 2018 2022 $1,500万 生物技术 Project
108 DARPA-2018-CMP-001 Electronics Resurgence Initiative 电子复兴计划 结题 2018 2025 $15,000万 微电子 Project
109 DARPA-2018-MIL-021 Ocean of Things 万物海洋 结题 2018 2024 $2,500万 通信网络 Project
110 DARPA-2018-SEC-007 Cyber Hunting 网络狩猎 结题 2018 2022 $1,500万 网络安全 Project
111 DARPA-2019-AI-023 AI for Data Curation AI数据策展 结题 2019 2023 $1,500万 人工智能 Project
112 DARPA-2019-BIO-009 Safe Genes 安全基因 结题 2019 2024 $2,000万 生物技术 Project
113 DARPA-2019-ENG-005 Solaren (Space Solar) 太空太阳能 结题 2019 2025 $5,000万 能源技术 Project
114 DARPA-2019-QUT-001 Quantum Benchmarking 量子基准测试 结题 2019 2024 $5,000万 量子科技 Project
115 DARPA-2019-ROB-011 No Ground Crew Required 无需地面人员 结题 2019 2023 $2,000万 无人系统 Project
116 DARPA-2019-SPC-001 Black Address 黑址计划 结题 2019 2024 $3,000万 太空技术 Project
117 DARPA-2020-AI-011 AI Quantum Initiative AI量子倡议 结题 2020 2025 $2,000万 量子科技 Project
118 DARPA-2020-BIO-011 Bio-Nanotechnology 生物纳米技术 结题 2020 2024 $2,000万 生物技术 Project
119 DARPA-2020-CMP-006 Toolchains for Western Design 西方设计工具链 结题 2020 2024 $3,000万 微电子 Project
120 DARPA-2020-MIL-022 Hypersonic Air-breathing Weapon 高超音速吸气式武器 研发中 2020 2026 $8,000万 高超音速 Project
121 DARPA-2020-QUT-005 Quantum Enablement 量子赋能 结题 2020 2025 $3,000万 量子科技 Project
122 DARPA-2021-AI-019 Automatic Machine Learning 自动机器学习 结题 2021 2025 $3,000万 人工智能 Project
123 DARPA-2021-BIO-004 Neural Engineering System Design 神经工程系统设计 结题 2021 2025 $6,500万 生物技术 Project
124 DARPA-2021-CMP-007 SPDC (Secure Processor Design) 安全处理器设计 结题 2021 2025 $2,500万 微电子 Project
125 DARPA-2021-MIL-003 Gremlins 小鬼计划 结题 2021 2025 $3,500万 无人系统 Project
126 DARPA-2021-MIL-025 SIXTH SENSE 第六感 结题 2021 2025 $2,500万 无人系统 Project
127 DARPA-2021-QUT-004 Optimization and Machine Learning 优化与机器学习 结题 2021 2025 $2,500万 量子科技 Project
128 DARPA-2021-ROB-012 Subterranean (SubT) Challenge 地下挑战 结题 2021 2024 $4,500万 无人系统 Project
129 DARPA-2022-AI-012 Semantic Forensics 语义取证 结题 2022 2027 $2,000万 人工智能 Project
130 DARPA-2022-BIO-007 PREventing EMerging Pathogenic Threats 预防新发病原威胁 研发中 2022 2027 $3,500万 生物技术 Project
131 DARPA-2022-CMP-002 CHIPS (Common Heterogeneous Integration) 通用异构集成 结题 2022 2028 $8,000万 微电子 Project
132 DARPA-2022-ENG-011 Clean Energy Initiative 清洁能源计划 结题 2022 2026 $3,000万 能源技术 Project
133 DARPA-2022-MIL-023 MACE (Mid-Infrared Acquisition) 中红外获取 研发中 2022 2026 $2,000万 无人系统 Project
134 DARPA-2022-ROB-013 Avatar 阿凡达 研发中 2022 2026 $5,000万 生物技术 Project
135 DARPA-2022-SEC-003 Zero Trust Architecture 零信任架构 结题 2022 2027 $3,000万 网络安全 Project
136 DARPA-2023-AI-020 Adaptive Electronics 自适应电子 研发中 2023 2027 $2,000万 人工智能 Project
137 DARPA-2023-ENG-006 AMMTO (Additive Manufacturing) 增材制造 研发中 2023 2027 $2,500万 材料科学 Project
138 DARPA-2023-HPM-001 Giant Leap 巨大飞跃 研发中 2023 2028 $6,000万 高超音速 Project
139 DARPA-2023-MIL-026 Multi-Domain Ops 多域作战 研发中 2023 2027 $3,500万 无人系统 Project
140 DARPA-2023-ROB-018 Squad Mission 班任务系统 研发中 2023 2027 $4,000万 无人系统 Project
141 DARPA-2023-SPC-002 Space-BACN 太空BACN 研发中 2023 2027 $4,000万 太空技术 Project
142 DARPA-2024-AI-013 AI-Assisted Science AI辅助科学 研发中 2024 2028 $5,000万 人工智能 Project
143 DARPA-2024-AI-024 Foundation Model Security 基础模型安全 研发中 2024 2028 $4,000万 人工智能 Project
144 DARPA-2024-BIO-008 Pandemic Prevention Platform 大流行预防平台 研发中 2024 2028 $5,000万 生物技术 Project
145 DARPA-2024-MIL-024 LongShank 长腿计划 研发中 2024 2028 $3,000万 无人系统 Project
146 DARPA-2024-QUT-002 Quantum Networks 量子网络 研发中 2024 2028 $5,500万 量子科技 Project
147 DARPA-2024-ROB-008 Atlas Next Gen 阿特拉斯下一代 研发中 2024 2028 $3,000万 无人系统 Project
148 DARPA-2024-SEC-004 Secure Computation 安全计算 研发中 2024 2028 $3,500万 网络安全 Project
149 DARPA-2025-AI-014 Trustworthy AI 可信AI 研发中 2025 2030 $10,000万 人工智能 Project
150 DARPA-2025-BIO-012 Synthetic Human 合成人类 研发中 2025 2030 $6,000万 生物技术 Project
151 DARPA-2025-MAT-002 Future Materials 未来材料 研发中 2025 2030 $3,500万 材料科学 Project
152 DARPA-2025-QUT-003 Quantum Advantage 量子优势 研发中 2025 2030 $8,000万 量子科技 Project
153 DARPA-2025-ROB-015 Mech Free 机械自由 研发中 2025 2029 $4,000万 无人系统 Project
154 PROJ-044 Project MAC MAC项目 已完成 1963 1974 $1,500万 操作系统、云计算 Project
155 PROJ-045 SAGE System 赛奇防空系统 已完成 1954 1963 $800,000万 防空系统、空中交通管制 Project
156 PROJ-046 AGILE Program 敏捷反叛乱项目 已完成 1961 1974 $5,000万 特种作战、反恐技术 Project
157 PROJ-047 ASW Technology 反潜战技术 已完成 1960 1980 $20,000万 海军装备、海洋监测 Project
158 PROJ-048 Gallium Arsenide 砷化镓半导体 已完成 1975 1990 $10,000万 通信、雷达、光电子 Project
159 PROJ-049 MIMIC Program 微波单片集成电路 已完成 1987 1995 $50,000万 雷达、通信、电子战 Project
160 PROJ-050 W/SEA Technology 宽禁带半导体 进行中 2001 进行中 $20,000万 雷达、电力电子、电动车 Project
161 PROJ-051 High Productivity Computing 高生产率计算系统 已完成 2002 2012 $10,000万 超级计算、科学计算 Project
162 PROJ-052 SyNAPSE 神经形态计算 已完成 2008 2016 $10,000万 AI芯片、边缘计算 Project
163 PROJ-053 UPSIDE 不确定性处理处理器 已完成 2012 2017 $3,500万 AI推理、传感器融合 Project

@ -0,0 +1,22 @@
techId:ID(Technology),name,:LABEL
TECH-HPCS_并行编程_Petaflop计算,HPCS、并行编程、Petaflop计算,Technology
TECH-MMIC_相控阵雷达_微波模块,MMIC、相控阵雷达、微波模块,Technology
TECH-SiC_GaN_高功率器件_高温电子,SiC、GaN、高功率器件、高温电子,Technology
TECH-人工智能,人工智能,Technology
TECH-分时系统_多用户计算_CTSS,分时系统、多用户计算、CTSS,Technology
TECH-化合物半导体_高频器件_光电集成,化合物半导体、高频器件、光电集成,Technology
TECH-反叛乱战术_传感器网络_远程侦察,反叛乱战术、传感器网络、远程侦察,Technology
TECH-声纳_信号处理_水下通信,声纳、信号处理、水下通信,Technology
TECH-太空技术,太空技术,Technology
TECH-实时计算_雷达网络_人机交互,实时计算、雷达网络、人机交互,Technology
TECH-微电子,微电子,Technology
TECH-无人系统,无人系统,Technology
TECH-材料科学,材料科学,Technology
TECH-概率计算_贝叶斯推断_非传统计算,概率计算、贝叶斯推断、非传统计算,Technology
TECH-生物技术,生物技术,Technology
TECH-神经形态芯片_类脑计算_低功耗AI,神经形态芯片、类脑计算、低功耗AI,Technology
TECH-网络安全,网络安全,Technology
TECH-能源技术,能源技术,Technology
TECH-通信网络,通信网络,Technology
TECH-量子科技,量子科技,Technology
TECH-高超音速,高超音速,Technology
1 techId:ID(Technology) name :LABEL
2 TECH-HPCS_并行编程_Petaflop计算 HPCS、并行编程、Petaflop计算 Technology
3 TECH-MMIC_相控阵雷达_微波模块 MMIC、相控阵雷达、微波模块 Technology
4 TECH-SiC_GaN_高功率器件_高温电子 SiC、GaN、高功率器件、高温电子 Technology
5 TECH-人工智能 人工智能 Technology
6 TECH-分时系统_多用户计算_CTSS 分时系统、多用户计算、CTSS Technology
7 TECH-化合物半导体_高频器件_光电集成 化合物半导体、高频器件、光电集成 Technology
8 TECH-反叛乱战术_传感器网络_远程侦察 反叛乱战术、传感器网络、远程侦察 Technology
9 TECH-声纳_信号处理_水下通信 声纳、信号处理、水下通信 Technology
10 TECH-太空技术 太空技术 Technology
11 TECH-实时计算_雷达网络_人机交互 实时计算、雷达网络、人机交互 Technology
12 TECH-微电子 微电子 Technology
13 TECH-无人系统 无人系统 Technology
14 TECH-材料科学 材料科学 Technology
15 TECH-概率计算_贝叶斯推断_非传统计算 概率计算、贝叶斯推断、非传统计算 Technology
16 TECH-生物技术 生物技术 Technology
17 TECH-神经形态芯片_类脑计算_低功耗AI 神经形态芯片、类脑计算、低功耗AI Technology
18 TECH-网络安全 网络安全 Technology
19 TECH-能源技术 能源技术 Technology
20 TECH-通信网络 通信网络 Technology
21 TECH-量子科技 量子科技 Technology
22 TECH-高超音速 高超音速 Technology

@ -0,0 +1,198 @@
:START_ID(Project),:END_ID(Institution),relationType,remark,:TYPE
DARPA-1958-CMP-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1959-GPS-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1959-SEN-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1960-SEN-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1961-ENG-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1962-NET-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1963-MIL-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1964-AI-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1965-AI-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1965-CMP-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1966-NET-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1967-CMP-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1969-NET-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1970-AIR-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1970-SEN-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1971-MIL-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1971-SPC-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1972-NET-004,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1973-AI-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1974-MIC-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1975-AIR-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1976-NET-005,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1978-AI-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1979-MIL-027,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1980-ENG-007,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1981-SPC-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1982-AI-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1982-ENG-008,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1983-NET-012,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1984-AI-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1984-AIR-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1985-CMP-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1986-NET-010,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1987-MAT-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1988-AI-004,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1988-CMP-009,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1989-MIL-030,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1990-ROB-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1990-ROB-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1992-CMP-010,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1993-ROB-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1994-BIO-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1995-SEC-004,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1996-NET-011,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1997-SEN-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1998-AI-005,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1998-BIO-009,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1999-AI-015,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-1999-NET-006,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2000-AI-006,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2000-MIL-016,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2001-ENG-005,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2001-NET-007,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2001-SEN-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2002-ENG-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2002-ENG-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2002-MIL-031,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2003-CMP-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2003-ENG-009,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2003-MIL-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2004-MIL-017,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2004-ROB-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2004-SEC-005,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2005-AI-016,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2005-MIL-028,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2005-ROB-004,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2006-BIO-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2006-CMP-011,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2006-ROB-014,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2007-BIO-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2007-CMP-004,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2008-BIO-010,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2008-NET-008,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2008-ROB-005,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2009-BIO-005,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2009-MIL-032,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2009-SEC-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2009-SPC-005,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2010-MIL-029,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2010-NET-009,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2010-ROB-006,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2011-AI-022,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2011-ENG-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2011-SEC-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2012-MIL-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2012-MIL-018,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2013-AI-007,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2013-ENG-004,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2013-ENG-010,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2013-SEC-006,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2014-CMP-012,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2014-ROB-007,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2014-ROB-009,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2015-AI-017,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2015-MIL-019,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2015-ROB-008,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2016-AI-009,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2016-CMP-005,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2016-MIL-020,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2016-ROB-016,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2017-AI-018,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2017-BIO-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2017-CMP-008,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2017-ROB-010,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2018-AI-010,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2018-BIO-006,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2018-CMP-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2018-MIL-021,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2018-SEC-007,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2019-AI-023,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2019-BIO-009,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2019-ENG-005,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2019-QUT-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2019-ROB-011,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2019-SPC-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2020-AI-011,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2020-BIO-011,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2020-CMP-006,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2020-MIL-022,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2020-QUT-005,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2021-AI-019,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2021-BIO-004,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2021-CMP-007,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2021-MIL-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2021-MIL-025,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2021-QUT-004,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2021-ROB-012,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2022-AI-012,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2022-BIO-007,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2022-CMP-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2022-ENG-011,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2022-MIL-023,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2022-ROB-013,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2022-SEC-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2023-AI-020,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2023-ENG-006,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2023-HPM-001,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2023-MIL-026,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2023-ROB-018,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2023-SPC-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2024-AI-013,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2024-AI-024,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2024-BIO-008,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2024-MIL-024,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2024-QUT-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2024-ROB-008,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2024-SEC-004,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2025-AI-014,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2025-BIO-012,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2025-MAT-002,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2025-QUT-003,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
DARPA-2025-ROB-015,INST-DARPA,主导方,项目管理,PARTICIPATED_BY
PROJ-044,INST-MIT,主导方,MAC项目主场CTSS和Multics开发地,PARTICIPATED_BY
PROJ-044,INST-GE,承包商,提供大型机硬件支持,PARTICIPATED_BY
PROJ-044,INST-Bell_Labs,参与方,受Multics启发开发Unix,PARTICIPATED_BY
PROJ-045,INST-MIT_Lincoln_Lab,主导方,系统架构设计和核心开发,PARTICIPATED_BY
PROJ-045,INST-IBM,承包商,AN/FSQ-7计算机制造,PARTICIPATED_BY
PROJ-045,INST-Burroughs,承包商,通信设备,PARTICIPATED_BY
PROJ-045,INST-AT_T,承包商,通信网络,PARTICIPATED_BY
PROJ-045,INST-RAND,参与方,系统分析,PARTICIPATED_BY
PROJ-046,INST-DARPA,主导方,项目管理和资金,PARTICIPATED_BY
PROJ-046,INST-US_Army,参与方,战术应用测试,PARTICIPATED_BY
PROJ-046,INST-SRI_International,承包商,传感器开发,PARTICIPATED_BY
PROJ-046,INST-EG_G,承包商,技术设备,PARTICIPATED_BY
PROJ-047,INST-US_Navy,主导方,需求定义和测试,PARTICIPATED_BY
PROJ-047,INST-Columbia_University,参与方,声学理论研究,PARTICIPATED_BY
PROJ-047,INST-Scripps_Institution,参与方,海洋学研究,PARTICIPATED_BY
PROJ-047,INST-Hughes_Aircraft,承包商,声纳系统,PARTICIPATED_BY
PROJ-047,INST-Lockheed,承包商,信号处理,PARTICIPATED_BY
PROJ-048,INST-Rockwell,主导方,GaAs器件开发,PARTICIPATED_BY
PROJ-048,INST-Hughes,主导方,微波器件,PARTICIPATED_BY
PROJ-048,INST-TI,承包商,数字GaAs电路,PARTICIPATED_BY
PROJ-048,INST-IBM,参与方,材料研究,PARTICIPATED_BY
PROJ-048,INST-Cornell,参与方,器件物理,PARTICIPATED_BY
PROJ-049,INST-TRW,主导方,MMIC设计和制造,PARTICIPATED_BY
PROJ-049,INST-Raytheon,主导方,雷达应用,PARTICIPATED_BY
PROJ-049,INST-Hughes,承包商,通信应用,PARTICIPATED_BY
PROJ-049,INST-Lockheed,承包商,系统集成,PARTICIPATED_BY
PROJ-049,INST-Northrop,承包商,电子战,PARTICIPATED_BY
PROJ-050,INST-Cree_Wolfspeed,主导方,SiC器件领导者,PARTICIPATED_BY
PROJ-050,INST-RF_Micro_Devices,主导方,GaN器件,PARTICIPATED_BY
PROJ-050,INST-Raytheon,承包商,雷达应用,PARTICIPATED_BY
PROJ-050,INST-Northrop,承包商,电子战,PARTICIPATED_BY
PROJ-050,INST-NREL,参与方,电力电子,PARTICIPATED_BY
PROJ-051,INST-IBM,主导方,PERCS系统,PARTICIPATED_BY
PROJ-051,INST-Cray,主导方,Cascade系统,PARTICIPATED_BY
PROJ-051,INST-Sun,主导方,Constellation系统,PARTICIPATED_BY
PROJ-051,INST-MIT,参与方,编程模型,PARTICIPATED_BY
PROJ-051,INST-UIUC,参与方,编译器技术,PARTICIPATED_BY
PROJ-052,INST-IBM,主导方,TrueNorth芯片,PARTICIPATED_BY
PROJ-052,INST-HP,主导方,忆阻器研究,PARTICIPATED_BY
PROJ-052,INST-HRL_Labs,承包商,神经形态电路,PARTICIPATED_BY
PROJ-052,INST-Stanford,参与方,神经科学,PARTICIPATED_BY
PROJ-052,INST-Columbia,参与方,器件物理,PARTICIPATED_BY
PROJ-053,INST-Lyric_Semiconductor,主导方,概率处理器,PARTICIPATED_BY
PROJ-053,INST-MIT,参与方,贝叶斯算法,PARTICIPATED_BY
PROJ-053,INST-Purdue,参与方,电路设计,PARTICIPATED_BY
1 :START_ID(Project) :END_ID(Institution) relationType remark :TYPE
2 DARPA-1958-CMP-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
3 DARPA-1959-GPS-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
4 DARPA-1959-SEN-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
5 DARPA-1960-SEN-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
6 DARPA-1961-ENG-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
7 DARPA-1962-NET-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
8 DARPA-1963-MIL-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
9 DARPA-1964-AI-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
10 DARPA-1965-AI-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
11 DARPA-1965-CMP-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
12 DARPA-1966-NET-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
13 DARPA-1967-CMP-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
14 DARPA-1969-NET-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
15 DARPA-1970-AIR-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
16 DARPA-1970-SEN-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
17 DARPA-1971-MIL-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
18 DARPA-1971-SPC-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
19 DARPA-1972-NET-004 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
20 DARPA-1973-AI-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
21 DARPA-1974-MIC-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
22 DARPA-1975-AIR-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
23 DARPA-1976-NET-005 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
24 DARPA-1978-AI-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
25 DARPA-1979-MIL-027 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
26 DARPA-1980-ENG-007 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
27 DARPA-1981-SPC-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
28 DARPA-1982-AI-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
29 DARPA-1982-ENG-008 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
30 DARPA-1983-NET-012 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
31 DARPA-1984-AI-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
32 DARPA-1984-AIR-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
33 DARPA-1985-CMP-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
34 DARPA-1986-NET-010 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
35 DARPA-1987-MAT-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
36 DARPA-1988-AI-004 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
37 DARPA-1988-CMP-009 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
38 DARPA-1989-MIL-030 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
39 DARPA-1990-ROB-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
40 DARPA-1990-ROB-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
41 DARPA-1992-CMP-010 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
42 DARPA-1993-ROB-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
43 DARPA-1994-BIO-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
44 DARPA-1995-SEC-004 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
45 DARPA-1996-NET-011 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
46 DARPA-1997-SEN-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
47 DARPA-1998-AI-005 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
48 DARPA-1998-BIO-009 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
49 DARPA-1999-AI-015 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
50 DARPA-1999-NET-006 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
51 DARPA-2000-AI-006 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
52 DARPA-2000-MIL-016 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
53 DARPA-2001-ENG-005 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
54 DARPA-2001-NET-007 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
55 DARPA-2001-SEN-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
56 DARPA-2002-ENG-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
57 DARPA-2002-ENG-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
58 DARPA-2002-MIL-031 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
59 DARPA-2003-CMP-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
60 DARPA-2003-ENG-009 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
61 DARPA-2003-MIL-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
62 DARPA-2004-MIL-017 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
63 DARPA-2004-ROB-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
64 DARPA-2004-SEC-005 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
65 DARPA-2005-AI-016 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
66 DARPA-2005-MIL-028 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
67 DARPA-2005-ROB-004 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
68 DARPA-2006-BIO-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
69 DARPA-2006-CMP-011 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
70 DARPA-2006-ROB-014 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
71 DARPA-2007-BIO-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
72 DARPA-2007-CMP-004 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
73 DARPA-2008-BIO-010 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
74 DARPA-2008-NET-008 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
75 DARPA-2008-ROB-005 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
76 DARPA-2009-BIO-005 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
77 DARPA-2009-MIL-032 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
78 DARPA-2009-SEC-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
79 DARPA-2009-SPC-005 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
80 DARPA-2010-MIL-029 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
81 DARPA-2010-NET-009 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
82 DARPA-2010-ROB-006 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
83 DARPA-2011-AI-022 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
84 DARPA-2011-ENG-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
85 DARPA-2011-SEC-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
86 DARPA-2012-MIL-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
87 DARPA-2012-MIL-018 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
88 DARPA-2013-AI-007 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
89 DARPA-2013-ENG-004 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
90 DARPA-2013-ENG-010 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
91 DARPA-2013-SEC-006 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
92 DARPA-2014-CMP-012 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
93 DARPA-2014-ROB-007 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
94 DARPA-2014-ROB-009 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
95 DARPA-2015-AI-017 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
96 DARPA-2015-MIL-019 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
97 DARPA-2015-ROB-008 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
98 DARPA-2016-AI-009 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
99 DARPA-2016-CMP-005 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
100 DARPA-2016-MIL-020 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
101 DARPA-2016-ROB-016 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
102 DARPA-2017-AI-018 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
103 DARPA-2017-BIO-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
104 DARPA-2017-CMP-008 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
105 DARPA-2017-ROB-010 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
106 DARPA-2018-AI-010 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
107 DARPA-2018-BIO-006 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
108 DARPA-2018-CMP-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
109 DARPA-2018-MIL-021 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
110 DARPA-2018-SEC-007 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
111 DARPA-2019-AI-023 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
112 DARPA-2019-BIO-009 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
113 DARPA-2019-ENG-005 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
114 DARPA-2019-QUT-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
115 DARPA-2019-ROB-011 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
116 DARPA-2019-SPC-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
117 DARPA-2020-AI-011 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
118 DARPA-2020-BIO-011 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
119 DARPA-2020-CMP-006 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
120 DARPA-2020-MIL-022 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
121 DARPA-2020-QUT-005 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
122 DARPA-2021-AI-019 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
123 DARPA-2021-BIO-004 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
124 DARPA-2021-CMP-007 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
125 DARPA-2021-MIL-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
126 DARPA-2021-MIL-025 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
127 DARPA-2021-QUT-004 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
128 DARPA-2021-ROB-012 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
129 DARPA-2022-AI-012 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
130 DARPA-2022-BIO-007 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
131 DARPA-2022-CMP-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
132 DARPA-2022-ENG-011 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
133 DARPA-2022-MIL-023 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
134 DARPA-2022-ROB-013 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
135 DARPA-2022-SEC-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
136 DARPA-2023-AI-020 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
137 DARPA-2023-ENG-006 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
138 DARPA-2023-HPM-001 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
139 DARPA-2023-MIL-026 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
140 DARPA-2023-ROB-018 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
141 DARPA-2023-SPC-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
142 DARPA-2024-AI-013 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
143 DARPA-2024-AI-024 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
144 DARPA-2024-BIO-008 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
145 DARPA-2024-MIL-024 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
146 DARPA-2024-QUT-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
147 DARPA-2024-ROB-008 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
148 DARPA-2024-SEC-004 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
149 DARPA-2025-AI-014 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
150 DARPA-2025-BIO-012 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
151 DARPA-2025-MAT-002 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
152 DARPA-2025-QUT-003 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
153 DARPA-2025-ROB-015 INST-DARPA 主导方 项目管理 PARTICIPATED_BY
154 PROJ-044 INST-MIT 主导方 MAC项目主场,CTSS和Multics开发地 PARTICIPATED_BY
155 PROJ-044 INST-GE 承包商 提供大型机硬件支持 PARTICIPATED_BY
156 PROJ-044 INST-Bell_Labs 参与方 受Multics启发开发Unix PARTICIPATED_BY
157 PROJ-045 INST-MIT_Lincoln_Lab 主导方 系统架构设计和核心开发 PARTICIPATED_BY
158 PROJ-045 INST-IBM 承包商 AN/FSQ-7计算机制造 PARTICIPATED_BY
159 PROJ-045 INST-Burroughs 承包商 通信设备 PARTICIPATED_BY
160 PROJ-045 INST-AT_T 承包商 通信网络 PARTICIPATED_BY
161 PROJ-045 INST-RAND 参与方 系统分析 PARTICIPATED_BY
162 PROJ-046 INST-DARPA 主导方 项目管理和资金 PARTICIPATED_BY
163 PROJ-046 INST-US_Army 参与方 战术应用测试 PARTICIPATED_BY
164 PROJ-046 INST-SRI_International 承包商 传感器开发 PARTICIPATED_BY
165 PROJ-046 INST-EG_G 承包商 技术设备 PARTICIPATED_BY
166 PROJ-047 INST-US_Navy 主导方 需求定义和测试 PARTICIPATED_BY
167 PROJ-047 INST-Columbia_University 参与方 声学理论研究 PARTICIPATED_BY
168 PROJ-047 INST-Scripps_Institution 参与方 海洋学研究 PARTICIPATED_BY
169 PROJ-047 INST-Hughes_Aircraft 承包商 声纳系统 PARTICIPATED_BY
170 PROJ-047 INST-Lockheed 承包商 信号处理 PARTICIPATED_BY
171 PROJ-048 INST-Rockwell 主导方 GaAs器件开发 PARTICIPATED_BY
172 PROJ-048 INST-Hughes 主导方 微波器件 PARTICIPATED_BY
173 PROJ-048 INST-TI 承包商 数字GaAs电路 PARTICIPATED_BY
174 PROJ-048 INST-IBM 参与方 材料研究 PARTICIPATED_BY
175 PROJ-048 INST-Cornell 参与方 器件物理 PARTICIPATED_BY
176 PROJ-049 INST-TRW 主导方 MMIC设计和制造 PARTICIPATED_BY
177 PROJ-049 INST-Raytheon 主导方 雷达应用 PARTICIPATED_BY
178 PROJ-049 INST-Hughes 承包商 通信应用 PARTICIPATED_BY
179 PROJ-049 INST-Lockheed 承包商 系统集成 PARTICIPATED_BY
180 PROJ-049 INST-Northrop 承包商 电子战 PARTICIPATED_BY
181 PROJ-050 INST-Cree_Wolfspeed 主导方 SiC器件领导者 PARTICIPATED_BY
182 PROJ-050 INST-RF_Micro_Devices 主导方 GaN器件 PARTICIPATED_BY
183 PROJ-050 INST-Raytheon 承包商 雷达应用 PARTICIPATED_BY
184 PROJ-050 INST-Northrop 承包商 电子战 PARTICIPATED_BY
185 PROJ-050 INST-NREL 参与方 电力电子 PARTICIPATED_BY
186 PROJ-051 INST-IBM 主导方 PERCS系统 PARTICIPATED_BY
187 PROJ-051 INST-Cray 主导方 Cascade系统 PARTICIPATED_BY
188 PROJ-051 INST-Sun 主导方 Constellation系统 PARTICIPATED_BY
189 PROJ-051 INST-MIT 参与方 编程模型 PARTICIPATED_BY
190 PROJ-051 INST-UIUC 参与方 编译器技术 PARTICIPATED_BY
191 PROJ-052 INST-IBM 主导方 TrueNorth芯片 PARTICIPATED_BY
192 PROJ-052 INST-HP 主导方 忆阻器研究 PARTICIPATED_BY
193 PROJ-052 INST-HRL_Labs 承包商 神经形态电路 PARTICIPATED_BY
194 PROJ-052 INST-Stanford 参与方 神经科学 PARTICIPATED_BY
195 PROJ-052 INST-Columbia 参与方 器件物理 PARTICIPATED_BY
196 PROJ-053 INST-Lyric_Semiconductor 主导方 概率处理器 PARTICIPATED_BY
197 PROJ-053 INST-MIT 参与方 贝叶斯算法 PARTICIPATED_BY
198 PROJ-053 INST-Purdue 参与方 电路设计 PARTICIPATED_BY

@ -0,0 +1,163 @@
:START_ID(Project),:END_ID(Manager),:TYPE
DARPA-1958-CMP-001,MGR-20470728,MANAGED_BY
DARPA-1959-GPS-001,MGR-88137902,MANAGED_BY
DARPA-1959-SEN-001,MGR-45095827,MANAGED_BY
DARPA-1960-SEN-003,MGR-56883573,MANAGED_BY
DARPA-1961-ENG-001,MGR-78216533,MANAGED_BY
DARPA-1962-NET-001,MGR-58980650,MANAGED_BY
DARPA-1963-MIL-002,MGR-12117627,MANAGED_BY
DARPA-1964-AI-003,MGR-62028279,MANAGED_BY
DARPA-1965-AI-002,MGR-43537160,MANAGED_BY
DARPA-1965-CMP-003,MGR-52944789,MANAGED_BY
DARPA-1966-NET-002,MGR-38011032,MANAGED_BY
DARPA-1967-CMP-001,MGR-21572927,MANAGED_BY
DARPA-1969-NET-003,MGR-38011032,MANAGED_BY
DARPA-1970-AIR-003,MGR-30572221,MANAGED_BY
DARPA-1970-SEN-002,MGR-65101126,MANAGED_BY
DARPA-1971-MIL-003,MGR-29442483,MANAGED_BY
DARPA-1971-SPC-002,MGR-89333365,MANAGED_BY
DARPA-1972-NET-004,MGR-89333365,MANAGED_BY
DARPA-1973-AI-001,MGR-89333365,MANAGED_BY
DARPA-1974-MIC-001,MGR-50959738,MANAGED_BY
DARPA-1975-AIR-001,MGR-29442483,MANAGED_BY
DARPA-1976-NET-005,MGR-89333365,MANAGED_BY
DARPA-1978-AI-001,MGR-89333365,MANAGED_BY
DARPA-1979-MIL-027,MGR-50959738,MANAGED_BY
DARPA-1980-ENG-007,MGR-11959388,MANAGED_BY
DARPA-1981-SPC-003,MGR-58272302,MANAGED_BY
DARPA-1982-AI-002,MGR-89333365,MANAGED_BY
DARPA-1982-ENG-008,MGR-11959388,MANAGED_BY
DARPA-1983-NET-012,MGR-89333365,MANAGED_BY
DARPA-1984-AI-003,MGR-89333365,MANAGED_BY
DARPA-1984-AIR-002,MGR-29442483,MANAGED_BY
DARPA-1985-CMP-002,MGR-50959738,MANAGED_BY
DARPA-1986-NET-010,MGR-89333365,MANAGED_BY
DARPA-1987-MAT-001,MGR-11959388,MANAGED_BY
DARPA-1988-AI-004,MGR-89333365,MANAGED_BY
DARPA-1988-CMP-009,MGR-50959738,MANAGED_BY
DARPA-1989-MIL-030,MGR-50959738,MANAGED_BY
DARPA-1990-ROB-001,MGR-11959388,MANAGED_BY
DARPA-1990-ROB-002,MGR-11959388,MANAGED_BY
DARPA-1992-CMP-010,MGR-50959738,MANAGED_BY
DARPA-1993-ROB-003,MGR-11959388,MANAGED_BY
DARPA-1994-BIO-001,MGR-82307048,MANAGED_BY
DARPA-1995-SEC-004,MGR-89333365,MANAGED_BY
DARPA-1996-NET-011,MGR-89333365,MANAGED_BY
DARPA-1997-SEN-001,MGR-89333365,MANAGED_BY
DARPA-1998-AI-005,MGR-89333365,MANAGED_BY
DARPA-1998-BIO-009,MGR-82307048,MANAGED_BY
DARPA-1999-AI-015,MGR-89333365,MANAGED_BY
DARPA-1999-NET-006,MGR-89333365,MANAGED_BY
DARPA-2000-AI-006,MGR-89333365,MANAGED_BY
DARPA-2000-MIL-016,MGR-29442483,MANAGED_BY
DARPA-2001-ENG-005,MGR-11959388,MANAGED_BY
DARPA-2001-NET-007,MGR-89333365,MANAGED_BY
DARPA-2001-SEN-003,MGR-50959738,MANAGED_BY
DARPA-2002-ENG-001,MGR-50959738,MANAGED_BY
DARPA-2002-ENG-002,MGR-50959738,MANAGED_BY
DARPA-2002-MIL-031,MGR-58272302,MANAGED_BY
DARPA-2003-CMP-003,MGR-50959738,MANAGED_BY
DARPA-2003-ENG-009,MGR-29442483,MANAGED_BY
DARPA-2003-MIL-001,MGR-29442483,MANAGED_BY
DARPA-2004-MIL-017,MGR-29442483,MANAGED_BY
DARPA-2004-ROB-003,MGR-11959388,MANAGED_BY
DARPA-2004-SEC-005,MGR-89333365,MANAGED_BY
DARPA-2005-AI-016,MGR-89333365,MANAGED_BY
DARPA-2005-MIL-028,MGR-29442483,MANAGED_BY
DARPA-2005-ROB-004,MGR-11959388,MANAGED_BY
DARPA-2006-BIO-001,MGR-82307048,MANAGED_BY
DARPA-2006-CMP-011,MGR-50959738,MANAGED_BY
DARPA-2006-ROB-014,MGR-11959388,MANAGED_BY
DARPA-2007-BIO-002,MGR-82307048,MANAGED_BY
DARPA-2007-CMP-004,MGR-50959738,MANAGED_BY
DARPA-2008-BIO-010,MGR-82307048,MANAGED_BY
DARPA-2008-NET-008,MGR-89333365,MANAGED_BY
DARPA-2008-ROB-005,MGR-29442483,MANAGED_BY
DARPA-2009-BIO-005,MGR-82307048,MANAGED_BY
DARPA-2009-MIL-032,MGR-29442483,MANAGED_BY
DARPA-2009-SEC-001,MGR-89333365,MANAGED_BY
DARPA-2009-SPC-005,MGR-58272302,MANAGED_BY
DARPA-2010-MIL-029,MGR-29442483,MANAGED_BY
DARPA-2010-NET-009,MGR-89333365,MANAGED_BY
DARPA-2010-ROB-006,MGR-11959388,MANAGED_BY
DARPA-2011-AI-022,MGR-89333365,MANAGED_BY
DARPA-2011-ENG-003,MGR-11959388,MANAGED_BY
DARPA-2011-SEC-002,MGR-89333365,MANAGED_BY
DARPA-2012-MIL-002,MGR-29442483,MANAGED_BY
DARPA-2012-MIL-018,MGR-29442483,MANAGED_BY
DARPA-2013-AI-007,MGR-89333365,MANAGED_BY
DARPA-2013-ENG-004,MGR-11959388,MANAGED_BY
DARPA-2013-ENG-010,MGR-11959388,MANAGED_BY
DARPA-2013-SEC-006,MGR-89333365,MANAGED_BY
DARPA-2014-CMP-012,MGR-50959738,MANAGED_BY
DARPA-2014-ROB-007,MGR-89333365,MANAGED_BY
DARPA-2014-ROB-009,MGR-11959388,MANAGED_BY
DARPA-2015-AI-017,MGR-89333365,MANAGED_BY
DARPA-2015-MIL-019,MGR-29442483,MANAGED_BY
DARPA-2015-ROB-008,MGR-29442483,MANAGED_BY
DARPA-2016-AI-009,MGR-89333365,MANAGED_BY
DARPA-2016-CMP-005,MGR-11959388,MANAGED_BY
DARPA-2016-MIL-020,MGR-11959388,MANAGED_BY
DARPA-2016-ROB-016,MGR-58272302,MANAGED_BY
DARPA-2017-AI-018,MGR-89333365,MANAGED_BY
DARPA-2017-BIO-003,MGR-82307048,MANAGED_BY
DARPA-2017-CMP-008,MGR-50959738,MANAGED_BY
DARPA-2017-ROB-010,MGR-29442483,MANAGED_BY
DARPA-2018-AI-010,MGR-89333365,MANAGED_BY
DARPA-2018-BIO-006,MGR-82307048,MANAGED_BY
DARPA-2018-CMP-001,MGR-50959738,MANAGED_BY
DARPA-2018-MIL-021,MGR-89333365,MANAGED_BY
DARPA-2018-SEC-007,MGR-89333365,MANAGED_BY
DARPA-2019-AI-023,MGR-89333365,MANAGED_BY
DARPA-2019-BIO-009,MGR-82307048,MANAGED_BY
DARPA-2019-ENG-005,MGR-58272302,MANAGED_BY
DARPA-2019-QUT-001,MGR-11959388,MANAGED_BY
DARPA-2019-ROB-011,MGR-11959388,MANAGED_BY
DARPA-2019-SPC-001,MGR-58272302,MANAGED_BY
DARPA-2020-AI-011,MGR-11959388,MANAGED_BY
DARPA-2020-BIO-011,MGR-82307048,MANAGED_BY
DARPA-2020-CMP-006,MGR-50959738,MANAGED_BY
DARPA-2020-MIL-022,MGR-29442483,MANAGED_BY
DARPA-2020-QUT-005,MGR-11959388,MANAGED_BY
DARPA-2021-AI-019,MGR-89333365,MANAGED_BY
DARPA-2021-BIO-004,MGR-82307048,MANAGED_BY
DARPA-2021-CMP-007,MGR-50959738,MANAGED_BY
DARPA-2021-MIL-003,MGR-29442483,MANAGED_BY
DARPA-2021-MIL-025,MGR-29442483,MANAGED_BY
DARPA-2021-QUT-004,MGR-11959388,MANAGED_BY
DARPA-2021-ROB-012,MGR-11959388,MANAGED_BY
DARPA-2022-AI-012,MGR-89333365,MANAGED_BY
DARPA-2022-BIO-007,MGR-82307048,MANAGED_BY
DARPA-2022-CMP-002,MGR-50959738,MANAGED_BY
DARPA-2022-ENG-011,MGR-11959388,MANAGED_BY
DARPA-2022-MIL-023,MGR-29442483,MANAGED_BY
DARPA-2022-ROB-013,MGR-82307048,MANAGED_BY
DARPA-2022-SEC-003,MGR-89333365,MANAGED_BY
DARPA-2023-AI-020,MGR-50959738,MANAGED_BY
DARPA-2023-ENG-006,MGR-50959738,MANAGED_BY
DARPA-2023-HPM-001,MGR-58272302,MANAGED_BY
DARPA-2023-MIL-026,MGR-58272302,MANAGED_BY
DARPA-2023-ROB-018,MGR-29442483,MANAGED_BY
DARPA-2023-SPC-002,MGR-58272302,MANAGED_BY
DARPA-2024-AI-013,MGR-11959388,MANAGED_BY
DARPA-2024-AI-024,MGR-89333365,MANAGED_BY
DARPA-2024-BIO-008,MGR-82307048,MANAGED_BY
DARPA-2024-MIL-024,MGR-29442483,MANAGED_BY
DARPA-2024-QUT-002,MGR-89333365,MANAGED_BY
DARPA-2024-ROB-008,MGR-11959388,MANAGED_BY
DARPA-2024-SEC-004,MGR-89333365,MANAGED_BY
DARPA-2025-AI-014,MGR-89333365,MANAGED_BY
DARPA-2025-BIO-012,MGR-82307048,MANAGED_BY
DARPA-2025-MAT-002,MGR-11959388,MANAGED_BY
DARPA-2025-QUT-003,MGR-11959388,MANAGED_BY
DARPA-2025-ROB-015,MGR-11959388,MANAGED_BY
PROJ-044,MGR-29103044,MANAGED_BY
PROJ-045,MGR-72808311,MANAGED_BY
PROJ-046,MGR-12117627,MANAGED_BY
PROJ-047,MGR-44867089,MANAGED_BY
PROJ-048,MGR-79938277,MANAGED_BY
PROJ-049,MGR-20235195,MANAGED_BY
PROJ-050,MGR-20235195,MANAGED_BY
PROJ-051,MGR-86429568,MANAGED_BY
PROJ-052,MGR-85126670,MANAGED_BY
PROJ-053,MGR-48169304,MANAGED_BY
1 :START_ID(Project) :END_ID(Manager) :TYPE
2 DARPA-1958-CMP-001 MGR-20470728 MANAGED_BY
3 DARPA-1959-GPS-001 MGR-88137902 MANAGED_BY
4 DARPA-1959-SEN-001 MGR-45095827 MANAGED_BY
5 DARPA-1960-SEN-003 MGR-56883573 MANAGED_BY
6 DARPA-1961-ENG-001 MGR-78216533 MANAGED_BY
7 DARPA-1962-NET-001 MGR-58980650 MANAGED_BY
8 DARPA-1963-MIL-002 MGR-12117627 MANAGED_BY
9 DARPA-1964-AI-003 MGR-62028279 MANAGED_BY
10 DARPA-1965-AI-002 MGR-43537160 MANAGED_BY
11 DARPA-1965-CMP-003 MGR-52944789 MANAGED_BY
12 DARPA-1966-NET-002 MGR-38011032 MANAGED_BY
13 DARPA-1967-CMP-001 MGR-21572927 MANAGED_BY
14 DARPA-1969-NET-003 MGR-38011032 MANAGED_BY
15 DARPA-1970-AIR-003 MGR-30572221 MANAGED_BY
16 DARPA-1970-SEN-002 MGR-65101126 MANAGED_BY
17 DARPA-1971-MIL-003 MGR-29442483 MANAGED_BY
18 DARPA-1971-SPC-002 MGR-89333365 MANAGED_BY
19 DARPA-1972-NET-004 MGR-89333365 MANAGED_BY
20 DARPA-1973-AI-001 MGR-89333365 MANAGED_BY
21 DARPA-1974-MIC-001 MGR-50959738 MANAGED_BY
22 DARPA-1975-AIR-001 MGR-29442483 MANAGED_BY
23 DARPA-1976-NET-005 MGR-89333365 MANAGED_BY
24 DARPA-1978-AI-001 MGR-89333365 MANAGED_BY
25 DARPA-1979-MIL-027 MGR-50959738 MANAGED_BY
26 DARPA-1980-ENG-007 MGR-11959388 MANAGED_BY
27 DARPA-1981-SPC-003 MGR-58272302 MANAGED_BY
28 DARPA-1982-AI-002 MGR-89333365 MANAGED_BY
29 DARPA-1982-ENG-008 MGR-11959388 MANAGED_BY
30 DARPA-1983-NET-012 MGR-89333365 MANAGED_BY
31 DARPA-1984-AI-003 MGR-89333365 MANAGED_BY
32 DARPA-1984-AIR-002 MGR-29442483 MANAGED_BY
33 DARPA-1985-CMP-002 MGR-50959738 MANAGED_BY
34 DARPA-1986-NET-010 MGR-89333365 MANAGED_BY
35 DARPA-1987-MAT-001 MGR-11959388 MANAGED_BY
36 DARPA-1988-AI-004 MGR-89333365 MANAGED_BY
37 DARPA-1988-CMP-009 MGR-50959738 MANAGED_BY
38 DARPA-1989-MIL-030 MGR-50959738 MANAGED_BY
39 DARPA-1990-ROB-001 MGR-11959388 MANAGED_BY
40 DARPA-1990-ROB-002 MGR-11959388 MANAGED_BY
41 DARPA-1992-CMP-010 MGR-50959738 MANAGED_BY
42 DARPA-1993-ROB-003 MGR-11959388 MANAGED_BY
43 DARPA-1994-BIO-001 MGR-82307048 MANAGED_BY
44 DARPA-1995-SEC-004 MGR-89333365 MANAGED_BY
45 DARPA-1996-NET-011 MGR-89333365 MANAGED_BY
46 DARPA-1997-SEN-001 MGR-89333365 MANAGED_BY
47 DARPA-1998-AI-005 MGR-89333365 MANAGED_BY
48 DARPA-1998-BIO-009 MGR-82307048 MANAGED_BY
49 DARPA-1999-AI-015 MGR-89333365 MANAGED_BY
50 DARPA-1999-NET-006 MGR-89333365 MANAGED_BY
51 DARPA-2000-AI-006 MGR-89333365 MANAGED_BY
52 DARPA-2000-MIL-016 MGR-29442483 MANAGED_BY
53 DARPA-2001-ENG-005 MGR-11959388 MANAGED_BY
54 DARPA-2001-NET-007 MGR-89333365 MANAGED_BY
55 DARPA-2001-SEN-003 MGR-50959738 MANAGED_BY
56 DARPA-2002-ENG-001 MGR-50959738 MANAGED_BY
57 DARPA-2002-ENG-002 MGR-50959738 MANAGED_BY
58 DARPA-2002-MIL-031 MGR-58272302 MANAGED_BY
59 DARPA-2003-CMP-003 MGR-50959738 MANAGED_BY
60 DARPA-2003-ENG-009 MGR-29442483 MANAGED_BY
61 DARPA-2003-MIL-001 MGR-29442483 MANAGED_BY
62 DARPA-2004-MIL-017 MGR-29442483 MANAGED_BY
63 DARPA-2004-ROB-003 MGR-11959388 MANAGED_BY
64 DARPA-2004-SEC-005 MGR-89333365 MANAGED_BY
65 DARPA-2005-AI-016 MGR-89333365 MANAGED_BY
66 DARPA-2005-MIL-028 MGR-29442483 MANAGED_BY
67 DARPA-2005-ROB-004 MGR-11959388 MANAGED_BY
68 DARPA-2006-BIO-001 MGR-82307048 MANAGED_BY
69 DARPA-2006-CMP-011 MGR-50959738 MANAGED_BY
70 DARPA-2006-ROB-014 MGR-11959388 MANAGED_BY
71 DARPA-2007-BIO-002 MGR-82307048 MANAGED_BY
72 DARPA-2007-CMP-004 MGR-50959738 MANAGED_BY
73 DARPA-2008-BIO-010 MGR-82307048 MANAGED_BY
74 DARPA-2008-NET-008 MGR-89333365 MANAGED_BY
75 DARPA-2008-ROB-005 MGR-29442483 MANAGED_BY
76 DARPA-2009-BIO-005 MGR-82307048 MANAGED_BY
77 DARPA-2009-MIL-032 MGR-29442483 MANAGED_BY
78 DARPA-2009-SEC-001 MGR-89333365 MANAGED_BY
79 DARPA-2009-SPC-005 MGR-58272302 MANAGED_BY
80 DARPA-2010-MIL-029 MGR-29442483 MANAGED_BY
81 DARPA-2010-NET-009 MGR-89333365 MANAGED_BY
82 DARPA-2010-ROB-006 MGR-11959388 MANAGED_BY
83 DARPA-2011-AI-022 MGR-89333365 MANAGED_BY
84 DARPA-2011-ENG-003 MGR-11959388 MANAGED_BY
85 DARPA-2011-SEC-002 MGR-89333365 MANAGED_BY
86 DARPA-2012-MIL-002 MGR-29442483 MANAGED_BY
87 DARPA-2012-MIL-018 MGR-29442483 MANAGED_BY
88 DARPA-2013-AI-007 MGR-89333365 MANAGED_BY
89 DARPA-2013-ENG-004 MGR-11959388 MANAGED_BY
90 DARPA-2013-ENG-010 MGR-11959388 MANAGED_BY
91 DARPA-2013-SEC-006 MGR-89333365 MANAGED_BY
92 DARPA-2014-CMP-012 MGR-50959738 MANAGED_BY
93 DARPA-2014-ROB-007 MGR-89333365 MANAGED_BY
94 DARPA-2014-ROB-009 MGR-11959388 MANAGED_BY
95 DARPA-2015-AI-017 MGR-89333365 MANAGED_BY
96 DARPA-2015-MIL-019 MGR-29442483 MANAGED_BY
97 DARPA-2015-ROB-008 MGR-29442483 MANAGED_BY
98 DARPA-2016-AI-009 MGR-89333365 MANAGED_BY
99 DARPA-2016-CMP-005 MGR-11959388 MANAGED_BY
100 DARPA-2016-MIL-020 MGR-11959388 MANAGED_BY
101 DARPA-2016-ROB-016 MGR-58272302 MANAGED_BY
102 DARPA-2017-AI-018 MGR-89333365 MANAGED_BY
103 DARPA-2017-BIO-003 MGR-82307048 MANAGED_BY
104 DARPA-2017-CMP-008 MGR-50959738 MANAGED_BY
105 DARPA-2017-ROB-010 MGR-29442483 MANAGED_BY
106 DARPA-2018-AI-010 MGR-89333365 MANAGED_BY
107 DARPA-2018-BIO-006 MGR-82307048 MANAGED_BY
108 DARPA-2018-CMP-001 MGR-50959738 MANAGED_BY
109 DARPA-2018-MIL-021 MGR-89333365 MANAGED_BY
110 DARPA-2018-SEC-007 MGR-89333365 MANAGED_BY
111 DARPA-2019-AI-023 MGR-89333365 MANAGED_BY
112 DARPA-2019-BIO-009 MGR-82307048 MANAGED_BY
113 DARPA-2019-ENG-005 MGR-58272302 MANAGED_BY
114 DARPA-2019-QUT-001 MGR-11959388 MANAGED_BY
115 DARPA-2019-ROB-011 MGR-11959388 MANAGED_BY
116 DARPA-2019-SPC-001 MGR-58272302 MANAGED_BY
117 DARPA-2020-AI-011 MGR-11959388 MANAGED_BY
118 DARPA-2020-BIO-011 MGR-82307048 MANAGED_BY
119 DARPA-2020-CMP-006 MGR-50959738 MANAGED_BY
120 DARPA-2020-MIL-022 MGR-29442483 MANAGED_BY
121 DARPA-2020-QUT-005 MGR-11959388 MANAGED_BY
122 DARPA-2021-AI-019 MGR-89333365 MANAGED_BY
123 DARPA-2021-BIO-004 MGR-82307048 MANAGED_BY
124 DARPA-2021-CMP-007 MGR-50959738 MANAGED_BY
125 DARPA-2021-MIL-003 MGR-29442483 MANAGED_BY
126 DARPA-2021-MIL-025 MGR-29442483 MANAGED_BY
127 DARPA-2021-QUT-004 MGR-11959388 MANAGED_BY
128 DARPA-2021-ROB-012 MGR-11959388 MANAGED_BY
129 DARPA-2022-AI-012 MGR-89333365 MANAGED_BY
130 DARPA-2022-BIO-007 MGR-82307048 MANAGED_BY
131 DARPA-2022-CMP-002 MGR-50959738 MANAGED_BY
132 DARPA-2022-ENG-011 MGR-11959388 MANAGED_BY
133 DARPA-2022-MIL-023 MGR-29442483 MANAGED_BY
134 DARPA-2022-ROB-013 MGR-82307048 MANAGED_BY
135 DARPA-2022-SEC-003 MGR-89333365 MANAGED_BY
136 DARPA-2023-AI-020 MGR-50959738 MANAGED_BY
137 DARPA-2023-ENG-006 MGR-50959738 MANAGED_BY
138 DARPA-2023-HPM-001 MGR-58272302 MANAGED_BY
139 DARPA-2023-MIL-026 MGR-58272302 MANAGED_BY
140 DARPA-2023-ROB-018 MGR-29442483 MANAGED_BY
141 DARPA-2023-SPC-002 MGR-58272302 MANAGED_BY
142 DARPA-2024-AI-013 MGR-11959388 MANAGED_BY
143 DARPA-2024-AI-024 MGR-89333365 MANAGED_BY
144 DARPA-2024-BIO-008 MGR-82307048 MANAGED_BY
145 DARPA-2024-MIL-024 MGR-29442483 MANAGED_BY
146 DARPA-2024-QUT-002 MGR-89333365 MANAGED_BY
147 DARPA-2024-ROB-008 MGR-11959388 MANAGED_BY
148 DARPA-2024-SEC-004 MGR-89333365 MANAGED_BY
149 DARPA-2025-AI-014 MGR-89333365 MANAGED_BY
150 DARPA-2025-BIO-012 MGR-82307048 MANAGED_BY
151 DARPA-2025-MAT-002 MGR-11959388 MANAGED_BY
152 DARPA-2025-QUT-003 MGR-11959388 MANAGED_BY
153 DARPA-2025-ROB-015 MGR-11959388 MANAGED_BY
154 PROJ-044 MGR-29103044 MANAGED_BY
155 PROJ-045 MGR-72808311 MANAGED_BY
156 PROJ-046 MGR-12117627 MANAGED_BY
157 PROJ-047 MGR-44867089 MANAGED_BY
158 PROJ-048 MGR-79938277 MANAGED_BY
159 PROJ-049 MGR-20235195 MANAGED_BY
160 PROJ-050 MGR-20235195 MANAGED_BY
161 PROJ-051 MGR-86429568 MANAGED_BY
162 PROJ-052 MGR-85126670 MANAGED_BY
163 PROJ-053 MGR-48169304 MANAGED_BY

@ -0,0 +1,163 @@
:START_ID(Project),:END_ID(Office),:TYPE
DARPA-1958-CMP-001,OFFICE-DSO,BELONGS_TO
DARPA-1959-GPS-001,OFFICE-STO,BELONGS_TO
DARPA-1959-SEN-001,OFFICE-MTO,BELONGS_TO
DARPA-1960-SEN-003,OFFICE-DSO,BELONGS_TO
DARPA-1961-ENG-001,OFFICE-STO,BELONGS_TO
DARPA-1962-NET-001,OFFICE-I2O,BELONGS_TO
DARPA-1963-MIL-002,OFFICE-TTO,BELONGS_TO
DARPA-1964-AI-003,OFFICE-I2O,BELONGS_TO
DARPA-1965-AI-002,OFFICE-I2O,BELONGS_TO
DARPA-1965-CMP-003,OFFICE-MTO,BELONGS_TO
DARPA-1966-NET-002,OFFICE-I2O,BELONGS_TO
DARPA-1967-CMP-001,OFFICE-I2O,BELONGS_TO
DARPA-1969-NET-003,OFFICE-I2O,BELONGS_TO
DARPA-1970-AIR-003,OFFICE-TTO,BELONGS_TO
DARPA-1970-SEN-002,OFFICE-MTO,BELONGS_TO
DARPA-1971-MIL-003,OFFICE-TTO,BELONGS_TO
DARPA-1971-SPC-002,OFFICE-I2O,BELONGS_TO
DARPA-1972-NET-004,OFFICE-I2O,BELONGS_TO
DARPA-1973-AI-001,OFFICE-I2O,BELONGS_TO
DARPA-1974-MIC-001,OFFICE-MTO,BELONGS_TO
DARPA-1975-AIR-001,OFFICE-TTO,BELONGS_TO
DARPA-1976-NET-005,OFFICE-I2O,BELONGS_TO
DARPA-1978-AI-001,OFFICE-I2O,BELONGS_TO
DARPA-1979-MIL-027,OFFICE-MTO,BELONGS_TO
DARPA-1980-ENG-007,OFFICE-DSO,BELONGS_TO
DARPA-1981-SPC-003,OFFICE-STO,BELONGS_TO
DARPA-1982-AI-002,OFFICE-I2O,BELONGS_TO
DARPA-1982-ENG-008,OFFICE-DSO,BELONGS_TO
DARPA-1983-NET-012,OFFICE-I2O,BELONGS_TO
DARPA-1984-AI-003,OFFICE-I2O,BELONGS_TO
DARPA-1984-AIR-002,OFFICE-TTO,BELONGS_TO
DARPA-1985-CMP-002,OFFICE-MTO,BELONGS_TO
DARPA-1986-NET-010,OFFICE-I2O,BELONGS_TO
DARPA-1987-MAT-001,OFFICE-DSO,BELONGS_TO
DARPA-1988-AI-004,OFFICE-I2O,BELONGS_TO
DARPA-1988-CMP-009,OFFICE-MTO,BELONGS_TO
DARPA-1989-MIL-030,OFFICE-MTO,BELONGS_TO
DARPA-1990-ROB-001,OFFICE-DSO,BELONGS_TO
DARPA-1990-ROB-002,OFFICE-DSO,BELONGS_TO
DARPA-1992-CMP-010,OFFICE-MTO,BELONGS_TO
DARPA-1993-ROB-003,OFFICE-DSO,BELONGS_TO
DARPA-1994-BIO-001,OFFICE-BTO,BELONGS_TO
DARPA-1995-SEC-004,OFFICE-I2O,BELONGS_TO
DARPA-1996-NET-011,OFFICE-I2O,BELONGS_TO
DARPA-1997-SEN-001,OFFICE-I2O,BELONGS_TO
DARPA-1998-AI-005,OFFICE-I2O,BELONGS_TO
DARPA-1998-BIO-009,OFFICE-BTO,BELONGS_TO
DARPA-1999-AI-015,OFFICE-I2O,BELONGS_TO
DARPA-1999-NET-006,OFFICE-I2O,BELONGS_TO
DARPA-2000-AI-006,OFFICE-I2O,BELONGS_TO
DARPA-2000-MIL-016,OFFICE-TTO,BELONGS_TO
DARPA-2001-ENG-005,OFFICE-DSO,BELONGS_TO
DARPA-2001-NET-007,OFFICE-I2O,BELONGS_TO
DARPA-2001-SEN-003,OFFICE-MTO,BELONGS_TO
DARPA-2002-ENG-001,OFFICE-MTO,BELONGS_TO
DARPA-2002-ENG-002,OFFICE-MTO,BELONGS_TO
DARPA-2002-MIL-031,OFFICE-STO,BELONGS_TO
DARPA-2003-CMP-003,OFFICE-MTO,BELONGS_TO
DARPA-2003-ENG-009,OFFICE-TTO,BELONGS_TO
DARPA-2003-MIL-001,OFFICE-TTO,BELONGS_TO
DARPA-2004-MIL-017,OFFICE-TTO,BELONGS_TO
DARPA-2004-ROB-003,OFFICE-DSO,BELONGS_TO
DARPA-2004-SEC-005,OFFICE-I2O,BELONGS_TO
DARPA-2005-AI-016,OFFICE-I2O,BELONGS_TO
DARPA-2005-MIL-028,OFFICE-TTO,BELONGS_TO
DARPA-2005-ROB-004,OFFICE-DSO,BELONGS_TO
DARPA-2006-BIO-001,OFFICE-BTO,BELONGS_TO
DARPA-2006-CMP-011,OFFICE-MTO,BELONGS_TO
DARPA-2006-ROB-014,OFFICE-DSO,BELONGS_TO
DARPA-2007-BIO-002,OFFICE-BTO,BELONGS_TO
DARPA-2007-CMP-004,OFFICE-MTO,BELONGS_TO
DARPA-2008-BIO-010,OFFICE-BTO,BELONGS_TO
DARPA-2008-NET-008,OFFICE-I2O,BELONGS_TO
DARPA-2008-ROB-005,OFFICE-TTO,BELONGS_TO
DARPA-2009-BIO-005,OFFICE-BTO,BELONGS_TO
DARPA-2009-MIL-032,OFFICE-TTO,BELONGS_TO
DARPA-2009-SEC-001,OFFICE-I2O,BELONGS_TO
DARPA-2009-SPC-005,OFFICE-STO,BELONGS_TO
DARPA-2010-MIL-029,OFFICE-TTO,BELONGS_TO
DARPA-2010-NET-009,OFFICE-I2O,BELONGS_TO
DARPA-2010-ROB-006,OFFICE-DSO,BELONGS_TO
DARPA-2011-AI-022,OFFICE-I2O,BELONGS_TO
DARPA-2011-ENG-003,OFFICE-DSO,BELONGS_TO
DARPA-2011-SEC-002,OFFICE-I2O,BELONGS_TO
DARPA-2012-MIL-002,OFFICE-TTO,BELONGS_TO
DARPA-2012-MIL-018,OFFICE-TTO,BELONGS_TO
DARPA-2013-AI-007,OFFICE-I2O,BELONGS_TO
DARPA-2013-ENG-004,OFFICE-DSO,BELONGS_TO
DARPA-2013-ENG-010,OFFICE-DSO,BELONGS_TO
DARPA-2013-SEC-006,OFFICE-I2O,BELONGS_TO
DARPA-2014-CMP-012,OFFICE-MTO,BELONGS_TO
DARPA-2014-ROB-007,OFFICE-I2O,BELONGS_TO
DARPA-2014-ROB-009,OFFICE-DSO,BELONGS_TO
DARPA-2015-AI-017,OFFICE-I2O,BELONGS_TO
DARPA-2015-MIL-019,OFFICE-TTO,BELONGS_TO
DARPA-2015-ROB-008,OFFICE-TTO,BELONGS_TO
DARPA-2016-AI-009,OFFICE-I2O,BELONGS_TO
DARPA-2016-CMP-005,OFFICE-DSO,BELONGS_TO
DARPA-2016-MIL-020,OFFICE-DSO,BELONGS_TO
DARPA-2016-ROB-016,OFFICE-STO,BELONGS_TO
DARPA-2017-AI-018,OFFICE-I2O,BELONGS_TO
DARPA-2017-BIO-003,OFFICE-BTO,BELONGS_TO
DARPA-2017-CMP-008,OFFICE-MTO,BELONGS_TO
DARPA-2017-ROB-010,OFFICE-TTO,BELONGS_TO
DARPA-2018-AI-010,OFFICE-I2O,BELONGS_TO
DARPA-2018-BIO-006,OFFICE-BTO,BELONGS_TO
DARPA-2018-CMP-001,OFFICE-MTO,BELONGS_TO
DARPA-2018-MIL-021,OFFICE-I2O,BELONGS_TO
DARPA-2018-SEC-007,OFFICE-I2O,BELONGS_TO
DARPA-2019-AI-023,OFFICE-I2O,BELONGS_TO
DARPA-2019-BIO-009,OFFICE-BTO,BELONGS_TO
DARPA-2019-ENG-005,OFFICE-STO,BELONGS_TO
DARPA-2019-QUT-001,OFFICE-DSO,BELONGS_TO
DARPA-2019-ROB-011,OFFICE-DSO,BELONGS_TO
DARPA-2019-SPC-001,OFFICE-STO,BELONGS_TO
DARPA-2020-AI-011,OFFICE-DSO,BELONGS_TO
DARPA-2020-BIO-011,OFFICE-BTO,BELONGS_TO
DARPA-2020-CMP-006,OFFICE-MTO,BELONGS_TO
DARPA-2020-MIL-022,OFFICE-TTO,BELONGS_TO
DARPA-2020-QUT-005,OFFICE-DSO,BELONGS_TO
DARPA-2021-AI-019,OFFICE-I2O,BELONGS_TO
DARPA-2021-BIO-004,OFFICE-BTO,BELONGS_TO
DARPA-2021-CMP-007,OFFICE-MTO,BELONGS_TO
DARPA-2021-MIL-003,OFFICE-TTO,BELONGS_TO
DARPA-2021-MIL-025,OFFICE-TTO,BELONGS_TO
DARPA-2021-QUT-004,OFFICE-DSO,BELONGS_TO
DARPA-2021-ROB-012,OFFICE-DSO,BELONGS_TO
DARPA-2022-AI-012,OFFICE-I2O,BELONGS_TO
DARPA-2022-BIO-007,OFFICE-BTO,BELONGS_TO
DARPA-2022-CMP-002,OFFICE-MTO,BELONGS_TO
DARPA-2022-ENG-011,OFFICE-DSO,BELONGS_TO
DARPA-2022-MIL-023,OFFICE-TTO,BELONGS_TO
DARPA-2022-ROB-013,OFFICE-BTO,BELONGS_TO
DARPA-2022-SEC-003,OFFICE-I2O,BELONGS_TO
DARPA-2023-AI-020,OFFICE-MTO,BELONGS_TO
DARPA-2023-ENG-006,OFFICE-MTO,BELONGS_TO
DARPA-2023-HPM-001,OFFICE-STO,BELONGS_TO
DARPA-2023-MIL-026,OFFICE-STO,BELONGS_TO
DARPA-2023-ROB-018,OFFICE-TTO,BELONGS_TO
DARPA-2023-SPC-002,OFFICE-STO,BELONGS_TO
DARPA-2024-AI-013,OFFICE-DSO,BELONGS_TO
DARPA-2024-AI-024,OFFICE-I2O,BELONGS_TO
DARPA-2024-BIO-008,OFFICE-BTO,BELONGS_TO
DARPA-2024-MIL-024,OFFICE-TTO,BELONGS_TO
DARPA-2024-QUT-002,OFFICE-I2O,BELONGS_TO
DARPA-2024-ROB-008,OFFICE-DSO,BELONGS_TO
DARPA-2024-SEC-004,OFFICE-I2O,BELONGS_TO
DARPA-2025-AI-014,OFFICE-I2O,BELONGS_TO
DARPA-2025-BIO-012,OFFICE-BTO,BELONGS_TO
DARPA-2025-MAT-002,OFFICE-DSO,BELONGS_TO
DARPA-2025-QUT-003,OFFICE-DSO,BELONGS_TO
DARPA-2025-ROB-015,OFFICE-DSO,BELONGS_TO
PROJ-044,OFFICE-I2O,BELONGS_TO
PROJ-045,OFFICE-STO,BELONGS_TO
PROJ-046,OFFICE-DSO,BELONGS_TO
PROJ-047,OFFICE-STO,BELONGS_TO
PROJ-048,OFFICE-MTO,BELONGS_TO
PROJ-049,OFFICE-MTO,BELONGS_TO
PROJ-050,OFFICE-MTO,BELONGS_TO
PROJ-051,OFFICE-I2O,BELONGS_TO
PROJ-052,OFFICE-MTO,BELONGS_TO
PROJ-053,OFFICE-MTO,BELONGS_TO
1 :START_ID(Project) :END_ID(Office) :TYPE
2 DARPA-1958-CMP-001 OFFICE-DSO BELONGS_TO
3 DARPA-1959-GPS-001 OFFICE-STO BELONGS_TO
4 DARPA-1959-SEN-001 OFFICE-MTO BELONGS_TO
5 DARPA-1960-SEN-003 OFFICE-DSO BELONGS_TO
6 DARPA-1961-ENG-001 OFFICE-STO BELONGS_TO
7 DARPA-1962-NET-001 OFFICE-I2O BELONGS_TO
8 DARPA-1963-MIL-002 OFFICE-TTO BELONGS_TO
9 DARPA-1964-AI-003 OFFICE-I2O BELONGS_TO
10 DARPA-1965-AI-002 OFFICE-I2O BELONGS_TO
11 DARPA-1965-CMP-003 OFFICE-MTO BELONGS_TO
12 DARPA-1966-NET-002 OFFICE-I2O BELONGS_TO
13 DARPA-1967-CMP-001 OFFICE-I2O BELONGS_TO
14 DARPA-1969-NET-003 OFFICE-I2O BELONGS_TO
15 DARPA-1970-AIR-003 OFFICE-TTO BELONGS_TO
16 DARPA-1970-SEN-002 OFFICE-MTO BELONGS_TO
17 DARPA-1971-MIL-003 OFFICE-TTO BELONGS_TO
18 DARPA-1971-SPC-002 OFFICE-I2O BELONGS_TO
19 DARPA-1972-NET-004 OFFICE-I2O BELONGS_TO
20 DARPA-1973-AI-001 OFFICE-I2O BELONGS_TO
21 DARPA-1974-MIC-001 OFFICE-MTO BELONGS_TO
22 DARPA-1975-AIR-001 OFFICE-TTO BELONGS_TO
23 DARPA-1976-NET-005 OFFICE-I2O BELONGS_TO
24 DARPA-1978-AI-001 OFFICE-I2O BELONGS_TO
25 DARPA-1979-MIL-027 OFFICE-MTO BELONGS_TO
26 DARPA-1980-ENG-007 OFFICE-DSO BELONGS_TO
27 DARPA-1981-SPC-003 OFFICE-STO BELONGS_TO
28 DARPA-1982-AI-002 OFFICE-I2O BELONGS_TO
29 DARPA-1982-ENG-008 OFFICE-DSO BELONGS_TO
30 DARPA-1983-NET-012 OFFICE-I2O BELONGS_TO
31 DARPA-1984-AI-003 OFFICE-I2O BELONGS_TO
32 DARPA-1984-AIR-002 OFFICE-TTO BELONGS_TO
33 DARPA-1985-CMP-002 OFFICE-MTO BELONGS_TO
34 DARPA-1986-NET-010 OFFICE-I2O BELONGS_TO
35 DARPA-1987-MAT-001 OFFICE-DSO BELONGS_TO
36 DARPA-1988-AI-004 OFFICE-I2O BELONGS_TO
37 DARPA-1988-CMP-009 OFFICE-MTO BELONGS_TO
38 DARPA-1989-MIL-030 OFFICE-MTO BELONGS_TO
39 DARPA-1990-ROB-001 OFFICE-DSO BELONGS_TO
40 DARPA-1990-ROB-002 OFFICE-DSO BELONGS_TO
41 DARPA-1992-CMP-010 OFFICE-MTO BELONGS_TO
42 DARPA-1993-ROB-003 OFFICE-DSO BELONGS_TO
43 DARPA-1994-BIO-001 OFFICE-BTO BELONGS_TO
44 DARPA-1995-SEC-004 OFFICE-I2O BELONGS_TO
45 DARPA-1996-NET-011 OFFICE-I2O BELONGS_TO
46 DARPA-1997-SEN-001 OFFICE-I2O BELONGS_TO
47 DARPA-1998-AI-005 OFFICE-I2O BELONGS_TO
48 DARPA-1998-BIO-009 OFFICE-BTO BELONGS_TO
49 DARPA-1999-AI-015 OFFICE-I2O BELONGS_TO
50 DARPA-1999-NET-006 OFFICE-I2O BELONGS_TO
51 DARPA-2000-AI-006 OFFICE-I2O BELONGS_TO
52 DARPA-2000-MIL-016 OFFICE-TTO BELONGS_TO
53 DARPA-2001-ENG-005 OFFICE-DSO BELONGS_TO
54 DARPA-2001-NET-007 OFFICE-I2O BELONGS_TO
55 DARPA-2001-SEN-003 OFFICE-MTO BELONGS_TO
56 DARPA-2002-ENG-001 OFFICE-MTO BELONGS_TO
57 DARPA-2002-ENG-002 OFFICE-MTO BELONGS_TO
58 DARPA-2002-MIL-031 OFFICE-STO BELONGS_TO
59 DARPA-2003-CMP-003 OFFICE-MTO BELONGS_TO
60 DARPA-2003-ENG-009 OFFICE-TTO BELONGS_TO
61 DARPA-2003-MIL-001 OFFICE-TTO BELONGS_TO
62 DARPA-2004-MIL-017 OFFICE-TTO BELONGS_TO
63 DARPA-2004-ROB-003 OFFICE-DSO BELONGS_TO
64 DARPA-2004-SEC-005 OFFICE-I2O BELONGS_TO
65 DARPA-2005-AI-016 OFFICE-I2O BELONGS_TO
66 DARPA-2005-MIL-028 OFFICE-TTO BELONGS_TO
67 DARPA-2005-ROB-004 OFFICE-DSO BELONGS_TO
68 DARPA-2006-BIO-001 OFFICE-BTO BELONGS_TO
69 DARPA-2006-CMP-011 OFFICE-MTO BELONGS_TO
70 DARPA-2006-ROB-014 OFFICE-DSO BELONGS_TO
71 DARPA-2007-BIO-002 OFFICE-BTO BELONGS_TO
72 DARPA-2007-CMP-004 OFFICE-MTO BELONGS_TO
73 DARPA-2008-BIO-010 OFFICE-BTO BELONGS_TO
74 DARPA-2008-NET-008 OFFICE-I2O BELONGS_TO
75 DARPA-2008-ROB-005 OFFICE-TTO BELONGS_TO
76 DARPA-2009-BIO-005 OFFICE-BTO BELONGS_TO
77 DARPA-2009-MIL-032 OFFICE-TTO BELONGS_TO
78 DARPA-2009-SEC-001 OFFICE-I2O BELONGS_TO
79 DARPA-2009-SPC-005 OFFICE-STO BELONGS_TO
80 DARPA-2010-MIL-029 OFFICE-TTO BELONGS_TO
81 DARPA-2010-NET-009 OFFICE-I2O BELONGS_TO
82 DARPA-2010-ROB-006 OFFICE-DSO BELONGS_TO
83 DARPA-2011-AI-022 OFFICE-I2O BELONGS_TO
84 DARPA-2011-ENG-003 OFFICE-DSO BELONGS_TO
85 DARPA-2011-SEC-002 OFFICE-I2O BELONGS_TO
86 DARPA-2012-MIL-002 OFFICE-TTO BELONGS_TO
87 DARPA-2012-MIL-018 OFFICE-TTO BELONGS_TO
88 DARPA-2013-AI-007 OFFICE-I2O BELONGS_TO
89 DARPA-2013-ENG-004 OFFICE-DSO BELONGS_TO
90 DARPA-2013-ENG-010 OFFICE-DSO BELONGS_TO
91 DARPA-2013-SEC-006 OFFICE-I2O BELONGS_TO
92 DARPA-2014-CMP-012 OFFICE-MTO BELONGS_TO
93 DARPA-2014-ROB-007 OFFICE-I2O BELONGS_TO
94 DARPA-2014-ROB-009 OFFICE-DSO BELONGS_TO
95 DARPA-2015-AI-017 OFFICE-I2O BELONGS_TO
96 DARPA-2015-MIL-019 OFFICE-TTO BELONGS_TO
97 DARPA-2015-ROB-008 OFFICE-TTO BELONGS_TO
98 DARPA-2016-AI-009 OFFICE-I2O BELONGS_TO
99 DARPA-2016-CMP-005 OFFICE-DSO BELONGS_TO
100 DARPA-2016-MIL-020 OFFICE-DSO BELONGS_TO
101 DARPA-2016-ROB-016 OFFICE-STO BELONGS_TO
102 DARPA-2017-AI-018 OFFICE-I2O BELONGS_TO
103 DARPA-2017-BIO-003 OFFICE-BTO BELONGS_TO
104 DARPA-2017-CMP-008 OFFICE-MTO BELONGS_TO
105 DARPA-2017-ROB-010 OFFICE-TTO BELONGS_TO
106 DARPA-2018-AI-010 OFFICE-I2O BELONGS_TO
107 DARPA-2018-BIO-006 OFFICE-BTO BELONGS_TO
108 DARPA-2018-CMP-001 OFFICE-MTO BELONGS_TO
109 DARPA-2018-MIL-021 OFFICE-I2O BELONGS_TO
110 DARPA-2018-SEC-007 OFFICE-I2O BELONGS_TO
111 DARPA-2019-AI-023 OFFICE-I2O BELONGS_TO
112 DARPA-2019-BIO-009 OFFICE-BTO BELONGS_TO
113 DARPA-2019-ENG-005 OFFICE-STO BELONGS_TO
114 DARPA-2019-QUT-001 OFFICE-DSO BELONGS_TO
115 DARPA-2019-ROB-011 OFFICE-DSO BELONGS_TO
116 DARPA-2019-SPC-001 OFFICE-STO BELONGS_TO
117 DARPA-2020-AI-011 OFFICE-DSO BELONGS_TO
118 DARPA-2020-BIO-011 OFFICE-BTO BELONGS_TO
119 DARPA-2020-CMP-006 OFFICE-MTO BELONGS_TO
120 DARPA-2020-MIL-022 OFFICE-TTO BELONGS_TO
121 DARPA-2020-QUT-005 OFFICE-DSO BELONGS_TO
122 DARPA-2021-AI-019 OFFICE-I2O BELONGS_TO
123 DARPA-2021-BIO-004 OFFICE-BTO BELONGS_TO
124 DARPA-2021-CMP-007 OFFICE-MTO BELONGS_TO
125 DARPA-2021-MIL-003 OFFICE-TTO BELONGS_TO
126 DARPA-2021-MIL-025 OFFICE-TTO BELONGS_TO
127 DARPA-2021-QUT-004 OFFICE-DSO BELONGS_TO
128 DARPA-2021-ROB-012 OFFICE-DSO BELONGS_TO
129 DARPA-2022-AI-012 OFFICE-I2O BELONGS_TO
130 DARPA-2022-BIO-007 OFFICE-BTO BELONGS_TO
131 DARPA-2022-CMP-002 OFFICE-MTO BELONGS_TO
132 DARPA-2022-ENG-011 OFFICE-DSO BELONGS_TO
133 DARPA-2022-MIL-023 OFFICE-TTO BELONGS_TO
134 DARPA-2022-ROB-013 OFFICE-BTO BELONGS_TO
135 DARPA-2022-SEC-003 OFFICE-I2O BELONGS_TO
136 DARPA-2023-AI-020 OFFICE-MTO BELONGS_TO
137 DARPA-2023-ENG-006 OFFICE-MTO BELONGS_TO
138 DARPA-2023-HPM-001 OFFICE-STO BELONGS_TO
139 DARPA-2023-MIL-026 OFFICE-STO BELONGS_TO
140 DARPA-2023-ROB-018 OFFICE-TTO BELONGS_TO
141 DARPA-2023-SPC-002 OFFICE-STO BELONGS_TO
142 DARPA-2024-AI-013 OFFICE-DSO BELONGS_TO
143 DARPA-2024-AI-024 OFFICE-I2O BELONGS_TO
144 DARPA-2024-BIO-008 OFFICE-BTO BELONGS_TO
145 DARPA-2024-MIL-024 OFFICE-TTO BELONGS_TO
146 DARPA-2024-QUT-002 OFFICE-I2O BELONGS_TO
147 DARPA-2024-ROB-008 OFFICE-DSO BELONGS_TO
148 DARPA-2024-SEC-004 OFFICE-I2O BELONGS_TO
149 DARPA-2025-AI-014 OFFICE-I2O BELONGS_TO
150 DARPA-2025-BIO-012 OFFICE-BTO BELONGS_TO
151 DARPA-2025-MAT-002 OFFICE-DSO BELONGS_TO
152 DARPA-2025-QUT-003 OFFICE-DSO BELONGS_TO
153 DARPA-2025-ROB-015 OFFICE-DSO BELONGS_TO
154 PROJ-044 OFFICE-I2O BELONGS_TO
155 PROJ-045 OFFICE-STO BELONGS_TO
156 PROJ-046 OFFICE-DSO BELONGS_TO
157 PROJ-047 OFFICE-STO BELONGS_TO
158 PROJ-048 OFFICE-MTO BELONGS_TO
159 PROJ-049 OFFICE-MTO BELONGS_TO
160 PROJ-050 OFFICE-MTO BELONGS_TO
161 PROJ-051 OFFICE-I2O BELONGS_TO
162 PROJ-052 OFFICE-MTO BELONGS_TO
163 PROJ-053 OFFICE-MTO BELONGS_TO

@ -0,0 +1,163 @@
:START_ID(Project),:END_ID(Technology),:TYPE
DARPA-1958-CMP-001,TECH-微电子,USES_TECHNOLOGY
DARPA-1959-GPS-001,TECH-太空技术,USES_TECHNOLOGY
DARPA-1959-SEN-001,TECH-微电子,USES_TECHNOLOGY
DARPA-1960-SEN-003,TECH-材料科学,USES_TECHNOLOGY
DARPA-1961-ENG-001,TECH-太空技术,USES_TECHNOLOGY
DARPA-1962-NET-001,TECH-通信网络,USES_TECHNOLOGY
DARPA-1963-MIL-002,TECH-无人系统,USES_TECHNOLOGY
DARPA-1964-AI-003,TECH-人工智能,USES_TECHNOLOGY
DARPA-1965-AI-002,TECH-人工智能,USES_TECHNOLOGY
DARPA-1965-CMP-003,TECH-微电子,USES_TECHNOLOGY
DARPA-1966-NET-002,TECH-通信网络,USES_TECHNOLOGY
DARPA-1967-CMP-001,TECH-人工智能,USES_TECHNOLOGY
DARPA-1969-NET-003,TECH-通信网络,USES_TECHNOLOGY
DARPA-1970-AIR-003,TECH-无人系统,USES_TECHNOLOGY
DARPA-1970-SEN-002,TECH-微电子,USES_TECHNOLOGY
DARPA-1971-MIL-003,TECH-无人系统,USES_TECHNOLOGY
DARPA-1971-SPC-002,TECH-通信网络,USES_TECHNOLOGY
DARPA-1972-NET-004,TECH-通信网络,USES_TECHNOLOGY
DARPA-1973-AI-001,TECH-人工智能,USES_TECHNOLOGY
DARPA-1974-MIC-001,TECH-微电子,USES_TECHNOLOGY
DARPA-1975-AIR-001,TECH-无人系统,USES_TECHNOLOGY
DARPA-1976-NET-005,TECH-通信网络,USES_TECHNOLOGY
DARPA-1978-AI-001,TECH-人工智能,USES_TECHNOLOGY
DARPA-1979-MIL-027,TECH-微电子,USES_TECHNOLOGY
DARPA-1980-ENG-007,TECH-能源技术,USES_TECHNOLOGY
DARPA-1981-SPC-003,TECH-太空技术,USES_TECHNOLOGY
DARPA-1982-AI-002,TECH-人工智能,USES_TECHNOLOGY
DARPA-1982-ENG-008,TECH-能源技术,USES_TECHNOLOGY
DARPA-1983-NET-012,TECH-通信网络,USES_TECHNOLOGY
DARPA-1984-AI-003,TECH-人工智能,USES_TECHNOLOGY
DARPA-1984-AIR-002,TECH-无人系统,USES_TECHNOLOGY
DARPA-1985-CMP-002,TECH-微电子,USES_TECHNOLOGY
DARPA-1986-NET-010,TECH-通信网络,USES_TECHNOLOGY
DARPA-1987-MAT-001,TECH-材料科学,USES_TECHNOLOGY
DARPA-1988-AI-004,TECH-人工智能,USES_TECHNOLOGY
DARPA-1988-CMP-009,TECH-微电子,USES_TECHNOLOGY
DARPA-1989-MIL-030,TECH-微电子,USES_TECHNOLOGY
DARPA-1990-ROB-001,TECH-无人系统,USES_TECHNOLOGY
DARPA-1990-ROB-002,TECH-无人系统,USES_TECHNOLOGY
DARPA-1992-CMP-010,TECH-微电子,USES_TECHNOLOGY
DARPA-1993-ROB-003,TECH-无人系统,USES_TECHNOLOGY
DARPA-1994-BIO-001,TECH-生物技术,USES_TECHNOLOGY
DARPA-1995-SEC-004,TECH-网络安全,USES_TECHNOLOGY
DARPA-1996-NET-011,TECH-通信网络,USES_TECHNOLOGY
DARPA-1997-SEN-001,TECH-通信网络,USES_TECHNOLOGY
DARPA-1998-AI-005,TECH-人工智能,USES_TECHNOLOGY
DARPA-1998-BIO-009,TECH-生物技术,USES_TECHNOLOGY
DARPA-1999-AI-015,TECH-人工智能,USES_TECHNOLOGY
DARPA-1999-NET-006,TECH-通信网络,USES_TECHNOLOGY
DARPA-2000-AI-006,TECH-人工智能,USES_TECHNOLOGY
DARPA-2000-MIL-016,TECH-无人系统,USES_TECHNOLOGY
DARPA-2001-ENG-005,TECH-材料科学,USES_TECHNOLOGY
DARPA-2001-NET-007,TECH-通信网络,USES_TECHNOLOGY
DARPA-2001-SEN-003,TECH-微电子,USES_TECHNOLOGY
DARPA-2002-ENG-001,TECH-微电子,USES_TECHNOLOGY
DARPA-2002-ENG-002,TECH-微电子,USES_TECHNOLOGY
DARPA-2002-MIL-031,TECH-太空技术,USES_TECHNOLOGY
DARPA-2003-CMP-003,TECH-微电子,USES_TECHNOLOGY
DARPA-2003-ENG-009,TECH-无人系统,USES_TECHNOLOGY
DARPA-2003-MIL-001,TECH-无人系统,USES_TECHNOLOGY
DARPA-2004-MIL-017,TECH-无人系统,USES_TECHNOLOGY
DARPA-2004-ROB-003,TECH-无人系统,USES_TECHNOLOGY
DARPA-2004-SEC-005,TECH-网络安全,USES_TECHNOLOGY
DARPA-2005-AI-016,TECH-人工智能,USES_TECHNOLOGY
DARPA-2005-MIL-028,TECH-无人系统,USES_TECHNOLOGY
DARPA-2005-ROB-004,TECH-无人系统,USES_TECHNOLOGY
DARPA-2006-BIO-001,TECH-生物技术,USES_TECHNOLOGY
DARPA-2006-CMP-011,TECH-微电子,USES_TECHNOLOGY
DARPA-2006-ROB-014,TECH-无人系统,USES_TECHNOLOGY
DARPA-2007-BIO-002,TECH-生物技术,USES_TECHNOLOGY
DARPA-2007-CMP-004,TECH-微电子,USES_TECHNOLOGY
DARPA-2008-BIO-010,TECH-生物技术,USES_TECHNOLOGY
DARPA-2008-NET-008,TECH-通信网络,USES_TECHNOLOGY
DARPA-2008-ROB-005,TECH-无人系统,USES_TECHNOLOGY
DARPA-2009-BIO-005,TECH-生物技术,USES_TECHNOLOGY
DARPA-2009-MIL-032,TECH-无人系统,USES_TECHNOLOGY
DARPA-2009-SEC-001,TECH-网络安全,USES_TECHNOLOGY
DARPA-2009-SPC-005,TECH-太空技术,USES_TECHNOLOGY
DARPA-2010-MIL-029,TECH-无人系统,USES_TECHNOLOGY
DARPA-2010-NET-009,TECH-网络安全,USES_TECHNOLOGY
DARPA-2010-ROB-006,TECH-无人系统,USES_TECHNOLOGY
DARPA-2011-AI-022,TECH-人工智能,USES_TECHNOLOGY
DARPA-2011-ENG-003,TECH-能源技术,USES_TECHNOLOGY
DARPA-2011-SEC-002,TECH-网络安全,USES_TECHNOLOGY
DARPA-2012-MIL-002,TECH-无人系统,USES_TECHNOLOGY
DARPA-2012-MIL-018,TECH-无人系统,USES_TECHNOLOGY
DARPA-2013-AI-007,TECH-人工智能,USES_TECHNOLOGY
DARPA-2013-ENG-004,TECH-能源技术,USES_TECHNOLOGY
DARPA-2013-ENG-010,TECH-材料科学,USES_TECHNOLOGY
DARPA-2013-SEC-006,TECH-网络安全,USES_TECHNOLOGY
DARPA-2014-CMP-012,TECH-微电子,USES_TECHNOLOGY
DARPA-2014-ROB-007,TECH-网络安全,USES_TECHNOLOGY
DARPA-2014-ROB-009,TECH-无人系统,USES_TECHNOLOGY
DARPA-2015-AI-017,TECH-人工智能,USES_TECHNOLOGY
DARPA-2015-MIL-019,TECH-无人系统,USES_TECHNOLOGY
DARPA-2015-ROB-008,TECH-无人系统,USES_TECHNOLOGY
DARPA-2016-AI-009,TECH-人工智能,USES_TECHNOLOGY
DARPA-2016-CMP-005,TECH-微电子,USES_TECHNOLOGY
DARPA-2016-MIL-020,TECH-无人系统,USES_TECHNOLOGY
DARPA-2016-ROB-016,TECH-太空技术,USES_TECHNOLOGY
DARPA-2017-AI-018,TECH-人工智能,USES_TECHNOLOGY
DARPA-2017-BIO-003,TECH-生物技术,USES_TECHNOLOGY
DARPA-2017-CMP-008,TECH-微电子,USES_TECHNOLOGY
DARPA-2017-ROB-010,TECH-无人系统,USES_TECHNOLOGY
DARPA-2018-AI-010,TECH-人工智能,USES_TECHNOLOGY
DARPA-2018-BIO-006,TECH-生物技术,USES_TECHNOLOGY
DARPA-2018-CMP-001,TECH-微电子,USES_TECHNOLOGY
DARPA-2018-MIL-021,TECH-通信网络,USES_TECHNOLOGY
DARPA-2018-SEC-007,TECH-网络安全,USES_TECHNOLOGY
DARPA-2019-AI-023,TECH-人工智能,USES_TECHNOLOGY
DARPA-2019-BIO-009,TECH-生物技术,USES_TECHNOLOGY
DARPA-2019-ENG-005,TECH-能源技术,USES_TECHNOLOGY
DARPA-2019-QUT-001,TECH-量子科技,USES_TECHNOLOGY
DARPA-2019-ROB-011,TECH-无人系统,USES_TECHNOLOGY
DARPA-2019-SPC-001,TECH-太空技术,USES_TECHNOLOGY
DARPA-2020-AI-011,TECH-量子科技,USES_TECHNOLOGY
DARPA-2020-BIO-011,TECH-生物技术,USES_TECHNOLOGY
DARPA-2020-CMP-006,TECH-微电子,USES_TECHNOLOGY
DARPA-2020-MIL-022,TECH-高超音速,USES_TECHNOLOGY
DARPA-2020-QUT-005,TECH-量子科技,USES_TECHNOLOGY
DARPA-2021-AI-019,TECH-人工智能,USES_TECHNOLOGY
DARPA-2021-BIO-004,TECH-生物技术,USES_TECHNOLOGY
DARPA-2021-CMP-007,TECH-微电子,USES_TECHNOLOGY
DARPA-2021-MIL-003,TECH-无人系统,USES_TECHNOLOGY
DARPA-2021-MIL-025,TECH-无人系统,USES_TECHNOLOGY
DARPA-2021-QUT-004,TECH-量子科技,USES_TECHNOLOGY
DARPA-2021-ROB-012,TECH-无人系统,USES_TECHNOLOGY
DARPA-2022-AI-012,TECH-人工智能,USES_TECHNOLOGY
DARPA-2022-BIO-007,TECH-生物技术,USES_TECHNOLOGY
DARPA-2022-CMP-002,TECH-微电子,USES_TECHNOLOGY
DARPA-2022-ENG-011,TECH-能源技术,USES_TECHNOLOGY
DARPA-2022-MIL-023,TECH-无人系统,USES_TECHNOLOGY
DARPA-2022-ROB-013,TECH-生物技术,USES_TECHNOLOGY
DARPA-2022-SEC-003,TECH-网络安全,USES_TECHNOLOGY
DARPA-2023-AI-020,TECH-人工智能,USES_TECHNOLOGY
DARPA-2023-ENG-006,TECH-材料科学,USES_TECHNOLOGY
DARPA-2023-HPM-001,TECH-高超音速,USES_TECHNOLOGY
DARPA-2023-MIL-026,TECH-无人系统,USES_TECHNOLOGY
DARPA-2023-ROB-018,TECH-无人系统,USES_TECHNOLOGY
DARPA-2023-SPC-002,TECH-太空技术,USES_TECHNOLOGY
DARPA-2024-AI-013,TECH-人工智能,USES_TECHNOLOGY
DARPA-2024-AI-024,TECH-人工智能,USES_TECHNOLOGY
DARPA-2024-BIO-008,TECH-生物技术,USES_TECHNOLOGY
DARPA-2024-MIL-024,TECH-无人系统,USES_TECHNOLOGY
DARPA-2024-QUT-002,TECH-量子科技,USES_TECHNOLOGY
DARPA-2024-ROB-008,TECH-无人系统,USES_TECHNOLOGY
DARPA-2024-SEC-004,TECH-网络安全,USES_TECHNOLOGY
DARPA-2025-AI-014,TECH-人工智能,USES_TECHNOLOGY
DARPA-2025-BIO-012,TECH-生物技术,USES_TECHNOLOGY
DARPA-2025-MAT-002,TECH-材料科学,USES_TECHNOLOGY
DARPA-2025-QUT-003,TECH-量子科技,USES_TECHNOLOGY
DARPA-2025-ROB-015,TECH-无人系统,USES_TECHNOLOGY
PROJ-044,TECH-分时系统_多用户计算_CTSS,USES_TECHNOLOGY
PROJ-045,TECH-实时计算_雷达网络_人机交互,USES_TECHNOLOGY
PROJ-046,TECH-反叛乱战术_传感器网络_远程侦察,USES_TECHNOLOGY
PROJ-047,TECH-声纳_信号处理_水下通信,USES_TECHNOLOGY
PROJ-048,TECH-化合物半导体_高频器件_光电集成,USES_TECHNOLOGY
PROJ-049,TECH-MMIC_相控阵雷达_微波模块,USES_TECHNOLOGY
PROJ-050,TECH-SiC_GaN_高功率器件_高温电子,USES_TECHNOLOGY
PROJ-051,TECH-HPCS_并行编程_Petaflop计算,USES_TECHNOLOGY
PROJ-052,TECH-神经形态芯片_类脑计算_低功耗AI,USES_TECHNOLOGY
PROJ-053,TECH-概率计算_贝叶斯推断_非传统计算,USES_TECHNOLOGY
1 :START_ID(Project) :END_ID(Technology) :TYPE
2 DARPA-1958-CMP-001 TECH-微电子 USES_TECHNOLOGY
3 DARPA-1959-GPS-001 TECH-太空技术 USES_TECHNOLOGY
4 DARPA-1959-SEN-001 TECH-微电子 USES_TECHNOLOGY
5 DARPA-1960-SEN-003 TECH-材料科学 USES_TECHNOLOGY
6 DARPA-1961-ENG-001 TECH-太空技术 USES_TECHNOLOGY
7 DARPA-1962-NET-001 TECH-通信网络 USES_TECHNOLOGY
8 DARPA-1963-MIL-002 TECH-无人系统 USES_TECHNOLOGY
9 DARPA-1964-AI-003 TECH-人工智能 USES_TECHNOLOGY
10 DARPA-1965-AI-002 TECH-人工智能 USES_TECHNOLOGY
11 DARPA-1965-CMP-003 TECH-微电子 USES_TECHNOLOGY
12 DARPA-1966-NET-002 TECH-通信网络 USES_TECHNOLOGY
13 DARPA-1967-CMP-001 TECH-人工智能 USES_TECHNOLOGY
14 DARPA-1969-NET-003 TECH-通信网络 USES_TECHNOLOGY
15 DARPA-1970-AIR-003 TECH-无人系统 USES_TECHNOLOGY
16 DARPA-1970-SEN-002 TECH-微电子 USES_TECHNOLOGY
17 DARPA-1971-MIL-003 TECH-无人系统 USES_TECHNOLOGY
18 DARPA-1971-SPC-002 TECH-通信网络 USES_TECHNOLOGY
19 DARPA-1972-NET-004 TECH-通信网络 USES_TECHNOLOGY
20 DARPA-1973-AI-001 TECH-人工智能 USES_TECHNOLOGY
21 DARPA-1974-MIC-001 TECH-微电子 USES_TECHNOLOGY
22 DARPA-1975-AIR-001 TECH-无人系统 USES_TECHNOLOGY
23 DARPA-1976-NET-005 TECH-通信网络 USES_TECHNOLOGY
24 DARPA-1978-AI-001 TECH-人工智能 USES_TECHNOLOGY
25 DARPA-1979-MIL-027 TECH-微电子 USES_TECHNOLOGY
26 DARPA-1980-ENG-007 TECH-能源技术 USES_TECHNOLOGY
27 DARPA-1981-SPC-003 TECH-太空技术 USES_TECHNOLOGY
28 DARPA-1982-AI-002 TECH-人工智能 USES_TECHNOLOGY
29 DARPA-1982-ENG-008 TECH-能源技术 USES_TECHNOLOGY
30 DARPA-1983-NET-012 TECH-通信网络 USES_TECHNOLOGY
31 DARPA-1984-AI-003 TECH-人工智能 USES_TECHNOLOGY
32 DARPA-1984-AIR-002 TECH-无人系统 USES_TECHNOLOGY
33 DARPA-1985-CMP-002 TECH-微电子 USES_TECHNOLOGY
34 DARPA-1986-NET-010 TECH-通信网络 USES_TECHNOLOGY
35 DARPA-1987-MAT-001 TECH-材料科学 USES_TECHNOLOGY
36 DARPA-1988-AI-004 TECH-人工智能 USES_TECHNOLOGY
37 DARPA-1988-CMP-009 TECH-微电子 USES_TECHNOLOGY
38 DARPA-1989-MIL-030 TECH-微电子 USES_TECHNOLOGY
39 DARPA-1990-ROB-001 TECH-无人系统 USES_TECHNOLOGY
40 DARPA-1990-ROB-002 TECH-无人系统 USES_TECHNOLOGY
41 DARPA-1992-CMP-010 TECH-微电子 USES_TECHNOLOGY
42 DARPA-1993-ROB-003 TECH-无人系统 USES_TECHNOLOGY
43 DARPA-1994-BIO-001 TECH-生物技术 USES_TECHNOLOGY
44 DARPA-1995-SEC-004 TECH-网络安全 USES_TECHNOLOGY
45 DARPA-1996-NET-011 TECH-通信网络 USES_TECHNOLOGY
46 DARPA-1997-SEN-001 TECH-通信网络 USES_TECHNOLOGY
47 DARPA-1998-AI-005 TECH-人工智能 USES_TECHNOLOGY
48 DARPA-1998-BIO-009 TECH-生物技术 USES_TECHNOLOGY
49 DARPA-1999-AI-015 TECH-人工智能 USES_TECHNOLOGY
50 DARPA-1999-NET-006 TECH-通信网络 USES_TECHNOLOGY
51 DARPA-2000-AI-006 TECH-人工智能 USES_TECHNOLOGY
52 DARPA-2000-MIL-016 TECH-无人系统 USES_TECHNOLOGY
53 DARPA-2001-ENG-005 TECH-材料科学 USES_TECHNOLOGY
54 DARPA-2001-NET-007 TECH-通信网络 USES_TECHNOLOGY
55 DARPA-2001-SEN-003 TECH-微电子 USES_TECHNOLOGY
56 DARPA-2002-ENG-001 TECH-微电子 USES_TECHNOLOGY
57 DARPA-2002-ENG-002 TECH-微电子 USES_TECHNOLOGY
58 DARPA-2002-MIL-031 TECH-太空技术 USES_TECHNOLOGY
59 DARPA-2003-CMP-003 TECH-微电子 USES_TECHNOLOGY
60 DARPA-2003-ENG-009 TECH-无人系统 USES_TECHNOLOGY
61 DARPA-2003-MIL-001 TECH-无人系统 USES_TECHNOLOGY
62 DARPA-2004-MIL-017 TECH-无人系统 USES_TECHNOLOGY
63 DARPA-2004-ROB-003 TECH-无人系统 USES_TECHNOLOGY
64 DARPA-2004-SEC-005 TECH-网络安全 USES_TECHNOLOGY
65 DARPA-2005-AI-016 TECH-人工智能 USES_TECHNOLOGY
66 DARPA-2005-MIL-028 TECH-无人系统 USES_TECHNOLOGY
67 DARPA-2005-ROB-004 TECH-无人系统 USES_TECHNOLOGY
68 DARPA-2006-BIO-001 TECH-生物技术 USES_TECHNOLOGY
69 DARPA-2006-CMP-011 TECH-微电子 USES_TECHNOLOGY
70 DARPA-2006-ROB-014 TECH-无人系统 USES_TECHNOLOGY
71 DARPA-2007-BIO-002 TECH-生物技术 USES_TECHNOLOGY
72 DARPA-2007-CMP-004 TECH-微电子 USES_TECHNOLOGY
73 DARPA-2008-BIO-010 TECH-生物技术 USES_TECHNOLOGY
74 DARPA-2008-NET-008 TECH-通信网络 USES_TECHNOLOGY
75 DARPA-2008-ROB-005 TECH-无人系统 USES_TECHNOLOGY
76 DARPA-2009-BIO-005 TECH-生物技术 USES_TECHNOLOGY
77 DARPA-2009-MIL-032 TECH-无人系统 USES_TECHNOLOGY
78 DARPA-2009-SEC-001 TECH-网络安全 USES_TECHNOLOGY
79 DARPA-2009-SPC-005 TECH-太空技术 USES_TECHNOLOGY
80 DARPA-2010-MIL-029 TECH-无人系统 USES_TECHNOLOGY
81 DARPA-2010-NET-009 TECH-网络安全 USES_TECHNOLOGY
82 DARPA-2010-ROB-006 TECH-无人系统 USES_TECHNOLOGY
83 DARPA-2011-AI-022 TECH-人工智能 USES_TECHNOLOGY
84 DARPA-2011-ENG-003 TECH-能源技术 USES_TECHNOLOGY
85 DARPA-2011-SEC-002 TECH-网络安全 USES_TECHNOLOGY
86 DARPA-2012-MIL-002 TECH-无人系统 USES_TECHNOLOGY
87 DARPA-2012-MIL-018 TECH-无人系统 USES_TECHNOLOGY
88 DARPA-2013-AI-007 TECH-人工智能 USES_TECHNOLOGY
89 DARPA-2013-ENG-004 TECH-能源技术 USES_TECHNOLOGY
90 DARPA-2013-ENG-010 TECH-材料科学 USES_TECHNOLOGY
91 DARPA-2013-SEC-006 TECH-网络安全 USES_TECHNOLOGY
92 DARPA-2014-CMP-012 TECH-微电子 USES_TECHNOLOGY
93 DARPA-2014-ROB-007 TECH-网络安全 USES_TECHNOLOGY
94 DARPA-2014-ROB-009 TECH-无人系统 USES_TECHNOLOGY
95 DARPA-2015-AI-017 TECH-人工智能 USES_TECHNOLOGY
96 DARPA-2015-MIL-019 TECH-无人系统 USES_TECHNOLOGY
97 DARPA-2015-ROB-008 TECH-无人系统 USES_TECHNOLOGY
98 DARPA-2016-AI-009 TECH-人工智能 USES_TECHNOLOGY
99 DARPA-2016-CMP-005 TECH-微电子 USES_TECHNOLOGY
100 DARPA-2016-MIL-020 TECH-无人系统 USES_TECHNOLOGY
101 DARPA-2016-ROB-016 TECH-太空技术 USES_TECHNOLOGY
102 DARPA-2017-AI-018 TECH-人工智能 USES_TECHNOLOGY
103 DARPA-2017-BIO-003 TECH-生物技术 USES_TECHNOLOGY
104 DARPA-2017-CMP-008 TECH-微电子 USES_TECHNOLOGY
105 DARPA-2017-ROB-010 TECH-无人系统 USES_TECHNOLOGY
106 DARPA-2018-AI-010 TECH-人工智能 USES_TECHNOLOGY
107 DARPA-2018-BIO-006 TECH-生物技术 USES_TECHNOLOGY
108 DARPA-2018-CMP-001 TECH-微电子 USES_TECHNOLOGY
109 DARPA-2018-MIL-021 TECH-通信网络 USES_TECHNOLOGY
110 DARPA-2018-SEC-007 TECH-网络安全 USES_TECHNOLOGY
111 DARPA-2019-AI-023 TECH-人工智能 USES_TECHNOLOGY
112 DARPA-2019-BIO-009 TECH-生物技术 USES_TECHNOLOGY
113 DARPA-2019-ENG-005 TECH-能源技术 USES_TECHNOLOGY
114 DARPA-2019-QUT-001 TECH-量子科技 USES_TECHNOLOGY
115 DARPA-2019-ROB-011 TECH-无人系统 USES_TECHNOLOGY
116 DARPA-2019-SPC-001 TECH-太空技术 USES_TECHNOLOGY
117 DARPA-2020-AI-011 TECH-量子科技 USES_TECHNOLOGY
118 DARPA-2020-BIO-011 TECH-生物技术 USES_TECHNOLOGY
119 DARPA-2020-CMP-006 TECH-微电子 USES_TECHNOLOGY
120 DARPA-2020-MIL-022 TECH-高超音速 USES_TECHNOLOGY
121 DARPA-2020-QUT-005 TECH-量子科技 USES_TECHNOLOGY
122 DARPA-2021-AI-019 TECH-人工智能 USES_TECHNOLOGY
123 DARPA-2021-BIO-004 TECH-生物技术 USES_TECHNOLOGY
124 DARPA-2021-CMP-007 TECH-微电子 USES_TECHNOLOGY
125 DARPA-2021-MIL-003 TECH-无人系统 USES_TECHNOLOGY
126 DARPA-2021-MIL-025 TECH-无人系统 USES_TECHNOLOGY
127 DARPA-2021-QUT-004 TECH-量子科技 USES_TECHNOLOGY
128 DARPA-2021-ROB-012 TECH-无人系统 USES_TECHNOLOGY
129 DARPA-2022-AI-012 TECH-人工智能 USES_TECHNOLOGY
130 DARPA-2022-BIO-007 TECH-生物技术 USES_TECHNOLOGY
131 DARPA-2022-CMP-002 TECH-微电子 USES_TECHNOLOGY
132 DARPA-2022-ENG-011 TECH-能源技术 USES_TECHNOLOGY
133 DARPA-2022-MIL-023 TECH-无人系统 USES_TECHNOLOGY
134 DARPA-2022-ROB-013 TECH-生物技术 USES_TECHNOLOGY
135 DARPA-2022-SEC-003 TECH-网络安全 USES_TECHNOLOGY
136 DARPA-2023-AI-020 TECH-人工智能 USES_TECHNOLOGY
137 DARPA-2023-ENG-006 TECH-材料科学 USES_TECHNOLOGY
138 DARPA-2023-HPM-001 TECH-高超音速 USES_TECHNOLOGY
139 DARPA-2023-MIL-026 TECH-无人系统 USES_TECHNOLOGY
140 DARPA-2023-ROB-018 TECH-无人系统 USES_TECHNOLOGY
141 DARPA-2023-SPC-002 TECH-太空技术 USES_TECHNOLOGY
142 DARPA-2024-AI-013 TECH-人工智能 USES_TECHNOLOGY
143 DARPA-2024-AI-024 TECH-人工智能 USES_TECHNOLOGY
144 DARPA-2024-BIO-008 TECH-生物技术 USES_TECHNOLOGY
145 DARPA-2024-MIL-024 TECH-无人系统 USES_TECHNOLOGY
146 DARPA-2024-QUT-002 TECH-量子科技 USES_TECHNOLOGY
147 DARPA-2024-ROB-008 TECH-无人系统 USES_TECHNOLOGY
148 DARPA-2024-SEC-004 TECH-网络安全 USES_TECHNOLOGY
149 DARPA-2025-AI-014 TECH-人工智能 USES_TECHNOLOGY
150 DARPA-2025-BIO-012 TECH-生物技术 USES_TECHNOLOGY
151 DARPA-2025-MAT-002 TECH-材料科学 USES_TECHNOLOGY
152 DARPA-2025-QUT-003 TECH-量子科技 USES_TECHNOLOGY
153 DARPA-2025-ROB-015 TECH-无人系统 USES_TECHNOLOGY
154 PROJ-044 TECH-分时系统_多用户计算_CTSS USES_TECHNOLOGY
155 PROJ-045 TECH-实时计算_雷达网络_人机交互 USES_TECHNOLOGY
156 PROJ-046 TECH-反叛乱战术_传感器网络_远程侦察 USES_TECHNOLOGY
157 PROJ-047 TECH-声纳_信号处理_水下通信 USES_TECHNOLOGY
158 PROJ-048 TECH-化合物半导体_高频器件_光电集成 USES_TECHNOLOGY
159 PROJ-049 TECH-MMIC_相控阵雷达_微波模块 USES_TECHNOLOGY
160 PROJ-050 TECH-SiC_GaN_高功率器件_高温电子 USES_TECHNOLOGY
161 PROJ-051 TECH-HPCS_并行编程_Petaflop计算 USES_TECHNOLOGY
162 PROJ-052 TECH-神经形态芯片_类脑计算_低功耗AI USES_TECHNOLOGY
163 PROJ-053 TECH-概率计算_贝叶斯推断_非传统计算 USES_TECHNOLOGY

@ -0,0 +1,131 @@
# -*- coding: utf-8 -*-
"""
Neo4j 数据库层 + 内存缓存
"""
import os
import json
import time
import functools
from neo4j import GraphDatabase
from neo4j.exceptions import ServiceUnavailable, SessionExpired, AuthError
from flask import jsonify, request
# ── 配置 ─────────────────────────────────────────────────
NEO4J_URI = os.environ.get("NEO4J_URI", "bolt://localhost:7687")
NEO4J_USER = os.environ.get("NEO4J_USER", "neo4j")
NEO4J_PASSWORD = os.environ.get("NEO4J_PASSWORD", "xh3.1415926")
if not os.environ.get("NEO4J_PASSWORD"):
print("[警告] 未设置 NEO4J_PASSWORD 环境变量,使用默认值。"
"建议: export NEO4J_PASSWORD=your_password")
# ── Neo4j Driver ─────────────────────────────────────────
driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD))
def run_query(cypher, params=None):
"""执行只读 Cypher 查询,出错时抛出明确异常"""
try:
with driver.session() as session:
result = session.run(cypher, params or {})
return [dict(r) for r in result]
except (ServiceUnavailable, SessionExpired) as e:
raise RuntimeError(f"Neo4j 数据库不可用: {e}") from e
except AuthError as e:
raise RuntimeError(f"Neo4j 认证失败: {e}") from e
except Exception as e:
raise RuntimeError(f"查询执行失败: {e}") from e
def run_write(cypher, params=None):
"""执行写入 Cypher 语句"""
try:
with driver.session() as session:
session.run(cypher, params or {})
except (ServiceUnavailable, SessionExpired) as e:
raise RuntimeError(f"Neo4j 数据库不可用: {e}") from e
except AuthError as e:
raise RuntimeError(f"Neo4j 认证失败: {e}") from e
except Exception as e:
raise RuntimeError(f"写入执行失败: {e}") from e
def run_write_batch(cypher, param_list):
"""批量写入,每批次在同一事务内提交"""
if not param_list:
return
try:
with driver.session() as session:
with session.begin_transaction() as tx:
for params in param_list:
tx.run(cypher, params)
tx.commit()
except (ServiceUnavailable, SessionExpired) as e:
raise RuntimeError(f"Neo4j 数据库不可用: {e}") from e
except AuthError as e:
raise RuntimeError(f"Neo4j 认证失败: {e}") from e
except Exception as e:
raise RuntimeError(f"批量写入失败: {e}") from e
# ── UNWIND 批量操作(供 import_data 使用)──────────────────
def run_unwind_batch(cypher, rows):
"""UNWIND 批量写入,一次请求完成"""
if not rows:
return
with driver.session() as s:
s.run(f"UNWIND $rows AS row {cypher}", {"rows": rows})
# ── 内存缓存(带 TTL─────────────────────────────────────
_cache_store = {} # key -> {"value": ..., "expire_at": float}
def ttl_cache(ttl_seconds=300):
"""
API 响应缓存装饰器默认 5 分钟过期
缓存的是 jsonify 之前的原始数据避免 Response 对象不可复用
"""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
key_parts = [func.__name__]
key_parts.append(str(sorted(request.args.items())) if request else "")
key_parts.extend(str(a) for a in args)
key_parts.append(str(sorted(kwargs.items())))
key = "|".join(key_parts)
now = time.time()
entry = _cache_store.get(key)
if entry and entry["expire_at"] > now:
raw = entry["value"]
resp = jsonify(raw) if isinstance(raw, (dict, list)) else raw
resp.headers["X-Cache"] = "HIT"
return resp
result = func(*args, **kwargs)
if hasattr(result, 'get_json'):
raw = result.get_json()
elif hasattr(result, 'get_data'):
raw = json.loads(result.get_data(as_text=True))
else:
raw = result
_cache_store[key] = {
"value": raw,
"expire_at": now + ttl_seconds,
}
result.headers["X-Cache"] = "MISS"
return result
return wrapper
return decorator
def clear_cache(pattern=None):
"""清除缓存。pattern=None 清除全部,指定字符串只清除匹配键。"""
if pattern is None:
_cache_store.clear()
return
keys = [k for k in _cache_store if pattern in k]
for k in keys:
del _cache_store[k]

@ -0,0 +1,178 @@
# -*- coding: utf-8 -*-
"""
CSV 数据导入 Neo4j
- 读取 CSV 文件解析预算批量 MERGE Neo4j
"""
import os
import csv
import re
import math
from database import driver, run_unwind_batch
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
CSV_DIR = os.path.join(BASE_DIR, "data")
def read_csv(filename):
"""读取 CSV自动处理 BOM清理 Neo4j 专用列名"""
path = os.path.join(CSV_DIR, filename)
rows = []
with open(path, newline="", encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
for row in reader:
clean = {}
for k, v in row.items():
key = k.strip()
key = re.sub(r":ID\([^)]*\)$", "", key) # projectId:ID(Project) → projectId
key = re.sub(r"^:?(START_ID|END_ID)\([^)]*\)$", # :START_ID(Project) → START_ID
r"\1", key)
key = re.sub(r":int$", "", key) # startYear:int → startYear
key = re.sub(r"^:", "", key) # :LABEL → LABEL
clean[key.strip()] = (v or "").strip()
rows.append(clean)
return rows
def parse_budget(raw):
"""
解析预算字符串为万元 float
'$1,500万' -> 1500.0
'$2亿' -> 20000.0
'$1.5亿' -> 15000.0
"""
if not raw:
return 0.0
s = str(raw).replace(",", "").replace("$", "").replace(" ", "").replace("", "")
m = re.search(r"([\d.]+)亿", s)
if m:
return float(m.group(1)) * 10000.0
m = re.search(r"([\d.]+)万", s)
if m:
return float(m.group(1))
m = re.search(r"[\d.]+", s)
if m:
return float(m.group(0))
return 0.0
def _has_existing_data():
"""检查 Neo4j 中是否已有 Project 节点"""
with driver.session() as s:
result = s.run("MATCH (p:Project) RETURN count(p) AS cnt")
return result.single()["cnt"] > 0
def import_all(force=False):
print("=" * 60)
print("[导入] 开始将 CSV 数据写入 Neo4j …")
print(f"[导入] CSV 目录: {CSV_DIR}")
# 检查是否已存在数据
if not force and _has_existing_data():
with driver.session() as s:
proj_count = s.run("MATCH (p:Project) RETURN count(p) AS cnt").single()["cnt"]
print(f"[导入] 数据库中已有 {proj_count} 个 Project 节点,跳过导入。")
print("[导入] 如需强制重导,请使用: python app.py --force-import")
print("=" * 60)
return
if force:
with driver.session() as s:
proj_count = s.run("MATCH (p:Project) RETURN count(p) AS cnt").single()["cnt"]
print(f"[导入] 强制重导模式,将更新已有 {proj_count} 个项目…")
# 索引
with driver.session() as s:
for idx in [
"CREATE INDEX IF NOT EXISTS FOR (p:Project) ON (p.projectId)",
"CREATE INDEX IF NOT EXISTS FOR (t:Technology) ON (t.techId)",
"CREATE INDEX IF NOT EXISTS FOR (i:Institution) ON (i.instId)",
"CREATE INDEX IF NOT EXISTS FOR (m:Manager) ON (m.managerId)",
"CREATE INDEX IF NOT EXISTS FOR (o:Office) ON (o.officeId)",
]:
s.run(idx)
print("[导入] 索引创建完毕")
# Office
rows = [{"officeId": r.get("officeId","").strip(), "name": r.get("name","").strip()}
for r in read_csv("nodes_office.csv") if r.get("officeId","").strip()]
run_unwind_batch("MERGE (o:Office {officeId:row.officeId}) SET o.name=row.name", rows)
print(f"[导入] Office: {len(rows)}")
# Technology
rows = [{"techId": r.get("techId","").strip(), "name": r.get("name","").strip()}
for r in read_csv("nodes_technology.csv") if r.get("techId","").strip()]
run_unwind_batch("MERGE (t:Technology {techId:row.techId}) SET t.name=row.name", rows)
print(f"[导入] Technology: {len(rows)}")
# Institution
rows = [{"instId": r.get("instId","").strip(), "name": r.get("name","").strip()}
for r in read_csv("nodes_institution.csv") if r.get("instId","").strip()]
run_unwind_batch("MERGE (i:Institution {instId:row.instId}) SET i.name=row.name", rows)
print(f"[导入] Institution: {len(rows)}")
# Manager
rows = [{"managerId": r.get("managerId","").strip(), "name": r.get("name","").strip()}
for r in read_csv("nodes_manager.csv") if r.get("managerId","").strip()]
run_unwind_batch("MERGE (m:Manager {managerId:row.managerId}) SET m.name=row.name", rows)
print(f"[导入] Manager: {len(rows)}")
# Project
proj_params = []
for r in read_csv("nodes_project.csv"):
pid = r.get("projectId","").strip()
if not pid:
continue
try: sy = int(r.get("startYear","0") or 0)
except: sy = 0
try: ey = int(r.get("endYear","0") or 0)
except: ey = 0
proj_params.append({
"projectId": pid,
"nameEn": r.get("nameEn","").strip(),
"nameCn": r.get("nameCn","").strip(),
"status": r.get("status","").strip(),
"startYear": sy, "endYear": ey,
"budget": r.get("budget","").strip(),
"budgetVal": parse_budget(r.get("budget","")),
"domain": r.get("transferDomain", r.get("domain","")).strip(),
})
run_unwind_batch("""MERGE (p:Project {projectId:row.projectId})
SET p.nameEn=row.nameEn, p.nameCn=row.nameCn, p.status=row.status,
p.startYear=row.startYear, p.endYear=row.endYear,
p.budget=row.budget, p.budgetVal=row.budgetVal, p.domain=row.domain""",
proj_params)
print(f"[导入] Project: {len(proj_params)}")
# USES_TECHNOLOGY
rows = [{"pid": r.get("START_ID","").strip(), "tid": r.get("END_ID","").strip()}
for r in read_csv("rels_project_technology.csv")
if r.get("START_ID","").strip() and r.get("END_ID","").strip()]
run_unwind_batch("MATCH (p:Project {projectId:row.pid}),(t:Technology {techId:row.tid}) MERGE (p)-[:USES_TECHNOLOGY]->(t)", rows)
print(f"[导入] USES_TECHNOLOGY: {len(rows)}")
# PARTICIPATED_BY
rows = [{"pid": r.get("START_ID","").strip(), "iid": r.get("END_ID","").strip(),
"rtype": r.get("relationType","合作方").strip() or "合作方"}
for r in read_csv("rels_project_institution.csv")
if r.get("START_ID","").strip() and r.get("END_ID","").strip()]
run_unwind_batch("MATCH (p:Project {projectId:row.pid}),(i:Institution {instId:row.iid}) MERGE (p)-[rel:PARTICIPATED_BY {relationType:row.rtype}]->(i)", rows)
print(f"[导入] PARTICIPATED_BY: {len(rows)}")
# MANAGED_BY
rows = [{"pid": r.get("START_ID","").strip(), "mid": r.get("END_ID","").strip()}
for r in read_csv("rels_project_manager.csv")
if r.get("START_ID","").strip() and r.get("END_ID","").strip()]
run_unwind_batch("MATCH (p:Project {projectId:row.pid}),(m:Manager {managerId:row.mid}) MERGE (p)-[:MANAGED_BY]->(m)", rows)
print(f"[导入] MANAGED_BY: {len(rows)}")
# BELONGS_TO
rows = [{"pid": r.get("START_ID","").strip(), "oid": r.get("END_ID","").strip()}
for r in read_csv("rels_project_office.csv")
if r.get("START_ID","").strip() and r.get("END_ID","").strip()]
run_unwind_batch("MATCH (p:Project {projectId:row.pid}),(o:Office {officeId:row.oid}) MERGE (p)-[:BELONGS_TO]->(o)", rows)
print(f"[导入] BELONGS_TO: {len(rows)}")
print("[导入] 全部完成!")
print("=" * 60)

@ -0,0 +1,364 @@
# -*- coding: utf-8 -*-
"""
导入 DARPA 数据富集结果到 Neo4j
读取 DARPA数据富集结果.xlsx 5 Sheet
1. Projects_Enriched 更新 Project 节点的 description/keywords/wikipediaUrl
2. Technologies_Enriched 更新 Technology 节点的 description/category/militaryRelevance/wikipediaUrl
3. Managers_Enriched 更新 Manager 节点的 bio/expertise/affiliation/wikipediaUrl
4. Offices_Enriched 更新 Office 节点的 description/director/foundedYear
5. Milestones_Enriched 创建 :Milestone 节点 + HAS_MILESTONE 关系
用法: python import_enrichment.py [--dry-run]
"""
import sys
import os
import openpyxl
from database import run_query, run_write, clear_cache
EXCEL_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)),
"..", "..", "DARPA数据富集结果.xlsx")
# 规范化路径
EXCEL_PATH = os.path.normpath(EXCEL_PATH)
def read_sheet(wb, name):
"""读取 sheet返回 list[dict]key 为中文列名"""
if name not in wb.sheetnames:
print(f" [跳过] Sheet '{name}' 不存在")
return []
ws = wb[name]
rows = list(ws.iter_rows(values_only=True))
if not rows:
return []
headers = [str(h).strip() if h else f"col_{i}" for i, h in enumerate(rows[0])]
data = []
for row in rows[1:]:
record = {}
for i, val in enumerate(row):
if i < len(headers):
record[headers[i]] = val
data.append(record)
return data
def import_projects(records, dry_run=False):
"""更新 Project 节点: description, keywords, wikipediaUrl"""
stats = {"updated": 0, "skipped": 0, "missing": 0}
for rec in records:
pid = rec.get("项目ID") or rec.get("項目ID") or ""
if not pid:
stats["skipped"] += 1
continue
desc = rec.get("项目摘要") or rec.get("項目摘要") or ""
keywords = rec.get("关键词") or rec.get("關鍵詞") or ""
wiki = rec.get("Wikipedia URL", "") or ""
# 检查节点是否存在
existing = run_query(
"MATCH (p:Project {projectId: $pid}) RETURN p.projectId AS id",
{"pid": str(pid)}
)
if not existing:
stats["missing"] += 1
continue
if not dry_run:
run_write("""
MATCH (p:Project {projectId: $pid})
SET p.description = $desc,
p.keywords = $keywords,
p.wikipediaUrl = $wiki
""", {
"pid": str(pid),
"desc": str(desc) if desc else "",
"keywords": str(keywords) if keywords else "",
"wiki": str(wiki) if wiki else "",
})
stats["updated"] += 1
return stats
def import_technologies(records, dry_run=False):
"""更新 Technology 节点: description, category, militaryRelevance, wikipediaUrl"""
stats = {"updated": 0, "skipped": 0, "missing": 0}
for rec in records:
tid = rec.get("技术ID") or rec.get("技術ID") or ""
if not tid:
stats["skipped"] += 1
continue
desc = rec.get("技术描述") or rec.get("技術描述") or ""
category = rec.get("技术类别") or rec.get("技術類別") or ""
military = rec.get("军事相关性") or rec.get("軍事相關性") or ""
wiki = rec.get("Wikipedia URL", "") or ""
existing = run_query(
"MATCH (t:Technology {techId: $tid}) RETURN t.techId AS id",
{"tid": str(tid)}
)
if not existing:
stats["missing"] += 1
continue
if not dry_run:
run_write("""
MATCH (t:Technology {techId: $tid})
SET t.description = $desc,
t.category = $category,
t.militaryRelevance = $military,
t.wikipediaUrl = $wiki
""", {
"tid": str(tid),
"desc": str(desc) if desc else "",
"category": str(category) if category else "",
"military": str(military) if military else "",
"wiki": str(wiki) if wiki else "",
})
stats["updated"] += 1
return stats
def import_managers(records, dry_run=False):
"""更新 Manager 节点: bio, expertise, affiliation, wikipediaUrl
跳过 type=placeholder 的行"""
stats = {"updated": 0, "skipped_placeholder": 0, "skipped": 0, "missing": 0}
for rec in records:
mid = rec.get("经理ID") or rec.get("經理ID") or ""
if not mid:
stats["skipped"] += 1
continue
mtype = str(rec.get("类型") or rec.get("類型") or "").strip().lower()
if mtype == "placeholder":
stats["skipped_placeholder"] += 1
continue
bio = rec.get("个人简介") or rec.get("個人簡介") or ""
expertise = rec.get("专业领域") or rec.get("專業領域") or ""
affiliation = rec.get("所属机构") or rec.get("所屬機構") or ""
wiki = rec.get("Wikipedia URL", "") or ""
existing = run_query(
"MATCH (m:Manager {managerId: $mid}) RETURN m.managerId AS id",
{"mid": str(mid)}
)
if not existing:
stats["missing"] += 1
continue
if not dry_run:
run_write("""
MATCH (m:Manager {managerId: $mid})
SET m.bio = $bio,
m.expertise = $expertise,
m.affiliation = $affiliation,
m.wikipediaUrl = $wiki
""", {
"mid": str(mid),
"bio": str(bio) if bio else "",
"expertise": str(expertise) if expertise else "",
"affiliation": str(affiliation) if affiliation else "",
"wiki": str(wiki) if wiki else "",
})
stats["updated"] += 1
return stats
def import_offices(records, dry_run=False):
"""更新 Office 节点: description, director, foundedYear"""
stats = {"updated": 0, "skipped": 0, "missing": 0}
for rec in records:
oid = rec.get("办公室ID") or rec.get("辦公室ID") or ""
if not oid:
stats["skipped"] += 1
continue
desc = rec.get("办公室描述") or rec.get("辦公室描述") or ""
director = rec.get("主任") or ""
founded = rec.get("成立年份") or rec.get("成立年份") or 0
existing = run_query(
"MATCH (o:Office {officeId: $oid}) RETURN o.officeId AS id",
{"oid": str(oid)}
)
if not existing:
stats["missing"] += 1
continue
if not dry_run:
run_write("""
MATCH (o:Office {officeId: $oid})
SET o.description = $desc,
o.director = $director,
o.foundedYear = $founded
""", {
"oid": str(oid),
"desc": str(desc) if desc else "",
"director": str(director) if director else "",
"founded": int(founded) if founded else 0,
})
stats["updated"] += 1
return stats
def import_milestones(records, dry_run=False):
"""创建 :Milestone 节点 + HAS_MILESTONE 关系关联到 Project"""
stats = {"created": 0, "relations": 0, "skipped": 0, "missing_project": 0}
for rec in records:
pid = rec.get("项目ID") or rec.get("項目ID") or ""
if not pid:
stats["skipped"] += 1
continue
# 检查项目是否存在
existing = run_query(
"MATCH (p:Project {projectId: $pid}) RETURN p.projectId AS id",
{"pid": str(pid)}
)
if not existing:
stats["missing_project"] += 1
continue
title_cn = rec.get("项目名称(中文)") or rec.get("項目名稱(中文)") or ""
title_en = rec.get("项目名称(英文)") or rec.get("項目名稱(英文)") or ""
era = rec.get("时代") or rec.get("時代") or ""
tech_domain = rec.get("技术域") or rec.get("技術域") or ""
significance = rec.get("历史意义") or rec.get("歷史意義") or ""
tech_detail = rec.get("技术细节") or rec.get("技術細節") or ""
tech_legacy = rec.get("技术遗产") or rec.get("技術遺產") or ""
key_figures = rec.get("关键人物") or rec.get("關鍵人物") or ""
# 用项目ID+标题生成唯一 Milestone ID
milestone_id = f"MILESTONE-{str(pid)}"
if not dry_run:
# 创建里程碑节点
run_write("""
MERGE (ms:Milestone {milestoneId: $msid})
SET ms.title = $title_cn,
ms.titleEn = $title_en,
ms.era = $era,
ms.techDomain = $tech_domain,
ms.historicalSignificance = $significance,
ms.technicalDetail = $tech_detail,
ms.techLegacy = $tech_legacy,
ms.keyFigures = $key_figures
""", {
"msid": milestone_id,
"title_cn": str(title_cn) if title_cn else "",
"title_en": str(title_en) if title_en else "",
"era": str(era) if era else "",
"tech_domain": str(tech_domain) if tech_domain else "",
"significance": str(significance) if significance else "",
"tech_detail": str(tech_detail) if tech_detail else "",
"tech_legacy": str(tech_legacy) if tech_legacy else "",
"key_figures": str(key_figures) if key_figures else "",
})
# 创建关系
run_write("""
MATCH (p:Project {projectId: $pid})
MATCH (ms:Milestone {milestoneId: $msid})
MERGE (p)-[:HAS_MILESTONE]->(ms)
""", {
"pid": str(pid),
"msid": milestone_id,
})
stats["created"] += 1
stats["relations"] += 1
return stats
def main():
dry_run = "--dry-run" in sys.argv
if not os.path.exists(EXCEL_PATH):
print(f"[错误] Excel 文件不存在: {EXCEL_PATH}")
print("请确认路径,或跳过 Step 1 直接执行其他步骤。")
sys.exit(1)
print(f"读取 Excel: {EXCEL_PATH}")
wb = openpyxl.load_workbook(EXCEL_PATH, read_only=True)
if dry_run:
print("=" * 60)
print(" DRY RUN 模式 — 不实际修改数据库")
print("=" * 60)
total_stats = {}
# 1. Projects
print("\n[1/5] 导入 Projects_Enriched ...")
proj_data = read_sheet(wb, "Projects_Enriched")
print(f" 读取 {len(proj_data)} 条记录")
stats = import_projects(proj_data, dry_run)
total_stats["projects"] = stats
print(f" 更新: {stats['updated']} 缺失: {stats['missing']} 跳过: {stats['skipped']}")
# 2. Technologies
print("\n[2/5] 导入 Technologies_Enriched ...")
tech_data = read_sheet(wb, "Technologies_Enriched")
print(f" 读取 {len(tech_data)} 条记录")
stats = import_technologies(tech_data, dry_run)
total_stats["technologies"] = stats
print(f" 更新: {stats['updated']} 缺失: {stats['missing']} 跳过: {stats['skipped']}")
# 3. Managers
print("\n[3/5] 导入 Managers_Enriched ...")
mgr_data = read_sheet(wb, "Managers_Enriched")
print(f" 读取 {len(mgr_data)} 条记录")
stats = import_managers(mgr_data, dry_run)
total_stats["managers"] = stats
print(f" 更新: {stats['updated']} 跳过(placeholder): {stats['skipped_placeholder']} 缺失: {stats['missing']} 跳过: {stats['skipped']}")
# 4. Offices
print("\n[4/5] 导入 Offices_Enriched ...")
office_data = read_sheet(wb, "Offices_Enriched")
print(f" 读取 {len(office_data)} 条记录")
stats = import_offices(office_data, dry_run)
total_stats["offices"] = stats
print(f" 更新: {stats['updated']} 缺失: {stats['missing']} 跳过: {stats['skipped']}")
# 5. Milestones
print("\n[5/5] 导入 Milestones_Enriched ...")
ms_data = read_sheet(wb, "Milestones_Enriched")
print(f" 读取 {len(ms_data)} 条记录")
stats = import_milestones(ms_data, dry_run)
total_stats["milestones"] = stats
print(f" 创建节点: {stats['created']} 创建关系: {stats['relations']} 缺失项目: {stats['missing_project']} 跳过: {stats['skipped']}")
wb.close()
# 汇总
print("\n" + "=" * 60)
print(" 导入完成汇总")
print("=" * 60)
total_updated = (
total_stats["projects"]["updated"] +
total_stats["technologies"]["updated"] +
total_stats["managers"]["updated"] +
total_stats["offices"]["updated"]
)
total_milestones = total_stats["milestones"]["created"]
total_missing = (
total_stats["projects"]["missing"] +
total_stats["technologies"]["missing"] +
total_stats["managers"]["missing"] +
total_stats["offices"]["missing"] +
total_stats["milestones"]["missing_project"]
)
print(f" 更新节点数: {total_updated}")
print(f" 创建里程碑: {total_milestones}")
print(f" 创建关系: {total_stats['milestones']['relations']}")
print(f" 缺失/跳过: {total_missing}")
if not dry_run:
clear_cache()
print("\n 数据库缓存已清除。")
else:
print("\n [DRY RUN] 未实际修改数据库。去掉 --dry-run 参数执行真实导入。")
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load Diff

@ -0,0 +1,4 @@
flask
flask-cors
neo4j
openpyxl

File diff suppressed because it is too large Load Diff

@ -0,0 +1,73 @@
/**
* 重置管理员密码 使用与前端 auth.js 完全一致的参数
*/
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
// 与前端 auth.js 一致的参数
const SYSTEM_SALT = new Uint8Array([
0xDA, 0x4A, 0x1F, 0x93, 0xB2, 0x7E, 0x05, 0xC1,
0x38, 0xD9, 0x6A, 0x2B, 0x44, 0xF0, 0x87, 0x3E
]);
const PBKDF2_ITERATIONS = 100000;
const KEY_LENGTH = 16; // AES-128
const DIGEST = 'sha256';
const PLAINTEXT = 'DARPA_AUTH';
function decrypt(b64, password) {
try {
const combined = Buffer.from(b64, 'base64');
const iv = combined.subarray(0, 12);
const authTag = combined.subarray(combined.length - 16);
const ciphertext = combined.subarray(12, combined.length - 16);
const key = crypto.pbkdf2Sync(password, SYSTEM_SALT, PBKDF2_ITERATIONS, KEY_LENGTH, DIGEST);
const decipher = crypto.createDecipheriv('aes-128-gcm', key, iv);
decipher.setAuthTag(authTag);
return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString('utf8');
} catch (e) {
return null;
}
}
function encrypt(password, plaintext) {
const key = crypto.pbkdf2Sync(password, SYSTEM_SALT, PBKDF2_ITERATIONS, KEY_LENGTH, DIGEST);
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv('aes-128-gcm', key, iv);
const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
const authTag = cipher.getAuthTag();
const combined = Buffer.concat([iv, encrypted, authTag]);
return combined.toString('base64');
}
// ── 读取 users.json ──
const usersPath = path.join(__dirname, '..', 'users.json');
const users = JSON.parse(fs.readFileSync(usersPath, 'utf8'));
const storedCT = users['woker'].ciphertext;
console.log('=== 当前状态 ===');
console.log('woker 的密文:', storedCT);
// 测试可能的旧密码
const testPwds = ['Worker@2026', 'Admin@2025', 'admin123', 'woker', 'DARPA2025', 'Work@2026'];
for (const pwd of testPwds) {
const r = decrypt(storedCT, pwd);
console.log(' 尝试密码 [' + pwd + ']:', r === PLAINTEXT ? 'OK' : (r || '解密失败'));
}
// ── 重置为 Worker@2026 ──
const NEW_PASSWORD = 'Worker@2026';
console.log('\n=== 重置 ===');
const newCT = encrypt(NEW_PASSWORD, PLAINTEXT);
console.log('新密码:', NEW_PASSWORD);
console.log('新密文:', newCT);
// 验证新密文可解密
const verify = decrypt(newCT, NEW_PASSWORD);
console.log('验证解密:', verify === PLAINTEXT ? '通过' : '失败!');
// 更新并写回
users['woker'].ciphertext = newCT;
users['woker'].name = '系统管理员';
fs.writeFileSync(usersPath, JSON.stringify(users, null, 2) + '\n', 'utf8');
console.log('\nusers.json 已更新!');

@ -0,0 +1,70 @@
/**
* 验证加密/解密是否与前端 auth.js 一致
*/
const crypto = require('crypto');
const path = require('path');
const SYSTEM_SALT = new Uint8Array([
0xDA, 0x4A, 0x1F, 0x93, 0xB2, 0x7E, 0x05, 0xC1,
0x38, 0xD9, 0x6A, 0x2B, 0x44, 0xF0, 0x87, 0x3E
]);
function encrypt(password, plaintext) {
const key = crypto.pbkdf2Sync(password, SYSTEM_SALT, 100000, 16, 'sha256');
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv('aes-128-gcm', key, iv);
const encrypted = Buffer.concat([
cipher.update(plaintext, 'utf8'),
cipher.final()
]);
const authTag = cipher.getAuthTag();
const combined = Buffer.concat([iv, encrypted, authTag]);
return combined.toString('base64');
}
function decrypt(b64, password) {
try {
const combined = Buffer.from(b64, 'base64');
const iv = combined.subarray(0, 12);
const authTag = combined.subarray(combined.length - 16);
const ciphertext = combined.subarray(12, combined.length - 16);
const key = crypto.pbkdf2Sync(password, SYSTEM_SALT, 100000, 16, 'sha256');
const decipher = crypto.createDecipheriv('aes-128-gcm', key, iv);
decipher.setAuthTag(authTag);
const decrypted = Buffer.concat([
decipher.update(ciphertext),
decipher.final()
]);
return decrypted.toString('utf8');
} catch (e) {
return null;
}
}
// ── 测试 ──────────────────────────────────────────────────────────
const testPassword = 'Admin@2025';
const plaintext = 'DARPA_AUTH';
// 测试 1: 加密后解密
const ciphertext = encrypt(testPassword, plaintext);
console.log('密文:', ciphertext);
const decrypted = decrypt(ciphertext, testPassword);
console.log('解密结果:', decrypted);
console.log('测试1 (加密→解密):', decrypted === plaintext ? '通过' : '失败');
// 测试 2: 验证 users.json 中的密文能否解密
const fs = require('fs');
const users = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'users.json'), 'utf8'));
const storedCiphertext = users['woker'].ciphertext;
console.log('\nusers.json 中 woker 的密文:', storedCiphertext);
const result = decrypt(storedCiphertext, testPassword);
console.log('用', testPassword, '解密结果:', result);
console.log('测试2 (文件密文解密):', result === plaintext ? '通过' : '失败');
// 测试 3: 额外测试 base64 编解码一致性
console.log('\nBase64 往返测试:');
const testBytes = Buffer.from([0x00, 0xFF, 0x80, 0x7F, 0xAB, 0xCD]);
const b64 = testBytes.toString('base64');
console.log('原始字节:', testBytes.toString('hex'));
console.log('Base64:', b64);
console.log('解码回:', Buffer.from(b64, 'base64').toString('hex'));

File diff suppressed because one or more lines are too long

@ -0,0 +1,12 @@
{
"names": [
"刘安柯",
"刘帝威",
"张三",
"张洺恺",
"徐航",
"李四",
"王锦博",
"系统管理员"
]
}

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

@ -0,0 +1,320 @@
# DARPA 知识图谱 — 数据补全任务书
> **目标读者**AI 助手 / 自动化脚本
> **当前状态**Neo4j 图数据库已建立162 项目 / 21 技术 / 36 机构 / 28 人员 / 6 办公室,关系网完整。
> **问题**:所有节点仅有名称和 ID缺少描述文本、分类信息、背景介绍。
> **目标**:为每个节点补充可读的描述字段,使前端可视化分析和 AI 研判能产出有深度的洞察。
---
## 0. 前置资源
### 0.1 当前节点全量清单
文件:`node_manifest.json`(与本文档同目录)
包含 5 个数组:
- `projects[162]`id / cn / en / domain / sy(startYear) / status
- `technologies[21]`id / name
- `institutions[36]`id / name
- `managers[28]`id / name
- `offices[6]`id / name
### 0.2 Neo4j 连接信息
```
URI: bolt://localhost:7687
数据库: neo4j
密码: 默认(环境变量 NEO4J_PASSWORD 或 neo4j/neo4j
```
### 0.3 写回 Neo4j 的 Cypher 模板
```
# 为项目添加字段
MATCH (p:Project {projectId: 'DARPA-1958-CMP-001'})
SET p.abstract = '摘要文本',
p.keywords = ['关键词1', '关键词2'],
p.wikipedia_url = 'https://...'
# 为技术添加字段
MATCH (t:Technology {techId: 'TECH-...'})
SET t.description = '技术说明',
t.category = '计算',
t.wikipedia_url = 'https://...'
# 为机构添加字段
MATCH (i:Institution {instId: 'INST-MIT'})
SET i.type = '高校',
i.country = '美国',
i.description = '简介',
i.wikipedia_url = 'https://...'
# 为人员添加字段
MATCH (m:Manager {managerId: 'MGR-...'})
SET m.bio = '生平简介',
m.expertise = ['专长1', '专长2'],
m.affiliation = '所属机构',
m.wikipedia_url = 'https://...'
# 为办公室添加字段
MATCH (o:Office {officeId: '...'})
SET o.description = '职责描述',
o.director = '现任主任'
```
---
## 1. 任务一:机构分类标注(人工,优先级最高)
### 1.1 任务说明
`node_manifest.json → institutions[36]`,为每个机构添加 `type` 字段,取值:
> `高校` / `企业` / `国家实验室` / `军方` / `非营利研究机构` / `政府`
### 1.2 逐机构标注
| instId | name | → type |
|--------|------|--------|
| INST-AT_T | AT&T | 企业 |
| INST-Bell_Labs | Bell Labs | 企业 |
| INST-Burroughs | Burroughs | 企业 |
| INST-Columbia | Columbia | 高校 |
| INST-Columbia_University | Columbia University | 高校 |
| INST-Cornell | Cornell | 高校 |
| INST-Cray | Cray | 企业 |
| INST-Cree_Wolfspeed | Cree/Wolfspeed | 企业 |
| INST-DARPA | DARPA | 政府 |
| INST-EG_G | EG&G | 企业 |
| INST-GE | GE | 企业 |
| INST-HP | HP | 企业 |
| INST-HRL_Labs | HRL Labs | 企业 |
| INST-Hughes | Hughes | 企业 |
| INST-Hughes_Aircraft | Hughes Aircraft | 企业 |
| INST-IBM | IBM | 企业 |
| INST-Lockheed | Lockheed | 企业 |
| INST-Lyric_Semiconductor | Lyric Semiconductor | 企业 |
| INST-MIT | MIT | 高校 |
| INST-MIT_Lincoln_Lab | MIT Lincoln Lab | 国家实验室 |
| INST-NREL | NREL | 国家实验室 |
| INST-Northrop | Northrop | 企业 |
| INST-Purdue | Purdue | 高校 |
| INST-RAND | RAND | 非营利研究机构 |
| INST-RF_Micro_Devices | RF Micro Devices | 企业 |
| INST-Raytheon | Raytheon | 企业 |
| INST-Rockwell | Rockwell | 企业 |
| INST-SRI_International | SRI International | 非营利研究机构 |
| INST-Scripps_Institution | Scripps Institution | 非营利研究机构 |
| INST-Stanford | Stanford | 高校 |
| INST-Sun | Sun | 企业 |
| INST-TI | TI | 企业 |
| INST-TRW | TRW | 企业 |
| INST-UIUC | UIUC | 高校 |
| INST-US_Army | US Army | 军方 |
| INST-US_Navy | US Navy | 军方 |
> 部分分类可能需要核验(例如 HRL Labs 是 Hughes 旗下还是独立实验室、Scripps 是高校还是研究机构)。请根据 Wikipedia 或常识确认后修正。
### 1.3 写回 Neo4j
对每个机构执行:
```cypher
MATCH (i:Institution {instId: 'INST-MIT'})
SET i.type = '高校'
```
---
## 2. 任务二:项目摘要爬取(自动化优先)
### 2.1 任务说明
`node_manifest.json → projects[162]`,为每个项目补充:
- `abstract`200-500 字项目摘要
- `keywords`3-8 个关键词数组
- `wikipedia_url`Wikipedia 或 DARPA 官网链接(若能找到)
### 2.2 搜索策略
对每个项目,按优先级尝试:
```
Step 1: Wikipedia API 搜索
GET https://en.wikipedia.org/w/api.php?action=query&list=search&srsearch={projectName}+DARPA&format=json&srlimit=3
Step 2: 若命中,取 pageid → 获取摘要
GET https://en.wikipedia.org/w/api.php?action=query&prop=extracts&exintro=true&explaintext=true&pageids={pageid}&format=json
Step 3: 若 Wikipedia 无结果Google 搜索
Google Custom Search API 或 Bing API搜索 "{nameCn} DARPA 项目"
Step 4: 若以上均无结果,尝试搜索英文名
"{nameEn} DARPA project"
Step 5: 仍无结果 → 标记为 needs_manual用 LLM 根据项目名+领域推测摘要
```
### 2.3 摘要质量要求
- 至少包含:项目背景(为什么做)、核心内容(做了什么)、影响(产出/意义)
- 语言:中文优先,找不到中文则保留英文
- 长度200-500 字
### 2.4 大规模爬取注意事项
- 请求间隔 ≥ 1.5 秒
- User-Agent 设为 `DARPA-KnowledgeGraph/1.0 (research project; contact@example.com)`
- 对返回 429 (rate limit) 做指数退避重试
- 162 个项目预计 8-15 分钟完成
### 2.5 写回 Neo4j
```cypher
MATCH (p:Project {projectId: '{projectId}'})
SET p.abstract = '{abstract}',
p.keywords = ['{kw1}', '{kw2}', '{kw3}'],
p.wikipedia_url = '{url}'
```
> 注意:文本中的单引号需转义为 `\'`
---
## 3. 任务三:技术描述补充
### 3.1 任务说明
`node_manifest.json → technologies[21]`,为每项技术补充:
- `description`300-800 字技术说明
- `category`:一级分类(从以下选择:计算 / 通信 / 材料 / 能源 / 生物 / 航天 / 武器系统 / 传感器 / 人工智能 / 其他)
- `military_relevance`该技术的军事应用场景100-300 字)
- `wikipedia_url`
### 3.2 搜索方式
同任务二Wikipedia 搜索关键词为技术名。若技术名过于专业(如 "SiC/GaN高功率"),补充通用名搜索("Silicon Carbide semiconductor DARPA")。
### 3.3 写回 Neo4j
```cypher
MATCH (t:Technology {techId: '{techId}'})
SET t.description = '{description}',
t.category = '{category}',
t.military_relevance = '{relevance}',
t.wikipedia_url = '{url}'
```
---
## 4. 任务四:人员背景补充
### 4.1 任务说明
`node_manifest.json → managers[28]`,为每位人员补充:
- `bio`100-300 字生平简介
- `expertise`:专长领域数组,如 ['半导体', '集成电路']
- `affiliation`:主要所属机构名
- `wikipedia_url`
### 4.2 注意事项
- 部分人名可能查不到(如 "Various MTO PMs"、"DARPA I2O" 等实际上是办公室代称而非真人),标记为 `type: placeholder`,不写回
- 合并名用 `/` 分隔的(如 "J.C.R. Licklider / Robert E. Kahn"),需拆分为多人并分别搜索
- 优先 Wikipedia其次 IEEE Xplore 或学术机构页面
### 4.3 写回 Neo4j
```cypher
MATCH (m:Manager {managerId: '{managerId}'})
SET m.bio = '{bio}',
m.expertise = ['{exp1}', '{exp2}'],
m.affiliation = '{affiliation}',
m.wikipedia_url = '{url}'
```
---
## 5. 任务五:办公室详情补充
### 5.1 任务说明
`node_manifest.json → offices[6]`,补充:
- `description`200-400 字职责范围说明
- `director`:现任/代表性主任
- `established`:成立年份
### 5.2 数据源
DARPA 官网各办公室页面:`https://www.darpa.mil/about-us/offices/{officeId}`
### 5.3 写回 Neo4j
```cypher
MATCH (o:Office {officeId: '{officeId}'})
SET o.description = '{description}',
o.director = '{director}',
o.established = '{year}'
```
---
## 6. 任务六:里程碑项目精选卡片(人工撰写)
### 6.1 选取标准
从 162 个项目中,按以下规则筛选 20-30 个:
- 预算最高的前 10 个
- 技术关联度最高degree 最大)的前 10 个
- 跨年代覆盖(每个年代至少 1-2 个)
### 6.2 每张卡片格式
```yaml
projectId: DARPA-XXXX-XXX-XXX
nameCn: 项目中文名
nameEn: 项目英文名
era: 1960s
domain: 技术领域
budget: 预算
significance: 为什么这个项目重要100-200字
technical_detail: 技术方案详解300-500字
legacy: 对后世的影响/衍生项目100-200字
key_figures: [关联人物1, 关联人物2]
```
### 6.3 写入方式
将上述字段作为 Neo4j 节点属性追加:
```cypher
MATCH (p:Project {projectId: '{projectId}'})
SET p.significance = '{significance}',
p.technical_detail = '{detail}',
p.legacy = '{legacy}',
p.key_figures = ['{fig1}', '{fig2}']
```
---
## 7. 执行顺序与产出物
| 顺序 | 任务 | 类型 | 预计耗时 | 产出 |
|:---:|------|:---:|------|------|
| 1 | 机构分类标注 | 人工 | 15 分钟 | 36 条 SET 语句 |
| 2 | 项目摘要爬取 | 脚本 | 15 分钟 + 运行 | 162 个项目 enriched |
| 3 | 技术描述补充 | 脚本 | 10 分钟 | 21 个技术 enriched |
| 4 | 人员背景补充 | 脚本+人工 | 30 分钟 | 28 个人员 enriched跳过占位符|
| 5 | 办公室详情 | 脚本 | 5 分钟 | 6 个办公室 enriched |
| 6 | 里程碑卡片 | 人工 | 2-3 小时 | 20-30 张详细卡片 |
---
## 8. 验收标准
完成后应满足:
- [ ] 每个项目节点有 `abstract` 字段,且非空
- [ ] 每个技术节点有 `description``category` 字段
- [ ] 每个机构节点有 `type` 字段
- [ ] 每个人员节点(非占位符)有 `bio``expertise`
- [ ] 每个办公室节点有 `description`
- [ ] 在前端图谱中点击任意节点,右侧详情面板能显示补充后的描述文字

@ -0,0 +1,144 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DARPA 智能情报分析系统</title>
<!-- CDN 依赖(保持与原项目一致,无需 npm 安装) -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Oswald:wght@500;600&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#1890FF',
techGray: '#F0F2F5',
navy: '#001529',
sidebar: '#001529',
},
fontFamily: {
sans: ['Inter', 'Microsoft YaHei', 'sans-serif'],
din: ['Oswald', 'sans-serif'],
}
}
}
}
</script>
<!-- 项目全局样式 -->
<link rel="stylesheet" href="/src/styles/main.css">
</head>
<body class="antialiased">
<!-- ============================================================
页面片段由 vite-plugin-html 在构建时注入
开发时修改 src/pages/*.html刷新即可生效
============================================================ -->
<%- PAGE_LOGIN %>
<%- PAGE_DASHBOARD %>
<%- PAGE_SEARCH %>
<%- PAGE_GRAPH %>
<%- PAGE_TREND %>
<%- PAGE_WIKI %>
<%- PAGE_GOVERNANCE %>
<%- PAGE_DETAIL %>
<!-- ============================================================
资料弹窗(全局,所有页面共用)
============================================================ -->
<div id="profileModal" class="fixed inset-0 bg-black/40 z-[100] hidden flex items-center justify-center" onclick="if(event.target===this)closeProfileModal()">
<div class="bg-white rounded-2xl shadow-2xl w-full max-w-lg mx-4 max-h-[85vh] overflow-y-auto custom-scrollbar profile-modal-inner">
<div class="p-6 border-b border-slate-100 flex items-center justify-between">
<h2 class="text-lg font-bold text-slate-900">个人资料</h2>
<button onclick="closeProfileModal()" class="p-1.5 hover:bg-slate-100 rounded-lg transition-colors">
<i data-lucide="x" class="w-5 h-5 text-slate-400"></i>
</button>
</div>
<div class="p-6 space-y-5">
<!-- Avatar section -->
<div class="flex items-center gap-4">
<div id="profileAvatarPreview" class="w-16 h-16 rounded-full bg-slate-200 flex items-center justify-center shrink-0 overflow-hidden">
<img id="profileAvatarImg" src="" alt="" class="w-full h-full object-cover hidden">
<i id="profileAvatarIcon" data-lucide="user" class="w-8 h-8 text-slate-500"></i>
</div>
<div>
<label class="block text-xs font-bold text-slate-500 mb-2">头像上传</label>
<div class="flex gap-2">
<input type="file" id="profileAvatarInput" accept="image/*" onchange="handleAvatarUpload(this)" class="hidden">
<button onclick="document.getElementById('profileAvatarInput').click()" class="px-3 py-1.5 text-xs font-medium bg-slate-100 hover:bg-slate-200 text-slate-700 rounded-lg transition-colors">选择图片</button>
<button onclick="removeAvatar()" class="px-3 py-1.5 text-xs font-medium bg-red-50 hover:bg-red-100 text-red-600 rounded-lg transition-colors">移除头像</button>
</div>
<p class="text-[10px] text-slate-400 mt-1">支持 JPG/PNG最大 500KB</p>
</div>
</div>
<!-- Account info -->
<div class="space-y-3">
<div>
<label class="text-[11px] text-slate-500 font-medium">账号</label>
<input id="profileUsername" class="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm bg-slate-50 text-slate-500" disabled readonly>
</div>
<div>
<label class="text-[11px] text-slate-500 font-medium">姓名</label>
<input id="profileName" class="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm bg-slate-50 text-slate-500" disabled readonly>
</div>
<div>
<label class="text-[11px] text-slate-500 font-medium">角色</label>
<input id="profileRole" class="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm bg-slate-50 text-slate-500" disabled readonly>
</div>
</div>
<!-- Password change -->
<div class="pt-3 border-t border-slate-100">
<h3 class="text-sm font-bold text-slate-800 mb-3">修改密码</h3>
<div class="space-y-3">
<div>
<label class="text-[11px] text-slate-500 font-medium">当前密码</label>
<input type="password" id="profileOldPwd" class="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:border-primary" placeholder="输入当前密码">
</div>
<div>
<label class="text-[11px] text-slate-500 font-medium">新密码</label>
<input type="password" id="profileNewPwd" class="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:border-primary" placeholder="至少8位含大小写字母、数字、特殊符号">
</div>
<button onclick="changePassword()" class="w-full py-2 bg-primary text-white rounded-lg text-sm font-medium hover:bg-blue-600 transition-colors">更新密码</button>
<p id="profilePwdMsg" class="text-xs hidden"></p>
</div>
</div>
<!-- Admin panel -->
<div id="profileAdminPanel" class="hidden pt-3 border-t border-slate-100 space-y-4">
<h3 class="text-sm font-bold text-slate-800 flex items-center gap-2">
<i data-lucide="shield-check" class="w-4 h-4 text-amber-500"></i> 用户管理(管理员)
</h3>
<!-- User list -->
<div>
<h4 class="text-xs font-bold text-slate-500 mb-2">已注册用户</h4>
<div id="profileUserList" class="space-y-2 max-h-48 overflow-y-auto custom-scrollbar">
<p class="text-xs text-slate-400">加载中...</p>
</div>
</div>
<!-- Whitelist management -->
<div>
<h4 class="text-xs font-bold text-slate-500 mb-2">注册白名单</h4>
<div id="profileWhitelistTags" class="flex flex-wrap gap-1.5 mb-2">
<span class="text-xs text-slate-400">加载中...</span>
</div>
<div class="flex gap-2">
<input id="profileWhitelistInput" type="text" class="flex-1 border border-slate-200 rounded-lg px-3 py-1.5 text-sm focus:outline-none focus:border-primary" placeholder="输入姓名添加">
<button onclick="addWhitelistName()" class="px-3 py-1.5 text-xs font-medium bg-primary text-white rounded-lg hover:bg-blue-600 transition-colors">添加</button>
</div>
<p id="profileWhitelistMsg" class="text-xs text-slate-400 mt-1 hidden"></p>
</div>
</div>
</div>
</div>
</div>
<!-- 全局配置(需在模块之前加载) -->
<script src="/src/js/config.js"></script>
<!-- JS 模块入口Vite 处理,开发热更新) -->
<script type="module" src="/src/js/main.js"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,17 @@
{
"name": "darpa-frontend",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^8.0.4"
},
"dependencies": {
"vite-plugin-html": "^3.2.2"
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.3 KiB

@ -0,0 +1,24 @@
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="bluesky-icon" viewBox="0 0 16 17">
<g clip-path="url(#bluesky-clip)"><path fill="#08060d" d="M7.75 7.735c-.693-1.348-2.58-3.86-4.334-5.097-1.68-1.187-2.32-.981-2.74-.79C.188 2.065.1 2.812.1 3.251s.241 3.602.398 4.13c.52 1.744 2.367 2.333 4.07 2.145-2.495.37-4.71 1.278-1.805 4.512 3.196 3.309 4.38-.71 4.987-2.746.608 2.036 1.307 5.91 4.93 2.746 2.72-2.746.747-4.143-1.747-4.512 1.702.189 3.55-.4 4.07-2.145.156-.528.397-3.691.397-4.13s-.088-1.186-.575-1.406c-.42-.19-1.06-.395-2.741.79-1.755 1.24-3.64 3.752-4.334 5.099"/></g>
<defs><clipPath id="bluesky-clip"><path fill="#fff" d="M.1.85h15.3v15.3H.1z"/></clipPath></defs>
</symbol>
<symbol id="discord-icon" viewBox="0 0 20 19">
<path fill="#08060d" d="M16.224 3.768a14.5 14.5 0 0 0-3.67-1.153c-.158.286-.343.67-.47.976a13.5 13.5 0 0 0-4.067 0c-.128-.306-.317-.69-.476-.976A14.4 14.4 0 0 0 3.868 3.77C1.546 7.28.916 10.703 1.231 14.077a14.7 14.7 0 0 0 4.5 2.306q.545-.748.965-1.587a9.5 9.5 0 0 1-1.518-.74q.191-.14.372-.293c2.927 1.369 6.107 1.369 8.999 0q.183.152.372.294-.723.437-1.52.74.418.838.963 1.588a14.6 14.6 0 0 0 4.504-2.308c.37-3.911-.63-7.302-2.644-10.309m-9.13 8.234c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.894 0 1.614.82 1.599 1.82.001 1-.705 1.82-1.6 1.82m5.91 0c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.893 0 1.614.82 1.599 1.82 0 1-.706 1.82-1.6 1.82"/>
</symbol>
<symbol id="documentation-icon" viewBox="0 0 21 20">
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="m15.5 13.333 1.533 1.322c.645.555.967.833.967 1.178s-.322.623-.967 1.179L15.5 18.333m-3.333-5-1.534 1.322c-.644.555-.966.833-.966 1.178s.322.623.966 1.179l1.534 1.321"/>
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M17.167 10.836v-4.32c0-1.41 0-2.117-.224-2.68-.359-.906-1.118-1.621-2.08-1.96-.599-.21-1.349-.21-2.848-.21-2.623 0-3.935 0-4.983.369-1.684.591-3.013 1.842-3.641 3.428C3 6.449 3 7.684 3 10.154v2.122c0 2.558 0 3.838.706 4.726q.306.383.713.671c.76.536 1.79.64 3.581.66"/>
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M3 10a2.78 2.78 0 0 1 2.778-2.778c.555 0 1.209.097 1.748-.047.48-.129.854-.503.982-.982.145-.54.048-1.194.048-1.749a2.78 2.78 0 0 1 2.777-2.777"/>
</symbol>
<symbol id="github-icon" viewBox="0 0 19 19">
<path fill="#08060d" fill-rule="evenodd" d="M9.356 1.85C5.05 1.85 1.57 5.356 1.57 9.694a7.84 7.84 0 0 0 5.324 7.44c.387.079.528-.168.528-.376 0-.182-.013-.805-.013-1.454-2.165.467-2.616-.935-2.616-.935-.349-.91-.864-1.143-.864-1.143-.71-.48.051-.48.051-.48.787.051 1.2.805 1.2.805.695 1.194 1.817.857 2.268.649.064-.507.27-.857.49-1.052-1.728-.182-3.545-.857-3.545-3.87 0-.857.31-1.558.8-2.104-.078-.195-.349-1 .077-2.078 0 0 .657-.208 2.14.805a7.5 7.5 0 0 1 1.946-.26c.657 0 1.328.092 1.946.26 1.483-1.013 2.14-.805 2.14-.805.426 1.078.155 1.883.078 2.078.502.546.799 1.247.799 2.104 0 3.013-1.818 3.675-3.558 3.87.284.247.528.714.528 1.454 0 1.052-.012 1.896-.012 2.156 0 .208.142.455.528.377a7.84 7.84 0 0 0 5.324-7.441c.013-4.338-3.48-7.844-7.773-7.844" clip-rule="evenodd"/>
</symbol>
<symbol id="social-icon" viewBox="0 0 20 20">
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M12.5 6.667a4.167 4.167 0 1 0-8.334 0 4.167 4.167 0 0 0 8.334 0"/>
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M2.5 16.667a5.833 5.833 0 0 1 8.75-5.053m3.837.474.513 1.035c.07.144.257.282.414.309l.93.155c.596.1.736.536.307.965l-.723.73a.64.64 0 0 0-.152.531l.207.903c.164.715-.213.991-.84.618l-.872-.52a.63.63 0 0 0-.577 0l-.872.52c-.624.373-1.003.094-.84-.618l.207-.903a.64.64 0 0 0-.152-.532l-.723-.729c-.426-.43-.289-.864.306-.964l.93-.156a.64.64 0 0 0 .412-.31l.513-1.034c.28-.562.735-.562 1.012 0"/>
</symbol>
<symbol id="x-icon" viewBox="0 0 19 19">
<path fill="#08060d" fill-rule="evenodd" d="M1.893 1.98c.052.072 1.245 1.769 2.653 3.77l2.892 4.114c.183.261.333.48.333.486s-.068.089-.152.183l-.522.593-.765.867-3.597 4.087c-.375.426-.734.834-.798.905a1 1 0 0 0-.118.148c0 .01.236.017.664.017h.663l.729-.83c.4-.457.796-.906.879-.999a692 692 0 0 0 1.794-2.038c.034-.037.301-.34.594-.675l.551-.624.345-.392a7 7 0 0 1 .34-.374c.006 0 .93 1.306 2.052 2.903l2.084 2.965.045.063h2.275c1.87 0 2.273-.003 2.266-.021-.008-.02-1.098-1.572-3.894-5.547-2.013-2.862-2.28-3.246-2.273-3.266.008-.019.282-.332 2.085-2.38l2-2.274 1.567-1.782c.022-.028-.016-.03-.65-.03h-.674l-.3.342a871 871 0 0 1-1.782 2.025c-.067.075-.405.458-.75.852a100 100 0 0 1-.803.91c-.148.172-.299.344-.99 1.127-.304.343-.32.358-.345.327-.015-.019-.904-1.282-1.976-2.808L6.365 1.85H1.8zm1.782.91 8.078 11.294c.772 1.08 1.413 1.973 1.425 1.984.016.017.241.02 1.05.017l1.03-.004-2.694-3.766L7.796 5.75 5.722 2.852l-1.039-.004-1.039-.004z" clip-rule="evenodd"/>
</symbol>
</svg>

After

Width:  |  Height:  |  Size: 4.9 KiB

@ -0,0 +1,364 @@
/* =============================================================================
* [MODULE: auth] 身份验证模块
* 包含AES-128-GCM 加解密用户存储会话管理登录/注册逻辑
* ============================================================================= */
// ── AES-128-GCM 工具函数 (Web Crypto API) ────────────────────────────────────
// 固定的系统级 salt128-bit用于 PBKDF2 密钥派生
const SYSTEM_SALT = new Uint8Array([
0xDA, 0x4A, 0x1F, 0x93, 0xB2, 0x7E, 0x05, 0xC1,
0x38, 0xD9, 0x6A, 0x2B, 0x44, 0xF0, 0x87, 0x3E
]);
/**
* 从密码字符串派生 AES-128 CryptoKey
* 使用 PBKDF2(SHA-256, 100000 iter) AES-GCM 128-bit
*/
async function deriveKey(password) {
const enc = new TextEncoder();
const keyMaterial = await crypto.subtle.importKey(
'raw', enc.encode(password), { name: 'PBKDF2' }, false, ['deriveKey']
);
return crypto.subtle.deriveKey(
{ name: 'PBKDF2', salt: SYSTEM_SALT, iterations: 100000, hash: 'SHA-256' },
keyMaterial,
{ name: 'AES-GCM', length: 128 }, // AES-128
false,
['encrypt', 'decrypt']
);
}
/**
* 加密返回 Base64(iv[12] + ciphertext)
*/
async function aesEncrypt(plaintext, password) {
const key = await deriveKey(password);
const iv = crypto.getRandomValues(new Uint8Array(12)); // 96-bit IV
const enc = new TextEncoder();
const cipherBuf = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv }, key, enc.encode(plaintext)
);
// 拼接 iv + ciphertext
const combined = new Uint8Array(12 + cipherBuf.byteLength);
combined.set(iv, 0);
combined.set(new Uint8Array(cipherBuf), 12);
return btoa(String.fromCharCode(...combined));
}
/**
* 解密传入 Base64 密文返回明文失败返回 null
*/
async function aesDecrypt(b64, password) {
try {
const combined = Uint8Array.from(atob(b64), c => c.charCodeAt(0));
const iv = combined.slice(0, 12);
const ciphertext = combined.slice(12);
const key = await deriveKey(password);
const plainBuf = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv }, key, ciphertext
);
return new TextDecoder().decode(plainBuf);
} catch {
return null;
}
}
// ── 用户存储localStorage──────────────────────────────────────────────────
// 格式:{ [username]: { ciphertext: string } }
const USERS_KEY = 'darpa_users';
function getUsers() {
try { return JSON.parse(localStorage.getItem(USERS_KEY)) || {}; }
catch { return {}; }
}
function saveUsers(users) {
localStorage.setItem(USERS_KEY, JSON.stringify(users));
// 同步到后端本地文件,清缓存后也能恢复
try {
fetch(`${window.APP_CONFIG.API_BASE}/users`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(users)
}).catch(() => {});
} catch {}
}
// 启动时从后端同步账号(后端为准,覆盖本地不一致的账号)
async function restoreUsers() {
try {
const resp = await fetch(`${window.APP_CONFIG.API_BASE}/users`);
const backendUsers = await resp.json();
if (!backendUsers || Object.keys(backendUsers).length === 0) return;
const localUsers = getUsers();
let changed = false;
for (const [username, data] of Object.entries(backendUsers)) {
if (!localUsers[username] || localUsers[username].ciphertext !== data.ciphertext) {
localUsers[username] = data;
changed = true;
}
}
if (changed) {
localStorage.setItem(USERS_KEY, JSON.stringify(localUsers));
}
} catch {}
}
// ── 会话持久化(仅 sessionStorage关闭标签页自动失效──────────────────────
function saveSession(username) {
localStorage.setItem('darpa_session', username);
}
function loadSession() {
return localStorage.getItem('darpa_session') || sessionStorage.getItem('darpa_session');
}
function clearSession() {
localStorage.removeItem('darpa_session');
sessionStorage.removeItem('darpa_session');
}
// ── UI 辅助函数 ───────────────────────────────────────────────────────────────
function showLoginError(msg) {
const el = document.getElementById('loginError');
document.getElementById('loginErrorMsg').textContent = msg;
el.classList.remove('hidden');
el.classList.add('flex');
lucide.createIcons();
}
function hideLoginError() {
const el = document.getElementById('loginError');
el.classList.add('hidden');
el.classList.remove('flex');
}
function showRegisterError(msg) {
const el = document.getElementById('registerError');
document.getElementById('registerErrorMsg').textContent = msg;
el.classList.remove('hidden');
el.classList.add('flex');
document.getElementById('registerSuccess').classList.add('hidden');
lucide.createIcons();
}
function hideRegisterFeedback() {
document.getElementById('registerError').classList.add('hidden');
document.getElementById('registerError').classList.remove('flex');
document.getElementById('registerSuccess').classList.add('hidden');
}
// ── 密码强度计算 ──────────────────────────────────────────────────────────────
function updatePwdStrength(val) {
let score = 0;
if (val.length >= 8) score++;
if (/[A-Z]/.test(val)) score++;
if (/[a-z]/.test(val)) score++;
if (/[0-9]/.test(val)) score++;
if (/[^A-Za-z0-9]/.test(val)) score++;
// 4条指示条满足0→灰1→红2→橙3→黄4-5→绿
const colors = ['bg-slate-700', 'bg-red-500', 'bg-orange-400', 'bg-yellow-400', 'bg-emerald-500'];
const labels = ['', '弱', '较弱', '中等', '强', '非常强'];
const txtCols = ['text-slate-500', 'text-red-400', 'text-orange-400', 'text-yellow-400', 'text-emerald-400', 'text-emerald-400'];
// 把 score(0-5) 映射到 4 格进度
const filled = Math.min(4, Math.round(score * 4 / 5));
const barColor = score <= 1 ? colors[1] : score === 2 ? colors[2] : score === 3 ? colors[3] : colors[4];
for (let i = 1; i <= 4; i++) {
const bar = document.getElementById(`psb${i}`);
bar.className = `h-1 flex-1 rounded-full transition-colors ${i <= filled ? barColor : 'bg-slate-700'}`;
}
const lbl = document.getElementById('pwdStrengthLabel');
lbl.textContent = val.length ? `密码强度:${labels[score]}` : '';
lbl.className = `text-[10px] ml-1 ${val.length ? txtCols[score] : 'text-slate-500'}`;
}
function switchAuthTab(tab) {
['login', 'register'].forEach(t => {
const btn = document.getElementById(`authTab-${t}`);
const panel = document.getElementById(`authPanel-${t}`);
if (t === tab) {
btn.classList.add('bg-primary', 'text-white', 'shadow');
btn.classList.remove('text-slate-400');
panel.classList.remove('hidden');
} else {
btn.classList.remove('bg-primary', 'text-white', 'shadow');
btn.classList.add('text-slate-400');
panel.classList.add('hidden');
}
});
hideLoginError();
hideRegisterFeedback();
lucide.createIcons();
}
// ── 挂载到 window供 HTML onclick 和跨模块调用使用
window.deriveKey = deriveKey;
window.aesEncrypt = aesEncrypt;
window.aesDecrypt = aesDecrypt;
window.getUsers = getUsers;
window.saveUsers = saveUsers;
window.restoreUsers = restoreUsers;
window.saveSession = saveSession;
window.loadSession = loadSession;
window.clearSession = clearSession;
window.showLoginError = showLoginError;
window.hideLoginError = hideLoginError;
window.showRegisterError = showRegisterError;
window.hideRegisterFeedback = hideRegisterFeedback;
window.updatePwdStrength = updatePwdStrength;
window.switchAuthTab = switchAuthTab;
/* =============================================================================
* [MODULE: auth] 登录 / 注册操作
* ============================================================================= */
async function login() {
hideLoginError();
const usernameEl = document.getElementById('username');
const passwordEl = document.getElementById('password');
const uVal = usernameEl.value.trim();
const pVal = passwordEl.value;
if (!uVal) {
usernameEl.classList.add('error-shake');
setTimeout(() => usernameEl.classList.remove('error-shake'), 500);
showLoginError('账号不能为空');
return;
}
if (!pVal) {
passwordEl.classList.add('error-shake');
setTimeout(() => passwordEl.classList.remove('error-shake'), 500);
showLoginError('密码不能为空');
return;
}
const btn = document.getElementById('loginBtn');
const btnText = document.getElementById('btnText');
const btnLoader = document.getElementById('btnLoader');
btn.disabled = true;
btnText.classList.add('hidden');
btnLoader.classList.remove('hidden');
try {
const users = getUsers();
if (!users[uVal]) {
showLoginError('账号不存在,请先申请账号');
return;
}
const decrypted = await aesDecrypt(users[uVal].ciphertext, pVal);
if (decrypted !== 'DARPA_AUTH') {
showLoginError('密码错误,请重新输入');
return;
}
saveSession(uVal);
// Update sidebar with real name
setTimeout(() => { updateSidebarUser(); updateHeaderAvatar(); }, 100);
setTimeout(() => { showPage('dashboardPage'); }, 600);
} finally {
btn.disabled = false;
btnText.classList.remove('hidden');
btnLoader.classList.add('hidden');
}
}
async function register() {
hideRegisterFeedback();
const uEl = document.getElementById('reg-username');
const nEl = document.getElementById('reg-name');
const pEl = document.getElementById('reg-password');
const cEl = document.getElementById('reg-confirm');
const uVal = uEl.value.trim();
const nVal = nEl ? nEl.value.trim() : '';
const pVal = pEl.value;
const cVal = cEl.value;
if (!uVal || !/^[a-zA-Z0-9]{4,20}$/.test(uVal)) {
uEl.classList.add('error-shake');
setTimeout(() => uEl.classList.remove('error-shake'), 500);
showRegisterError('账号须为 4-20 位字母或数字');
return;
}
if (!nVal) {
if (nEl) { nEl.classList.add('error-shake'); setTimeout(() => nEl.classList.remove('error-shake'), 500); }
showRegisterError('姓名不能为空');
return;
}
if (pVal.length < 8) {
pEl.classList.add('error-shake');
setTimeout(() => pEl.classList.remove('error-shake'), 500);
showRegisterError('密码长度至少 8 位');
return;
}
const pwdRules = [
{ re: /[A-Z]/, msg: '须包含大写字母A-Z' },
{ re: /[a-z]/, msg: '须包含小写字母a-z' },
{ re: /[0-9]/, msg: '须包含数字0-9' },
{ re: /[^A-Za-z0-9]/, msg: '须包含特殊符号(如 !@#$%' },
];
for (const rule of pwdRules) {
if (!rule.re.test(pVal)) {
pEl.classList.add('error-shake');
setTimeout(() => pEl.classList.remove('error-shake'), 500);
showRegisterError('密码' + rule.msg);
return;
}
}
if (pVal !== cVal) {
cEl.classList.add('error-shake');
setTimeout(() => cEl.classList.remove('error-shake'), 500);
showRegisterError('两次输入的密码不一致');
return;
}
const users = getUsers();
if (users[uVal]) {
showRegisterError('该账号已存在,请直接登录');
return;
}
// Whitelist validation
try {
const wlResp = await fetch(`${window.APP_CONFIG.API_BASE}/whitelist`);
const wl = await wlResp.json();
const whitelist = wl.names || [];
if (whitelist.length > 0 && !whitelist.includes(nVal)) {
showRegisterError('您的姓名不在授权名单中,请联系管理员');
return;
}
} catch {
// Backend unreachable, fall through (allow registration)
}
const btn = document.getElementById('registerBtn');
const btnTxt = document.getElementById('regBtnText');
const loader = document.getElementById('regBtnLoader');
btn.disabled = true;
btnTxt.classList.add('hidden');
loader.classList.remove('hidden');
try {
const ciphertext = await aesEncrypt('DARPA_AUTH', pVal);
users[uVal] = {
ciphertext,
name: nVal,
avatar: null,
role: 'user'
};
saveUsers(users);
document.getElementById('registerSuccess').classList.remove('hidden');
setTimeout(() => {
switchAuthTab('login');
document.getElementById('username').value = uVal;
uEl.value = ''; pEl.value = ''; cEl.value = '';
if (nEl) nEl.value = '';
}, 1500);
} finally {
btn.disabled = false;
btnTxt.classList.remove('hidden');
loader.classList.add('hidden');
}
}
function logout() {
clearSession();
showPage('loginPage');
}
window.login = login;
window.register = register;
window.logout = logout;

@ -0,0 +1,7 @@
/* =============================================================================
* [CONFIG] 前端全局配置 修改此处即可适配不同环境
* ============================================================================= */
window.APP_CONFIG = {
// 后端 API 地址(部署到其他机器时改这里)
API_BASE: 'http://localhost:5001/api',
};

@ -0,0 +1,71 @@
/* =============================================================================
* [GLOBAL] 全局状态变量
* ============================================================================= */
let currentPage = 'loginPage';
let loginTimerId = null;
let dashboardChartInited = false;
/* =============================================================================
* [MODULE: core] 核心路由模块
* 包含showPage 页面切换侧边栏高亮togglePwd键盘快捷键window.onload
* ============================================================================= */
// Page → sidebar nav key mapping
const PAGE_NAV_KEY = {
dashboardPage: 'dashboard',
searchPage: 'search',
graphPage: 'graph',
trendPage: 'trend',
wikiPage: 'wiki',
governancePage: 'governance',
detailPage: 'detail',
};
function showPage(pageId) {
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
document.getElementById(pageId).classList.add('active');
currentPage = pageId;
// Update ALL sidebars: clear then re-highlight by data-nav-key
const key = PAGE_NAV_KEY[pageId] || '';
document.querySelectorAll('aside a[data-nav-key]').forEach(a => {
a.classList.toggle('menu-active', a.dataset.navKey === key);
});
// Refresh sidebar user info (on every page switch)
if (typeof updateSidebarUser === 'function') updateSidebarUser();
if (typeof updateHeaderAvatar === 'function') updateHeaderAvatar();
// Reinitialize icons
setTimeout(() => lucide.createIcons(), 100);
// Initialize charts if needed
if (pageId === 'dashboardPage') initDashboardChart();
if (pageId === 'graphPage') setTimeout(() => { initGraph(); if (typeof graphChart !== 'undefined' && graphChart) graphChart.resize(); }, 150);
if (pageId === 'trendPage') setTimeout(() => initTrendCharts(), 150);
if (pageId === 'searchPage') setTimeout(() => initSearchPage(), 100);
if (pageId === 'wikiPage') setTimeout(() => initWiki(), 100);
if (pageId === 'detailPage') setTimeout(() => initDetail(), 100);
}
function togglePwd(inputId, iconId) {
const pwd = document.getElementById(inputId);
const icon = document.getElementById(iconId);
if (pwd.type === 'password') {
pwd.type = 'text';
icon.setAttribute('data-lucide', 'eye-off');
} else {
pwd.type = 'password';
icon.setAttribute('data-lucide', 'eye');
}
lucide.createIcons();
}
function toggleRemember() {} // removed
// ── 挂载到 window供 HTML onclick 和跨模块调用使用
window.showPage = showPage;
window.togglePwd = togglePwd;
window.toggleRemember = toggleRemember;

@ -0,0 +1,381 @@
/* =============================================================================
* [MODULE: dashboard] 工作台模块 (API 驱动)
* ============================================================================= */
const API_BASE = window.APP_CONFIG.API_BASE;
let dashInited = false;
let dashCharts = {};
let dashProjectData = []; // 缓存项目列表数据
let dashEditTarget = null; // 正在编辑的项目 ID (null=新增)
// ── 颜色方案 ────────────────────────────────────────────────
const DASH_COLORS = [
'#1890FF','#10b981','#8b5cf6','#f59e0b','#ef4444',
'#06b6d4','#ec4899','#84cc16','#f97316','#6366f1',
'#14b8a6','#e11d48','#22c55e','#a855f7','#0ea5e9'
];
// ── 主初始化 ──────────────────────────────────────────────────
async function initDashboardChart() {
if (dashInited) {
Object.values(dashCharts).forEach(c => c && c.resize());
return;
}
try {
const [report, domainCluster, timeline] = await Promise.all([
fetch(`${API_BASE}/intelligence_report`).then(r => r.json()),
fetch(`${API_BASE}/domain_cluster`).then(r => r.json()),
fetch(`${API_BASE}/timeline`).then(r => r.json()),
]);
buildDashStats(report.stats, timeline);
buildDashTimeline(timeline);
buildDashDomainTop5(domainCluster);
buildDashAiSummary(report);
buildDashKeyProjects(report);
dashInited = true;
} catch (err) {
console.error('Dashboard init error:', err);
showDashError();
}
}
function showDashError() {
const dom = document.getElementById('dashTimelineChart');
if (dom) dom.innerHTML = '<p class="text-sm text-red-400 text-center pt-28">数据加载失败,请检查后端服务</p>';
const statIds = ['dashTotalProj', 'dashTechCount', 'dashInstCount', 'dashTotalBudget'];
statIds.forEach(id => {
const el = document.getElementById(id);
if (el) { el.textContent = 'ERR'; el.classList.remove('skeleton-text'); }
});
const card = document.getElementById('dashAiSummaryCard');
const errCard = document.getElementById('dashAiSummaryError');
if (card) card.classList.add('hidden');
if (errCard) errCard.classList.remove('hidden');
}
// ── 1. 统计卡片 + 趋势 ──────────────────────────────────────
function buildDashStats(stats, timeline) {
if (!stats) return;
const decadeMap = {};
timeline.forEach(d => {
const dec = Math.floor(d.year / 10) * 10;
const key = `${dec}s`;
if (!decadeMap[key]) decadeMap[key] = 0;
decadeMap[key] += d.count;
});
const decades = Object.keys(decadeMap).sort();
let trendPct = null;
if (decades.length >= 2) {
const prev = decadeMap[decades[decades.length - 2]];
const curr = decadeMap[decades[decades.length - 1]];
if (prev > 0) trendPct = ((curr - prev) / prev * 100);
}
const trendText = trendPct !== null ? `${trendPct >= 0 ? '+' : ''}${trendPct.toFixed(1)}%` : '--';
const trendColor = trendPct !== null && trendPct >= 0 ? 'text-emerald-500' : 'text-red-400';
setStatVal('dashTotalProj', stats.totalProj);
setTrend('dashTotalProjTrend', trendText, trendColor);
setStatVal('dashTechCount', stats.techCount);
setTrend('dashTechCountTrend', '--', 'text-slate-400');
setStatVal('dashInstCount', stats.instCount);
setTrend('dashInstCountTrend', '--', 'text-slate-400');
setStatVal('dashTotalBudget', (stats.totalBudget / 10000).toFixed(1) + '亿');
setTrend('dashTotalBudgetTrend', trendText, trendColor);
}
function setStatVal(id, val) {
const el = document.getElementById(id);
if (el) { el.textContent = val; el.classList.remove('skeleton-text'); }
}
function setTrend(id, text, colorClass) {
const el = document.getElementById(id);
if (el) { el.textContent = text; el.classList.remove('skeleton-text-sm'); el.className = 'text-[10px] font-medium ' + colorClass; }
}
// ── 2. 年代趋势图 (柱状 + 折线叠加) ─────────────────────────
function buildDashTimeline(data) {
const dom = document.getElementById('dashTimelineChart');
if (!dom) return;
const decadeMap = {};
data.forEach(d => {
const dec = Math.floor(d.year / 10) * 10;
const key = `${dec}s`;
if (!decadeMap[key]) decadeMap[key] = 0;
decadeMap[key] += d.count;
});
const decades = Object.keys(decadeMap).sort();
const values = decades.map(d => decadeMap[d]);
const existing = echarts.getInstanceByDom(dom);
if (existing) existing.dispose();
const chart = echarts.init(dom);
chart.setOption({
tooltip: { trigger: 'axis' },
grid: { left: '3%', right: '4%', top: '8%', bottom: '3%', containLabel: true },
xAxis: { type: 'category', data: decades, axisLabel: { color: '#64748b', fontSize: 10 }, axisLine: { lineStyle: { color: '#e2e8f0' } } },
yAxis: { type: 'value', name: '项目数', splitLine: { lineStyle: { type: 'dashed', color: '#f1f5f9' } } },
series: [
{ type: 'bar', data: values, barWidth: '50%', itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#1890FF' }, { offset: 1, color: '#91caff' }]), borderRadius: [6, 6, 0, 0] }, label: { show: true, position: 'top', color: '#64748b', fontSize: 10 } },
{ type: 'line', data: values, smooth: true, symbol: 'circle', symbolSize: 6, lineStyle: { color: '#f59e0b', width: 2.5 }, itemStyle: { color: '#f59e0b', borderColor: '#fff', borderWidth: 2 }, label: { show: false } }
]
});
dashCharts.timeline = chart;
}
// ── 3. 领域预算 Top5 迷你条 ──────────────────────────────────
function buildDashDomainTop5(data) {
const barsDom = document.getElementById('dashDomainMiniBars');
if (!barsDom) return;
const top5 = [...data].sort((a, b) => (b.budgetTotal || 0) - (a.budgetTotal || 0)).slice(0, 5);
const maxBudget = Math.max(...top5.map(d => d.budgetTotal || 0), 1);
barsDom.innerHTML = top5.map((d, i) => {
const pct = Math.round(((d.budgetTotal || 0) / maxBudget) * 100);
return `<div>
<div class="flex justify-between text-[11px] mb-0.5">
<span class="font-medium text-slate-700 truncate mr-2" title="${d.domain}">${d.domain}</span>
<span class="text-slate-400 font-mono whitespace-nowrap">${((d.budgetTotal||0)/10000).toFixed(1)}亿</span>
</div>
<div class="w-full bg-slate-100 rounded-full h-1.5 overflow-hidden">
<div class="h-full rounded-full transition-all duration-700" style="width:${pct}%;background:${DASH_COLORS[i]}"></div>
</div></div>`;
}).join('');
}
// ── 4. AI 情报研判摘要 ─────────────────────────────────────
function buildDashAiSummary(report) {
const container = document.getElementById('dashAiSummary');
if (!container || !report.sections) return;
const overview = report.sections.find(s => s.title === '图谱全景概述');
if (!overview) { container.innerHTML = '<p class="text-slate-400">暂无研判摘要</p>'; return; }
container.innerHTML = `<p>${overview.content.replace(/<[^>]+>/g, '')}</p>`;
}
// ── 5. 重点预算项目 ─────────────────────────────────────────
function buildDashKeyProjects(report) {
const dom = document.getElementById('dashKeyProjects');
if (!dom) return;
const sec = report.sections?.find(s => s.title === '重大投入项目识别');
if (!sec) { dom.innerHTML = '<p class="text-slate-400 text-sm">暂无数据</p>'; return; }
const items = sec.content.split('').filter(Boolean).slice(0, 5);
dom.innerHTML = items.map((item, i) => {
const name = item.match(/<b>(.*?)<\/b>/)?.[1] || item.substring(0, 30);
const clean = item.replace(/<b>/g, '').replace(/<\/b>/g, '');
return `<div class="flex items-start gap-3 py-2.5 ${i > 0 ? 'border-t border-slate-50' : ''}">
<div class="w-6 h-6 rounded-full bg-blue-100 text-blue-600 flex items-center justify-center text-[10px] font-bold shrink-0 mt-0.5">${i+1}</div>
<div><p class="text-sm font-medium text-slate-800">${name}</p><p class="text-[11px] text-slate-400 mt-0.5 line-clamp-1">${clean}</p></div></div>`;
}).join('');
}
// ════════════════════════════════════════════════════════════════
// 数据表格 + CRUD
// ════════════════════════════════════════════════════════════════
async function dashShowTable(type) {
const panel = document.getElementById('dashDataTable');
const title = document.getElementById('dashTableTitle');
panel.classList.remove('hidden');
panel.scrollIntoView({ behavior: 'smooth' });
if (type === 'projects') {
title.innerHTML = '<div class="w-1 h-5 bg-primary rounded-full"></div>项目列表';
await loadProjectTable();
} else if (type === 'domains') {
title.innerHTML = '<div class="w-1 h-5 bg-purple-500 rounded-full"></div>技术领域分布';
await loadDomainTable();
} else if (type === 'institutions') {
title.innerHTML = '<div class="w-1 h-5 bg-amber-500 rounded-full"></div>合作机构列表';
await loadInstTable();
}
setTimeout(() => lucide.createIcons(), 100);
}
async function loadProjectTable() {
const tbody = document.getElementById('dashTableBody');
tbody.innerHTML = '<tr><td colspan="8" class="py-8 text-center text-slate-400">加载中...</td></tr>';
try {
const data = await fetch(`${API_BASE}/project_list`).then(r => r.json());
dashProjectData = data;
renderProjectRows(data);
document.getElementById('dashTableCount').textContent = `${data.length} 条记录`;
} catch (e) {
tbody.innerHTML = '<tr><td colspan="8" class="py-8 text-center text-red-400">加载失败,请检查后端服务</td></tr>';
}
}
function renderProjectRows(data) {
const tbody = document.getElementById('dashTableBody');
if (!data.length) {
tbody.innerHTML = '<tr><td colspan="8" class="py-8 text-center text-slate-400">暂无数据</td></tr>';
return;
}
tbody.innerHTML = data.map(p => {
const statusCls = p.status === '结题' ? 'bg-slate-100 text-slate-600' :
p.status === '研发中' ? 'bg-emerald-100 text-emerald-700' :
p.status === '进行中' ? 'bg-blue-100 text-blue-700' : 'bg-amber-100 text-amber-700';
return `<tr class="hover:bg-slate-50 transition-colors">
<td class="py-2 px-3 font-mono text-[10px] text-slate-500">${p.projectId}</td>
<td class="py-2 px-3 font-medium text-slate-800">${p.nameCn || '-'}</td>
<td class="py-2 px-3 text-slate-600">${p.domain || '-'}</td>
<td class="py-2 px-3"><span class="px-2 py-0.5 rounded-full text-[10px] font-medium ${statusCls}">${p.status || '-'}</span></td>
<td class="py-2 px-3 font-mono text-slate-600 text-right">${p.budgetVal ? p.budgetVal.toFixed(0) : '-'}</td>
<td class="py-2 px-3 text-slate-500">${p.startYear || '-'}</td>
<td class="py-2 px-3 text-slate-500">${p.endYear || '-'}</td>
<td class="py-2 px-3 text-right whitespace-nowrap">
<button onclick="dashEditRow('${p.projectId}')" class="text-blue-500 hover:text-blue-700 mr-2 text-[11px] font-medium">编辑</button>
<button onclick="dashDeleteRow('${p.projectId}')" class="text-red-400 hover:text-red-600 text-[11px] font-medium">删除</button>
</td></tr>`;
}).join('');
document.getElementById('dashTableCount').textContent = `${data.length} 条记录`;
}
async function loadDomainTable() {
const tbody = document.getElementById('dashTableBody');
tbody.innerHTML = '<tr><td colspan="8" class="py-8 text-center text-slate-400">加载中...</td></tr>';
try {
const data = await fetch(`${API_BASE}/domain_cluster`).then(r => r.json());
const sorted = [...data].sort((a, b) => (b.budgetTotal || 0) - (a.budgetTotal || 0));
tbody.innerHTML = sorted.map((d, i) => `<tr class="hover:bg-slate-50">
<td class="py-2 px-3 font-medium text-slate-400">${i + 1}</td>
<td class="py-2 px-3 font-medium text-slate-800">${d.domain}</td>
<td class="py-2 px-3 text-slate-600">${d.projectCount} 个项目</td>
<td class="py-2 px-3 font-mono text-slate-600 text-right">${((d.budgetTotal||0)/10000).toFixed(1)} 亿</td>
<td class="py-2 px-3 text-slate-500">${d.yearMin} - ${d.yearMax}</td>
<td class="py-2 px-3 text-slate-500">${(d.avgDuration||0).toFixed(1)} </td>
<td class="py-2 px-3 text-slate-500">${d.activeCount || 0} 活跃</td>
<td class="py-2 px-3"></td>
</tr>`).join('');
document.getElementById('dashTableCount').textContent = `${sorted.length} 个领域`;
} catch (e) {
tbody.innerHTML = '<tr><td colspan="8" class="py-8 text-center text-red-400">加载失败</td></tr>';
}
}
async function loadInstTable() {
const tbody = document.getElementById('dashTableBody');
tbody.innerHTML = '<tr><td colspan="8" class="py-8 text-center text-slate-400">加载中...</td></tr>';
try {
const data = await fetch(`${API_BASE}/institution_network`).then(r => r.json());
const sorted = [...data.nodes].sort((a, b) => (b.projectCount || 0) - (a.projectCount || 0));
tbody.innerHTML = sorted.map((n, i) => `<tr class="hover:bg-slate-50">
<td class="py-2 px-3 font-medium text-slate-400">${i + 1}</td>
<td class="py-2 px-3 font-medium text-slate-800">${n.name}</td>
<td class="py-2 px-3 text-slate-600">${n.id}</td>
<td class="py-2 px-3 text-slate-600">${n.projectCount || 0} 个项目</td>
<td class="py-2 px-3"></td>
<td class="py-2 px-3"></td>
<td class="py-2 px-3"></td>
<td class="py-2 px-3"></td>
</tr>`).join('');
document.getElementById('dashTableCount').textContent = `${sorted.length} 家机构`;
} catch (e) {
tbody.innerHTML = '<tr><td colspan="8" class="py-8 text-center text-red-400">加载失败</td></tr>';
}
}
// ── CRUD 操作 ─────────────────────────────────────────────────
function dashAddRow() {
dashEditTarget = null;
document.getElementById('dashModalTitle').textContent = '新增项目';
document.getElementById('dashF_projectId').value = '';
document.getElementById('dashF_projectId').disabled = false;
document.getElementById('dashF_nameCn').value = '';
document.getElementById('dashF_nameEn').value = '';
document.getElementById('dashF_domain').value = '';
document.getElementById('dashF_status').value = '研发中';
document.getElementById('dashF_budgetVal').value = '';
document.getElementById('dashF_startYear').value = '';
document.getElementById('dashF_endYear').value = '';
document.getElementById('dashEditModal').classList.remove('hidden');
setTimeout(() => lucide.createIcons(), 100);
}
function dashEditRow(projectId) {
const p = dashProjectData.find(d => d.projectId === projectId);
if (!p) return;
dashEditTarget = projectId;
document.getElementById('dashModalTitle').textContent = '编辑项目';
document.getElementById('dashF_projectId').value = p.projectId;
document.getElementById('dashF_projectId').disabled = true;
document.getElementById('dashF_nameCn').value = p.nameCn || '';
document.getElementById('dashF_nameEn').value = p.nameEn || '';
document.getElementById('dashF_domain').value = p.domain || '';
document.getElementById('dashF_status').value = p.status || '研发中';
document.getElementById('dashF_budgetVal').value = p.budgetVal || '';
document.getElementById('dashF_startYear').value = p.startYear || '';
document.getElementById('dashF_endYear').value = p.endYear || '';
document.getElementById('dashEditModal').classList.remove('hidden');
setTimeout(() => lucide.createIcons(), 100);
}
async function dashSaveRow() {
const pid = document.getElementById('dashF_projectId').value.trim();
if (!pid) { alert('项目编号不能为空'); return; }
const payload = {
projectId: pid,
nameCn: document.getElementById('dashF_nameCn').value.trim(),
nameEn: document.getElementById('dashF_nameEn').value.trim(),
domain: document.getElementById('dashF_domain').value.trim(),
status: document.getElementById('dashF_status').value,
budgetVal: parseFloat(document.getElementById('dashF_budgetVal').value) || 0,
budget: document.getElementById('dashF_budgetVal').value ? '$' + document.getElementById('dashF_budgetVal').value + '万' : '',
startYear: parseInt(document.getElementById('dashF_startYear').value) || 0,
endYear: parseInt(document.getElementById('dashF_endYear').value) || 0,
};
try {
const url = dashEditTarget
? `${API_BASE}/project/${dashEditTarget}`
: `${API_BASE}/project`;
const method = dashEditTarget ? 'PUT' : 'POST';
const resp = await fetch(url, {
method,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
const result = await resp.json();
if (!result.ok && result.error) { alert('保存失败: ' + result.error); return; }
document.getElementById('dashEditModal').classList.add('hidden');
await loadProjectTable(); // 刷新表格
} catch (e) {
alert('保存失败: ' + e.message);
}
}
async function dashDeleteRow(projectId) {
if (!confirm(`确定要删除项目 ${projectId} 吗?此操作不可撤销。`)) return;
try {
const resp = await fetch(`${API_BASE}/project/${projectId}`, { method: 'DELETE' });
const result = await resp.json();
if (!result.ok) { alert('删除失败'); return; }
await loadProjectTable(); // 刷新表格
} catch (e) {
alert('删除失败: ' + e.message);
}
}
// ════════════════════════════════════════════════════════════════
window.addEventListener('resize', () => {
clearTimeout(window._dashResizeTimer);
window._dashResizeTimer = setTimeout(() => {
Object.values(dashCharts).forEach(c => c && c.resize());
}, 200);
});
// ── 挂载 ──────────────────────────────────────────────────
window.initDashboardChart = initDashboardChart;
window.dashShowTable = dashShowTable;
window.dashEditRow = dashEditRow;
window.dashDeleteRow = dashDeleteRow;
window.dashAddRow = dashAddRow;
window.dashSaveRow = dashSaveRow;

@ -0,0 +1,216 @@
/* =============================================================================
* [MODULE: detail] 项目详情模块 动态加载
* ============================================================================= */
const API_BASE = window.APP_CONFIG.API_BASE;
let detailProjectId = null;
// ── 初始化 ──────────────────────────────────────────────────
function initDetail() {
const params = new URLSearchParams(window.location.search);
const pid = params.get('id');
if (pid) {
detailProjectId = pid;
loadProjectDetail(pid);
} else {
// 无 ID 时显示默认占位
showDetailPlaceholder();
}
}
// ── 加载项目详情 ────────────────────────────────────────────
async function loadProjectDetail(pid) {
showDetailSkeleton();
try {
const resp = await fetch(`${API_BASE}/project/${encodeURIComponent(pid)}/detail`);
if (!resp.ok) {
showDetailError('项目不存在或加载失败');
return;
}
const data = await resp.json();
renderDetail(data);
} catch (e) {
console.error('Detail load error:', e);
showDetailError('数据加载失败,请检查后端服务');
}
}
// ── 骨架屏 ──────────────────────────────────────────────────
function showDetailSkeleton() {
const titleEl = document.getElementById('detailTitle');
if (titleEl) titleEl.innerHTML = '<div class="h-8 bg-slate-100 rounded w-3/4 animate-pulse"></div>';
const abstractEl = document.getElementById('detailAbstractContent');
if (abstractEl) abstractEl.innerHTML = '<div class="space-y-2 animate-pulse"><div class="h-3 bg-slate-50 rounded w-full"></div><div class="h-3 bg-slate-50 rounded w-5/6"></div><div class="h-3 bg-slate-50 rounded w-4/6"></div></div>';
document.querySelectorAll('.detail-stat-val').forEach(el => { el.textContent = '...'; el.classList.add('skeleton-text'); });
document.querySelectorAll('.detail-tag-area').forEach(el => el.innerHTML = '<span class="px-3 py-1 bg-slate-50 rounded-full text-xs skeleton-text-sm">---</span>');
}
function showDetailError(msg) {
const titleEl = document.getElementById('detailTitle');
if (titleEl) titleEl.innerHTML = `<span class="text-red-400">${msg}</span>`;
}
function showDetailPlaceholder() {
const titleEl = document.getElementById('detailTitle');
if (titleEl) titleEl.innerHTML = '<span class="text-slate-400">请从知识图谱中选择项目查看详情</span>';
}
// ── 渲染详情 ────────────────────────────────────────────────
function renderDetail(data) {
// Title
const titleEl = document.getElementById('detailTitle');
if (titleEl) {
titleEl.innerHTML = `<span id="detailNameCn">${data.nameCn || data.projectId}</span>`;
titleEl.classList.remove('skeleton-text');
}
// Subtitle / English name
const enEl = document.getElementById('detailNameEn');
if (enEl) { enEl.textContent = data.nameEn || ''; enEl.classList.remove('skeleton-text'); }
// Status badge
const statusEl = document.getElementById('detailStatus');
if (statusEl) {
const st = data.status || '';
const colorMap = { '结题': 'bg-slate-100 text-slate-600', '研发中': 'bg-emerald-100 text-emerald-700', '进行中': 'bg-blue-100 text-blue-700', '已完成': 'bg-green-100 text-green-700' };
statusEl.textContent = st || '未知';
statusEl.className = `px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider rounded-full ${colorMap[st] || 'bg-slate-100 text-slate-500'}`;
}
// Project ID
const idEl = document.getElementById('detailProjectId');
if (idEl) { idEl.textContent = `ID: ${data.projectId}`; idEl.classList.remove('skeleton-text'); }
// Basic info grid
setDetailStat('detailOffice', data.office ? data.office.name : '-');
setDetailStat('detailDomain', data.domain || '-');
setDetailStat('detailPeriod', data.startYear && data.endYear ? `${data.startYear}${data.endYear}` : '-');
setDetailStat('detailBudget', data.budget || '-');
setDetailStat('detailManager', data.manager ? data.manager.name : '-');
// Abstract
const abstractEl = document.getElementById('detailAbstractContent');
if (abstractEl) {
abstractEl.innerHTML = (data.description || '暂无项目摘要').replace(/\n/g, '<br>');
abstractEl.classList.remove('line-clamp-4');
// Hide expand overlay if not too long
const overlay = document.getElementById('detailAbstractOverlay');
if (overlay && (data.description || '').length < 300) overlay.style.display = 'none';
}
// Keywords
const kwEl = document.getElementById('detailKeywords');
if (kwEl) {
const kws = (data.keywords || '').split(/[,,、]/).filter(Boolean);
if (kws.length) {
kwEl.innerHTML = kws.map(k => `<span class="px-3 py-1 bg-blue-50 text-blue-600 text-xs font-semibold rounded-full">${k.trim()}</span>`).join('');
} else {
kwEl.innerHTML = '<span class="text-slate-300 text-xs">暂无关键词</span>';
}
}
// Technology tags
const techEl = document.getElementById('detailTechnologies');
if (techEl) {
if (data.technologies && data.technologies.length) {
techEl.innerHTML = data.technologies.map(t => `<span class="px-3 py-1 bg-purple-50 text-purple-600 text-xs font-semibold rounded-full cursor-pointer hover:bg-purple-100" title="${t.description || ''}">${t.name}</span>`).join('');
} else {
techEl.innerHTML = '<span class="text-slate-300 text-xs">暂无</span>';
}
}
// Wikipedia link
const wikiEl = document.getElementById('detailWikipedia');
if (wikiEl) {
if (data.wikipediaUrl) {
wikiEl.innerHTML = `<a href="${data.wikipediaUrl}" target="_blank" class="inline-flex items-center gap-1 text-xs text-blue-500 hover:text-blue-600"><i data-lucide="external-link" class="w-3 h-3"></i> Wikipedia</a>`;
wikiEl.classList.remove('hidden');
} else {
wikiEl.classList.add('hidden');
}
}
// Institutions
const instEl = document.getElementById('detailInstitutions');
if (instEl) {
if (data.institutions && data.institutions.length) {
instEl.innerHTML = data.institutions.map(i => `<div class="flex items-center gap-2 py-1.5">
<i data-lucide="building-2" class="w-3.5 h-3.5 text-slate-400"></i>
<span class="text-xs text-slate-700">${i.name}</span></div>`).join('');
} else {
instEl.innerHTML = '<span class="text-slate-300 text-xs">暂无机构数据</span>';
}
}
// Manager info
const mgrDetailEl = document.getElementById('detailManagerInfo');
if (mgrDetailEl && data.manager) {
const m = data.manager;
mgrDetailEl.innerHTML = `<div class="text-xs font-bold text-slate-800">${m.name}</div>
${m.bio ? `<p class="text-[10px] text-slate-500 mt-1">${m.bio.substring(0, 150)}</p>` : ''}
${m.expertise ? `<p class="text-[10px] text-slate-400 mt-1">专长:${m.expertise}</p>` : ''}
${m.affiliation ? `<p class="text-[10px] text-slate-400">机构:${m.affiliation}</p>` : ''}`;
}
// Milestones timeline
const msEl = document.getElementById('detailMilestones');
if (msEl) {
if (data.milestones && data.milestones.length) {
const eraColors = { '1950s': '#ef4444','1960s': '#f97316','1970s': '#f59e0b','1980s': '#10b981','1990s': '#06b6d4','2000s': '#3B82F6','2010s': '#8b5cf6','2020s': '#ec4899' };
msEl.innerHTML = data.milestones.map((ms, i) => {
const color = eraColors[ms.era] || '#64748b';
return `<div class="relative pl-6 detail-timeline-dot pb-5 ${i === data.milestones.length - 1 ? '' : ''}">
<div class="absolute -left-[5px] top-1 w-2.5 h-2.5 rounded-full border-2 border-white" style="background:${color}"></div>
<p class="text-[10px] font-bold uppercase mb-1" style="color:${color}">${ms.era || ''}</p>
<p class="text-xs font-bold text-slate-800">${ms.title}</p>
${ms.historicalSignificance ? `<p class="text-[10px] text-slate-500 mt-1 line-clamp-2">${ms.historicalSignificance}</p>` : ''}
${ms.technicalDetail ? `<p class="text-[10px] text-slate-400 mt-0.5 line-clamp-2">${ms.technicalDetail}</p>` : ''}
</div>`;
}).join('');
} else {
msEl.innerHTML = '<p class="text-xs text-slate-300">暂无里程碑数据</p>';
}
}
lucide.createIcons();
}
function setDetailStat(id, val) {
const el = document.getElementById(id);
if (el) { el.textContent = val; el.classList.remove('skeleton-text'); }
}
// ── 导航到详情页 ───────────────────────────────────────────
function navigateToDetail(projectId) {
const newUrl = `${window.location.pathname}?id=${encodeURIComponent(projectId)}`;
window.history.pushState({ id: projectId }, '', newUrl);
detailProjectId = projectId;
showPage('detailPage');
setTimeout(() => loadProjectDetail(projectId), 100);
}
// ── 展开/收起摘要 ──────────────────────────────────────────
let detailAbstractExpanded = false;
function toggleDetailAbstract() {
const content = document.getElementById('detailAbstractContent');
const overlay = document.getElementById('detailAbstractOverlay');
const btn = overlay ? overlay.querySelector('button') : null;
if (!detailAbstractExpanded) {
content.classList.remove('line-clamp-4');
if (overlay) { overlay.classList.remove('detail-abstract-fade'); overlay.style.background = 'none'; overlay.style.position = 'relative'; }
if (btn) btn.innerHTML = '收起全文 <i data-lucide="chevron-up" class="w-3 h-3"></i>';
detailAbstractExpanded = true;
} else {
content.classList.add('line-clamp-4');
if (overlay) { overlay.classList.add('detail-abstract-fade'); overlay.style.background = ''; overlay.style.position = 'absolute'; }
if (btn) btn.innerHTML = '展开全文 <i data-lucide="chevron-down" class="w-3 h-3"></i>';
detailAbstractExpanded = false;
}
lucide.createIcons();
}
// ── 挂载到 window ──────────────────────────────────────────
window.initDetail = initDetail;
window.navigateToDetail = navigateToDetail;
window.toggleDetailAbstract = toggleDetailAbstract;
window.loadProjectDetail = loadProjectDetail;

@ -0,0 +1,40 @@
/* =============================================================================
* [MODULE: governance] 数据治理模块
* 包含switchGovTab三Tab切换toggleGovModal导入弹窗
* clearGovSelection清空批量选择checkbox 批量选择委托事件
* ============================================================================= */
function switchGovTab(tab) {
const tabs = ['governance', 'crawler', 'backup'];
tabs.forEach(t => {
const btn = document.getElementById(`gtab-${t}`);
const panel = document.getElementById(`gpanel-${t}`);
const isActive = t === tab;
if (btn) {
btn.classList.toggle('text-primary', isActive);
btn.classList.toggle('border-b-2', isActive);
btn.classList.toggle('border-primary', isActive);
btn.classList.toggle('text-slate-500', !isActive);
}
if (panel) {
panel.classList.toggle('hidden', !isActive);
panel.classList.toggle('flex', isActive);
}
});
}
function toggleGovModal() {
document.getElementById('govImportModal').classList.toggle('hidden');
setTimeout(() => lucide.createIcons(), 50);
}
function clearGovSelection() {
document.querySelectorAll('.gov-row-cb').forEach(cb => cb.checked = false);
document.getElementById('govSelectAll').checked = false;
document.getElementById('govBatchBar').classList.add('hidden');
document.getElementById('govBatchBar').classList.remove('flex');
}
// ── 挂载到 window供 HTML onclick 和跨模块调用使用
window.switchGovTab = switchGovTab;
window.toggleGovModal = toggleGovModal;
window.clearGovSelection = clearGovSelection;

@ -0,0 +1,572 @@
/* =============================================================================
* [MODULE: graph] 可视化分析模块 (API 驱动 连接 graph_backend)
* ============================================================================= */
const API_BASE = window.APP_CONFIG.API_BASE;
// ── 颜色/符号映射 ──────────────────────────────────────────────
const STATUS_COLOR = {
'结题': '#0EA5E9', '研发中': '#3B82F6', '已完成': '#22C55E', '进行中': '#F97316'
};
const TYPE_COLOR = {
'Project': '#1d4ed8',
'Technology': '#6d28d9',
'Institution': '#F59E0B',
'Manager': '#e67e22',
'Office': '#e74c3c',
};
const REL_COLOR = {
'主导方': '#ef5350',
'承担方': '#42a5f5',
'合作方': '#546e7a',
'USES_TECHNOLOGY': '#9c27b0',
'BELONGS_TO': '#ffa726',
'MANAGED_BY': '#ffd600',
'PARTICIPATED_BY': '#78909c'
};
const TYPE_SYMBOL = {
'Project': 'roundRect', 'Technology': 'diamond',
'Institution': 'circle', 'Manager': 'triangle', 'Office': 'rect'
};
const TYPE_ICON = {
'Project': 'rocket', 'Technology': 'cpu',
'Institution': 'building-2', 'Manager': 'user', 'Office': 'landmark'
};
const TYPE_LABEL_CN = {
'Project': '科研项目', 'Technology': '关键技术',
'Institution': '研究机构', 'Manager': '项目经理', 'Office': '办公室'
};
// ── 状态变量 ──────────────────────────────────────────────────
let graphChart = null;
let graphResizeTimer = null;
let graphData = { nodes: [], edges: [] };
let pathHighlight = new Set();
let breadcrumbTrail = []; // [{id, label, type, nodeData}, ...]
let filteredNodeSet = null; // Set of visible node IDs (null = show all)
let selectedNode = null; // Currently selected node for detail panel
// ── 工具函数 ──────────────────────────────────────────────────
function domainColor(domain) {
const colors = ['#42a5f5','#ab47bc','#26a69a','#ef5350','#ff7043',
'#66bb6a','#ffa726','#8d6e63','#5c6bc0','#29b6f6',
'#ec407a','#9ccc65','#78909c','#ffca28','#26c6da'];
let hash = 0;
for (let i = 0; i < (domain||'').length; i++) hash = ((hash<<5)-hash)+domain.charCodeAt(i);
return colors[Math.abs(hash) % colors.length];
}
// ── 数据加载 ──────────────────────────────────────────────────
async function reloadGraph() {
if (!graphChart) return;
// 清除两级过滤状态
breadcrumbTrail = [];
filteredNodeSet = null;
pathHighlight = new Set();
renderBreadcrumb();
const hideDarpa = document.getElementById('hideDarpa')?.checked ?? true;
const types = [];
if (document.getElementById('chkProj')?.checked) types.push('Project');
if (document.getElementById('chkTech')?.checked) types.push('Technology');
if (document.getElementById('chkInst')?.checked) types.push('Institution');
if (!types.length) { graphChart.clear(); return; }
try {
const resp = await fetch(
`${API_BASE}/graph?hide_darpa=${hideDarpa}&node_types=${types.join(',')}`
);
const data = await resp.json();
graphData = data;
renderGraph(data);
renderStatBar(data);
} catch (e) {
console.error('无法连接后端 API:', e);
}
}
// ── 图谱渲染 ──────────────────────────────────────────────────
function renderGraph(data) {
const ecNodes = data.nodes.map(n => {
const hl = pathHighlight.has(n.id);
const typeColor = (n.type === 'Project' ? (STATUS_COLOR[n.status] || '#42a5f5') : TYPE_COLOR[n.type]);
const color = hl ? '#ffd600' : (typeColor || '#42a5f5');
const symbol = TYPE_SYMBOL[n.type] || 'circle';
const size = n.size ? n.size * 1.5 : 28;
return {
id: n.id, name: n.label, _raw: n,
symbol, symbolSize: hl ? size * 1.8 : size,
itemStyle: {
color,
opacity: pathHighlight.size > 0 && !hl ? 0.18 : 1,
borderColor: hl ? '#fff' : 'transparent',
borderWidth: hl ? 3 : 0,
shadowBlur: hl ? 18 : 0,
shadowColor: hl ? '#ffd60088' : 'transparent'
},
emphasis: { scale: true, itemStyle: { borderColor: '#4fc3f7', borderWidth: 2 } },
label: {
show: true,
position: 'bottom',
color: hl ? '#f59e0b' : '#000000',
fontSize: hl ? 12 : 10,
fontWeight: hl ? 'bold' : 'normal',
distance: 4
}
};
});
const ecEdges = data.edges.map(e => {
const rt = e.relationType || e.relType || '';
const hl = pathHighlight.has(e.source) && pathHighlight.has(e.target);
const col = REL_COLOR[rt] || REL_COLOR[e.relType] || '#475569';
return {
source: e.source, target: e.target,
lineStyle: {
color: hl ? '#ffd600' : col,
width: hl ? 4 : 1,
opacity: pathHighlight.size > 0 ? (hl ? 1 : 0.08) : 0.55,
curveness: 0.08,
type: e.relType === 'USES_TECHNOLOGY' ? 'dashed' : 'solid',
shadowBlur: hl ? 8 : 0,
shadowColor: hl ? '#ffd60066' : 'transparent'
}
};
});
graphChart.setOption({
backgroundColor: 'transparent',
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(255,255,255,0.96)',
borderColor: 'rgba(59,130,246,0.25)',
textStyle: { color: '#1e293b', fontSize: 11 },
formatter: p => {
if (p.dataType !== 'node') return '';
const n = p.data._raw; if (!n) return p.data.name;
if (n.type === 'Project') {
const kws = n.keywords || '';
return `<div style="font-weight:bold;font-size:13px;margin-bottom:2px">${n.nameCn||n.label}</div>` +
(n.nameEn ? `<div style="color:#475569;font-size:10px">${n.nameEn}</div>` : '') +
`<div style="margin-top:4px;font-size:10px">领域:${n.domain||'-'} 状态:<span style="color:${STATUS_COLOR[n.status]||'#aaa'}">${n.status||'-'}</span></div>` +
`<div style="font-size:10px">预算:${n.budget||'-'} ${n.startYear||'?'}${n.endYear||'?'}</div>` +
(kws ? `<div style="margin-top:2px;font-size:9px;color:#94a3b8">关键词:${kws}</div>` : '') +
`<div style="margin-top:3px;font-size:9px;color:#3B82F6">点击查看详情 →</div>`;
}
if (n.type === 'Technology') {
const desc = n.description || '';
const descShort = desc.length > 100 ? desc.substring(0, 100) + '...' : desc;
return `<div style="font-weight:bold">${n.label}</div><div style="font-size:10px;color:#94a3b8">关联项目:${n.projectCount||0} 个</div>` +
(descShort ? `<div style="margin-top:3px;font-size:10px;color:#64748b;line-height:1.4;max-width:220px">${descShort}</div>` : '');
}
if (n.type === 'Institution') {
const desc = n.description || '';
const descShort = desc.length > 100 ? desc.substring(0, 100) + '...' : desc;
return `<div style="font-weight:bold">${n.label}</div><div style="font-size:10px;color:#94a3b8">参与项目:${n.projectCount||0} 个</div>` +
(descShort ? `<div style="margin-top:3px;font-size:10px;color:#64748b;line-height:1.4;max-width:220px">${descShort}</div>` : '');
}
if (n.type === 'Office') {
const desc = n.description || '';
const descShort = desc.length > 100 ? desc.substring(0, 100) + '...' : desc;
const director = n.director || '';
return `<div style="font-weight:bold">${n.label}</div><div style="font-size:10px;color:#94a3b8">项目:${n.projectCount||0} 个</div>` +
(director ? `<div style="font-size:10px;color:#64748b">主任:${director}</div>` : '') +
(descShort ? `<div style="margin-top:2px;font-size:10px;color:#64748b;line-height:1.4;max-width:220px">${descShort}</div>` : '');
}
return `<div style="font-weight:bold">${n.label}</div>`;
}
},
series: [{
type: 'graph', layout: 'force', roam: true, draggable: true,
data: ecNodes, edges: ecEdges,
force: { repulsion: 500, edgeLength: [90, 300], gravity: 0.06, friction: 0.6 },
emphasis: { lineStyle: { opacity: 0.9 } }
}]
}, true);
}
// ── 统计栏 ────────────────────────────────────────────────────
function renderStatBar(data) {
const c = t => data.nodes.filter(n => n.type === t).length;
const nc = c('Project') + c('Technology') + c('Institution') + c('Manager') + c('Office');
const ec = data.edges.length;
// Legend overlay
const gn = document.getElementById('graphNodeCount');
const ge = document.getElementById('graphEdgeCount');
if (gn) gn.textContent = nc;
if (ge) ge.textContent = ec;
// Right panel global stats
const tn = document.getElementById('gspTotalNodes');
const te = document.getElementById('gspTotalEdges');
const pc = document.getElementById('gspProjCount');
const tc = document.getElementById('gspTechInstCount');
if (tn) tn.textContent = nc;
if (te) te.textContent = ec;
if (pc) pc.textContent = c('Project');
if (tc) tc.textContent = `${c('Technology')} / ${c('Institution')}`;
}
// ── 节点详情面板 ──────────────────────────────────────────────
function renderGraphDetail(n) {
if (!n) return;
const cat = TYPE_LABEL_CN[n.type] || n.type || '';
const color = n.type === 'Project' ? (STATUS_COLOR[n.status] || '#1d4ed8') : (TYPE_COLOR[n.type] || '#fff');
const icon = TYPE_ICON[n.type] || 'info';
const wrap = document.getElementById('gsp-icon-wrap');
if (wrap) { wrap.style.background = `${color}22`; wrap.style.borderColor = `${color}55`; }
const iconEl = document.getElementById('gsp-icon');
if (iconEl) { iconEl.setAttribute('data-lucide', icon); iconEl.style.color = color; }
const catEl = document.getElementById('gsp-cat');
if (catEl) { catEl.textContent = cat; catEl.style.color = color; catEl.style.background = `${color}18`; }
const titleEl = document.getElementById('gsp-title');
if (titleEl) titleEl.textContent = n.nameCn || n.label || '';
const orgEl = document.getElementById('gsp-org');
if (orgEl) {
if (n.type === 'Project') orgEl.textContent = n.nameEn || '';
else if (n.type === 'Technology') orgEl.textContent = `关联项目: ${n.projectCount || 0}`;
else if (n.type === 'Institution') orgEl.textContent = `参与项目: ${n.projectCount || 0}`;
else orgEl.textContent = '';
}
const centEl = document.getElementById('gsp-centrality');
if (centEl) {
centEl.textContent = n.size ? n.size.toFixed(1) : '--';
centEl.style.color = color;
}
const degEl = document.getElementById('gsp-degree');
if (degEl) degEl.textContent = n.projectCount || '--';
const summaryEl = document.getElementById('gsp-summary');
if (summaryEl) {
if (n.type === 'Project') {
const desc = n.description || '';
const descShort = desc.length > 150 ? desc.substring(0, 150) + '...' : desc;
summaryEl.innerHTML = (descShort ? `<span class="text-xs text-slate-500">${descShort}</span><br>` : '') +
`<span class="text-[10px] text-slate-400">领域:${n.domain||'-'} | 状态:${n.status||'-'} | 周期:${n.startYear||'?'}${n.endYear||'?'}</span>`;
} else {
summaryEl.textContent = `${cat}节点在图谱中共关联 ${n.projectCount||0} 个项目`;
}
}
// Detail page link for Projects
const detailBtn = document.getElementById('gsp-detail-btn');
if (detailBtn) {
if (n.type === 'Project') {
detailBtn.classList.remove('hidden');
detailBtn.onclick = () => navigateToDetail(n.id);
} else {
detailBtn.classList.add('hidden');
}
}
lucide.createIcons();
}
// ══════════════════════════════════════════════════════════════
// 两级关系过滤 + 面包屑导航
// ══════════════════════════════════════════════════════════════
function computeTwoHopNeighbors(startNodeId) {
const adj = new Map();
for (const e of graphData.edges) {
if (!adj.has(e.source)) adj.set(e.source, new Set());
if (!adj.has(e.target)) adj.set(e.target, new Set());
adj.get(e.source).add(e.target);
adj.get(e.target).add(e.source);
}
const visited = new Set([startNodeId]);
const queue = [{ nodeId: startNodeId, depth: 0 }];
while (queue.length) {
const { nodeId, depth } = queue.shift();
if (depth >= 2) continue;
const neighbors = adj.get(nodeId);
if (!neighbors) continue;
for (const nb of neighbors) {
if (!visited.has(nb)) {
visited.add(nb);
queue.push({ nodeId: nb, depth: depth + 1 });
}
}
}
return visited;
}
function renderFilteredGraph() {
if (filteredNodeSet === null) {
renderGraph(graphData);
return;
}
const filtered = {
nodes: graphData.nodes.filter(n => filteredNodeSet.has(n.id)),
edges: graphData.edges.filter(e => filteredNodeSet.has(e.source) && filteredNodeSet.has(e.target))
};
renderGraph(filtered);
}
function renderBreadcrumb() {
const bar = document.getElementById('graphBreadcrumb');
const path = document.getElementById('breadcrumbPath');
if (!bar || !path) return;
if (breadcrumbTrail.length === 0) {
bar.style.display = 'none';
return;
}
bar.style.display = 'flex';
// "全部" 起始段
let html = `<button onclick="breadcrumbReset()" class="text-blue-500 hover:text-blue-600 font-medium transition-colors px-1" title="显示全图">全部</button>`;
for (let i = 0; i < breadcrumbTrail.length; i++) {
const item = breadcrumbTrail[i];
const isLast = i === breadcrumbTrail.length - 1;
const color = TYPE_COLOR[item.type] || '#94a3b8';
html += `<span class="text-slate-600">/</span>`;
if (isLast) {
html += `<span class="font-bold text-slate-800 px-1" style="font-size:11px">${item.label}</span>`;
} else {
html += `<button onclick="breadcrumbGoTo(${i})" class="text-slate-500 hover:text-slate-800 transition-colors px-1" style="font-size:10px;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="${item.label}">${item.label}</button>`;
}
}
path.innerHTML = html;
setTimeout(() => lucide.createIcons(), 50);
}
function focusNode(nodeData) {
const nodeId = nodeData.id;
const nodeLabel = nodeData.nameCn || nodeData.label || nodeId;
const shortLabel = nodeLabel.length > 10 ? nodeLabel.slice(0, 10) + '…' : nodeLabel;
// 追加到面包屑
breadcrumbTrail.push({ id: nodeId, label: shortLabel, type: nodeData.type, nodeData });
// 计算 2-hop 邻居
filteredNodeSet = computeTwoHopNeighbors(nodeId);
renderFilteredGraph();
renderBreadcrumb();
}
function breadcrumbBack() {
breadcrumbTrail.pop();
if (breadcrumbTrail.length === 0) {
// 恢复全量视图
filteredNodeSet = null;
renderGraph(graphData);
renderBreadcrumb();
// 重置路径高亮
pathHighlight = new Set();
return;
}
// 对上一个节点重新过滤
const prev = breadcrumbTrail[breadcrumbTrail.length - 1];
filteredNodeSet = computeTwoHopNeighbors(prev.id);
renderFilteredGraph();
renderBreadcrumb();
}
function breadcrumbReset() {
breadcrumbTrail = [];
filteredNodeSet = null;
pathHighlight = new Set();
renderGraph(graphData);
renderBreadcrumb();
}
function focusSelectedNode() {
if (!selectedNode) return;
focusNode(selectedNode);
renderGraphDetail(selectedNode);
}
function breadcrumbGoTo(index) {
// 裁剪到指定位置
breadcrumbTrail = breadcrumbTrail.slice(0, index + 1);
const target = breadcrumbTrail[index];
filteredNodeSet = computeTwoHopNeighbors(target.id);
renderFilteredGraph();
renderBreadcrumb();
}
// ── 初始化 ────────────────────────────────────────────────────
function initGraph() {
const dom = document.getElementById('mainGraph');
if (!dom) return;
if (graphChart) { graphChart.dispose(); graphChart = null; }
graphChart = echarts.init(dom);
pathHighlight = new Set();
// 节点单击 → 右侧详情面板(不改变图谱过滤状态)
graphChart.on('click', p => {
if (p.dataType === 'node' && p.data._raw) {
selectedNode = p.data._raw;
// 确保右侧面板可见
const panel = document.getElementById('graphSidePanel');
if (panel && panel.style.width === '0px') {
panel.style.width = '380px';
panel.style.overflow = '';
setTimeout(() => { if (graphChart) graphChart.resize(); }, 520);
}
renderGraphDetail(selectedNode);
// 更新底部按钮跳转目标
const archiveBtn = document.getElementById('gsp-archive-btn');
if (archiveBtn && selectedNode.type === 'Project') {
archiveBtn.onclick = () => { if (selectedNode) navigateToDetail(selectedNode.id); };
}
}
});
// 节点双击 → 两级关系过滤 + 面包屑
graphChart.on('dblclick', p => {
if (p.dataType === 'node' && p.data._raw) {
focusNode(p.data._raw);
}
});
reloadGraph();
initNodeList();
}
// ── 视图操作 ──────────────────────────────────────────────────
function resetGraphView() {
if (graphChart) graphChart.dispatchAction({ type: 'restore' });
}
function changeLayout(val) {
if (!graphChart) return;
graphChart.setOption({ series: [{ layout: val }] });
}
function switchGraphTab(tab) {
['proj','tech','org'].forEach(t => {
const btn = document.getElementById(`gtab-${t}`);
if (!btn) return;
if (t === tab) { btn.classList.add('bg-blue-600','text-white'); btn.classList.remove('text-slate-600'); }
else { btn.classList.remove('bg-blue-600','text-white'); btn.classList.add('text-slate-600'); }
});
}
function toggleGraphSidebar() {
const panel = document.getElementById('graphSidePanel');
if (!panel) return;
const isOpen = panel.style.width !== '0px';
panel.style.width = isOpen ? '0px' : '380px';
panel.style.overflow = isOpen ? 'hidden' : '';
setTimeout(() => { if (graphChart) graphChart.resize(); }, 520);
}
// ── 最短路径查询 ──────────────────────────────────────────────
let nodeListCache = [];
async function initNodeList() {
try {
const resp = await fetch(`${API_BASE}/node_list`);
nodeListCache = await resp.json();
populateSelect(document.getElementById('pathFrom'), nodeListCache);
populateSelect(document.getElementById('pathTo'), nodeListCache);
} catch (e) { console.error('无法加载节点列表:', e); }
}
function populateSelect(sel, nodes) {
if (!sel) return;
sel.innerHTML = '<option value="">── 选择节点 ──</option>';
let currentType = '';
nodes.forEach(n => {
if (n.type !== currentType) {
currentType = n.type;
const opt = document.createElement('option');
opt.disabled = true;
opt.textContent = `── ${TYPE_LABEL_CN[currentType] || currentType} ──`;
opt.style.color = '#64748b';
sel.appendChild(opt);
}
const opt = document.createElement('option');
opt.value = n.id;
opt.textContent = n.label;
sel.appendChild(opt);
});
}
async function queryPath() {
const fromId = document.getElementById('pathFrom')?.value;
const toId = document.getElementById('pathTo')?.value;
const ignoreDarpa = document.getElementById('pathIgnoreDarpa')?.checked ?? true;
const resultBox = document.getElementById('pathResult');
if (!fromId || !toId) {
if (resultBox) resultBox.textContent = '请先选择起点和终点';
return;
}
if (resultBox) resultBox.textContent = '查询中...';
try {
const resp = await fetch(
`${API_BASE}/shortest_path?from_id=${encodeURIComponent(fromId)}&to_id=${encodeURIComponent(toId)}&ignore_darpa=${ignoreDarpa}`
);
const data = await resp.json();
pathHighlight = new Set();
if (data.pathNodes) {
data.pathNodes.forEach(n => pathHighlight.add(n.id));
const names = data.pathNodes.map(n => n.label).join(' → ');
if (resultBox) resultBox.innerHTML = `<span style="color:#52b788">路径长度: ${data.pathLen} 跳</span><br>${names}`;
} else if (data.error) {
if (resultBox) resultBox.textContent = data.error;
} else {
if (resultBox) resultBox.textContent = '未找到路径';
}
renderGraph(graphData);
} catch (e) {
if (resultBox) resultBox.textContent = '查询失败';
console.error(e);
}
}
function clearPath() {
pathHighlight = new Set();
const resultBox = document.getElementById('pathResult');
if (resultBox) resultBox.textContent = '';
renderGraph(graphData);
}
// ── 导出 ──────────────────────────────────────────────────────
function exportGraphImage() {
if (!graphChart) return;
const url = graphChart.getDataURL({ type: 'png', pixelRatio: 2, backgroundColor: '#ffffff' });
const a = document.createElement('a'); a.href = url; a.download = 'DARPA知识图谱.png'; a.click();
}
// ── resize ────────────────────────────────────────────────────
window.addEventListener('resize', () => {
clearTimeout(graphResizeTimer);
graphResizeTimer = setTimeout(() => { if (graphChart) graphChart.resize(); }, 200);
});
// ── 挂载到 window ────────────────────────────────────────────
window.initGraph = initGraph;
window.reloadGraph = reloadGraph;
window.resetGraphView = resetGraphView;
window.changeLayout = changeLayout;
window.switchGraphTab = switchGraphTab;
window.toggleGraphSidebar = toggleGraphSidebar;
window.queryPath = queryPath;
window.clearPath = clearPath;
window.exportGraphImage = exportGraphImage;
window.breadcrumbBack = breadcrumbBack;
window.breadcrumbReset = breadcrumbReset;
window.breadcrumbGoTo = breadcrumbGoTo;
window.focusSelectedNode = focusSelectedNode;

@ -0,0 +1,56 @@
/* =============================================================================
* [GLOBAL] 主入口 汇总所有模块
* 修改某个功能时直接编辑对应的模块文件即可
* ============================================================================= */
// 核心路由showPage / PAGE_NAV_KEY / togglePwd
import './core.js';
// 身份验证AES-128-GCM / login / register / logout
import './auth.js';
// 各功能页模块
import './dashboard.js';
import './search.js';
import './detail.js';
import './graph.js';
import './trend.js';
import './wiki.js';
import './governance.js';
// 资料弹窗 & 侧边栏动态更新
import './profile.js';
/* =============================================================================
* [GLOBAL] 初始化入口
* 会话恢复 + governance checkbox 委托事件
* ============================================================================= */
document.addEventListener('DOMContentLoaded', async () => {
// 如果浏览器缓存被清除,从后端本地文件恢复账号
await restoreUsers();
// 会话恢复:若已登录则直接进入工作台,否则显示登录页
const savedUser = loadSession();
if (savedUser) {
showPage('dashboardPage');
initProfile();
} else {
showPage('loginPage');
}
// Governance checkbox logic (delegated)
document.addEventListener('change', e => {
if (e.target.id === 'govSelectAll') {
document.querySelectorAll('.gov-row-cb').forEach(cb => cb.checked = e.target.checked);
}
if (e.target.id === 'govSelectAll' || e.target.classList.contains('gov-row-cb')) {
const count = Array.from(document.querySelectorAll('.gov-row-cb')).filter(cb => cb.checked).length;
const bar = document.getElementById('govBatchBar');
if (count > 0) {
bar.classList.remove('hidden'); bar.classList.add('flex');
document.getElementById('govSelectedCount').textContent = count;
} else {
bar.classList.add('hidden'); bar.classList.remove('flex');
}
}
});
});

@ -0,0 +1,469 @@
/* =============================================================================
* [MODULE: profile] 资料弹窗 / 头像上传 / 侧边栏动态更新 / 管理员面板
* ============================================================================= */
const PROFILE_API = window.APP_CONFIG.API_BASE;
let _profileData = null; // cached user profile from server
/* ── Modal open/close ────────────────────────────────────────── */
async function openProfileModal() {
const username = loadSession();
if (!username) return;
const modal = document.getElementById('profileModal');
modal.classList.add('active');
modal.classList.remove('hidden');
await _loadAndFill(username);
setTimeout(() => lucide.createIcons(), 100);
}
function closeProfileModal() {
const modal = document.getElementById('profileModal');
modal.classList.remove('active');
modal.classList.add('hidden');
clearPwdMsg();
}
/* ── Fetch user profile from server ─────────────────────────── */
async function _loadAndFill(username) {
document.getElementById('profileUsername').value = username;
try {
const resp = await fetch(`${PROFILE_API}/users/${encodeURIComponent(username)}`);
if (!resp.ok) throw new Error('not found');
_profileData = await resp.json();
} catch {
// fallback: use localStorage data
const users = getUsers();
_profileData = { name: username, role: 'user', avatar: null };
if (users[username]) {
_profileData.name = users[username].name || username;
_profileData.role = users[username].role || 'user';
_profileData.avatar = users[username].avatar || null;
}
}
document.getElementById('profileName').value = _profileData.name || username;
document.getElementById('profileRole').value = _profileData.role === 'admin' ? '管理员' : '普通用户';
// avatar
_renderProfileAvatar();
// admin panel
if (_profileData.role === 'admin') {
document.getElementById('profileAdminPanel').classList.remove('hidden');
_loadAdminPanel();
} else {
document.getElementById('profileAdminPanel').classList.add('hidden');
}
}
function _renderProfileAvatar() {
const img = document.getElementById('profileAvatarImg');
const icon = document.getElementById('profileAvatarIcon');
if (_profileData.avatar) {
img.src = _profileData.avatar;
img.classList.remove('hidden');
icon.classList.add('hidden');
} else {
img.src = '';
img.classList.add('hidden');
icon.classList.remove('hidden');
}
}
/* ── Avatar upload / remove ─────────────────────────────────── */
async function handleAvatarUpload(input) {
const file = input.files[0];
if (!file) return;
if (file.size > 500 * 1024) {
alert('图片大小不能超过 500KB');
input.value = '';
return;
}
// resize + compress to base64
const dataUrl = await _resizeImage(file, 200, 200, 0.6);
const username = loadSession();
if (!username) return;
// update UI immediately
_profileData.avatar = dataUrl;
_renderProfileAvatar();
// save to server
try {
await fetch(`${PROFILE_API}/users/${encodeURIComponent(username)}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ avatar: dataUrl })
});
} catch {}
// also update localStorage
const users = getUsers();
if (users[username]) {
users[username].avatar = dataUrl;
saveUsers(users);
}
updateSidebarUser();
updateHeaderAvatar();
input.value = '';
}
async function removeAvatar() {
const username = loadSession();
if (!username) return;
_profileData.avatar = null;
_renderProfileAvatar();
try {
await fetch(`${PROFILE_API}/users/${encodeURIComponent(username)}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ avatar: null })
});
} catch {}
const users = getUsers();
if (users[username]) {
users[username].avatar = null;
saveUsers(users);
}
updateSidebarUser();
updateHeaderAvatar();
}
function _resizeImage(file, maxW, maxH, quality) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
const img = new Image();
img.onload = () => {
let w = img.width, h = img.height;
if (w > maxW) { h = h * maxW / w; w = maxW; }
if (h > maxH) { w = w * maxH / h; h = maxH; }
const canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, w, h);
resolve(canvas.toDataURL('image/jpeg', quality));
};
img.src = reader.result;
};
reader.readAsDataURL(file);
});
}
/* ── Change password ────────────────────────────────────────── */
async function changePassword() {
clearPwdMsg();
const oldPwd = document.getElementById('profileOldPwd').value;
const newPwd = document.getElementById('profileNewPwd').value;
const username = loadSession();
if (!username) return;
if (!oldPwd || !newPwd) {
_showPwdMsg('请填写当前密码和新密码', 'error');
return;
}
if (newPwd.length < 8) {
_showPwdMsg('新密码长度至少 8 位', 'error');
return;
}
const rules = [/[A-Z]/, /[a-z]/, /[0-9]/, /[^A-Za-z0-9]/];
for (const r of rules) {
if (!r.test(newPwd)) {
_showPwdMsg('新密码须含大写、小写、数字、特殊符号', 'error');
return;
}
}
// verify old password
const users = getUsers();
if (!users[username]) return;
const decrypted = await aesDecrypt(users[username].ciphertext, oldPwd);
if (decrypted !== 'DARPA_AUTH') {
_showPwdMsg('当前密码错误', 'error');
return;
}
// encrypt new password
const newCipher = await aesEncrypt('DARPA_AUTH', newPwd);
users[username].ciphertext = newCipher;
saveUsers(users);
try {
await fetch(`${PROFILE_API}/users/${encodeURIComponent(username)}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ciphertext: newCipher })
});
} catch {}
_showPwdMsg('密码修改成功!', 'success');
document.getElementById('profileOldPwd').value = '';
document.getElementById('profileNewPwd').value = '';
}
function _showPwdMsg(msg, type) {
const el = document.getElementById('profilePwdMsg');
el.textContent = msg;
el.classList.remove('hidden');
el.className = el.className.replace(/text-\S+-\d+/g, '');
el.classList.add(type === 'error' ? 'text-red-500' : 'text-emerald-500', 'text-xs');
}
function clearPwdMsg() {
const el = document.getElementById('profilePwdMsg');
el.classList.add('hidden');
el.textContent = '';
}
/* ── Sidebar & header dynamic update ────────────────────────── */
function updateSidebarUser() {
const username = loadSession();
if (!username) return;
// try localStorage first for speed
const users = getUsers();
let name = username, role = '普通用户', avatar = null;
if (users[username]) {
name = users[username].name || username;
role = users[username].role === 'admin' ? '管理员' : '普通用户';
avatar = users[username].avatar || null;
}
document.querySelectorAll('.sidebar-user-name').forEach(el => {
el.textContent = name;
});
document.querySelectorAll('.sidebar-user-role').forEach(el => {
el.textContent = role;
});
document.querySelectorAll('.sidebar-user-avatar').forEach(el => {
el.onclick = openProfileModal;
const img = el.querySelector('img');
const icon = el.querySelector('i');
if (avatar) {
if (img) {
img.src = avatar;
} else {
const newImg = document.createElement('img');
newImg.src = avatar;
newImg.className = 'w-full h-full rounded-full object-cover';
if (icon) icon.remove();
el.appendChild(newImg);
}
} else {
if (img) img.remove();
if (!icon) {
const newIcon = document.createElement('i');
newIcon.setAttribute('data-lucide', 'user');
newIcon.className = 'w-4 h-4';
el.appendChild(newIcon);
lucide.createIcons();
}
}
});
}
function updateHeaderAvatar() {
const username = loadSession();
if (!username) return;
const users = getUsers();
let avatar = null;
if (users[username]) {
avatar = users[username].avatar || null;
}
document.querySelectorAll('.header-user-avatar').forEach(el => {
const img = el.querySelector('img');
const icon = el.querySelector('i');
if (avatar) {
if (img) {
img.src = avatar;
} else {
const newImg = document.createElement('img');
newImg.src = avatar;
newImg.className = 'w-full h-full rounded-full object-cover';
if (icon) icon.remove();
el.appendChild(newImg);
}
} else {
if (img) img.remove();
if (!icon) {
const newIcon = document.createElement('i');
newIcon.setAttribute('data-lucide', 'user');
newIcon.className = 'w-4 h-4 text-slate-500';
el.appendChild(newIcon);
lucide.createIcons();
}
}
});
}
/* ── Admin panel ────────────────────────────────────────────── */
async function _loadAdminPanel() {
// Load user list
try {
const resp = await fetch(`${PROFILE_API}/users`);
const users = await resp.json();
_renderUserList(users);
} catch {
_renderUserList(getUsers());
}
// Load whitelist
try {
const resp = await fetch(`${PROFILE_API}/whitelist`);
const wl = await resp.json();
_renderWhitelistTags(wl.names || []);
} catch {
_renderWhitelistTags([]);
}
}
function _renderUserList(users) {
const container = document.getElementById('profileUserList');
const currentUser = loadSession();
let html = '';
const sorted = Object.entries(users).sort((a, b) => {
if ((a[1].role || 'user') === 'admin') return -1;
if ((b[1].role || 'user') === 'admin') return 1;
return (a[0] || '').localeCompare(b[0] || '');
});
for (const [username, data] of sorted) {
const name = (data && data.name) || username;
const role = (data && data.role) === 'admin' ? '管理员' : '用户';
const isSelf = username === currentUser;
html += `<div class="flex items-center justify-between p-2 bg-slate-50 rounded-lg">
<div class="flex-1 min-w-0">
<span class="text-xs font-bold text-slate-700 truncate">${_escHtml(name)}</span>
<span class="text-[10px] text-slate-400 ml-2">@${_escHtml(username)}</span>
${role === '管理员' ? '<span class="text-[10px] text-amber-500 ml-1">[' + role + ']</span>' : ''}
</div>
<div class="flex gap-1 shrink-0 ml-2">
${!isSelf && role !== '管理员' ? `<button onclick="resetUserPassword('${_escAttr(username)}')" class="px-2 py-1 text-[10px] bg-blue-50 hover:bg-blue-100 text-blue-600 rounded transition-colors">重置密码</button>
<button onclick="deleteUserAccount('${_escAttr(username)}')" class="px-2 py-1 text-[10px] bg-red-50 hover:bg-red-100 text-red-600 rounded transition-colors">删除</button>` : ''}
</div>
</div>`;
}
container.innerHTML = html || '<p class="text-xs text-slate-400">暂无用户</p>';
}
function _renderWhitelistTags(names) {
const container = document.getElementById('profileWhitelistTags');
if (!names.length) {
container.innerHTML = '<span class="text-xs text-slate-400">白名单为空</span>';
return;
}
container.innerHTML = names.map(n =>
`<span class="whitelist-tag">${_escHtml(n)}<button onclick="removeWhitelistName('${_escAttr(n)}')">&times;</button></span>`
).join('');
}
async function resetUserPassword(username) {
// Generate random password
const newPwd = _generatePwd();
const ciphertext = await aesEncrypt('DARPA_AUTH', newPwd);
try {
await fetch(`${PROFILE_API}/users/${encodeURIComponent(username)}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ciphertext })
});
} catch {}
// Update localStorage too
const users = getUsers();
if (users[username]) {
users[username].ciphertext = ciphertext;
saveUsers(users);
}
alert(`用户 ${username} 的密码已重置为: ${newPwd}\n请通知用户登录后修改密码。`);
_loadAdminPanel();
}
async function deleteUserAccount(username) {
if (!confirm(`确认删除用户 "${username}"?此操作不可恢复。`)) return;
try {
await fetch(`${PROFILE_API}/users/${encodeURIComponent(username)}`, { method: 'DELETE' });
} catch {}
const users = getUsers();
delete users[username];
saveUsers(users);
_loadAdminPanel();
}
async function addWhitelistName() {
const input = document.getElementById('profileWhitelistInput');
const name = input.value.trim();
if (!name) return;
try {
const resp = await fetch(`${PROFILE_API}/whitelist`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'add', names: [name] })
});
const wl = await resp.json();
_renderWhitelistTags(wl.names || []);
} catch {}
input.value = '';
}
async function removeWhitelistName(name) {
if (!confirm(`确认从白名单移除 "${name}"`)) return;
try {
const resp = await fetch(`${PROFILE_API}/whitelist`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'remove', names: [name] })
});
const wl = await resp.json();
_renderWhitelistTags(wl.names || []);
} catch {}
}
function _generatePwd() {
const upper = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
const lower = 'abcdefghjkmnpqrstuvwxyz';
const digits = '23456789';
const special = '!@#$%';
const all = upper + lower + digits + special;
let pwd = '';
pwd += upper[Math.floor(Math.random() * upper.length)];
pwd += lower[Math.floor(Math.random() * lower.length)];
pwd += digits[Math.floor(Math.random() * digits.length)];
pwd += special[Math.floor(Math.random() * special.length)];
for (let i = 4; i < 12; i++) {
pwd += all[Math.floor(Math.random() * all.length)];
}
return pwd.split('').sort(() => Math.random() - 0.5).join('');
}
// ── HTML escaping helpers ──────────────────────────────────────
function _escHtml(s) {
const d = document.createElement('div');
d.textContent = s;
return d.innerHTML;
}
function _escAttr(s) {
return s.replace(/'/g, "\\'").replace(/"/g, '&quot;').replace(/</g, '&lt;');
}
// ── Global init: called on page load after session is restored ─
function initProfile() {
updateSidebarUser();
updateHeaderAvatar();
// Make sidebar avatars clickable
document.querySelectorAll('.sidebar-user-avatar').forEach(el => {
el.onclick = openProfileModal;
});
}
// ── Exports to window ─────────────────────────────────────────
window.openProfileModal = openProfileModal;
window.closeProfileModal = closeProfileModal;
window.handleAvatarUpload = handleAvatarUpload;
window.removeAvatar = removeAvatar;
window.changePassword = changePassword;
window.updateSidebarUser = updateSidebarUser;
window.updateHeaderAvatar = updateHeaderAvatar;
window.resetUserPassword = resetUserPassword;
window.deleteUserAccount = deleteUserAccount;
window.addWhitelistName = addWhitelistName;
window.removeWhitelistName = removeWhitelistName;
window.initProfile = initProfile;

@ -0,0 +1,559 @@
/* =============================================================================
* [MODULE: search] 智能检索模块 全动态 API 驱动
* ============================================================================= */
const SEARCH_API = window.APP_CONFIG.API_BASE;
// ── 状态 ──────────────────────────────────────────────────────
let searchPageActive = false; // 是否已初始化
let searchState = {
mode: 'fuzzy', // fuzzy | precise | advanced
query: '',
preciseField: '',
page: 1,
perPage: 20,
sort: 'relevance',
domain: '',
status: '',
dateFrom: '',
dateTo: '',
activeDomainTags: [], // 侧栏领域筛选选中的标签
activeStatusTag: '',
dateRangeActive: false,
};
let searchFilters = null; // 缓存服务端返回的 domains
// ── 初始化入口 ──────────────────────────────────────────────────
function initSearchPage() {
if (searchPageActive) return;
searchPageActive = true;
// 模糊搜索 — 按钮点击 & Enter
const fuzzyBtn = document.getElementById('fuzzySearchBtn');
const fuzzyInput = document.getElementById('fuzzyInput');
if (fuzzyBtn) fuzzyBtn.addEventListener('click', () => {
searchState.mode = 'fuzzy';
searchState.query = fuzzyInput?.value.trim() || '';
searchState.page = 1;
executeSearch();
});
if (fuzzyInput) fuzzyInput.addEventListener('keydown', e => {
if (e.key === 'Enter') {
searchState.mode = 'fuzzy';
searchState.query = fuzzyInput.value.trim();
searchState.page = 1;
executeSearch();
}
});
// 精准搜索
const preciseBtn = document.getElementById('preciseSearchBtn');
const preciseField = document.getElementById('preciseField');
const preciseValue = document.getElementById('preciseValue');
if (preciseBtn) preciseBtn.addEventListener('click', () => {
searchState.mode = 'precise';
searchState.preciseField = preciseField?.value || '';
searchState.query = preciseValue?.value.trim() || '';
searchState.page = 1;
executeSearch();
});
if (preciseValue) preciseValue.addEventListener('keydown', e => {
if (e.key === 'Enter') preciseBtn?.click();
});
// 排序 & 每页条数
const sortSel = document.getElementById('searchSort');
if (sortSel) sortSel.addEventListener('change', () => {
searchState.sort = sortSel.value;
searchState.page = 1;
executeSearch();
});
const perPageSel = document.getElementById('searchPerPage');
if (perPageSel) perPageSel.addEventListener('change', () => {
searchState.perPage = parseInt(perPageSel.value) || 20;
searchState.page = 1;
executeSearch();
});
// 智能推荐 — 聚焦显示,失焦延迟隐藏
const fuzzyInputEl = document.getElementById('fuzzyInput');
if (fuzzyInputEl) {
fuzzyInputEl.addEventListener('focus', () => loadSuggestions());
fuzzyInputEl.addEventListener('blur', () => setTimeout(hideSuggestions, 250));
}
}
// ══════════════════════════════════════════════════════════════
// 筛选面板
// ══════════════════════════════════════════════════════════════
function initFilterPanel(domains) {
searchFilters = { domains: domains || [] };
renderDomainFilters();
renderStatusFilters();
}
function renderDomainFilters() {
const container = document.getElementById('sorg-list');
if (!container || !searchFilters) return;
const domains = searchFilters.domains || [];
container.innerHTML = domains.map((d, i) => {
const checked = searchState.activeDomainTags.includes(d.name);
return `<label class="flex items-center gap-2 text-sm text-slate-600 cursor-pointer hover:text-primary">
<input type="checkbox" value="${d.name}" ${checked ? 'checked' : ''} class="w-4 h-4 accent-primary domain-cb" onchange="toggleDomainFilter(this.value)">
<span class="flex-1 truncate">${d.name}</span>
<span class="text-[10px] bg-slate-100 px-1.5 rounded text-slate-400">${d.count}</span>
</label>`;
}).join('');
}
function renderStatusFilters() {
const container = document.getElementById('sstatus-list');
if (!container) return;
const statuses = ['研发中', '已完成', '结题', '进行中'];
container.innerHTML = statuses.map(s => {
const checked = searchState.activeStatusTag === s;
return `<label class="flex items-center gap-2 text-sm text-slate-600 cursor-pointer hover:text-primary">
<input type="radio" name="searchStatus" value="${s}" ${checked ? 'checked' : ''} class="w-4 h-4 accent-primary" onchange="toggleStatusFilter(this.value)">
<span>${s}</span>
</label>`;
}).join('');
}
function toggleDomainFilter(val) {
// 单选模式:已选中则取消,否则替换
if (searchState.activeDomainTags.includes(val)) {
searchState.activeDomainTags = [];
} else {
searchState.activeDomainTags = [val];
}
searchState.page = 1;
renderDomainFilters(); // 刷新 checkbox 状态
executeSearch();
renderActiveTags();
}
function toggleStatusFilter(val) {
if (searchState.activeStatusTag === val) {
searchState.activeStatusTag = '';
// 清除 radio 选中
document.querySelectorAll('input[name="searchStatus"]').forEach(r => r.checked = false);
} else {
searchState.activeStatusTag = val;
}
searchState.page = 1;
executeSearch();
renderActiveTags();
}
function applyDateFilter() {
const fromEl = document.getElementById('searchDateFrom');
const toEl = document.getElementById('searchDateTo');
searchState.dateFrom = fromEl?.value || '';
searchState.dateTo = toEl?.value || '';
searchState.page = 1;
searchState.dateRangeActive = !!(searchState.dateFrom || searchState.dateTo);
executeSearch();
renderActiveTags();
}
function clearDateFilter() {
const fromEl = document.getElementById('searchDateFrom');
const toEl = document.getElementById('searchDateTo');
if (fromEl) fromEl.value = '';
if (toEl) toEl.value = '';
searchState.dateFrom = '';
searchState.dateTo = '';
searchState.dateRangeActive = false;
searchState.page = 1;
executeSearch();
renderActiveTags();
}
function resetAllFilters() {
searchState.activeDomainTags = [];
searchState.activeStatusTag = '';
searchState.dateFrom = '';
searchState.dateTo = '';
searchState.dateRangeActive = false;
searchState.page = 1;
searchState.sort = 'relevance';
const sortSel = document.getElementById('searchSort');
if (sortSel) sortSel.value = 'relevance';
const fromEl = document.getElementById('searchDateFrom');
const toEl = document.getElementById('searchDateTo');
if (fromEl) fromEl.value = '';
if (toEl) toEl.value = '';
document.querySelectorAll('input[name="searchStatus"]').forEach(r => r.checked = false);
renderDomainFilters();
executeSearch();
renderActiveTags();
}
function renderActiveTags() {
const container = document.getElementById('activeFilterTags');
if (!container) return;
let tags = '';
searchState.activeDomainTags.forEach(d => {
tags += `<span class="flex items-center gap-1 px-2 py-1 bg-blue-50 text-primary rounded text-[10px] font-bold">${d} <i data-lucide="x" class="w-3 h-3 cursor-pointer" onclick="event.stopPropagation();toggleDomainFilter('${d.replace(/'/g,"\\'")}')"></i></span>`;
});
if (searchState.activeStatusTag) {
tags += `<span class="flex items-center gap-1 px-2 py-1 bg-emerald-50 text-emerald-600 rounded text-[10px] font-bold">${searchState.activeStatusTag} <i data-lucide="x" class="w-3 h-3 cursor-pointer" onclick="toggleStatusFilter('${searchState.activeStatusTag}')"></i></span>`;
}
if (searchState.dateRangeActive) {
const label = [searchState.dateFrom, searchState.dateTo].filter(Boolean).join(' — ');
tags += `<span class="flex items-center gap-1 px-2 py-1 bg-amber-50 text-amber-600 rounded text-[10px] font-bold">${label} <i data-lucide="x" class="w-3 h-3 cursor-pointer" onclick="clearDateFilter()"></i></span>`;
}
container.innerHTML = tags || '<span class="text-[10px] text-slate-400">无筛选条件</span>';
setTimeout(() => lucide.createIcons(), 60);
}
// ══════════════════════════════════════════════════════════════
// 核心搜索
// ══════════════════════════════════════════════════════════════
function buildSearchParams() {
const params = new URLSearchParams();
if (searchState.query) params.set('q', searchState.query);
params.set('page', searchState.page);
params.set('per_page', searchState.perPage);
params.set('sort', searchState.sort);
// 搜索类型 & 精准字段
params.set('type', searchState.mode);
if (searchState.mode === 'precise' && searchState.preciseField) {
params.set('field', searchState.preciseField);
}
if (searchState.activeDomainTags.length > 0) {
params.set('domain', searchState.activeDomainTags.join(','));
}
if (searchState.activeStatusTag) params.set('status', searchState.activeStatusTag);
if (searchState.dateFrom) params.set('date_from', searchState.dateFrom);
if (searchState.dateTo) params.set('date_to', searchState.dateTo);
return params;
}
async function executeSearch() {
// 显示 loading
const container = document.getElementById('searchResults');
if (container) container.innerHTML = renderSkeleton();
const pagination = document.getElementById('searchPagination');
if (pagination) pagination.innerHTML = '';
try {
const resp = await fetch(`${SEARCH_API}/search?${buildSearchParams().toString()}`);
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const data = await resp.json();
// 初始化筛选面板(首次加载)
if (!searchFilters && data.filters?.domains) {
initFilterPanel(data.filters.domains);
}
renderSearchResults(data);
renderPagination(data);
updateSearchStats(data);
} catch (e) {
console.error('[search] API 调用失败:', e);
if (container) container.innerHTML = renderError();
}
}
// ══════════════════════════════════════════════════════════════
// 结果渲染
// ══════════════════════════════════════════════════════════════
function renderSkeleton() {
let html = '';
for (let i = 0; i < 5; i++) {
html += `<div class="bg-white p-5 rounded-xl border border-slate-100 animate-pulse">
<div class="flex justify-between">
<div class="flex-1 space-y-3">
<div class="h-5 bg-slate-200 rounded w-3/4"></div>
<div class="flex gap-4">
<div class="h-3 bg-slate-100 rounded w-32"></div>
<div class="h-3 bg-slate-100 rounded w-24"></div>
<div class="h-3 bg-slate-100 rounded w-20"></div>
</div>
<div class="h-4 bg-slate-100 rounded w-full mt-2"></div>
<div class="h-4 bg-slate-100 rounded w-2/3"></div>
</div>
<div class="w-16 h-16 bg-slate-100 rounded-full ml-8"></div>
</div>
</div>`;
}
return html;
}
function renderEmpty() {
return `<div class="text-center py-16">
<i data-lucide="search-x" class="w-12 h-12 text-slate-300 mx-auto mb-4"></i>
<p class="text-slate-500 font-medium">未找到匹配结果</p>
<p class="text-xs text-slate-400 mt-1">尝试更换关键词或调整筛选条件</p>
<button onclick="resetAllFilters()" class="mt-4 px-4 py-2 text-xs font-bold text-primary border border-primary/30 rounded-lg hover:bg-blue-50 transition-colors">重置所有筛选条件</button>
</div>`;
}
function renderError() {
return `<div class="text-center py-16">
<i data-lucide="alert-triangle" class="w-12 h-12 text-amber-400 mx-auto mb-4"></i>
<p class="text-slate-500 font-medium">数据加载失败请检查后端服务</p>
<button onclick="executeSearch()" class="mt-4 px-4 py-2 text-xs font-bold text-white bg-primary rounded-lg hover:bg-blue-600 transition-colors">重新加载</button>
</div>`;
}
function renderSearchResults(data) {
const container = document.getElementById('searchResults');
if (!container) return;
if (!data.results || data.results.length === 0) {
container.innerHTML = renderEmpty();
setTimeout(() => lucide.createIcons(), 100);
return;
}
const query = searchState.query || '';
container.innerHTML = data.results.map(item => renderResultCard(item, query)).join('');
setTimeout(() => lucide.createIcons(), 100);
}
function renderResultCard(item, query) {
const score = computeMatchScore(item, query);
const scoreColor = score >= 80 ? 'text-emerald-500' : score >= 50 ? 'text-amber-500' : 'text-rose-400';
const scoreLabel = score >= 80 ? '高匹配度' : score >= 50 ? '中匹配度' : '低匹配度';
const offset = 176 - (176 * score / 100);
const statusBadge = item.status === '研发中' || item.status === '进行中'
? '<span class="px-2 py-0.5 bg-amber-50 text-amber-600 text-[10px] font-bold rounded uppercase">' + item.status + '</span>'
: item.status === '已完成'
? '<span class="px-2 py-0.5 bg-emerald-50 text-emerald-600 text-[10px] font-bold rounded uppercase">' + item.status + '</span>'
: '<span class="px-2 py-0.5 bg-slate-100 text-slate-500 text-[10px] font-bold rounded uppercase">' + (item.status || '结题') + '</span>';
// 关键词标签取前4
let kwTags = '';
const kws = (item.keywords || '').split(/[,,、]/).map(s => s.trim()).filter(Boolean).slice(0, 4);
if (kws.length > 0) {
kwTags = kws.map(k => `<span class="px-1.5 py-0.5 bg-slate-100 text-slate-500 rounded text-[10px]">${highlightText(k, query)}</span>`).join('');
}
// 技术标签
let techTags = '';
if (item.techs && item.techs.length > 0) {
techTags = item.techs.slice(0, 3).map(t => `<span class="px-1.5 py-0.5 bg-purple-50 text-purple-600 rounded text-[10px]">${highlightText(t, query)}</span>`).join('');
}
// 高亮名称
const cnName = highlightText(item.nameCn || '', query);
const enName = highlightText(item.nameEn || '', query);
// 摘要截断
const desc = (item.description || '').length > 200
? item.description.substring(0, 200) + '…' : (item.description || '');
// 机构截断
const insts = (item.institutions || []).slice(0, 3).join(' / ') + ((item.institutions || []).length > 3 ? ' 等' : '');
return `<div class="group bg-white p-5 rounded-xl border border-slate-100 hover:shadow-xl hover:border-blue-200 transition-all relative overflow-hidden cursor-pointer" onclick="navigateToDetail('${item.projectId}')">
<div class="flex justify-between items-start">
<div class="flex-1 min-w-0 pr-4">
<div class="flex items-center gap-3 mb-2 flex-wrap">
<h3 class="text-lg font-bold text-slate-900 group-hover:text-primary transition-colors">${cnName || enName || item.projectId}</h3>
${statusBadge}
</div>
<div class="flex gap-6 text-sm text-slate-500 mb-3 flex-wrap">
${insts ? `<span class="flex items-center gap-1.5"><i data-lucide="building-2" class="w-4 h-4"></i> ${insts}</span>` : ''}
<span class="flex items-center gap-1.5"><i data-lucide="calendar" class="w-4 h-4"></i> ${item.startYear || '?'} ${item.endYear || '?'}</span>
${item.domain ? `<span class="flex items-center gap-1.5"><i data-lucide="tag" class="w-4 h-4"></i> ${highlightText(item.domain, query)}</span>` : ''}
</div>
<p class="text-sm text-slate-600 leading-relaxed line-clamp-2">${highlightText(desc, query)}</p>
${kwTags || techTags ? `<div class="flex flex-wrap gap-1.5 mt-3">${kwTags}${techTags}</div>` : ''}
</div>
<div class="flex flex-col items-center gap-2 ml-8 shrink-0">
<div class="relative w-16 h-16">
<svg class="w-full h-full transform -rotate-90">
<circle cx="32" cy="32" r="28" stroke="currentColor" stroke-width="5" fill="transparent" class="text-slate-100"></circle>
<circle cx="32" cy="32" r="28" stroke="currentColor" stroke-width="5" fill="transparent" stroke-dasharray="176" stroke-dashoffset="${offset}" class="${scoreColor}"></circle>
</svg>
<span class="absolute inset-0 flex items-center justify-center text-sm font-black ${scoreColor}">${score}%</span>
</div>
<span class="text-[10px] font-bold text-slate-400">${scoreLabel}</span>
</div>
</div>
<div class="flex items-center gap-4 pt-4 border-t border-slate-50 mt-3 opacity-0 group-hover:opacity-100 transition-opacity">
<button class="text-xs font-bold text-primary flex items-center gap-1 hover:underline">查看详情 <i data-lucide="external-link" class="w-3 h-3"></i></button>
<span class="text-xs font-bold text-slate-500 flex items-center gap-1 cursor-pointer hover:text-primary transition-colors" onclick="event.stopPropagation();navigateToDetail('${item.projectId}')"><i data-lucide="plus-circle" class="w-3 h-3"></i> </span>
</div>
</div>`;
}
// ── 匹配度计算 ──────────────────────────────────────────────
function computeMatchScore(item, query) {
if (!query) return 50; // 无查询时给中等分数
const q = query.toLowerCase();
const fields = [
(item.nameCn || '').toLowerCase(),
(item.nameEn || '').toLowerCase(),
(item.description || '').toLowerCase(),
(item.keywords || '').toLowerCase(),
(item.domain || '').toLowerCase(),
(item.office || '').toLowerCase(),
(Array.isArray(item.institutions) ? item.institutions.join(' ') : '').toLowerCase(),
(Array.isArray(item.techs) ? item.techs.join(' ') : '').toLowerCase(),
];
// 名称命中权重 x3
let nameHit = false;
if (fields[0].includes(q) || fields[1].includes(q)) nameHit = true;
const hitCount = fields.filter(f => f.includes(q)).length;
let score = hitCount * 12;
if (nameHit) score += 30;
return Math.min(98, Math.max(10, score));
}
// ── 关键词高亮 ──────────────────────────────────────────────
function highlightText(text, query) {
if (!query || query.length < 2) return text;
try {
const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
return text.replace(new RegExp(`(${escaped})`, 'gi'), '<mark class="bg-yellow-200 text-yellow-900 rounded px-0.5">$1</mark>');
} catch {
return text;
}
}
// ── 更新统计 ──────────────────────────────────────────────
function updateSearchStats(data) {
const statsEl = document.getElementById('searchStats');
if (!statsEl) return;
const total = data.total || 0;
statsEl.innerHTML = `共找到 <span class="font-bold text-slate-900">${total.toLocaleString()}</span> 条结果`;
}
// ══════════════════════════════════════════════════════════════
// 分页
// ══════════════════════════════════════════════════════════════
function renderPagination(data) {
const container = document.getElementById('searchPagination');
if (!container) return;
const total = data.total_pages || 1;
const current = data.page || 1;
if (total <= 1) { container.innerHTML = ''; return; }
const pages = buildPageRange(current, total);
let html = `<button onclick="goToPage(${current - 1})" class="p-2 border rounded-lg hover:bg-slate-50 ${current <= 1 ? 'opacity-30 pointer-events-none' : ''}" ${current <= 1 ? 'disabled' : ''}><i data-lucide="chevron-left" class="w-4 h-4"></i></button>`;
pages.forEach(p => {
if (p === '...') html += `<span class="px-2 text-slate-400">...</span>`;
else if (p === current) html += `<button class="w-10 h-10 bg-primary text-white rounded-lg font-bold">${p}</button>`;
else html += `<button onclick="goToPage(${p})" class="w-10 h-10 hover:bg-slate-100 rounded-lg font-medium">${p}</button>`;
});
html += `<button onclick="goToPage(${current + 1})" class="p-2 border rounded-lg hover:bg-slate-50 ${current >= total ? 'opacity-30 pointer-events-none' : ''}" ${current >= total ? 'disabled' : ''}><i data-lucide="chevron-right" class="w-4 h-4"></i></button>`;
container.innerHTML = html;
setTimeout(() => lucide.createIcons(), 60);
}
function buildPageRange(current, total) {
if (total <= 7) {
return Array.from({ length: total }, (_, i) => i + 1);
}
const pages = [1];
let start = Math.max(2, current - 1);
let end = Math.min(total - 1, current + 1);
if (current <= 3) end = Math.min(5, total - 1);
if (current >= total - 2) start = Math.max(total - 4, 2);
if (start > 2) pages.push('...');
for (let i = start; i <= end; i++) pages.push(i);
if (end < total - 1) pages.push('...');
pages.push(total);
return pages;
}
function goToPage(p) {
searchState.page = p;
executeSearch();
// 滚动到顶部
const results = document.getElementById('searchResults');
if (results) results.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
// ══════════════════════════════════════════════════════════════
// 智能推荐
// ══════════════════════════════════════════════════════════════
async function loadSuggestions() {
const panel = document.getElementById('searchSuggestions');
const container = document.getElementById('searchSuggestionsList');
if (!panel || !container) return;
try {
const resp = await fetch(`${SEARCH_API}/search?sort=budget&per_page=4`);
const data = await resp.json();
if (!data.results || data.results.length === 0) return;
const icons = ['trending-up', 'building', 'cpu', 'clock'];
container.innerHTML = (data.results || []).map((r, i) => `
<div class="p-2 hover:bg-slate-50 rounded flex items-center gap-3 cursor-pointer" onclick="quickSearch('${(r.nameCn || '').replace(/'/g,"\\'")}')">
<i data-lucide="${icons[i] || 'search'}" class="w-4 h-4 ${i === 0 ? 'text-blue-500' : i === 1 ? 'text-emerald-500' : i === 2 ? 'text-purple-500' : 'text-slate-400'}"></i>
<span class="text-sm truncate">${r.nameCn || r.nameEn || ''}</span>
</div>
`).join('');
panel.classList.remove('hidden');
setTimeout(() => lucide.createIcons(), 60);
} catch (e) { /* 推荐加载失败不影响主功能 */ }
}
function hideSuggestions() {
const panel = document.getElementById('searchSuggestions');
if (panel) panel.classList.add('hidden');
}
function quickSearch(keyword) {
const input = document.getElementById('fuzzyInput');
if (input) input.value = keyword;
searchState.mode = 'fuzzy';
searchState.query = keyword;
searchState.page = 1;
executeSearch();
}
// ══════════════════════════════════════════════════════════════
// 标签页切换
// ══════════════════════════════════════════════════════════════
function switchSearchTab(mode) {
searchState.mode = mode;
if (mode !== 'precise') searchState.preciseField = '';
['fuzzy', 'precise', 'advanced'].forEach(t => {
const btn = document.getElementById(`stab-${t}`);
const panel = document.getElementById(`spanel-${t}`);
if (t === mode) {
btn.classList.add('bg-white', 'text-primary', 'shadow-sm');
btn.classList.remove('text-slate-600');
panel.classList.remove('hidden');
} else {
btn.classList.remove('bg-white', 'text-primary', 'shadow-sm');
btn.classList.add('text-slate-600');
panel.classList.add('hidden');
}
});
}
function toggleSearchFilter(listId, iconId) {
const el = document.getElementById(listId);
const icon = document.getElementById(iconId);
if (el.classList.contains('hidden')) {
el.classList.remove('hidden');
icon.style.transform = 'rotate(0deg)';
} else {
el.classList.add('hidden');
icon.style.transform = 'rotate(-90deg)';
}
}
// ── 挂载到 window ──────────────────────────────────────────────
window.initSearchPage = initSearchPage;
window.switchSearchTab = switchSearchTab;
window.toggleSearchFilter = toggleSearchFilter;
window.executeSearch = executeSearch;
window.goToPage = goToPage;
window.toggleDomainFilter = toggleDomainFilter;
window.toggleStatusFilter = toggleStatusFilter;
window.applyDateFilter = applyDateFilter;
window.clearDateFilter = clearDateFilter;
window.resetAllFilters = resetAllFilters;
window.quickSearch = quickSearch;
window.hideSuggestions = hideSuggestions;

@ -0,0 +1,440 @@
/* =============================================================================
* [MODULE: trend] 趋势分析模块 (API 驱动 5 + AI 研判)
* ============================================================================= */
const API_BASE_TREND = window.APP_CONFIG.API_BASE;
let trendCharts = {};
let trendInited = false;
// ── 颜色方案 ──────────────────────────────────────────────────
const DOMAIN_COLORS = [
'#1890FF','#10b981','#8b5cf6','#f59e0b','#ef4444',
'#06b6d4','#ec4899','#84cc16','#f97316','#6366f1',
'#14b8a6','#e11d48','#22c55e','#a855f7','#0ea5e9'
];
// ── 主初始化 ──────────────────────────────────────────────────
async function initTrendCharts() {
if (trendInited) {
Object.values(trendCharts).forEach(c => c && c.resize());
return;
}
trendInited = true;
// 并行加载全部数据
const [timeline, domainCluster, instNetwork, centrality, officeAnalysis, intelReport] =
await Promise.all([
fetch(`${API_BASE_TREND}/timeline`).then(r => r.json()),
fetch(`${API_BASE_TREND}/domain_cluster`).then(r => r.json()),
fetch(`${API_BASE_TREND}/institution_network`).then(r => r.json()),
fetch(`${API_BASE_TREND}/centrality`).then(r => r.json()),
fetch(`${API_BASE_TREND}/office_analysis`).then(r => r.json()),
fetch(`${API_BASE_TREND}/intelligence_report`).then(r => r.json()),
]);
buildTimelineChart(timeline);
buildDomainChart(domainCluster);
buildInstitutionNetwork(instNetwork);
buildTechRanking(centrality);
buildOfficeRadar(officeAnalysis);
buildIntelReport(intelReport);
}
// ══════════════════════════════════════════════════════════════
// Chart 1: 项目增长趋势 — 按年代堆叠柱状图 + 年度折线
// ══════════════════════════════════════════════════════════════
function buildTimelineChart(data) {
const dom = document.getElementById('trendChartMain');
if (!dom) return;
// 按年代聚合 domain
const decadeMap = {};
data.forEach(d => {
const dec = Math.floor(d.year / 10) * 10;
const key = `${dec}s`;
if (!decadeMap[key]) decadeMap[key] = {};
const dm = d.domain || '未分类';
decadeMap[key][dm] = (decadeMap[key][dm] || 0) + d.count;
});
const decades = Object.keys(decadeMap).sort();
const allDomains = new Set();
decades.forEach(dec => Object.keys(decadeMap[dec]).forEach(d => allDomains.add(d)));
const domainList = [...allDomains];
const series = domainList.map((dm, i) => ({
name: dm,
type: 'bar',
stack: 'total',
data: decades.map(d => decadeMap[d][dm] || 0),
itemStyle: { color: DOMAIN_COLORS[i % DOMAIN_COLORS.length] },
emphasis: { focus: 'series' }
}));
const chart = echarts.init(dom);
chart.setOption({
tooltip: {
trigger: 'item',
formatter: p => `${p.seriesName}<br/>项目数: <b>${p.value}</b>`
},
legend: {
type: 'scroll',
bottom: 0,
textStyle: { color: '#64748b', fontSize: 10 },
pageTextStyle: { color: '#64748b' }
},
grid: { top: '8%', left: '3%', right: '4%', bottom: '12%', containLabel: true },
xAxis: {
type: 'category',
data: decades,
axisLabel: { color: '#64748b', fontSize: 11 }
},
yAxis: {
type: 'value',
name: '项目数',
splitLine: { lineStyle: { type: 'dashed', color: '#e2e8f0' } }
},
series
});
trendCharts.trend = chart;
}
// ══════════════════════════════════════════════════════════════
// Chart 2: 技术领域分布 — 环形图 + 预算排行横向柱状图
// ══════════════════════════════════════════════════════════════
function buildDomainChart(data) {
const domDonut = document.getElementById('distChartMain');
const domBar = document.getElementById('distBudgetChart');
if (!domDonut) return;
const top = data.slice(0, 10);
const otherCount = data.slice(10).reduce((s, d) => s + d.projectCount, 0);
const pieData = top.map((d, i) => ({
value: d.projectCount,
name: d.domain,
itemStyle: { color: DOMAIN_COLORS[i % DOMAIN_COLORS.length] }
}));
if (otherCount > 0) {
pieData.push({ value: otherCount, name: '其他领域', itemStyle: { color: '#cbd5e1' } });
}
// 环形图
const c1 = echarts.init(domDonut);
c1.setOption({
tooltip: {
trigger: 'item',
formatter: p => `${p.name}<br/>项目数: <b>${p.value}</b> (${p.percent}%)`
},
legend: {
bottom: 0, textStyle: { color: '#64748b', fontSize: 9 },
type: 'scroll'
},
series: [{
type: 'pie', radius: ['42%', '68%'], center: ['50%', '43%'],
itemStyle: { borderRadius: 6, borderColor: '#fff', borderWidth: 2 },
label: { show: false },
emphasis: { label: { show: true, fontSize: 13, fontWeight: 'bold' } },
data: pieData
}]
});
trendCharts.dist = c1;
// 预算排名横向柱状图
if (domBar) {
const budgetTop = [...data].sort((a, b) => b.budgetTotal - a.budgetTotal).slice(0, 10);
const c2 = echarts.init(domBar);
c2.setOption({
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
formatter: p => {
const d = budgetTop[p[0].dataIndex];
return `<b>${d.domain}</b><br/>预算总额: ${(d.budgetTotal/10000).toFixed(2)} 亿<br/>项目: ${d.projectCount} 个 | 活跃: ${d.activeCount} 个<br/>平均周期: ${d.avgDuration}`;
}
},
grid: { top: '3%', left: '3%', right: '8%', bottom: '3%', containLabel: true },
xAxis: {
type: 'value',
name: '万元',
axisLabel: { fontSize: 9, color: '#94a3b8',
formatter: v => (v/10000).toFixed(1) + '亿' },
splitLine: { lineStyle: { type: 'dashed', color: '#e2e8f0' } }
},
yAxis: {
type: 'category',
data: budgetTop.map(d => d.domain).reverse(),
axisLabel: { fontSize: 10, color: '#64748b',
formatter: v => v.length > 5 ? v.slice(0,5)+'…' : v },
inverse: true
},
series: [{
type: 'bar',
data: budgetTop.map((d, i) => ({
value: d.budgetTotal,
itemStyle: { color: DOMAIN_COLORS[i % DOMAIN_COLORS.length] }
})).reverse(),
barMaxWidth: 20
}]
});
trendCharts.distBudget = c2;
}
}
// ══════════════════════════════════════════════════════════════
// Chart 3: 机构合作网络 — 力导向图
// ══════════════════════════════════════════════════════════════
function buildInstitutionNetwork(data) {
const dom = document.getElementById('networkChartMain');
if (!dom) return;
const maxCnt = Math.max(...data.nodes.map(n => n.projectCount), 1);
const maxWt = Math.max(...data.edges.map(e => e.weight), 1);
// 节点配色: 明亮色系 (淡蓝/明黄/亮橙/亮青/亮粉)
const BRIGHT_COLORS = ['#38BDF8','#FBBF24','#FB923C','#34D399','#F472B6','#A78BFA','#F87171'];
function nodeColor(i) { return BRIGHT_COLORS[i % BRIGHT_COLORS.length]; }
const ecNodes = data.nodes.map((n, i) => ({
name: n.name,
symbolSize: 18 + (n.projectCount / maxCnt) * 42,
itemStyle: {
color: nodeColor(i),
borderColor: '#ffffff',
borderWidth: 2,
shadowBlur: 4,
shadowColor: 'rgba(0,0,0,0.1)'
},
label: {
show: true,
position: 'bottom',
fontSize: 10,
fontWeight: 600,
color: '#000000',
distance: 4
}
}));
const ecLinks = data.edges.map(e => ({
source: e.source,
target: e.target,
lineStyle: {
width: 0.5 + (e.weight / maxWt) * 3,
opacity: 0.12 + (e.weight / maxWt) * 0.45,
color: '#cbd5e1'
}
}));
console.log('[trend] buildInstitutionNetwork v3 — bright nodes');
const chart = echarts.init(dom);
chart.setOption({
backgroundColor: '#ffffff',
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(255,255,255,0.96)',
borderColor: 'rgba(59,130,246,0.25)',
textStyle: { color: '#1e293b', fontSize: 11 },
formatter: p => {
if (p.dataType === 'node') {
const n = data.nodes.find(x => x.name === p.data.name || x.id === p.data.name);
if (!n) return p.data.name;
const desc = n.description || '';
const descShort = desc.length > 120 ? desc.substring(0, 120) + '...' : desc;
return `<b style="font-size:12px">${n.name}</b><br/>` +
`<span style="font-size:10px;color:#64748b">参与项目: <b>${n.projectCount}</b> 个</span>` +
(descShort ? `<br/><span style="font-size:9px;color:#94a3b8;line-height:1.3">${descShort}</span>` : '');
}
return `${p.data.source}${p.data.target}<br/><span style="font-size:10px;color:#64748b">合作项目: <b>${p.data.weight || '--'}</b> 个</span>`;
}
},
series: [{
type: 'graph', layout: 'force', roam: true,
data: ecNodes, links: ecLinks,
force: { repulsion: 180, edgeLength: [20, 100], gravity: 0.1 },
emphasis: {
scale: 1.1,
itemStyle: { borderColor: '#000000', borderWidth: 2 },
label: { fontSize: 11, fontWeight: 'bold', color: '#000000' }
},
lineStyle: { curveness: 0.15 }
}]
});
trendCharts.network = chart;
}
// ══════════════════════════════════════════════════════════════
// Chart 4: 技术关联度排行 — 横向柱状图
// ══════════════════════════════════════════════════════════════
function buildTechRanking(data) {
const dom = document.getElementById('cloudChartMain');
if (!dom) return;
const techs = [...data.technologies].sort((a, b) => b.degree - a.degree);
const colors = techs.map((_, i) => DOMAIN_COLORS[i % DOMAIN_COLORS.length]);
const chart = echarts.init(dom);
chart.setOption({
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
formatter: p => `<b>${p[0].name}</b><br/>关联项目数: <b>${p[0].value}</b>`
},
grid: { top: '3%', left: '3%', right: '8%', bottom: '3%', containLabel: true },
xAxis: {
type: 'value',
name: '关联项目数',
axisLabel: { fontSize: 9, color: '#94a3b8' },
splitLine: { lineStyle: { type: 'dashed', color: '#e2e8f0' } }
},
yAxis: {
type: 'category',
data: techs.map(t => t.name).reverse(),
axisLabel: { fontSize: 10, color: '#475569',
formatter: v => v.length > 6 ? v.slice(0,6)+'…' : v },
inverse: true
},
series: [{
type: 'bar',
data: techs.map((t, i) => ({
value: t.degree,
itemStyle: { color: colors[i], borderRadius: [0, 4, 4, 0] }
})).reverse(),
barMaxWidth: 22,
label: {
show: true, position: 'right', fontSize: 10,
color: '#64748b', formatter: '{c}'
}
}]
});
trendCharts.cloud = chart;
}
// ══════════════════════════════════════════════════════════════
// Chart 5: 办公室多维度对比 — 雷达图
// ══════════════════════════════════════════════════════════════
function buildOfficeRadar(data) {
const dom = document.getElementById('officeRadarChart');
if (!dom) return;
// 归一化到 0-100
const maxVals = {
projCount: Math.max(...data.map(d => d.projCount), 1),
budgetTotal: Math.max(...data.map(d => d.budgetTotal), 1),
activeProjects: Math.max(...data.map(d => d.activeProjects), 1),
managerCount: Math.max(...data.map(d => d.managerCount), 1),
avgBudget: Math.max(...data.map(d => d.avgBudget), 1),
};
const indicator = [
{ name: '项目数量', max: 100 },
{ name: '预算总额', max: 100 },
{ name: '活跃项目', max: 100 },
{ name: '管理人数', max: 100 },
{ name: '平均预算', max: 100 },
];
const series = data.map((d, i) => ({
name: d.officeName,
type: 'radar',
symbol: 'circle',
symbolSize: 4,
lineStyle: { width: 2 },
areaStyle: { opacity: 0.08 },
itemStyle: { color: DOMAIN_COLORS[i % DOMAIN_COLORS.length] },
data: [{
value: [
(d.projCount / maxVals.projCount) * 100,
(d.budgetTotal / maxVals.budgetTotal) * 100,
(d.activeProjects / maxVals.activeProjects) * 100,
(d.managerCount / maxVals.managerCount) * 100,
(d.avgBudget / maxVals.avgBudget) * 100,
],
name: d.officeName
}],
emphasis: { areaStyle: { opacity: 0.2 } }
}));
const chart = echarts.init(dom);
chart.setOption({
tooltip: {
trigger: 'item',
formatter: p => {
if (!p.data || !p.seriesName) return '';
const idx = data.findIndex(d => d.officeName === p.seriesName);
if (idx < 0) return `<b>${p.seriesName}</b>`;
const dd = data[idx];
return `<b>${dd.officeName}</b><br/>
项目数: ${dd.projCount}<br/>
预算总额: ${(dd.budgetTotal/10000).toFixed(2)} 亿<br/>
活跃项目: ${dd.activeProjects}<br/>
管理人员: ${dd.managerCount}<br/>
平均预算: ${(dd.avgBudget/10000).toFixed(2)} 亿`;
}
},
legend: {
bottom: 0,
data: data.map(d => d.officeName),
textStyle: { color: '#64748b', fontSize: 9 },
type: 'scroll'
},
radar: {
center: ['50%', '45%'],
radius: '65%',
indicator,
axisName: { color: '#475569', fontSize: 10 }
},
series
});
trendCharts.officeRadar = chart;
}
// ══════════════════════════════════════════════════════════════
// AI 研判摘要 — 渲染后端情报报告
// ══════════════════════════════════════════════════════════════
function buildIntelReport(report) {
const container = document.getElementById('aiIntelContent');
if (!container || !report.sections) return;
// 取关键段落: 全景、技术重心、机构、时代演进选4段
const keySections = report.sections.filter(s =>
['图谱全景概述', '战略技术重心分析', '核心机构图谱解析', '时代演进规律'].includes(s.title)
);
container.innerHTML = keySections.map((s, i) =>
`<p>${i + 1}. <strong>${s.title}</strong> ${s.content.replace(/<b>/g, '<strong>').replace(/<\/b>/g, '</strong>')}</p>`
).join('');
// 更新统计数字
if (report.stats) {
const totalEl = document.getElementById('intelTotalProj');
const budgetEl = document.getElementById('intelTotalBudget');
const yearEl = document.getElementById('intelYearRange');
if (totalEl) totalEl.textContent = report.stats.totalProj;
if (budgetEl) budgetEl.textContent = (report.stats.totalBudget / 10000).toFixed(1) + ' 亿';
if (yearEl) yearEl.textContent = report.stats.yearRange.join(' ');
}
}
// ── 折线/柱状切换 ────────────────────────────────────────────
function changeTrendType(type) {
if (!trendCharts.trend) return;
const opt = trendCharts.trend.getOption();
const newSeries = opt.series.map(s => ({
...s,
type,
stack: type === 'bar' ? 'total' : undefined,
areaStyle: type === 'line' ? { opacity: 0.15 } : null
}));
trendCharts.trend.setOption({ series: newSeries });
}
// ── resize ────────────────────────────────────────────────────
window.addEventListener('resize', () => {
clearTimeout(window._trendResizeTimer);
window._trendResizeTimer = setTimeout(() => {
Object.values(trendCharts).forEach(c => c && c.resize());
}, 200);
});
// ── 挂载到 window ────────────────────────────────────────────
window.initTrendCharts = initTrendCharts;
window.changeTrendType = changeTrendType;

@ -0,0 +1,380 @@
/* =============================================================================
* [MODULE: wiki] 情报百科模块
* ============================================================================= */
const API_BASE = window.APP_CONFIG.API_BASE;
let wikiCurrentTab = 'tech';
let wikiData = {}; // cache loaded data
// ── Era color map ─────────────────────────────────────────
const ERA_COLOR = {
'1950s': '#ef4444', '1960s': '#f97316', '1970s': '#f59e0b',
'1980s': '#10b981', '1990s': '#06b6d4', '2000s': '#3B82F6',
'2010s': '#8b5cf6', '2020s': '#ec4899'
};
// ── Tab Switching ────────────────────────────────────────
function switchWikiTab(tab) {
wikiCurrentTab = tab;
// Update tab buttons
document.querySelectorAll('#wikiTabs button').forEach(btn => {
const isActive = btn.dataset.wikiTab === tab;
btn.classList.toggle('bg-white', isActive);
btn.classList.toggle('text-slate-900', isActive);
btn.classList.toggle('shadow-sm', isActive);
btn.classList.toggle('text-slate-500', !isActive);
btn.classList.toggle('hover:text-slate-700', !isActive);
});
// Show/hide content
document.querySelectorAll('.wiki-tab-content').forEach(el => el.classList.add('hidden'));
const contentMap = {
tech: 'wikiTabTech', milestone: 'wikiTabMilestone',
office: 'wikiTabOffice', manager: 'wikiTabManager'
};
const target = document.getElementById(contentMap[tab]);
if (target) target.classList.remove('hidden');
// Load data if needed
loadWikiTab(tab);
lucide.createIcons();
}
// ── Lazy Load ────────────────────────────────────────────
async function loadWikiTab(tab) {
if (wikiData[tab]) return; // already loaded
try {
switch (tab) {
case 'tech':
await loadTechTab();
break;
case 'milestone':
await loadMilestoneTab();
break;
case 'office':
await loadOfficeTab();
break;
case 'manager':
await loadManagerTab();
break;
}
wikiData[tab] = true;
} catch (e) {
console.error(`Wiki tab ${tab} load error:`, e);
showWikiError(tab);
}
}
function showWikiError(tab) {
const map = { tech: 'wikiTechError', milestone: 'wikiMsError', office: 'wikiOfficeError', manager: 'wikiMgrError' };
const skMap = { tech: 'wikiTechSkeleton', milestone: 'wikiMsSkeleton', office: 'wikiOfficeSkeleton', manager: 'wikiMgrSkeleton' };
const sk = document.getElementById(skMap[tab]);
const err = document.getElementById(map[tab]);
if (sk) sk.classList.add('hidden');
if (err) err.classList.remove('hidden');
}
// ══════════════════════════════════════════════════════════
// Tab 1: 技术图谱
// ══════════════════════════════════════════════════════════
async function loadTechTab() {
const skeleton = document.getElementById('wikiTechSkeleton');
const content = document.getElementById('wikiTechContent');
const resp = await fetch(`${API_BASE}/graph?hide_darpa=true&node_types=Technology`);
const data = await resp.json();
const techNodes = data.nodes.sort((a, b) => (b.projectCount || 0) - (a.projectCount || 0));
// Fetch detailed info for each tech
const details = await Promise.all(techNodes.slice(0, 21).map(async n => {
try {
const r = await fetch(`${API_BASE}/technology/${encodeURIComponent(n.id)}`);
return await r.json();
} catch { return n; }
}));
const catColor = {
'计算': '#3B82F6', '通信': '#06b6d4', '电子': '#8b5cf6',
'材料': '#10b981', '太空': '#f59e0b', '生物': '#ec4899',
'人工智能': '#6366f1', '无人系统': '#f97316'
};
content.innerHTML = details.map((d, i) => {
const name = d.name || d.label || 'Unknown';
const desc = (d.description || '').substring(0, 150);
const cat = d.category || '';
const military = d.militaryRelevance || '';
const catClr = catColor[cat] || '#64748b';
const projCnt = d.projectCount || 0;
const wikiUrl = d.wikipediaUrl || '';
const iconMap = { '计算': 'cpu', '通信': 'radio', '电子': 'zap', '材料': 'flask-conical', '太空': 'orbit', '生物': 'dna', '人工智能': 'brain', '无人系统': 'plane' };
const icon = iconMap[cat] || 'microchip';
return `<div class="bg-white rounded-xl border border-slate-100 shadow-sm hover:shadow-md transition-all duration-200 group cursor-pointer overflow-hidden" onclick="toggleWikiTechCard(this)" data-expanded="false">
<div class="p-5">
<div class="flex items-start justify-between mb-3">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-lg flex items-center justify-center text-white shrink-0" style="background:${catClr}">
<i data-lucide="${icon}" class="w-5 h-5"></i>
</div>
<div>
<h3 class="font-bold text-slate-800 text-sm leading-tight">${name}</h3>
<p class="text-[10px] text-slate-400 font-mono mt-0.5">${projCnt} 个项目</p>
</div>
</div>
${cat ? `<span class="px-2.5 py-0.5 rounded-full text-[10px] font-bold shrink-0" style="background:${catClr}18;color:${catClr}">${cat}</span>` : ''}
</div>
${desc ? `<p class="text-xs text-slate-500 leading-relaxed line-clamp-2 wiki-tech-desc">${desc}</p>` : ''}
${military ? `<div class="mt-2 flex items-start gap-1.5">
<i data-lucide="shield-alert" class="w-3 h-3 text-red-400 shrink-0 mt-0.5"></i>
<p class="text-[10px] text-red-500 leading-relaxed wiki-tech-military line-clamp-2">${military}</p>
</div>` : ''}
</div>
<div class="wiki-tech-expand hidden px-5 pb-5 border-t border-slate-50 pt-4">
${desc ? `<p class="text-xs text-slate-600 leading-relaxed">${d.description || desc}</p>` : ''}
${military ? `<p class="text-xs text-red-500 leading-relaxed mt-3"><span class="font-bold">军事意义:</span>${d.militaryRelevance || military}</p>` : ''}
${wikiUrl ? `<a href="${wikiUrl}" target="_blank" class="inline-flex items-center gap-1 mt-3 text-[10px] text-blue-500 hover:text-blue-600"><i data-lucide="external-link" class="w-3 h-3"></i> Wikipedia</a>` : ''}
</div>
<div class="wiki-tech-expand-indicator text-center pb-2 text-[10px] text-slate-300">点击展开详情 <i data-lucide="chevron-down" class="w-3 h-3 inline"></i></div>
</div>`;
}).join('');
skeleton.classList.add('hidden');
content.classList.remove('hidden');
lucide.createIcons();
}
function toggleWikiTechCard(card) {
const expanded = card.dataset.expanded === 'true';
const expandEl = card.querySelector('.wiki-tech-expand');
const descEl = card.querySelector('.wiki-tech-desc');
const militaryEl = card.querySelector('.wiki-tech-military');
const indicator = card.querySelector('.wiki-tech-expand-indicator');
if (expanded) {
expandEl.classList.add('hidden');
if (descEl) descEl.classList.remove('line-clamp-none');
if (militaryEl) militaryEl.classList.remove('line-clamp-none');
indicator.innerHTML = '点击展开详情 <i data-lucide="chevron-down" class="w-3 h-3 inline"></i>';
card.dataset.expanded = 'false';
} else {
expandEl.classList.remove('hidden');
if (descEl) descEl.classList.add('line-clamp-none');
if (militaryEl) militaryEl.classList.add('line-clamp-none');
indicator.innerHTML = '收起 <i data-lucide="chevron-up" class="w-3 h-3 inline"></i>';
card.dataset.expanded = 'true';
}
lucide.createIcons();
}
// ══════════════════════════════════════════════════════════
// Tab 2: 里程碑时间线
// ══════════════════════════════════════════════════════════
async function loadMilestoneTab() {
const skeleton = document.getElementById('wikiMsSkeleton');
const content = document.getElementById('wikiMsContent');
const resp = await fetch(`${API_BASE}/milestones`);
const milestones = await resp.json();
// Build era filter buttons
const eras = [...new Set(milestones.map(m => m.era))].sort();
const eraFilter = document.getElementById('wikiMsEraFilter');
eraFilter.innerHTML = `<button onclick="filterWikiMilestones('all')" class="px-3 py-1.5 text-[11px] font-bold rounded-full bg-primary text-white transition-all wiki-era-btn">全部</button>` +
eras.map(e => `<button onclick="filterWikiMilestones('${e}')" class="px-3 py-1.5 text-[11px] font-bold rounded-full bg-slate-100 text-slate-500 hover:bg-slate-200 transition-all wiki-era-btn">${e}</button>`).join('');
// Render timeline
const timeline = document.getElementById('wikiMsTimeline');
timeline.setAttribute('data-milestones', JSON.stringify(milestones));
renderWikiMilestones(milestones);
skeleton.classList.add('hidden');
content.classList.remove('hidden');
lucide.createIcons();
}
function renderWikiMilestones(msList) {
const timeline = document.getElementById('wikiMsTimeline');
if (!msList.length) {
timeline.innerHTML = '<p class="text-center text-slate-400 py-12">暂无里程碑数据</p>';
return;
}
const sorted = [...msList].sort((a, b) => {
const eraOrder = ['1950s','1960s','1970s','1980s','1990s','2000s','2010s','2020s'];
return eraOrder.indexOf(a.era) - eraOrder.indexOf(b.era);
});
let lastEra = '';
timeline.innerHTML = sorted.map(m => {
const eraHeader = m.era !== lastEra ? `<div class="flex items-center gap-3 mb-4 ${lastEra ? 'mt-8' : ''}">
<span class="px-3 py-1 rounded-full text-xs font-bold text-white" style="background:${ERA_COLOR[m.era] || '#64748b'}">${m.era}</span>
<span class="h-px flex-1 bg-slate-200"></span>
</div>` : '';
lastEra = m.era;
const shortDetail = (m.technicalDetail || '').substring(0, 180);
const shortSig = (m.historicalSignificance || '').substring(0, 200);
return eraHeader + `<div class="ml-4 pl-8 border-l-2 border-slate-200 relative pb-6 group cursor-pointer" onclick="toggleWikiMsCard(this)" data-expanded="false">
<div class="absolute -left-[9px] top-1 w-4 h-4 rounded-full border-2 border-white shadow-sm" style="background:${ERA_COLOR[m.era] || '#64748b'}"></div>
<div class="bg-white rounded-xl border border-slate-100 p-5 shadow-sm hover:shadow-md transition-all">
<div class="flex items-start justify-between">
<div>
<h3 class="font-bold text-slate-800 text-sm">${m.title}</h3>
<p class="text-[10px] text-slate-400 mt-0.5">${m.projectName || m.projectId || ''} · ${m.techDomain || ''}</p>
</div>
<span class="text-[10px] text-slate-300 shrink-0">${m.era}</span>
</div>
${shortSig ? `<p class="text-xs text-slate-600 mt-3 leading-relaxed line-clamp-2 wiki-ms-sig">${shortSig}</p>` : ''}
<div class="wiki-ms-expand hidden mt-3 pt-3 border-t border-slate-50">
${m.historicalSignificance ? `<p class="text-xs text-slate-700 leading-relaxed"><span class="font-bold">历史意义:</span>${m.historicalSignificance}</p>` : ''}
${m.technicalDetail ? `<p class="text-xs text-slate-600 leading-relaxed mt-2"><span class="font-bold">技术细节:</span>${m.technicalDetail}</p>` : ''}
${m.techLegacy ? `<p class="text-xs text-slate-500 leading-relaxed mt-2"><span class="font-bold">技术遗产:</span>${m.techLegacy}</p>` : ''}
${m.keyFigures ? `<p class="text-xs text-slate-500 leading-relaxed mt-2"><span class="font-bold">关键人物:</span>${m.keyFigures}</p>` : ''}
</div>
<div class="wiki-ms-expand-indicator text-center mt-2 text-[10px] text-slate-300">点击展开详情 <i data-lucide="chevron-down" class="w-3 h-3 inline"></i></div>
</div>
</div>`;
}).join('');
lucide.createIcons();
}
function toggleWikiMsCard(card) {
const expanded = card.dataset.expanded === 'true';
const expandEl = card.querySelector('.wiki-ms-expand');
const sigEl = card.querySelector('.wiki-ms-sig');
const indicator = card.querySelector('.wiki-ms-expand-indicator');
if (expanded) {
expandEl.classList.add('hidden');
if (sigEl) sigEl.classList.remove('line-clamp-none');
indicator.innerHTML = '点击展开详情 <i data-lucide="chevron-down" class="w-3 h-3 inline"></i>';
card.dataset.expanded = 'false';
} else {
expandEl.classList.remove('hidden');
if (sigEl) sigEl.classList.add('line-clamp-none');
indicator.innerHTML = '收起 <i data-lucide="chevron-up" class="w-3 h-3 inline"></i>';
card.dataset.expanded = 'true';
}
lucide.createIcons();
}
function filterWikiMilestones(era) {
const timeline = document.getElementById('wikiMsTimeline');
const allMs = JSON.parse(timeline.getAttribute('data-milestones') || '[]');
const filtered = era === 'all' ? allMs : allMs.filter(m => m.era === era);
// Update button styles
document.querySelectorAll('.wiki-era-btn').forEach(btn => {
const isActive = (era === 'all' && btn.textContent === '全部') || btn.textContent === era;
btn.classList.toggle('bg-primary', isActive);
btn.classList.toggle('text-white', isActive);
btn.classList.toggle('bg-slate-100', !isActive);
btn.classList.toggle('text-slate-500', !isActive);
});
renderWikiMilestones(filtered);
}
// ══════════════════════════════════════════════════════════
// Tab 3: DARPA 办公室
// ══════════════════════════════════════════════════════════
async function loadOfficeTab() {
const skeleton = document.getElementById('wikiOfficeSkeleton');
const content = document.getElementById('wikiOfficeContent');
const resp = await fetch(`${API_BASE}/office_list`);
const offices = await resp.json();
const colors = ['#3B82F6', '#10b981', '#f59e0b', '#8b5cf6', '#ef4444', '#06b6d4'];
content.innerHTML = offices.map((o, i) => {
const desc = (o.description || '').substring(0, 200);
const color = colors[i % colors.length];
return `<div class="bg-white rounded-xl border border-slate-100 shadow-sm hover:shadow-md transition-all duration-200 overflow-hidden group">
<div class="h-2" style="background:${color}"></div>
<div class="p-5">
<div class="flex items-start gap-3 mb-3">
<div class="w-10 h-10 rounded-lg flex items-center justify-center text-white shrink-0" style="background:${color}">
<i data-lucide="landmark" class="w-5 h-5"></i>
</div>
<div>
<h3 class="font-bold text-slate-800 text-sm">${o.name}</h3>
<p class="text-[10px] text-slate-400 font-mono">${o.id}</p>
</div>
</div>
${desc ? `<p class="text-xs text-slate-500 leading-relaxed line-clamp-3">${desc}</p>` : '<p class="text-xs text-slate-300 italic">暂无描述</p>'}
<div class="mt-4 pt-3 border-t border-slate-50 grid grid-cols-2 gap-2 text-[10px]">
${o.director ? `<div><span class="text-slate-400">主任</span><p class="font-medium text-slate-700">${o.director}</p></div>` : ''}
${o.foundedYear ? `<div><span class="text-slate-400">成立</span><p class="font-medium text-slate-700">${o.foundedYear} 年</p></div>` : ''}
<div><span class="text-slate-400">项目数</span><p class="font-medium text-slate-700">${o.projectCount || 0} </p></div>
</div>
</div>
</div>`;
}).join('');
skeleton.classList.add('hidden');
content.classList.remove('hidden');
lucide.createIcons();
}
// ══════════════════════════════════════════════════════════
// Tab 4: 关键人物
// ══════════════════════════════════════════════════════════
async function loadManagerTab() {
const skeleton = document.getElementById('wikiMgrSkeleton');
const content = document.getElementById('wikiMgrContent');
const resp = await fetch(`${API_BASE}/manager_list`);
const managers = await resp.json();
const expertiseColors = {
'半导体': '#3B82F6', '集成电路': '#3B82F6', '微电子': '#8b5cf6',
'通信': '#06b6d4', '太空': '#f59e0b', '人工智能': '#6366f1',
'网络安全': '#ef4444', '量子': '#10b981', '无人系统': '#f97316',
'材料': '#ec4899', '雷达': '#14b8a6'
};
content.innerHTML = managers.map(m => {
const bio = (m.bio || '').substring(0, 120);
const expertise = (m.expertise || '').split(/[,]/).filter(Boolean).slice(0, 3);
const initials = m.name ? m.name.split(' ').map(s => s[0]).join('').substring(0, 2).toUpperCase() : '?';
const colorHash = (m.name || '').split('').reduce((h, c) => h + c.charCodeAt(0), 0) % 15;
const avatarColors = ['#3B82F6','#10b981','#f59e0b','#8b5cf6','#ef4444','#06b6d4','#ec4899','#f97316','#6366f1','#14b8a6','#e11d48','#22c55e','#a855f7','#0ea5e9','#84cc16'];
const avatarColor = avatarColors[colorHash];
return `<div class="bg-white rounded-xl border border-slate-100 shadow-sm hover:shadow-md transition-all duration-200 p-5 text-center group">
<div class="w-14 h-14 rounded-full flex items-center justify-center text-white font-bold text-lg mx-auto mb-3" style="background:${avatarColor}">
${initials}
</div>
<h3 class="font-bold text-slate-800 text-sm">${m.name}</h3>
${m.affiliation ? `<p class="text-[10px] text-slate-400 mt-0.5">${m.affiliation}</p>` : ''}
${bio ? `<p class="text-[11px] text-slate-500 leading-relaxed mt-2 line-clamp-2">${bio}</p>` : ''}
${expertise.length ? `<div class="flex flex-wrap justify-center gap-1 mt-3">${expertise.map(e => {
const eclr = Object.keys(expertiseColors).find(k => e.includes(k));
const clr = eclr ? expertiseColors[eclr] : '#64748b';
return `<span class="px-2 py-0.5 rounded-full text-[9px] font-medium" style="background:${clr}18;color:${clr}">${e.trim()}</span>`;
}).join('')}</div>` : ''}
<p class="text-[10px] text-slate-300 mt-2">管理 ${m.projectCount || 0} 个项目</p>
${m.wikipediaUrl ? `<a href="${m.wikipediaUrl}" target="_blank" class="inline-flex items-center gap-1 mt-2 text-[10px] text-blue-400 hover:text-blue-500"><i data-lucide="external-link" class="w-3 h-3"></i> Wiki</a>` : ''}
</div>`;
}).join('');
skeleton.classList.add('hidden');
content.classList.remove('hidden');
lucide.createIcons();
}
// ── Initial Load ─────────────────────────────────────────
function initWiki() {
loadWikiTab('tech');
}
// ── 挂载 ──────────────────────────────────────────────────
window.switchWikiTab = switchWikiTab;
window.toggleWikiTechCard = toggleWikiTechCard;
window.toggleWikiMsCard = toggleWikiMsCard;
window.filterWikiMilestones = filterWikiMilestones;
window.initWiki = initWiki;

@ -0,0 +1,323 @@
<div id="dashboardPage" class="page">
<div class="w-full h-screen flex">
<!-- Sidebar -->
<aside class="w-64 bg-sidebar text-slate-400 flex flex-col">
<div class="p-6 flex items-center gap-3">
<div class="w-8 h-8 bg-primary rounded flex items-center justify-center text-white">
<i data-lucide="shield-half" class="w-5 h-5"></i>
</div>
<span class="text-white font-bold tracking-tight text-lg">DARPA Intelligence</span>
</div>
<nav class="flex-1 px-4 py-4 space-y-1 overflow-y-auto custom-scrollbar">
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mb-2">主导航</div>
<a data-nav-key="dashboard" onclick="showPage('dashboardPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg menu-active text-sm cursor-pointer">
<i data-lucide="layout-dashboard" class="w-4 h-4"></i> 工作台
</a>
<a data-nav-key="search" onclick="showPage('searchPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="search" class="w-4 h-4"></i> 智能检索
</a>
<a data-nav-key="graph" onclick="showPage('graphPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="share-2" class="w-4 h-4"></i> 可视化分析
</a>
<a data-nav-key="trend" onclick="showPage('trendPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="trending-up" class="w-4 h-4"></i> 趋势分析
</a>
<a data-nav-key="wiki" onclick="showPage('wikiPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="book-open" class="w-4 h-4"></i> 情报百科
</a>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-6 mb-2">数据管理</div>
<a data-nav-key="governance" onclick="showPage('governancePage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="database" class="w-4 h-4"></i> 数据治理
</a>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-6 mb-2">系统</div>
<a onclick="logout()" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="log-out" class="w-4 h-4"></i> 退出登录
</a>
</nav>
<div class="p-4 border-t border-white/5 flex items-center gap-3">
<div class="sidebar-user-avatar w-8 h-8 rounded-full bg-slate-700 flex items-center justify-center text-slate-300 shrink-0">
<i data-lucide="user" class="w-4 h-4"></i>
</div>
<div class="flex-1 min-w-0">
<p class="sidebar-user-name text-xs font-bold text-white truncate">--</p>
<p class="sidebar-user-role text-[10px] text-slate-500 truncate">--</p>
</div>
</div>
</aside>
<!-- Main Content -->
<main class="flex-1 flex flex-col">
<header class="h-16 glass-nav border-b border-gray-200 px-6 flex items-center justify-between">
<div>
<h1 class="text-lg font-bold text-slate-800">DARPA 情报工作台</h1>
<p class="text-[11px] text-slate-400">数据来源: Neo4j 图数据库 · 实时分析</p>
</div>
<div class="flex items-center gap-4">
<button class="relative p-2 hover:bg-slate-100 rounded-lg transition-colors" title="通知">
<i data-lucide="bell" class="w-5 h-5 text-slate-500"></i>
<span class="absolute top-1.5 right-1.5 w-2 h-2 rounded-full bg-red-500"></span>
</button>
<div onclick="openProfileModal()" class="header-user-avatar w-8 h-8 rounded-full bg-slate-200 flex items-center justify-center cursor-pointer">
<i data-lucide="user" class="w-4 h-4 text-slate-500"></i>
</div>
</div>
</header>
<div class="p-6 space-y-6 overflow-y-auto custom-scrollbar flex-1 bg-slate-50">
<!-- 统计卡片 (可点击) -->
<div class="grid grid-cols-4 gap-4" id="dashStatCards">
<div onclick="dashShowTable('projects')" class="bg-white rounded-xl shadow-sm border border-slate-100 hover:shadow-md hover:border-primary/30 transition-all overflow-hidden cursor-pointer group">
<div class="h-[3px] bg-gradient-to-r from-blue-500 to-blue-400"></div>
<div class="p-5">
<div class="flex justify-between items-start">
<span class="text-xs font-medium text-slate-500 group-hover:text-primary transition-colors">项目总数</span>
<div class="p-1.5 bg-blue-50 rounded-lg text-primary"><i data-lucide="layers" class="w-4 h-4"></i></div>
</div>
<div class="mt-3">
<span id="dashTotalProj" class="text-3xl font-din font-bold text-slate-900 skeleton-text">--</span>
<div class="flex items-center gap-1 mt-1">
<span id="dashTotalProjTrend" class="text-[10px] font-medium skeleton-text-sm">--</span>
<span class="text-[10px] text-slate-400">环比</span>
</div>
</div>
<p class="text-[10px] text-slate-400 mt-2 opacity-0 group-hover:opacity-100 transition-opacity">点击查看完整列表 →</p>
</div>
</div>
<div onclick="dashShowTable('domains')" class="bg-white rounded-xl shadow-sm border border-slate-100 hover:shadow-md hover:border-purple-500/30 transition-all overflow-hidden cursor-pointer group">
<div class="h-[3px] bg-gradient-to-r from-purple-500 to-purple-400"></div>
<div class="p-5">
<div class="flex justify-between items-start">
<span class="text-xs font-medium text-slate-500 group-hover:text-purple-600 transition-colors">技术领域</span>
<div class="p-1.5 bg-purple-50 rounded-lg text-purple-500"><i data-lucide="cpu" class="w-4 h-4"></i></div>
</div>
<div class="mt-3">
<span id="dashTechCount" class="text-3xl font-din font-bold text-slate-900 skeleton-text">--</span>
<div class="flex items-center gap-1 mt-1">
<span id="dashTechCountTrend" class="text-[10px] font-medium skeleton-text-sm">--</span>
<span class="text-[10px] text-slate-400">个领域</span>
</div>
</div>
<p class="text-[10px] text-slate-400 mt-2 opacity-0 group-hover:opacity-100 transition-opacity">点击查看领域分布 →</p>
</div>
</div>
<div onclick="dashShowTable('institutions')" class="bg-white rounded-xl shadow-sm border border-slate-100 hover:shadow-md hover:border-amber-500/30 transition-all overflow-hidden cursor-pointer group">
<div class="h-[3px] bg-gradient-to-r from-amber-500 to-amber-400"></div>
<div class="p-5">
<div class="flex justify-between items-start">
<span class="text-xs font-medium text-slate-500 group-hover:text-amber-600 transition-colors">合作机构</span>
<div class="p-1.5 bg-amber-50 rounded-lg text-amber-500"><i data-lucide="building-2" class="w-4 h-4"></i></div>
</div>
<div class="mt-3">
<span id="dashInstCount" class="text-3xl font-din font-bold text-slate-900 skeleton-text">--</span>
<div class="flex items-center gap-1 mt-1">
<span id="dashInstCountTrend" class="text-[10px] font-medium skeleton-text-sm">--</span>
<span class="text-[10px] text-slate-400">家机构</span>
</div>
</div>
<p class="text-[10px] text-slate-400 mt-2 opacity-0 group-hover:opacity-100 transition-opacity">点击查看机构列表 →</p>
</div>
</div>
<div onclick="dashShowTable('projects')" class="bg-white rounded-xl shadow-sm border border-slate-100 hover:shadow-md hover:border-emerald-500/30 transition-all overflow-hidden cursor-pointer group">
<div class="h-[3px] bg-gradient-to-r from-emerald-500 to-emerald-400"></div>
<div class="p-5">
<div class="flex justify-between items-start">
<span class="text-xs font-medium text-slate-500 group-hover:text-emerald-600 transition-colors">预算总额</span>
<div class="p-1.5 bg-emerald-50 rounded-lg text-emerald-500"><i data-lucide="dollar-sign" class="w-4 h-4"></i></div>
</div>
<div class="mt-3">
<span id="dashTotalBudget" class="text-3xl font-din font-bold text-slate-900 skeleton-text">--</span>
<div class="flex items-center gap-1 mt-1">
<span id="dashTotalBudgetTrend" class="text-[10px] font-medium skeleton-text-sm">--</span>
<span class="text-[10px] text-slate-400">环比</span>
</div>
</div>
<p class="text-[10px] text-slate-400 mt-2 opacity-0 group-hover:opacity-100 transition-opacity">点击查看项目明细 →</p>
</div>
</div>
</div>
<!-- 数据表格 (默认隐藏) -->
<div id="dashDataTable" class="bg-white rounded-xl shadow-sm border border-slate-100 p-6 hidden">
<div class="flex items-center justify-between mb-4">
<h3 class="font-bold text-slate-800 flex items-center gap-2" id="dashTableTitle">
<div class="w-1 h-5 bg-primary rounded-full"></div>
项目列表
</h3>
<div class="flex items-center gap-2">
<button onclick="dashAddRow()" class="flex items-center gap-1 px-3 py-1.5 bg-primary text-white rounded-lg text-xs font-medium hover:bg-blue-600 transition-colors">
<i data-lucide="plus" class="w-3.5 h-3.5"></i> 新增
</button>
<button onclick="document.getElementById('dashDataTable').classList.add('hidden')" class="p-1.5 hover:bg-slate-100 rounded-lg transition-colors">
<i data-lucide="x" class="w-4 h-4 text-slate-400"></i>
</button>
</div>
</div>
<div class="overflow-x-auto max-h-96 overflow-y-auto custom-scrollbar">
<table class="w-full text-xs">
<thead class="sticky top-0 bg-slate-50 z-10">
<tr class="text-left text-slate-500">
<th class="py-2 px-3 font-medium">项目编号</th>
<th class="py-2 px-3 font-medium">项目名称</th>
<th class="py-2 px-3 font-medium">领域</th>
<th class="py-2 px-3 font-medium">状态</th>
<th class="py-2 px-3 font-medium">预算(万美元)</th>
<th class="py-2 px-3 font-medium">开始</th>
<th class="py-2 px-3 font-medium">结束</th>
<th class="py-2 px-3 font-medium text-right">操作</th>
</tr>
</thead>
<tbody id="dashTableBody" class="divide-y divide-slate-50">
<tr><td colspan="8" class="py-8 text-center text-slate-400">加载中...</td></tr>
</tbody>
</table>
</div>
<p id="dashTableCount" class="text-[10px] text-slate-400 mt-2"></p>
</div>
<!-- 主图表行: 年代趋势 + Top5 -->
<div class="grid grid-cols-5 gap-6">
<div class="col-span-3 bg-white rounded-xl shadow-sm border border-slate-100 p-6">
<h3 class="font-bold text-slate-800 mb-3 flex items-center gap-2">
<div class="w-1 h-5 bg-primary rounded-full"></div>
项目数量年代分布
</h3>
<div id="dashTimelineChart" style="width:100%;height:300px">
<p class="text-sm text-slate-400 text-center pt-28">加载中...</p>
</div>
</div>
<div class="col-span-2 bg-white rounded-xl shadow-sm border border-slate-100 p-6 flex flex-col">
<h3 class="font-bold text-slate-800 mb-3 flex items-center gap-2">
<div class="w-1 h-5 bg-emerald-500 rounded-full"></div>
领域预算 Top5
</h3>
<div id="dashDomainMiniBars" class="space-y-2.5 flex-1">
<p class="text-xs text-slate-400">加载中...</p>
</div>
<div class="mt-3 pt-4 border-t border-slate-100">
<h4 class="text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-2.5">快捷入口</h4>
<div class="grid grid-cols-2 gap-2">
<button onclick="showPage('graphPage')" class="flex items-center gap-2 p-2 rounded-lg bg-blue-50 hover:bg-blue-100 text-blue-700 text-xs font-medium transition-colors">
<i data-lucide="share-2" class="w-3.5 h-3.5"></i> 知识图谱
</button>
<button onclick="showPage('trendPage')" class="flex items-center gap-2 p-2 rounded-lg bg-purple-50 hover:bg-purple-100 text-purple-700 text-xs font-medium transition-colors">
<i data-lucide="trending-up" class="w-3.5 h-3.5"></i> 趋势分析
</button>
<button onclick="showPage('wikiPage')" class="flex items-center gap-2 p-2 rounded-lg bg-amber-50 hover:bg-amber-100 text-amber-700 text-xs font-medium transition-colors">
<i data-lucide="book-open" class="w-3.5 h-3.5"></i> 情报百科
</button>
<button onclick="showPage('searchPage')" class="flex items-center gap-2 p-2 rounded-lg bg-emerald-50 hover:bg-emerald-100 text-emerald-700 text-xs font-medium transition-colors">
<i data-lucide="search" class="w-3.5 h-3.5"></i> 智能检索
</button>
<button onclick="showPage('governancePage')" class="flex items-center gap-2 p-2 rounded-lg bg-slate-100 hover:bg-slate-200 text-slate-700 text-xs font-medium transition-colors">
<i data-lucide="database" class="w-3.5 h-3.5"></i> 数据治理
</button>
</div>
</div>
</div>
</div>
<!-- AI 情报研判摘要 -->
<div id="dashAiSummaryCard" class="bg-white rounded-xl shadow-sm border p-6" style="border-left:4px solid #eab308;background:#fefce8">
<div class="flex items-start gap-3">
<div class="w-9 h-9 bg-white rounded-full flex items-center justify-center shadow-sm border border-yellow-200 shrink-0 mt-0.5">
<i data-lucide="sparkles" class="w-4 h-4 text-yellow-500"></i>
</div>
<div class="flex-1 min-w-0">
<div class="flex items-center justify-between mb-2">
<h4 class="font-bold text-slate-800 text-sm">AI 情报研判摘要</h4>
<span class="text-[10px] text-slate-400">基于图谱实时生成</span>
</div>
<div id="dashAiSummary" class="text-sm text-slate-600 leading-relaxed line-clamp-4">
<p class="text-slate-400 italic">数据加载中...</p>
</div>
<a onclick="showPage('trendPage')" class="inline-block mt-2 text-xs text-primary hover:text-blue-700 font-medium cursor-pointer">
查看完整分析 <i data-lucide="arrow-right" class="w-3 h-3 inline"></i>
</a>
</div>
</div>
</div>
<div id="dashAiSummaryError" class="bg-white rounded-xl shadow-sm border border-slate-100 p-6 hidden">
<div class="flex items-start gap-3">
<div class="w-9 h-9 bg-red-50 rounded-full flex items-center justify-center shrink-0 mt-0.5">
<i data-lucide="alert-circle" class="w-4 h-4 text-red-400"></i>
</div>
<div>
<h4 class="font-bold text-slate-800 text-sm">数据加载失败</h4>
<p class="text-sm text-slate-500 mt-1">AI 研判数据获取失败,请检查后端服务。</p>
</div>
</div>
</div>
<!-- 重点预算项目 -->
<div class="bg-white rounded-xl shadow-sm border border-slate-100 p-6">
<h3 class="font-bold text-slate-800 mb-3 flex items-center gap-2">
<div class="w-1 h-5 bg-orange-500 rounded-full"></div>
重大预算投入项目 (Top 5)
</h3>
<div id="dashKeyProjects" class="divide-y divide-slate-50">
<p class="text-sm text-slate-400">加载中...</p>
</div>
</div>
</div>
</main>
</div>
<!-- 编辑/新增弹窗 -->
<div id="dashEditModal" class="fixed inset-0 bg-black/40 z-50 hidden flex items-center justify-center" onclick="if(event.target===this)this.classList.add('hidden')">
<div class="bg-white rounded-xl shadow-2xl p-6 w-full max-w-lg mx-4 max-h-[85vh] overflow-y-auto">
<h3 class="font-bold text-slate-800 text-lg mb-4" id="dashModalTitle">编辑项目</h3>
<div class="space-y-3">
<div>
<label class="text-[11px] text-slate-500 font-medium">项目编号</label>
<input id="dashF_projectId" class="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:border-primary" placeholder="DARPA-2026-XX-001">
</div>
<div class="grid grid-cols-2 gap-3">
<div>
<label class="text-[11px] text-slate-500 font-medium">中文名称</label>
<input id="dashF_nameCn" class="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:border-primary">
</div>
<div>
<label class="text-[11px] text-slate-500 font-medium">英文名称</label>
<input id="dashF_nameEn" class="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:border-primary">
</div>
</div>
<div class="grid grid-cols-2 gap-3">
<div>
<label class="text-[11px] text-slate-500 font-medium">技术领域</label>
<input id="dashF_domain" class="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:border-primary">
</div>
<div>
<label class="text-[11px] text-slate-500 font-medium">状态</label>
<select id="dashF_status" class="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:border-primary">
<option value="研发中">研发中</option>
<option value="结题">结题</option>
<option value="已完成">已完成</option>
<option value="进行中">进行中</option>
<option value="立项中">立项中</option>
</select>
</div>
</div>
<div class="grid grid-cols-3 gap-3">
<div>
<label class="text-[11px] text-slate-500 font-medium">预算(万美元)</label>
<input id="dashF_budgetVal" type="number" class="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:border-primary">
</div>
<div>
<label class="text-[11px] text-slate-500 font-medium">开始年份</label>
<input id="dashF_startYear" type="number" class="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:border-primary">
</div>
<div>
<label class="text-[11px] text-slate-500 font-medium">结束年份</label>
<input id="dashF_endYear" type="number" class="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:border-primary">
</div>
</div>
</div>
<div class="flex justify-end gap-2 mt-5">
<button onclick="document.getElementById('dashEditModal').classList.add('hidden')" class="px-4 py-2 text-sm text-slate-600 hover:bg-slate-100 rounded-lg transition-colors">取消</button>
<button onclick="dashSaveRow()" class="px-4 py-2 text-sm bg-primary text-white rounded-lg hover:bg-blue-600 transition-colors font-medium">保存</button>
</div>
</div>
</div>
</div>

@ -0,0 +1,234 @@
<div id="detailPage" class="page bg-[#F8FAFC]">
<div class="w-full h-screen flex">
<!-- Sidebar (与 dashboard 一致) -->
<aside class="w-64 bg-sidebar text-slate-400 flex flex-col shrink-0">
<div class="p-6 flex items-center gap-3">
<div class="w-8 h-8 bg-primary rounded flex items-center justify-center text-white">
<i data-lucide="shield-half" class="w-5 h-5"></i>
</div>
<span class="text-white font-bold tracking-tight text-lg">DARPA Intelligence</span>
</div>
<nav class="flex-1 px-4 py-4 space-y-1 overflow-y-auto custom-scrollbar">
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mb-2">主导航</div>
<a data-nav-key="dashboard" onclick="showPage('dashboardPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="layout-dashboard" class="w-4 h-4"></i> 工作台
</a>
<a data-nav-key="search" onclick="showPage('searchPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="search" class="w-4 h-4"></i> 智能检索
</a>
<a data-nav-key="graph" onclick="showPage('graphPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="share-2" class="w-4 h-4"></i> 可视化分析
</a>
<a data-nav-key="trend" onclick="showPage('trendPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="trending-up" class="w-4 h-4"></i> 趋势分析
</a>
<a data-nav-key="wiki" onclick="showPage('wikiPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="book-open" class="w-4 h-4"></i> 情报百科
</a>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-6 mb-2">数据管理</div>
<a data-nav-key="governance" onclick="showPage('governancePage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="database" class="w-4 h-4"></i> 数据治理
</a>
<a data-nav-key="detail" class="flex items-center gap-3 px-3 py-2.5 rounded-lg menu-active text-sm cursor-pointer">
<i data-lucide="file-text" class="w-4 h-4"></i> 项目详情
</a>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-6 mb-2">系统</div>
<a onclick="logout()" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="log-out" class="w-4 h-4"></i> 退出登录
</a>
</nav>
<!-- User info at bottom -->
<div class="p-4 border-t border-white/5 flex items-center gap-3">
<div class="sidebar-user-avatar w-8 h-8 rounded-full bg-slate-700 flex items-center justify-center text-slate-300 shrink-0">
<i data-lucide="user" class="w-4 h-4"></i>
</div>
<div class="flex-1 min-w-0">
<p class="sidebar-user-name text-xs font-bold text-white truncate">--</p>
<p class="sidebar-user-role text-[10px] text-slate-500 truncate">--</p>
</div>
<button onclick="logout()" class="text-slate-500 hover:text-slate-300 transition-colors" title="退出">
<i data-lucide="log-out" class="w-4 h-4"></i>
</button>
</div>
</aside>
<!-- Right: header + main + footer (scrollable) -->
<div class="flex-1 flex flex-col overflow-y-auto custom-scrollbar bg-[#F8FAFC]">
<!-- Sticky Header / Breadcrumb -->
<header class="detail-glass-header sticky top-0 z-50 px-8 py-4 flex items-center justify-between shrink-0">
<nav class="flex items-center space-x-2 text-sm">
<button onclick="showPage('searchPage')" class="text-slate-400 hover:text-primary transition-colors">智能检索</button>
<i data-lucide="chevron-right" class="w-4 h-4 text-slate-300"></i>
<button onclick="showPage('governancePage')" class="text-slate-400 hover:text-primary transition-colors">情报库</button>
<i data-lucide="chevron-right" class="w-4 h-4 text-slate-300"></i>
<span class="text-slate-800 font-medium">项目详情: ACE</span>
</nav>
<div class="flex items-center space-x-3">
<button onclick="history.back ? showPage('searchPage') : null" class="flex items-center gap-2 px-4 py-2 text-sm font-medium text-slate-600 bg-white border border-slate-200 rounded-lg hover:shadow-sm transition-all">
<i data-lucide="arrow-left" class="w-4 h-4"></i> 返回
</button>
<button class="flex items-center gap-2 px-4 py-2 text-sm font-medium text-slate-600 bg-white border border-slate-200 rounded-lg hover:shadow-sm transition-all">
<i data-lucide="star" class="w-4 h-4 text-amber-400"></i> 收藏
</button>
<div class="relative group">
<button class="flex items-center gap-2 px-4 py-2 text-sm font-medium text-white bg-primary rounded-lg hover:bg-blue-600 shadow transition-all">
<i data-lucide="download" class="w-4 h-4"></i> 导出数据 <i data-lucide="chevron-down" class="w-3 h-3"></i>
</button>
<div class="absolute right-0 mt-2 w-48 bg-white border border-slate-100 rounded-xl shadow-xl opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 overflow-hidden z-50">
<a href="#" class="flex items-center gap-3 px-4 py-3 text-sm text-slate-600 hover:bg-slate-50 border-b border-slate-50"><i data-lucide="file-type" class="w-4 h-4 text-red-500"></i> 生成分析 PDF</a>
<a href="#" class="flex items-center gap-3 px-4 py-3 text-sm text-slate-600 hover:bg-slate-50 border-b border-slate-50"><i data-lucide="image" class="w-4 h-4 text-emerald-500"></i> 导出长图 PNG</a>
<a href="#" class="flex items-center gap-3 px-4 py-3 text-sm text-slate-600 hover:bg-slate-50"><i data-lucide="code-2" class="w-4 h-4 text-blue-500"></i> 结构化 JSON</a>
</div>
</div>
<button class="p-2 text-slate-400 hover:text-primary transition-colors"><i data-lucide="share-2" class="w-5 h-5"></i></button>
<div onclick="openProfileModal()" class="header-user-avatar w-8 h-8 rounded-full bg-slate-200 flex items-center justify-center cursor-pointer shrink-0">
<i data-lucide="user" class="w-4 h-4 text-slate-500"></i>
</div>
</div>
</header>
<!-- Main Content -->
<main class="flex-1 px-8 py-8 grid grid-cols-12 gap-8">
<!-- Left Column (8/12) -->
<div class="col-span-8 space-y-8">
<!-- Title Section -->
<section>
<div class="flex items-center gap-4 mb-3">
<span id="detailStatus" class="px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider status-tag-in rounded">--</span>
<span id="detailProjectId" class="text-slate-400 text-sm font-mono">ID: --</span>
</div>
<h1 id="detailTitle" class="text-3xl font-extrabold text-slate-900 tracking-tight leading-tight skeleton-text">
加载中...
</h1>
<p id="detailNameEn" class="mt-2 text-slate-500 flex items-center gap-2 text-sm">
<i data-lucide="info" class="w-4 h-4 shrink-0"></i>
</p>
</section>
<!-- Base Info Grid -->
<div class="detail-card p-6 grid grid-cols-3 gap-y-8">
<div>
<p class="text-[11px] font-bold text-slate-400 uppercase tracking-widest mb-1">主管办公室</p>
<p id="detailOffice" class="text-sm font-bold text-slate-900 flex items-center gap-2 detail-stat-val skeleton-text">
<i data-lucide="building-2" class="w-4 h-4 text-primary"></i> --
</p>
</div>
<div>
<p class="text-[11px] font-bold text-slate-400 uppercase tracking-widest mb-1">研究领域</p>
<p id="detailDomain" class="text-sm font-bold text-slate-900 detail-stat-val skeleton-text">--</p>
</div>
<div>
<p class="text-[11px] font-bold text-slate-400 uppercase tracking-widest mb-1">项目周期</p>
<p id="detailPeriod" class="text-sm font-bold text-slate-900 detail-stat-val skeleton-text">--</p>
</div>
<div>
<p class="text-[11px] font-bold text-slate-400 uppercase tracking-widest mb-1">预估经费</p>
<p id="detailBudget" class="text-sm font-bold text-primary detail-stat-val skeleton-text">--</p>
</div>
<div>
<p class="text-[11px] font-bold text-slate-400 uppercase tracking-widest mb-1">项目经理</p>
<p id="detailManager" class="text-sm font-bold text-slate-900 detail-stat-val skeleton-text">--</p>
</div>
<div class="col-span-3">
<p class="text-[11px] font-bold text-slate-400 uppercase tracking-widest mb-2">关键词</p>
<div id="detailKeywords" class="flex flex-wrap gap-2 detail-tag-area"></div>
</div>
<div class="col-span-3">
<p class="text-[11px] font-bold text-slate-400 uppercase tracking-widest mb-2">技术领域标签</p>
<div id="detailTechnologies" class="flex flex-wrap gap-2 detail-tag-area"></div>
</div>
</div>
<!-- Abstract Card -->
<div class="detail-card overflow-hidden">
<div class="px-6 py-4 border-b border-slate-50 flex justify-between items-center">
<h3 class="font-bold text-slate-900 flex items-center gap-2">
<i data-lucide="file-text" class="w-4 h-4 text-primary"></i> 项目摘要
</h3>
<span id="detailWikipedia" class="text-xs text-blue-500 font-medium hover:underline hidden"></span>
</div>
<div class="p-6 relative">
<div id="detailAbstractContent" class="text-sm text-slate-600 leading-relaxed">
加载中...
</div>
<div id="detailAbstractOverlay" class="detail-abstract-fade absolute bottom-0 left-0 w-full h-14 flex items-end justify-center pb-3" style="display:none">
<button onclick="toggleDetailAbstract()" class="text-xs font-bold text-primary flex items-center gap-1 bg-white px-4 py-1.5 rounded-full shadow-sm border border-slate-100 hover:shadow-md transition-all">
展开全文 <i data-lucide="chevron-down" class="w-3 h-3"></i>
</button>
</div>
</div>
</div>
<!-- Milestones Timeline -->
<div class="space-y-4">
<h3 class="font-bold text-slate-900 flex items-center gap-2 px-1">
<i data-lucide="clock" class="w-4 h-4 text-orange-500"></i> 里程碑
</h3>
<div id="detailMilestones" class="ml-4 border-l-2 border-slate-100 space-y-0 pb-2">
<p class="text-xs text-slate-300">加载中...</p>
</div>
</div>
</div>
<!-- Right Column (4/12) -->
<div class="col-span-4 space-y-8">
<!-- Related Entities -->
<div class="detail-card p-6">
<h3 class="font-bold text-slate-900 text-sm mb-4">项目经理</h3>
<div id="detailManagerInfo" class="space-y-4">
<p class="text-xs text-slate-300">加载中...</p>
</div>
</div>
<!-- Institutions -->
<div class="detail-card p-6">
<h3 class="font-bold text-slate-900 text-sm mb-4">参与机构</h3>
<div id="detailInstitutions" class="space-y-1">
<p class="text-xs text-slate-300">加载中...</p>
</div>
<button onclick="showPage('graphPage')" class="w-full mt-3 py-2 text-xs font-bold text-primary border border-primary/30 rounded-lg hover:bg-blue-50 transition-colors flex items-center justify-center gap-2">
<i data-lucide="share-2" class="w-3 h-3"></i> 在关系图谱中查看
</button>
</div>
<!-- Quick Links -->
<div class="bg-slate-900 rounded-2xl p-6 shadow-xl text-white">
<h3 class="font-bold text-sm mb-4 flex items-center gap-2">
<i data-lucide="book-open" class="w-4 h-4 text-blue-400"></i> 情报百科
</h3>
<div class="space-y-3">
<div class="group cursor-pointer" onclick="showPage('wikiPage')">
<p class="text-xs font-bold text-blue-400 group-hover:underline">技术图谱</p>
<p class="text-[10px] text-slate-400 mt-1">查阅相关技术领域详细描述与军事意义</p>
</div>
<div class="h-px bg-slate-800"></div>
<div class="group cursor-pointer" onclick="showPage('wikiPage')">
<p class="text-xs font-bold text-blue-400 group-hover:underline">里程碑时间线</p>
<p class="text-[10px] text-slate-400 mt-1">查看 DARPA 历史性技术突破里程碑</p>
</div>
</div>
</div>
</div>
</main>
<!-- Footer -->
<footer class="px-8 py-5 border-t border-slate-200 bg-white flex items-center justify-between text-[11px] text-slate-400 shrink-0">
<div class="flex items-center gap-4">
<span class="flex items-center gap-1"><i data-lucide="database" class="w-3 h-3"></i> 数据来源DARPA Open Data Portal / 情报采集站 A-12</span>
<span class="text-slate-200">|</span>
<span>安全分级:<span class="font-bold text-emerald-600">Unclassified</span></span>
</div>
<div class="flex items-center gap-4">
<span>最后同步2024-10-24 10:24:41</span>
<span class="flex items-center gap-1 text-primary cursor-pointer hover:underline"><i data-lucide="refresh-cw" class="w-3 h-3"></i> 手动刷新</span>
</div>
</footer>
</div><!-- end right flex col -->
</div><!-- end h-screen flex -->
</div><!-- end detailPage -->

@ -0,0 +1,336 @@
<div id="governancePage" class="page">
<div class="w-full h-screen flex">
<!-- Sidebar -->
<aside class="w-64 bg-sidebar text-slate-400 flex flex-col shrink-0">
<div class="p-6 flex items-center gap-3">
<div class="w-8 h-8 bg-primary rounded flex items-center justify-center text-white">
<i data-lucide="shield-half" class="w-5 h-5"></i>
</div>
<span class="text-white font-bold tracking-tight text-lg">DARPA Intelligence</span>
</div>
<nav class="flex-1 px-4 py-4 space-y-1 overflow-y-auto custom-scrollbar">
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mb-2">主导航</div>
<a data-nav-key="dashboard" onclick="showPage('dashboardPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="layout-dashboard" class="w-4 h-4"></i> 工作台
</a>
<a data-nav-key="search" onclick="showPage('searchPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="search" class="w-4 h-4"></i> 智能检索
</a>
<a data-nav-key="graph" onclick="showPage('graphPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="share-2" class="w-4 h-4"></i> 可视化分析
</a>
<a data-nav-key="trend" onclick="showPage('trendPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="trending-up" class="w-4 h-4"></i> 趋势分析
</a>
<a data-nav-key="wiki" onclick="showPage('wikiPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="book-open" class="w-4 h-4"></i> 情报百科
</a>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-6 mb-2">数据管理</div>
<a data-nav-key="governance" onclick="showPage('governancePage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg menu-active text-sm cursor-pointer">
<i data-lucide="database" class="w-4 h-4"></i> 数据治理
</a>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-6 mb-2">系统</div>
<a onclick="logout()" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="log-out" class="w-4 h-4"></i> 退出登录
</a>
</nav>
<div class="p-4 border-t border-white/5 flex items-center gap-3">
<div class="sidebar-user-avatar w-8 h-8 rounded-full bg-slate-700 flex items-center justify-center text-slate-300 shrink-0">
<i data-lucide="user" class="w-4 h-4"></i>
</div>
<div class="flex-1 min-w-0">
<p class="sidebar-user-name text-xs font-bold text-white truncate">--</p>
<p class="sidebar-user-role text-[10px] text-slate-500 truncate">--</p>
</div>
</div>
</aside>
<!-- Right content -->
<div class="flex-1 flex flex-col bg-slate-100 overflow-hidden">
<!-- Action Bar (原来的顶部 nav 精简为操作栏,去掉 logo 和返回按钮) -->
<div class="h-14 px-6 border-b border-slate-200 bg-white flex items-center justify-between shrink-0">
<div class="flex items-center gap-3">
<span class="font-bold text-slate-900 text-sm">Governance <span class="text-primary">Console</span></span>
<div class="h-4 w-px bg-slate-200"></div>
<div class="flex gap-5 text-sm font-medium text-slate-500">
<a id="gtab-governance" onclick="switchGovTab('governance')" class="text-primary border-b-2 border-primary pb-[13px] pt-[13px] cursor-pointer">数据治理</a>
<a id="gtab-crawler" onclick="switchGovTab('crawler')" class="hover:text-slate-900 transition-colors py-[13px] cursor-pointer">采集任务</a>
<a id="gtab-backup" onclick="switchGovTab('backup')" class="hover:text-slate-900 transition-colors py-[13px] cursor-pointer">数据备份</a>
</div>
</div>
<div class="flex items-center gap-3">
<div class="relative">
<i data-lucide="search" class="w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-slate-400"></i>
<input type="text" placeholder="搜索项目或机构..." class="pl-10 pr-4 py-1.5 bg-slate-100 border-transparent focus:bg-white focus:border-primary rounded-lg text-sm w-52 outline-none transition-all border">
</div>
<div onclick="openProfileModal()" class="header-user-avatar w-8 h-8 rounded-full bg-slate-200 flex items-center justify-center cursor-pointer">
<i data-lucide="user" class="w-4 h-4 text-slate-600"></i>
</div>
</div>
</div>
<!-- Action Bar -->
<div class="px-6 py-3 border-b border-slate-200 bg-white flex items-center justify-between shrink-0">
<div class="flex items-center gap-3">
<button onclick="toggleGovModal()" class="bg-primary hover:bg-blue-600 text-white px-4 py-2 rounded-lg text-sm font-semibold flex items-center gap-2 shadow-sm transition-all">
<i data-lucide="upload-cloud" class="w-4 h-4"></i> 数据导入
</button>
<button class="bg-white border border-slate-200 px-4 py-2 rounded-lg text-sm font-medium flex items-center gap-2 hover:bg-slate-50">
批量操作 <i data-lucide="chevron-down" class="w-4 h-4"></i>
</button>
<button class="p-2 text-slate-500 hover:bg-slate-200 rounded-lg transition-colors"><i data-lucide="rotate-cw" class="w-4 h-4"></i></button>
</div>
<div class="flex items-center gap-2">
<span class="text-xs text-slate-400 font-medium mr-2">筛选状态:</span>
<select class="text-xs border-slate-200 rounded-md py-1.5 px-2 outline-none border">
<option>全部状态</option><option>已入库</option><option>清洗中</option><option>校验失败</option><option>待采集</option>
</select>
</div>
</div>
<!-- Content: Table + Sidebar -->
<div id="gpanel-governance" class="flex flex-1 overflow-hidden relative">
<!-- Floating Batch Bar -->
<div id="govBatchBar" class="hidden absolute top-4 left-1/2 -translate-x-1/2 bg-slate-900 text-white px-6 py-3 rounded-full shadow-2xl flex items-center gap-6 z-30">
<span class="text-sm font-medium">已选中 <span id="govSelectedCount" class="text-blue-400">0</span> 项数据</span>
<div class="h-4 w-px bg-slate-700"></div>
<div class="flex items-center gap-4">
<button class="text-sm hover:text-blue-400 flex items-center gap-1"><i data-lucide="download" class="w-4 h-4"></i> 导出</button>
<button class="text-sm hover:text-blue-400 flex items-center gap-1"><i data-lucide="tag" class="w-4 h-4"></i> 标记</button>
<button class="text-sm hover:text-red-400 flex items-center gap-1"><i data-lucide="trash-2" class="w-4 h-4"></i> 删除</button>
</div>
<button onclick="clearGovSelection()" class="ml-4 text-slate-400 hover:text-white"><i data-lucide="x" class="w-4 h-4"></i></button>
</div>
<!-- Table -->
<div class="flex-1 overflow-auto p-6">
<table class="w-full text-left border-collapse text-sm">
<thead>
<tr class="text-slate-400 text-xs font-bold uppercase tracking-wider border-b border-slate-200">
<th class="pb-3 w-10"><input type="checkbox" id="govSelectAll" class="rounded border-slate-300"></th>
<th class="pb-3">项目编号</th>
<th class="pb-3">项目名称</th>
<th class="pb-3">承担机构</th>
<th class="pb-3">采集时间</th>
<th class="pb-3">清洗状态</th>
<th class="pb-3 text-right">操作</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100">
<tr class="hover:bg-white transition-colors group">
<td class="py-3"><input type="checkbox" class="gov-row-cb rounded border-slate-300"></td>
<td class="py-3 font-mono text-xs text-slate-500">D2024-QX-089</td>
<td class="py-3 font-semibold text-slate-800 cursor-pointer hover:text-primary" onclick="showPage('detailPage')">下一代空战系统算法验证</td>
<td class="py-3 text-slate-600">洛克希德·马丁</td>
<td class="py-3 text-slate-500 text-xs">2024-10-24 09:15</td>
<td class="py-3"><span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-semibold bg-emerald-50 text-emerald-700 border border-emerald-100"><i data-lucide="check-circle-2" class="w-3 h-3"></i> 已入库</span></td>
<td class="py-3 text-right"><button class="text-primary hover:underline font-medium text-xs" onclick="showPage('detailPage')">详情</button></td>
</tr>
<tr class="hover:bg-white transition-colors">
<td class="py-3"><input type="checkbox" class="gov-row-cb rounded border-slate-300"></td>
<td class="py-3 font-mono text-xs text-slate-500">D2024-QX-102</td>
<td class="py-3 font-semibold text-slate-800">量子保密通信协议分析</td>
<td class="py-3 text-slate-600">哈佛大学研究院</td>
<td class="py-3 text-slate-500 text-xs">2024-10-24 10:30</td>
<td class="py-3"><span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-semibold bg-amber-50 text-amber-700 border border-amber-100"><i data-lucide="loader-2" class="w-3 h-3 animate-spin"></i> 清洗中</span></td>
<td class="py-3 text-right"><button class="text-slate-400 cursor-not-allowed text-xs">停止</button></td>
</tr>
<tr class="hover:bg-white transition-colors">
<td class="py-3"><input type="checkbox" class="gov-row-cb rounded border-slate-300"></td>
<td class="py-3 font-mono text-xs text-slate-500">D2024-QX-115</td>
<td class="py-3 font-semibold text-slate-800">深海自主潜航器感知集群</td>
<td class="py-3 text-slate-600">波音防御系统</td>
<td class="py-3 text-slate-500 text-xs">2024-10-23 16:45</td>
<td class="py-3"><span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-semibold bg-rose-50 text-rose-700 border border-rose-100"><i data-lucide="alert-circle" class="w-3 h-3"></i> 校验失败</span></td>
<td class="py-3 text-right"><button class="text-primary hover:underline font-medium text-xs">重试</button></td>
</tr>
<tr class="hover:bg-white transition-colors">
<td class="py-3"><input type="checkbox" class="gov-row-cb rounded border-slate-300"></td>
<td class="py-3 font-mono text-xs text-slate-500">D2024-QX-121</td>
<td class="py-3 font-semibold text-slate-800">高超音速材料热防护测试</td>
<td class="py-3 text-slate-600">桑迪亚国家实验室</td>
<td class="py-3 text-slate-500 text-xs">2024-10-24 11:20</td>
<td class="py-3"><span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-semibold bg-slate-100 text-slate-500 border border-slate-200"><i data-lucide="clock" class="w-3 h-3"></i> 待采集</span></td>
<td class="py-3 text-right"><button class="text-primary hover:underline font-medium text-xs">开始</button></td>
</tr>
<tr class="hover:bg-white transition-colors">
<td class="py-3"><input type="checkbox" class="gov-row-cb rounded border-slate-300"></td>
<td class="py-3 font-mono text-xs text-slate-500">D2024-QX-138</td>
<td class="py-3 font-semibold text-slate-800">自主无人机编队控制算法</td>
<td class="py-3 text-slate-600">MIT林肯实验室</td>
<td class="py-3 text-slate-500 text-xs">2024-10-24 13:05</td>
<td class="py-3"><span class="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-semibold bg-emerald-50 text-emerald-700 border border-emerald-100"><i data-lucide="check-circle-2" class="w-3 h-3"></i> 已入库</span></td>
<td class="py-3 text-right"><button class="text-primary hover:underline font-medium text-xs" onclick="showPage('detailPage')">详情</button></td>
</tr>
</tbody>
</table>
<!-- Pagination -->
<div class="mt-6 flex items-center justify-between">
<span class="text-xs text-slate-500">显示 1 到 5 条,共 1,240 条记录</span>
<div class="flex items-center gap-2">
<button class="p-2 border border-slate-200 rounded hover:bg-slate-50"><i data-lucide="chevron-left" class="w-4 h-4"></i></button>
<button class="w-8 h-8 bg-primary text-white rounded text-sm font-bold">1</button>
<button class="w-8 h-8 hover:bg-slate-100 rounded text-sm">2</button>
<button class="w-8 h-8 hover:bg-slate-100 rounded text-sm">3</button>
<button class="p-2 border border-slate-200 rounded hover:bg-slate-50"><i data-lucide="chevron-right" class="w-4 h-4"></i></button>
</div>
</div>
</div>
<!-- Right Sidebar: Task Monitor -->
<aside class="w-72 border-l border-slate-200 bg-white flex flex-col shrink-0">
<div class="p-4 border-b border-slate-100 flex items-center justify-between">
<h3 class="font-bold text-sm flex items-center gap-2"><i data-lucide="activity" class="w-4 h-4 text-primary"></i> 任务实时监控</h3>
</div>
<div class="flex-1 overflow-auto p-4 space-y-5">
<!-- Progress -->
<div>
<div class="flex justify-between items-end mb-2">
<span class="text-xs font-bold text-slate-500 uppercase">数据清洗进度</span>
<span class="text-xs font-mono text-primary font-bold">78.4%</span>
</div>
<div class="h-1.5 w-full bg-slate-200 rounded-full overflow-hidden">
<div class="h-full bg-primary transition-all duration-500" style="width:78.4%"></div>
</div>
<p class="text-[10px] text-slate-400 mt-1.5">正在处理: D2024-QX-102 (哈佛大学研究院)</p>
</div>
<!-- Crawler Task -->
<div class="bg-slate-50 p-4 rounded-xl border border-slate-200 flex items-center gap-3">
<div class="relative w-12 h-12 flex items-center justify-center shrink-0">
<svg class="w-full h-full transform -rotate-90">
<circle cx="24" cy="24" r="20" stroke="currentColor" stroke-width="4" fill="transparent" class="text-slate-200"/>
<circle cx="24" cy="24" r="20" stroke="currentColor" stroke-width="4" fill="transparent" stroke-dasharray="125.6" stroke-dashoffset="30" class="text-emerald-500"/>
</svg>
<span class="absolute text-[10px] font-bold text-slate-700">爬虫</span>
</div>
<div>
<h4 class="text-xs font-bold text-slate-800">分布式爬虫任务 B-09</h4>
<p class="text-[10px] text-emerald-600 font-medium mt-0.5">运行中 · 耗时 12m</p>
</div>
</div>
<!-- History -->
<div>
<h4 class="text-xs font-bold text-slate-400 uppercase mb-3 flex items-center gap-2">
<i data-lucide="history" class="w-3 h-3"></i> 最近完成任务
</h4>
<div class="space-y-2">
<div class="text-[11px] p-2 hover:bg-slate-50 rounded border-l-2 border-emerald-400">
<div class="flex justify-between font-bold text-slate-700"><span>全量备份</span><span class="text-emerald-600">完成</span></div>
<div class="flex justify-between text-slate-400 mt-1"><span>2024-10-24 08:00</span><span>4.2GB</span></div>
</div>
<div class="text-[11px] p-2 hover:bg-slate-50 rounded border-l-2 border-primary">
<div class="flex justify-between font-bold text-slate-700"><span>字段解析 (Batch)</span><span class="text-primary">完成</span></div>
<div class="flex justify-between text-slate-400 mt-1"><span>2024-10-23 18:20</span><span>1.2s</span></div>
</div>
<div class="text-[11px] p-2 hover:bg-slate-50 rounded border-l-2 border-slate-300">
<div class="flex justify-between font-bold text-slate-700"><span>实体识别清洗</span><span class="text-slate-500">完成</span></div>
<div class="flex justify-between text-slate-400 mt-1"><span>2024-10-23 10:40</span><span>892条</span></div>
</div>
</div>
</div>
</div>
<button class="m-4 py-2 border border-slate-200 rounded-lg text-xs font-bold text-slate-600 hover:bg-slate-50 transition-colors">查看全部任务</button>
</aside>
</div>
<!-- Footer Stats -->
<footer class="h-12 border-t border-slate-200 bg-white px-6 flex items-center justify-between shrink-0">
<div class="flex items-center gap-8">
<div class="flex items-baseline gap-2">
<span class="text-[10px] font-bold text-slate-400 uppercase">数据总量</span>
<span class="text-sm font-bold text-slate-900">1,420,892</span>
</div>
<div class="flex items-baseline gap-2">
<span class="text-[10px] font-bold text-slate-400 uppercase">今日新增</span>
<span class="text-sm font-bold text-emerald-600">+1,240</span>
</div>
<div class="flex items-baseline gap-2">
<span class="text-[10px] font-bold text-slate-400 uppercase">异常警告</span>
<span class="text-sm font-bold text-rose-500">12</span>
</div>
</div>
<button class="text-xs font-bold text-primary flex items-center gap-2 hover:bg-blue-50 px-3 py-1.5 rounded-md transition-colors">
<i data-lucide="shield-check" class="w-4 h-4"></i> 立即执行系统备份
</button>
</footer>
<!-- 采集任务 Tab Panel -->
<div id="gpanel-crawler" class="hidden flex-1 flex items-center justify-center bg-slate-50">
<div class="text-center">
<div class="w-16 h-16 bg-slate-100 rounded-2xl flex items-center justify-center mx-auto mb-4">
<i data-lucide="rss" class="w-8 h-8 text-slate-400"></i>
</div>
<h3 class="text-sm font-bold text-slate-700 mb-1">采集任务管理</h3>
<p class="text-xs text-slate-400">分布式爬虫任务配置与监控</p>
<button class="mt-4 px-4 py-2 bg-primary text-white rounded-lg text-xs font-bold hover:bg-blue-600 transition-colors">
新建采集任务
</button>
</div>
</div>
<!-- 数据备份 Tab Panel -->
<div id="gpanel-backup" class="hidden flex-1 flex items-center justify-center bg-slate-50">
<div class="text-center">
<div class="w-16 h-16 bg-slate-100 rounded-2xl flex items-center justify-center mx-auto mb-4">
<i data-lucide="hard-drive" class="w-8 h-8 text-slate-400"></i>
</div>
<h3 class="text-sm font-bold text-slate-700 mb-1">数据备份中心</h3>
<p class="text-xs text-slate-400">全量/增量备份策略管理与历史记录</p>
<button class="mt-4 px-4 py-2 bg-primary text-white rounded-lg text-xs font-bold hover:bg-blue-600 transition-colors">
立即执行备份
</button>
</div>
</div>
<!-- Import Modal -->
<div id="govImportModal" class="hidden fixed inset-0 z-50 flex items-center justify-center bg-slate-900/60 backdrop-blur-sm">
<div class="bg-white w-[720px] rounded-2xl shadow-2xl overflow-hidden">
<div class="p-6 border-b border-slate-100 flex items-center justify-between">
<div>
<h2 class="text-lg font-bold text-slate-900">数据导入向导</h2>
<p class="text-xs text-slate-400 mt-1">支持 Excel/CSV 格式,单次最大 10,000 条记录</p>
</div>
<button onclick="toggleGovModal()" class="text-slate-400 hover:text-slate-600"><i data-lucide="x" class="w-6 h-6"></i></button>
</div>
<!-- Steps -->
<div class="px-12 py-6 bg-slate-50 flex justify-between relative">
<div class="absolute top-[52px] left-24 right-24 h-0.5 bg-slate-200"></div>
<div class="relative flex flex-col items-center gap-2 z-10">
<div class="w-8 h-8 rounded-full bg-primary text-white flex items-center justify-center text-xs font-bold">1</div>
<span class="text-[10px] font-bold text-primary uppercase">文件上传</span>
</div>
<div class="relative flex flex-col items-center gap-2 z-10">
<div class="w-8 h-8 rounded-full bg-white border-2 border-slate-200 text-slate-400 flex items-center justify-center text-xs font-bold">2</div>
<span class="text-[10px] font-bold text-slate-400 uppercase">智能解析</span>
</div>
<div class="relative flex flex-col items-center gap-2 z-10">
<div class="w-8 h-8 rounded-full bg-white border-2 border-slate-200 text-slate-400 flex items-center justify-center text-xs font-bold">3</div>
<span class="text-[10px] font-bold text-slate-400 uppercase">字段映射</span>
</div>
<div class="relative flex flex-col items-center gap-2 z-10">
<div class="w-8 h-8 rounded-full bg-white border-2 border-slate-200 text-slate-400 flex items-center justify-center text-xs font-bold">4</div>
<span class="text-[10px] font-bold text-slate-400 uppercase">结果预览</span>
</div>
</div>
<!-- Upload Zone -->
<div class="p-10">
<div class="border-2 border-dashed border-slate-200 rounded-2xl p-12 flex flex-col items-center justify-center bg-slate-50 hover:border-primary hover:bg-blue-50 transition-all cursor-pointer">
<div class="w-16 h-16 bg-white rounded-2xl shadow-sm flex items-center justify-center mb-4">
<i data-lucide="file-up" class="w-8 h-8 text-primary"></i>
</div>
<p class="text-sm font-bold text-slate-700">点击或将文件拖拽到此处</p>
<p class="text-xs text-slate-400 mt-2">支持 .xlsx, .xls, .csv 格式 (最大 20MB)</p>
</div>
</div>
<div class="p-6 border-t border-slate-100 flex justify-end gap-3 bg-slate-50">
<button onclick="toggleGovModal()" class="px-6 py-2 text-sm font-medium text-slate-600 hover:bg-slate-200 rounded-lg">取消</button>
<button class="px-6 py-2 text-sm font-bold bg-primary text-white rounded-lg hover:bg-blue-600 shadow-lg transition-all">下一步</button>
</div>
</div>
</div><!-- end govImportModal -->
</div><!-- end right wrapper -->
</div><!-- end h-screen flex -->
</div><!-- end governancePage -->

@ -0,0 +1,257 @@
<div id="graphPage" class="page">
<div class="w-full h-screen flex">
<!-- Sidebar (dark theme to match graph bg) -->
<aside class="w-64 bg-sidebar text-slate-400 flex flex-col shrink-0">
<div class="p-6 flex items-center gap-3">
<div class="w-8 h-8 bg-blue-600 rounded flex items-center justify-center text-white">
<i data-lucide="share-2" class="w-5 h-5"></i>
</div>
<span class="text-white font-bold tracking-tight text-lg">DARPA <span class="text-blue-400 font-light">Graph</span></span>
</div>
<nav class="flex-1 px-4 py-4 space-y-1 overflow-y-auto custom-scrollbar">
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mb-2">主导航</div>
<a data-nav-key="dashboard" onclick="showPage('dashboardPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="layout-dashboard" class="w-4 h-4"></i> 工作台
</a>
<a data-nav-key="search" onclick="showPage('searchPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="search" class="w-4 h-4"></i> 智能检索
</a>
<a data-nav-key="graph" onclick="showPage('graphPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg menu-active text-sm cursor-pointer">
<i data-lucide="share-2" class="w-4 h-4"></i> 可视化分析
</a>
<a data-nav-key="trend" onclick="showPage('trendPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="trending-up" class="w-4 h-4"></i> 趋势分析
</a>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-6 mb-2">图谱控制</div>
<div class="px-2 space-y-2">
<label class="flex items-center gap-2 text-xs text-slate-300 cursor-pointer">
<input type="checkbox" id="chkProj" checked onchange="reloadGraph()" class="accent-blue-500 rounded"> 项目节点
</label>
<label class="flex items-center gap-2 text-xs text-slate-300 cursor-pointer">
<input type="checkbox" id="chkTech" checked onchange="reloadGraph()" class="accent-purple-500 rounded"> 技术节点
</label>
<label class="flex items-center gap-2 text-xs text-slate-300 cursor-pointer">
<input type="checkbox" id="chkInst" checked onchange="reloadGraph()" class="accent-amber-600 rounded"> 机构节点
</label>
<label class="flex items-center justify-between text-xs text-slate-300 cursor-pointer">
<span>隐藏 DARPA</span>
<input type="checkbox" id="hideDarpa" checked onchange="reloadGraph()" class="accent-blue-500 rounded">
</label>
</div>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-4 mb-2">最短路径</div>
<div class="px-2 space-y-2">
<select id="pathFrom" class="w-full bg-slate-800 border border-slate-700 rounded px-2 py-1 text-xs text-slate-200 outline-none focus:border-blue-500"><option value="">── 选择起点 ──</option></select>
<select id="pathTo" class="w-full bg-slate-800 border border-slate-700 rounded px-2 py-1 text-xs text-slate-200 outline-none focus:border-blue-500"><option value="">── 选择终点 ──</option></select>
<label class="flex items-center justify-between text-xs text-slate-300 cursor-pointer">
<span>排除 DARPA 中转</span>
<input type="checkbox" id="pathIgnoreDarpa" checked class="accent-blue-500 rounded">
</label>
<div class="flex gap-1">
<button onclick="queryPath()" class="flex-1 px-2 py-1 bg-blue-700 hover:bg-blue-600 rounded text-xs font-medium transition-all">查询路径</button>
<button onclick="clearPath()" class="px-2 py-1 bg-slate-700 hover:bg-slate-600 rounded text-xs font-medium transition-all">清除</button>
</div>
<div id="pathResult" class="text-[10px] text-emerald-400 leading-relaxed min-h-[20px] break-all"></div>
</div>
<a data-nav-key="wiki" onclick="showPage('wikiPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="book-open" class="w-4 h-4"></i> 情报百科
</a>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-6 mb-2">数据管理</div>
<a data-nav-key="governance" onclick="showPage('governancePage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="database" class="w-4 h-4"></i> 数据治理
</a>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-6 mb-2">系统</div>
<a onclick="logout()" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="log-out" class="w-4 h-4"></i> 退出登录
</a>
</nav>
<div class="p-4 border-t border-white/5 flex items-center gap-3">
<div class="sidebar-user-avatar w-8 h-8 rounded-full bg-slate-700 flex items-center justify-center text-slate-300 shrink-0">
<i data-lucide="user" class="w-4 h-4"></i>
</div>
<div class="flex-1 min-w-0">
<p class="sidebar-user-name text-xs font-bold text-white truncate">--</p>
<p class="sidebar-user-role text-[10px] text-slate-500 truncate">--</p>
</div>
</div>
</aside>
<!-- Right content -->
<div class="flex-1 flex flex-col bg-slate-50 text-slate-800 overflow-hidden">
<!-- Top Control Bar (工具栏,去掉了原来的 logo 和返回按钮) -->
<header class="h-14 px-6 flex items-center justify-between shrink-0 z-50" style="background:rgba(255,255,255,0.88);backdrop-filter:blur(12px);border-bottom:1px solid rgba(0,0,0,0.06)">
<div class="flex items-center gap-6">
<!-- Graph Type Tabs -->
<div class="flex bg-slate-200/60 p-1 rounded-lg">
<button id="gtab-proj" onclick="switchGraphTab('proj')" class="px-3 py-1 text-xs font-medium rounded-md bg-blue-600 text-white transition-all">项目关联</button>
<button id="gtab-tech" onclick="switchGraphTab('tech')" class="px-3 py-1 text-xs font-medium text-slate-600 hover:text-slate-800 transition-all">技术演进</button>
<button id="gtab-org" onclick="switchGraphTab('org')" class="px-3 py-1 text-xs font-medium text-slate-600 hover:text-slate-800 transition-all">机构合作</button>
</div>
</div>
<div class="flex items-center gap-4">
<div onclick="openProfileModal()" class="header-user-avatar w-8 h-8 rounded-full bg-slate-200 flex items-center justify-center cursor-pointer shrink-0">
<i data-lucide="user" class="w-4 h-4 text-slate-500"></i>
</div>
<!-- Algorithm Select -->
<div class="flex items-center gap-2 text-xs text-slate-500">
<span>布局算法:</span>
<select id="graphLayout" onchange="changeLayout(this.value)" class="bg-white border border-slate-300 rounded px-2 py-1 text-slate-600 outline-none focus:border-blue-500">
<option value="force">力导向 (Force)</option>
<option value="circular">环形布局 (Circular)</option>
<option value="none">无布局 (None)</option>
</select>
</div>
<!-- Threshold Slider -->
<div class="flex items-center gap-2 text-xs text-slate-500">
<span>关联阈值:</span>
<input type="range" class="w-24 accent-blue-500" min="0" max="100" value="30">
</div>
<div class="h-6 w-px bg-slate-300"></div>
<div class="flex items-center gap-2">
<button onclick="resetGraphView()" class="p-2 text-slate-500 hover:text-slate-700 hover:bg-slate-100 rounded-lg transition-all" title="重置视图">
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
</button>
<button onclick="exportGraphImage()" class="flex items-center gap-2 px-3 py-1.5 bg-white hover:bg-slate-100 border border-slate-300 rounded-lg text-xs font-medium transition-all">
<i data-lucide="camera" class="w-4 h-4 text-blue-500"></i> 截图导出
</button>
<button onclick="reloadGraph()" class="flex items-center gap-2 px-3 py-1.5 bg-blue-600 hover:bg-blue-500 rounded-lg text-xs font-medium transition-all">
<i data-lucide="refresh-cw" class="w-4 h-4"></i> 刷新数据
</button>
</div>
</div>
</header>
<!-- Main Area -->
<main class="flex-1 flex overflow-hidden relative">
<!-- Left Legend (dark glass) -->
<div class="absolute left-6 top-6 z-10 p-4 rounded-xl shadow-lg glass-panel" style="min-width:160px">
<h4 class="text-[10px] font-bold text-slate-500 uppercase tracking-widest mb-3">节点图例</h4>
<div class="space-y-2">
<div class="flex items-center gap-2 text-[10px] text-slate-600">
<span class="w-2.5 h-2.5 rounded inline-block" style="background:#1d4ed8"></span> 项目 (圆角矩形)
</div>
<div class="flex items-center gap-2 text-[10px] text-slate-600">
<span class="w-2.5 h-2.5 inline-block" style="background:#6d28d9;clip-path:polygon(50% 0,100% 100%,0 100%)"></span> 技术 (菱形)
</div>
<div class="flex items-center gap-2 text-[10px] text-slate-600">
<span class="w-2.5 h-2.5 rounded-full inline-block" style="background:#b45309"></span> 机构 (圆)
</div>
</div>
<div class="mt-3 pt-3 border-t border-slate-200 space-y-1">
<div class="flex justify-between text-[10px]">
<span class="text-slate-500">节点总数</span><span id="graphNodeCount" class="font-mono text-blue-600">--</span>
</div>
<div class="flex justify-between text-[10px]">
<span class="text-slate-500">关系边数</span><span id="graphEdgeCount" class="font-mono text-blue-600">--</span>
</div>
</div>
</div>
<!-- Breadcrumb Navigation Bar -->
<div id="graphBreadcrumb" class="absolute top-4 left-1/2 -translate-x-1/2 z-20 flex items-center gap-2 px-4 py-2 rounded-full shadow-2xl transition-all" style="display:none;background:rgba(255,255,255,0.92);backdrop-filter:blur(12px);border:1px solid rgba(0,0,0,0.08)">
<button onclick="breadcrumbBack()" class="p-1 text-slate-500 hover:text-slate-800 transition-colors" title="返回上一级">
<i data-lucide="arrow-left" class="w-3.5 h-3.5"></i>
</button>
<div id="breadcrumbPath" class="flex items-center gap-1 text-xs"></div>
<button onclick="breadcrumbReset()" class="p-1 text-slate-500 hover:text-slate-800 transition-colors" title="重置视图">
<i data-lucide="x" class="w-3 h-3"></i>
</button>
</div>
<!-- Graph Canvas -->
<div id="mainGraph" class="flex-1 cursor-grab active:cursor-grabbing graph-canvas-bg" style="background-color:#ffffff"></div>
<!-- Right Side Panel -->
<aside id="graphSidePanel" class="w-[380px] flex flex-col shrink-0 transition-all duration-500" style="background:rgba(255,255,255,0.92);backdrop-filter:blur(12px);border-left:1px solid rgba(0,0,0,0.06)">
<div class="p-5 flex items-center justify-between shrink-0" style="border-bottom:1px solid rgba(0,0,0,0.06)">
<h3 class="font-bold flex items-center gap-2 text-sm text-slate-800">
<i data-lucide="info" class="w-4 h-4 text-blue-500"></i> 节点情报详情
</h3>
<button onclick="toggleGraphSidebar()" class="text-slate-400 hover:text-slate-600 transition-colors">
<i data-lucide="x" class="w-5 h-5"></i>
</button>
</div>
<div class="flex-1 overflow-y-auto p-5 space-y-6 custom-scrollbar">
<!-- Node Header -->
<div class="flex items-start gap-4">
<div id="gsp-icon-wrap" class="w-14 h-14 rounded-2xl flex items-center justify-center shrink-0" style="background:rgba(59,130,246,0.08);border:1px solid rgba(59,130,246,0.2)">
<i id="gsp-icon" data-lucide="rocket" class="w-7 h-7" style="color:#3b82f6"></i>
</div>
<div>
<span id="gsp-cat" class="text-[10px] font-bold uppercase tracking-widest px-2 py-0.5 rounded" style="color:#3b82f6;background:rgba(59,130,246,0.08)">科研项目</span>
<h2 id="gsp-title" class="text-base font-bold mt-1 text-slate-800 leading-snug">ACE — 空战演进计划</h2>
<p id="gsp-org" class="text-[11px] text-slate-500 mt-0.5">DARPA / STO</p>
</div>
</div>
<!-- Stats Grid -->
<div class="grid grid-cols-2 gap-3">
<div class="p-3 rounded-xl" style="background:rgba(248,250,252,0.9);border:1px solid rgba(0,0,0,0.06)">
<p class="text-[10px] text-slate-500 uppercase font-bold">中心度得分</p>
<p id="gsp-centrality" class="text-xl font-mono font-bold mt-1" style="color:#3b82f6">0.862</p>
</div>
<div class="p-3 rounded-xl" style="background:rgba(248,250,252,0.9);border:1px solid rgba(0,0,0,0.06)">
<p class="text-[10px] text-slate-500 uppercase font-bold">关联节点数</p>
<p id="gsp-degree" class="text-xl font-mono text-emerald-600 font-bold mt-1">8</p>
</div>
</div>
<!-- Summary -->
<div>
<h4 class="text-xs font-bold text-slate-500 mb-2 uppercase tracking-wider">情报摘要</h4>
<p id="gsp-summary" class="text-sm text-slate-600 leading-relaxed">通过空中格斗环境验证受信任人工智能算法,探索在复杂对抗决策场景下人机协同的极限边界。重点评估自主系统在高度不确定环境中的适应性与安全性。</p>
<button id="gsp-detail-btn" class="hidden mt-3 w-full py-2 text-xs font-bold text-white bg-primary rounded-lg hover:bg-blue-600 transition-colors flex items-center justify-center gap-1.5">
<i data-lucide="file-text" class="w-3.5 h-3.5"></i> 查看项目详情
</button>
</div>
<!-- Graph Stats -->
<div class="pt-5" style="border-top:1px solid rgba(0,0,0,0.06)">
<h4 class="text-xs font-bold text-slate-500 mb-4 uppercase tracking-wider">全局拓扑统计</h4>
<div class="space-y-3">
<div class="flex justify-between items-center text-xs">
<span class="text-slate-500">全图节点总数</span><span id="gspTotalNodes" class="text-slate-800 font-mono">--</span>
</div>
<div class="flex justify-between items-center text-xs">
<span class="text-slate-500">关系边总数</span><span id="gspTotalEdges" class="text-slate-800 font-mono">--</span>
</div>
<div class="flex justify-between items-center text-xs">
<span class="text-slate-500">项目节点数</span><span id="gspProjCount" class="text-slate-800 font-mono">--</span>
</div>
<div class="flex justify-between items-center text-xs">
<span class="text-slate-500">技术/机构</span><span id="gspTechInstCount" class="text-slate-800 font-mono">--</span>
</div>
</div>
</div>
<!-- Hint -->
<div class="rounded-lg px-3 py-2 text-[11px] text-slate-500 flex items-center gap-2" style="background:rgba(59,130,246,0.04);border:1px solid rgba(59,130,246,0.1)">
<i data-lucide="mouse-pointer-click" class="w-3.5 h-3.5 shrink-0" style="color:#3b82f6"></i>
单击节点查看详情,双击聚焦子图
</div>
</div>
<!-- Footer Actions -->
<div class="p-5 grid grid-cols-2 gap-3 shrink-0" style="border-top:1px solid rgba(0,0,0,0.06)">
<button id="gsp-archive-btn" onclick="showPage('detailPage')" class="px-4 py-2 rounded-lg text-xs font-bold text-slate-600 transition-all flex items-center justify-center gap-2" style="background:rgba(248,250,252,0.9);border:1px solid rgba(0,0,0,0.08)">
<i data-lucide="external-link" class="w-4 h-4"></i> 查看档案
</button>
<button id="gsp-focus-btn" onclick="focusSelectedNode()" class="px-4 py-2 bg-blue-600 hover:bg-blue-500 text-white rounded-lg text-xs font-bold transition-all flex items-center justify-center gap-2">
<i data-lucide="crosshair" class="w-4 h-4"></i> 聚焦子图
</button>
</div>
</aside>
</main>
<!-- Bottom Hint Bar -->
<div class="absolute bottom-6 left-1/2 -translate-x-1/2 flex items-center gap-4 px-4 py-2 rounded-full shadow-xl z-20" style="background:rgba(255,255,255,0.92);backdrop-filter:blur(12px);border:1px solid rgba(0,0,0,0.08)">
<div class="flex items-center gap-2 text-[10px] text-slate-500">
<kbd class="px-1.5 py-0.5 rounded border text-[10px]" style="background:rgba(248,250,252,0.9);border-color:rgba(0,0,0,0.1)">滚轮</kbd> 缩放
</div>
<div class="w-px h-3 bg-slate-300"></div>
<div class="flex items-center gap-2 text-[10px] text-slate-500">
<kbd class="px-1.5 py-0.5 rounded border text-[10px]" style="background:rgba(248,250,252,0.9);border-color:rgba(0,0,0,0.1)">拖拽</kbd> 移动
</div>
<div class="w-px h-3 bg-slate-300"></div>
<div class="flex items-center gap-2 text-[10px] text-slate-500">
<kbd class="px-1.5 py-0.5 rounded border text-[10px]" style="background:rgba(248,250,252,0.9);border-color:rgba(0,0,0,0.1)">双击</kbd> 聚焦子图
</div>
</div>
</div><!-- end right wrapper -->
</div><!-- end h-screen flex -->
</div><!-- end graphPage -->

@ -0,0 +1,188 @@
<div id="loginPage" class="page login-page">
<div class="top-gradient-bar w-full h-1 bg-gradient-to-r from-navy via-primary to-navy"></div>
<header class="w-full pt-5 pb-3 flex flex-col items-center z-10 relative shrink-0">
<div class="top-gradient-bar w-full fixed top-0 left-0 h-1 bg-gradient-to-r from-navy via-primary to-navy"></div>
<div class="flex items-center gap-4 mb-2">
<div class="p-3 bg-primary/10 rounded-xl border border-primary/30 shadow-[0_0_20px_rgba(24,144,255,0.3)]">
<i data-lucide="shield-check" class="w-8 h-8 text-primary"></i>
</div>
<div class="h-12 w-[1px] bg-slate-700 mx-2"></div>
<div>
<h1 class="text-2xl font-black tracking-widest text-white uppercase italic">DARPA</h1>
<p class="text-xs text-primary font-bold tracking-[0.3em] uppercase opacity-80">Intelligent Analysis System</p>
</div>
</div>
<div class="h-[2px] w-64 bg-gradient-to-r from-transparent via-primary/50 to-transparent mt-4"></div>
</header>
<main class="flex-1 flex items-center justify-center px-6 py-4 z-10 relative">
<div class="glass-card w-full max-w-[440px] rounded-2xl p-7 relative overflow-hidden">
<div class="absolute top-0 right-0 w-24 h-24 bg-primary/5 rounded-full -mr-12 -mt-12 blur-2xl"></div>
<!-- Auth Mode Tabs -->
<div class="flex bg-slate-900/60 p-1 rounded-xl mb-5 border border-slate-700/50">
<button id="authTab-login" onclick="switchAuthTab('login')"
class="flex-1 py-2 rounded-lg text-sm font-bold transition-all bg-primary text-white shadow">
登录系统
</button>
<button id="authTab-register" onclick="switchAuthTab('register')"
class="flex-1 py-2 rounded-lg text-sm font-bold transition-all text-slate-400 hover:text-white">
申请账号
</button>
</div>
<!-- Login Panel -->
<div id="authPanel-login">
<div class="mb-5">
<h2 class="text-xl font-bold text-white mb-1">欢迎回来,指挥官</h2>
<p class="text-slate-400 text-xs">请输入您的凭据以访问高级情报数据库</p>
</div>
<div class="space-y-4">
<div class="space-y-1.5">
<label class="text-xs font-bold text-slate-400 uppercase tracking-wider ml-1">Access Account</label>
<div class="relative group">
<span class="absolute left-4 top-1/2 -translate-y-1/2 text-slate-500 group-focus-within:text-primary transition-colors">
<i data-lucide="user" class="w-4 h-4"></i>
</span>
<input type="text" id="username" placeholder="请输入系统账号"
class="w-full bg-slate-900/50 border border-slate-700 rounded-xl py-2.5 pl-11 pr-4 text-sm text-white placeholder:text-slate-600 outline-none transition-all input-focus-glow">
</div>
</div>
<div class="space-y-1.5">
<label class="text-xs font-bold text-slate-400 uppercase tracking-wider ml-1">Encrypted Password</label>
<div class="relative group">
<span class="absolute left-4 top-1/2 -translate-y-1/2 text-slate-500 group-focus-within:text-primary transition-colors">
<i data-lucide="lock" class="w-4 h-4"></i>
</span>
<input type="password" id="password" placeholder="请输入访问密码"
class="w-full bg-slate-900/50 border border-slate-700 rounded-xl py-2.5 pl-11 pr-12 text-sm text-white placeholder:text-slate-600 outline-none transition-all input-focus-glow">
<button onclick="togglePwd('password','eyeIcon')" class="absolute right-4 top-1/2 -translate-y-1/2 text-slate-500 hover:text-slate-300">
<i data-lucide="eye" class="w-4 h-4" id="eyeIcon"></i>
</button>
</div>
</div>
<!-- 错误提示 -->
<div id="loginError" class="hidden text-xs text-red-400 bg-red-500/10 border border-red-500/20 rounded-lg px-3 py-2 flex items-center gap-2">
<i data-lucide="alert-triangle" class="w-3.5 h-3.5 shrink-0"></i>
<span id="loginErrorMsg"></span>
</div>
<div class="space-y-3">
<button onclick="login()" id="loginBtn" class="w-full bg-primary hover:bg-blue-600 text-white font-bold py-3 rounded-xl shadow-[0_8px_16px_-4px_rgba(24,144,255,0.4)] transition-all active:scale-[0.98] flex items-center justify-center gap-2 text-sm">
<span id="btnText">进入分析系统</span>
<div id="btnLoader" class="hidden">
<svg class="animate-spin h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</div>
</button>
<div class="flex items-center justify-center gap-2 text-[10px] text-slate-500 font-bold uppercase tracking-tighter">
<i data-lucide="lock-keyhole" class="w-3 h-3 text-emerald-500"></i>
<span>符合 4.2 安全协议:所有数据均通过 AES-128-GCM 加密传输</span>
</div>
</div>
</div>
</div>
<!-- Register Panel -->
<div id="authPanel-register" class="hidden">
<div class="mb-5">
<h2 class="text-xl font-bold text-white mb-1">申请系统账号</h2>
<p class="text-slate-400 text-xs">创建新的分析员凭据,密码将以 AES-128 加密存储</p>
</div>
<div class="space-y-4">
<div class="space-y-1.5">
<label class="text-xs font-bold text-slate-400 uppercase tracking-wider ml-1">New Account ID</label>
<div class="relative group">
<span class="absolute left-4 top-1/2 -translate-y-1/2 text-slate-500 group-focus-within:text-primary transition-colors">
<i data-lucide="user-plus" class="w-4 h-4"></i>
</span>
<input type="text" id="reg-username" placeholder="请输入账号4-20位字母数字"
class="w-full bg-slate-900/50 border border-slate-700 rounded-xl py-2.5 pl-11 pr-4 text-sm text-white placeholder:text-slate-600 outline-none transition-all input-focus-glow">
</div>
</div>
<div class="space-y-1.5">
<label class="text-xs font-bold text-slate-400 uppercase tracking-wider ml-1">Real Name <span class="text-yellow-400">*白名单验证</span></label>
<div class="relative group">
<span class="absolute left-4 top-1/2 -translate-y-1/2 text-slate-500 group-focus-within:text-primary transition-colors">
<i data-lucide="id-card" class="w-4 h-4"></i>
</span>
<input type="text" id="reg-name" placeholder="请输入真实姓名(需在白名单内)"
class="w-full bg-slate-900/50 border border-slate-700 rounded-xl py-2.5 pl-11 pr-4 text-sm text-white placeholder:text-slate-600 outline-none transition-all input-focus-glow">
</div>
</div>
<div class="space-y-1.5">
<label class="text-xs font-bold text-slate-400 uppercase tracking-wider ml-1">Set Password</label>
<div class="relative group">
<span class="absolute left-4 top-1/2 -translate-y-1/2 text-slate-500 group-focus-within:text-primary transition-colors">
<i data-lucide="lock" class="w-4 h-4"></i>
</span>
<input type="password" id="reg-password" placeholder="至少8位含大小写字母、数字、特殊符号"
oninput="updatePwdStrength(this.value)"
class="w-full bg-slate-900/50 border border-slate-700 rounded-xl py-2.5 pl-11 pr-12 text-sm text-white placeholder:text-slate-600 outline-none transition-all input-focus-glow">
<button onclick="togglePwd('reg-password','eyeIcon2')" class="absolute right-4 top-1/2 -translate-y-1/2 text-slate-500 hover:text-slate-300">
<i data-lucide="eye" class="w-4 h-4" id="eyeIcon2"></i>
</button>
</div>
<!-- 密码强度指示条 -->
<div class="flex gap-1 mt-1" id="pwdStrengthBars">
<div class="h-1 flex-1 rounded-full bg-slate-700 transition-colors" id="psb1"></div>
<div class="h-1 flex-1 rounded-full bg-slate-700 transition-colors" id="psb2"></div>
<div class="h-1 flex-1 rounded-full bg-slate-700 transition-colors" id="psb3"></div>
<div class="h-1 flex-1 rounded-full bg-slate-700 transition-colors" id="psb4"></div>
</div>
<p class="text-[10px] text-slate-500 ml-1" id="pwdStrengthLabel"></p>
</div>
<div class="space-y-1.5">
<label class="text-xs font-bold text-slate-400 uppercase tracking-wider ml-1">Confirm Password</label>
<div class="relative group">
<span class="absolute left-4 top-1/2 -translate-y-1/2 text-slate-500 group-focus-within:text-primary transition-colors">
<i data-lucide="shield-check" class="w-4 h-4"></i>
</span>
<input type="password" id="reg-confirm" placeholder="再次输入密码"
class="w-full bg-slate-900/50 border border-slate-700 rounded-xl py-2.5 pl-11 pr-4 text-sm text-white placeholder:text-slate-600 outline-none transition-all input-focus-glow">
</div>
</div>
<!-- 注册错误/成功提示 -->
<div id="registerError" class="hidden text-xs text-red-400 bg-red-500/10 border border-red-500/20 rounded-lg px-3 py-2 flex items-center gap-2">
<i data-lucide="alert-triangle" class="w-3.5 h-3.5 shrink-0"></i>
<span id="registerErrorMsg"></span>
</div>
<div id="registerSuccess" class="hidden text-xs text-emerald-400 bg-emerald-500/10 border border-emerald-500/20 rounded-lg px-3 py-2 flex items-center gap-2">
<i data-lucide="check-circle" class="w-3.5 h-3.5 shrink-0"></i>
<span>账号已创建成功,正在跳转至登录...</span>
</div>
<div>
<button onclick="register()" id="registerBtn" class="w-full bg-primary hover:bg-blue-600 text-white font-bold py-3 rounded-xl shadow-[0_8px_16px_-4px_rgba(24,144,255,0.4)] transition-all active:scale-[0.98] flex items-center justify-center gap-2 text-sm">
<span id="regBtnText">创建账号</span>
<div id="regBtnLoader" class="hidden">
<svg class="animate-spin h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</div>
</button>
</div>
</div>
</div>
</div>
</main>
<!-- 登录页页脚 -->
<footer class="w-full py-3 px-12 flex flex-col md:flex-row items-center justify-between text-[10px] text-slate-600 uppercase tracking-widest z-10 relative border-t border-slate-900/50 shrink-0">
<div class="flex items-center gap-4 mb-2 md:mb-0">
<span>Copyright © 2024 DARPA Advanced Technology Group</span>
<span class="w-1 h-1 bg-slate-800 rounded-full"></span>
<span>All Intelligence Restricted</span>
</div>
<div class="flex items-center gap-6">
<a href="#" class="hover:text-primary transition-colors">技术支持说明</a>
<a href="#" class="hover:text-primary transition-colors">系统运行状态</a>
<div class="flex items-center gap-1.5 px-2 py-0.5 bg-slate-900 border border-slate-800 rounded">
<span class="w-1.5 h-1.5 bg-emerald-500 rounded-full animate-pulse"></span>
<span class="text-emerald-500">Node: Secure-04</span>
</div>
</div>
</footer>
</div>

@ -0,0 +1,215 @@
<div id="searchPage" class="page">
<div class="w-full h-screen flex">
<!-- Sidebar -->
<aside class="w-64 bg-sidebar text-slate-400 flex flex-col shrink-0">
<div class="p-6 flex items-center gap-3">
<div class="w-8 h-8 bg-primary rounded flex items-center justify-center text-white">
<i data-lucide="shield-half" class="w-5 h-5"></i>
</div>
<span class="text-white font-bold tracking-tight text-lg">DARPA Intelligence</span>
</div>
<nav class="flex-1 px-4 py-4 space-y-1 overflow-y-auto custom-scrollbar">
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mb-2">主导航</div>
<a data-nav-key="dashboard" onclick="showPage('dashboardPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="layout-dashboard" class="w-4 h-4"></i> 工作台
</a>
<a data-nav-key="search" onclick="showPage('searchPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg menu-active text-sm cursor-pointer">
<i data-lucide="search" class="w-4 h-4"></i> 智能检索
</a>
<a data-nav-key="graph" onclick="showPage('graphPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="share-2" class="w-4 h-4"></i> 可视化分析
</a>
<a data-nav-key="trend" onclick="showPage('trendPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="trending-up" class="w-4 h-4"></i> 趋势分析
</a>
<a data-nav-key="wiki" onclick="showPage('wikiPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="book-open" class="w-4 h-4"></i> 情报百科
</a>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-6 mb-2">数据管理</div>
<a data-nav-key="governance" onclick="showPage('governancePage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="database" class="w-4 h-4"></i> 数据治理
</a>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-6 mb-2">系统</div>
<a onclick="logout()" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="log-out" class="w-4 h-4"></i> 退出登录
</a>
</nav>
<div class="p-4 border-t border-white/5 flex items-center gap-3">
<div class="sidebar-user-avatar w-8 h-8 rounded-full bg-slate-700 flex items-center justify-center text-slate-300 shrink-0">
<i data-lucide="user" class="w-4 h-4"></i>
</div>
<div class="flex-1 min-w-0">
<p class="sidebar-user-name text-xs font-bold text-white truncate">--</p>
<p class="sidebar-user-role text-[10px] text-slate-500 truncate">--</p>
</div>
</div>
</aside>
<!-- Right content -->
<div class="flex-1 flex flex-col overflow-hidden bg-slate-50">
<!-- Search Header -->
<section class="px-8 py-6 border-b bg-gradient-to-r from-slate-50 to-blue-50 shrink-0">
<div class="max-w-5xl mx-auto">
<!-- Mode Tabs -->
<div class="flex items-center justify-between mb-5">
<div class="flex bg-slate-200/60 p-1 rounded-xl w-fit">
<button onclick="switchSearchTab('fuzzy')" id="stab-fuzzy" class="px-6 py-2 rounded-lg text-sm font-semibold transition-all bg-white text-primary shadow-sm">模糊检索</button>
<button onclick="switchSearchTab('precise')" id="stab-precise" class="px-6 py-2 rounded-lg text-sm font-semibold transition-all text-slate-600 hover:text-primary">精准检索</button>
<button onclick="switchSearchTab('advanced')" id="stab-advanced" class="px-6 py-2 rounded-lg text-sm font-semibold transition-all text-slate-600 hover:text-primary">高级检索</button>
</div>
<div onclick="openProfileModal()" class="header-user-avatar w-8 h-8 rounded-full bg-slate-200 flex items-center justify-center cursor-pointer shrink-0">
<i data-lucide="user" class="w-4 h-4 text-slate-500"></i>
</div>
</div>
<!-- Fuzzy Panel -->
<div id="spanel-fuzzy">
<div class="flex items-center bg-white rounded-2xl shadow-xl border border-blue-100 p-2 pl-6 focus-within:ring-4 ring-blue-100 transition-all">
<i data-lucide="search" class="text-slate-400 w-6 h-6 shrink-0"></i>
<input type="text" id="fuzzyInput" placeholder="输入项目名称、机构或技术关键字..." class="flex-1 px-4 py-3 text-lg outline-none placeholder:text-slate-300">
<button id="fuzzySearchBtn" class="bg-primary text-white px-8 py-3 rounded-xl font-bold hover:bg-blue-600 transition-colors flex items-center gap-2">
<i data-lucide="search" class="w-4 h-4"></i><span>搜索</span>
</button>
</div>
<!-- Smart Suggestions -->
<div id="searchSuggestions" class="mt-2 bg-white rounded-xl shadow-2xl border border-slate-100 p-4 hidden">
<p class="text-xs font-bold text-slate-400 uppercase mb-2 tracking-wider">智能推荐</p>
<div class="grid grid-cols-2 gap-2" id="searchSuggestionsList">
<div class="col-span-2 text-xs text-slate-400">加载中...</div>
</div>
</div>
</div>
<!-- Precise Panel -->
<div id="spanel-precise" class="hidden">
<div class="bg-white p-6 rounded-2xl shadow-lg border border-slate-100 grid grid-cols-4 gap-4">
<div class="space-y-1">
<label class="text-xs font-bold text-slate-500 ml-1">检索字段</label>
<select id="preciseField" class="w-full border rounded-lg p-2 text-sm outline-none focus:border-primary">
<option value="nameCn">项目名称</option>
<option value="institution">执行机构</option>
<option value="domain">技术领域</option>
<option value="description">项目摘要</option>
<option value="office">管理办公室</option>
<option value="technology">关键技术</option>
<option value="keywords">关键词</option>
</select>
</div>
<div class="col-span-2 space-y-1">
<label class="text-xs font-bold text-slate-500 ml-1">检索值</label>
<input type="text" id="preciseValue" class="w-full border rounded-lg p-2 text-sm outline-none focus:border-primary" placeholder="请输入...">
</div>
<div class="flex items-end">
<button id="preciseSearchBtn" class="w-full bg-primary text-white px-4 py-2 rounded-lg font-bold hover:bg-blue-600 text-sm flex items-center justify-center gap-1">
<i data-lucide="search" class="w-4 h-4"></i> 搜索
</button>
</div>
</div>
</div>
<!-- Advanced Panel -->
<div id="spanel-advanced" class="hidden">
<div class="bg-slate-800 p-6 rounded-2xl shadow-xl text-white">
<div class="flex justify-between items-center mb-4">
<h4 class="text-sm font-bold flex items-center gap-2"><i data-lucide="cpu" class="w-4 h-4"></i> 逻辑表达式编辑器</h4>
<span class="text-xs text-slate-400">支持 SQL 风格逻辑组合</span>
</div>
<div class="space-y-3" id="advancedExprList">
<p class="text-xs text-slate-500 text-center py-4">开发中,敬请期待...</p>
</div>
<div class="mt-4 pt-4 border-t border-slate-700 flex justify-between">
<button class="text-sm text-slate-400 hover:text-white flex items-center gap-1">
<i data-lucide="help-circle" class="w-4 h-4"></i> 语法说明
</button>
<button class="bg-primary px-6 py-2 rounded-lg text-sm font-bold hover:bg-blue-600">执行组合检索</button>
</div>
</div>
</div>
</div>
</section>
<!-- Results Area -->
<div class="flex-1 flex overflow-hidden">
<!-- Results List -->
<div class="flex-1 p-8 overflow-y-auto custom-scrollbar">
<!-- Stats & Sort Bar -->
<div class="flex items-center justify-between mb-6">
<div id="searchStats" class="text-sm text-slate-500">
输入关键词开始检索
</div>
<div class="flex items-center gap-4">
<div class="flex items-center gap-2 bg-white border rounded-lg px-3 py-1.5 shadow-sm">
<span class="text-xs font-bold text-slate-400">排序:</span>
<select id="searchSort" class="text-xs font-semibold outline-none bg-transparent">
<option value="relevance">相关性优先</option>
<option value="newest">最新发布</option>
<option value="budget">预算从高到低</option>
<option value="name">名称排序</option>
</select>
</div>
</div>
</div>
<!-- Result Items (dynamic) -->
<div id="searchResults" class="space-y-4">
<div class="text-center py-16">
<i data-lucide="search" class="w-12 h-12 text-slate-300 mx-auto mb-4"></i>
<p class="text-slate-500 font-medium">输入关键词或选择筛选条件开始检索</p>
<p class="text-xs text-slate-400 mt-1">共 162 个项目可供探索</p>
</div>
</div>
<!-- Pagination (dynamic) -->
<div id="searchPagination" class="mt-10 flex items-center justify-center"></div>
</div>
<!-- Right Filter Panel -->
<aside class="w-72 bg-white border-l p-6 overflow-y-auto custom-scrollbar shrink-0">
<div class="flex items-center justify-between mb-6">
<h3 class="font-bold text-slate-900 flex items-center gap-2"><i data-lucide="filter" class="w-4 h-4"></i> 筛选过滤</h3>
<button onclick="resetAllFilters()" class="text-xs text-primary font-bold hover:underline">一键重置</button>
</div>
<!-- Active Tags -->
<div id="activeFilterTags" class="mb-6 flex flex-wrap gap-2">
<span class="text-[10px] text-slate-400">无筛选条件</span>
</div>
<!-- Filter Groups -->
<div class="space-y-6">
<!-- Domain -->
<div class="space-y-3">
<div class="flex justify-between items-center cursor-pointer" onclick="toggleSearchFilter('sorg-list', 'sorg-icon')">
<span class="text-sm font-bold text-slate-700">技术领域</span>
<i data-lucide="chevron-down" id="sorg-icon" class="w-4 h-4 text-slate-400 transition-transform"></i>
</div>
<div id="sorg-list" class="space-y-2">
<p class="text-xs text-slate-400">加载中...</p>
</div>
</div>
<!-- Status -->
<div class="space-y-3">
<div class="flex justify-between items-center cursor-pointer" onclick="toggleSearchFilter('sstatus-list', 'sstatus-icon')">
<span class="text-sm font-bold text-slate-700">项目状态</span>
<i data-lucide="chevron-down" id="sstatus-icon" class="w-4 h-4 text-slate-400 transition-transform"></i>
</div>
<div id="sstatus-list" class="space-y-2">
<p class="text-xs text-slate-400">加载中...</p>
</div>
</div>
<!-- Date Range -->
<div class="space-y-3">
<span class="text-sm font-bold text-slate-700">时间跨度</span>
<div class="flex gap-2">
<input type="number" id="searchDateFrom" placeholder="起始年" min="1950" max="2026" class="w-20 border rounded px-2 py-1 text-xs outline-none focus:border-primary">
<span class="text-xs text-slate-400 self-center"></span>
<input type="number" id="searchDateTo" placeholder="结束年" min="1950" max="2026" class="w-20 border rounded px-2 py-1 text-xs outline-none focus:border-primary">
</div>
<button onclick="applyDateFilter()" class="w-full py-1.5 text-xs font-bold text-primary border border-primary/30 rounded-lg hover:bg-blue-50 transition-colors">应用时间范围</button>
</div>
</div>
</aside>
</div>
</div><!-- end right wrapper -->
</div><!-- end h-screen flex -->
</div><!-- end searchPage -->

@ -0,0 +1,177 @@
<div id="trendPage" class="page">
<div class="w-full h-screen flex">
<!-- Sidebar -->
<aside class="w-64 bg-sidebar text-slate-400 flex flex-col shrink-0">
<div class="p-6 flex items-center gap-3">
<div class="w-8 h-8 bg-primary rounded flex items-center justify-center text-white">
<i data-lucide="shield-half" class="w-5 h-5"></i>
</div>
<span class="text-white font-bold tracking-tight text-lg">DARPA Intelligence</span>
</div>
<nav class="flex-1 px-4 py-4 space-y-1 overflow-y-auto custom-scrollbar">
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mb-2">主导航</div>
<a data-nav-key="dashboard" onclick="showPage('dashboardPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="layout-dashboard" class="w-4 h-4"></i> 工作台
</a>
<a data-nav-key="search" onclick="showPage('searchPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="search" class="w-4 h-4"></i> 智能检索
</a>
<a data-nav-key="graph" onclick="showPage('graphPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="share-2" class="w-4 h-4"></i> 可视化分析
</a>
<a data-nav-key="trend" onclick="showPage('trendPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg menu-active text-sm cursor-pointer">
<i data-lucide="trending-up" class="w-4 h-4"></i> 趋势分析
</a>
<a data-nav-key="wiki" onclick="showPage('wikiPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="book-open" class="w-4 h-4"></i> 情报百科
</a>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-6 mb-2">数据管理</div>
<a data-nav-key="governance" onclick="showPage('governancePage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="database" class="w-4 h-4"></i> 数据治理
</a>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-6 mb-2">系统</div>
<a onclick="logout()" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="log-out" class="w-4 h-4"></i> 退出登录
</a>
</nav>
<div class="p-4 border-t border-white/5 flex items-center gap-3">
<div class="sidebar-user-avatar w-8 h-8 rounded-full bg-slate-700 flex items-center justify-center text-slate-300 shrink-0">
<i data-lucide="user" class="w-4 h-4"></i>
</div>
<div class="flex-1 min-w-0">
<p class="sidebar-user-name text-xs font-bold text-white truncate">--</p>
<p class="sidebar-user-role text-[10px] text-slate-500 truncate">--</p>
</div>
</div>
</aside>
<!-- Right content -->
<div class="flex-1 flex flex-col bg-slate-50 overflow-y-auto custom-scrollbar">
<!-- Header -->
<div class="px-8 pt-8 pb-0 shrink-0">
<div class="flex items-center justify-between mb-6">
<div>
<h1 class="text-2xl font-bold text-slate-900 tracking-tight">技术演进与趋势分析</h1>
<p class="text-sm text-slate-500 mt-1">
数据范围: <span id="intelYearRange" class="font-mono text-slate-700">--</span>
| 项目总数: <span id="intelTotalProj" class="font-mono text-slate-700 font-bold">--</span>
| 预算总额: <span id="intelTotalBudget" class="font-mono text-slate-700 font-bold">--</span>
</p>
</div>
<div class="flex items-center gap-3">
<button onclick="trendInitFallback()" class="flex items-center gap-2 px-4 py-2 bg-slate-100 hover:bg-slate-200 text-slate-600 rounded-lg text-sm font-medium transition-all" title="重新加载数据">
<i data-lucide="refresh-cw" class="w-4 h-4"></i> 刷新数据
</button>
<div onclick="openProfileModal()" class="header-user-avatar w-8 h-8 rounded-full bg-slate-200 flex items-center justify-center cursor-pointer shrink-0 ml-2">
<i data-lucide="user" class="w-4 h-4 text-slate-500"></i>
</div>
</div>
</div>
</div>
<!-- Charts Grid -->
<div class="px-8 pb-8">
<!-- Row 1 -->
<div class="grid grid-cols-2 gap-6 mb-6">
<!-- 1. 项目增长趋势 -->
<div class="bg-white rounded-2xl p-6 border border-slate-100 shadow-sm hover:shadow-md transition-shadow">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center gap-2">
<div class="w-1.5 h-6 bg-primary rounded-full"></div>
<h3 class="font-bold text-slate-800">各年代技术领域项目分布</h3>
</div>
<div class="flex gap-1">
<button onclick="changeTrendType('bar')" class="p-1.5 hover:bg-slate-100 rounded text-slate-400 hover:text-primary" title="柱状图"><i data-lucide="bar-chart-3" class="w-4 h-4"></i></button>
<button onclick="changeTrendType('line')" class="p-1.5 hover:bg-slate-100 rounded text-slate-400 hover:text-primary" title="折线图"><i data-lucide="line-chart" class="w-4 h-4"></i></button>
</div>
</div>
<div id="trendChartMain" style="width:100%;height:300px"></div>
</div>
<!-- 2. 技术领域分布 -->
<div class="bg-white rounded-2xl p-6 border border-slate-100 shadow-sm hover:shadow-md transition-shadow">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center gap-2">
<div class="w-1.5 h-6 bg-emerald-500 rounded-full"></div>
<h3 class="font-bold text-slate-800">关键技术领域分布</h3>
</div>
</div>
<div class="flex gap-0">
<div id="distChartMain" style="width:55%;height:260px"></div>
<div id="distBudgetChart" style="width:45%;height:260px"></div>
</div>
</div>
<!-- 3. 机构合作网络 -->
<div class="bg-white rounded-2xl p-6 border border-slate-100 shadow-sm hover:shadow-md transition-shadow">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center gap-2">
<div class="w-1.5 h-6 bg-purple-500 rounded-full"></div>
<h3 class="font-bold text-slate-800">核心机构合作网络</h3>
</div>
<span class="text-[10px] text-slate-400">节点大小 ∝ 参与项目数</span>
</div>
<div id="networkChartMain" style="width:100%;height:300px"></div>
</div>
<!-- 4. 技术关联度排行 -->
<div class="bg-white rounded-2xl p-6 border border-slate-100 shadow-sm hover:shadow-md transition-shadow">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center gap-2">
<div class="w-1.5 h-6 bg-orange-500 rounded-full"></div>
<h3 class="font-bold text-slate-800">技术关联度排行 (Top 15)</h3>
</div>
<span class="text-[10px] text-slate-400">按关联项目数降序</span>
</div>
<div id="cloudChartMain" style="width:100%;height:300px"></div>
</div>
</div>
<!-- Row 2: 办公室雷达图 (全宽) -->
<div class="mb-6">
<div class="bg-white rounded-2xl p-6 border border-slate-100 shadow-sm hover:shadow-md transition-shadow">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center gap-2">
<div class="w-1.5 h-6 bg-cyan-500 rounded-full"></div>
<h3 class="font-bold text-slate-800">DARPA 六大办公室多维度对比</h3>
</div>
<span class="text-[10px] text-slate-400">维度已归一化至 0-100 | 悬停查看绝对值</span>
</div>
<div id="officeRadarChart" style="width:100%;height:400px"></div>
</div>
</div>
<!-- AI 研判摘要 (动态) -->
<div class="bg-white rounded-2xl p-6 border border-slate-100 shadow-sm" style="border-left:4px solid #eab308;background:#fefce8">
<div class="flex items-start gap-4">
<div class="w-10 h-10 bg-white rounded-full flex items-center justify-center shadow-sm border border-yellow-200 shrink-0">
<i data-lucide="sparkles" class="w-5 h-5 text-yellow-500"></i>
</div>
<div class="flex-1">
<div class="flex items-center justify-between mb-3">
<h4 class="font-bold text-slate-800">AI 智能研判摘要</h4>
<span class="text-[10px] text-slate-400">基于 Neo4j 图谱实时生成</span>
</div>
<div id="aiIntelContent" class="text-sm text-slate-600 leading-relaxed space-y-2">
<p class="text-slate-400 italic">数据加载中...</p>
</div>
</div>
</div>
</div>
</div>
</div><!-- end right wrapper -->
</div><!-- end h-screen flex -->
</div><!-- end trendPage -->
<!-- fallback: 如果模块加载失败,提供一个重试手段 -->
<script>
window.trendInitFallback = function() {
if (window.initTrendCharts) {
Object.values(window.trendCharts||{}).forEach(c => c && c.dispose && c.dispose());
window.trendCharts = {};
window.trendInited = false;
window.initTrendCharts();
}
};
</script>

@ -0,0 +1,148 @@
<div id="wikiPage" class="page bg-[#F8FAFC]">
<div class="w-full h-screen flex">
<!-- Sidebar (与 dashboard 一致) -->
<aside class="w-64 bg-sidebar text-slate-400 flex flex-col shrink-0">
<div class="p-6 flex items-center gap-3">
<div class="w-8 h-8 bg-primary rounded flex items-center justify-center text-white">
<i data-lucide="shield-half" class="w-5 h-5"></i>
</div>
<span class="text-white font-bold tracking-tight text-lg">DARPA Intelligence</span>
</div>
<nav class="flex-1 px-4 py-4 space-y-1 overflow-y-auto custom-scrollbar">
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mb-2">主导航</div>
<a data-nav-key="dashboard" onclick="showPage('dashboardPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="layout-dashboard" class="w-4 h-4"></i> 工作台
</a>
<a data-nav-key="search" onclick="showPage('searchPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="search" class="w-4 h-4"></i> 智能检索
</a>
<a data-nav-key="graph" onclick="showPage('graphPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="share-2" class="w-4 h-4"></i> 可视化分析
</a>
<a data-nav-key="trend" onclick="showPage('trendPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="trending-up" class="w-4 h-4"></i> 趋势分析
</a>
<a data-nav-key="wiki" onclick="showPage('wikiPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg menu-active text-sm cursor-pointer">
<i data-lucide="book-open" class="w-4 h-4"></i> 情报百科
</a>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-6 mb-2">数据管理</div>
<a data-nav-key="governance" onclick="showPage('governancePage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="database" class="w-4 h-4"></i> 数据治理
</a>
<a data-nav-key="detail" onclick="showPage('detailPage')" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="file-text" class="w-4 h-4"></i> 项目详情
</a>
<div class="text-[10px] font-bold text-slate-500 uppercase tracking-widest px-2 mt-6 mb-2">系统</div>
<a onclick="logout()" class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-white/5 hover:text-white transition-all text-sm cursor-pointer">
<i data-lucide="log-out" class="w-4 h-4"></i> 退出登录
</a>
</nav>
<div class="p-4 border-t border-white/5 flex items-center gap-3">
<div class="sidebar-user-avatar w-8 h-8 rounded-full bg-slate-700 flex items-center justify-center text-slate-300 shrink-0">
<i data-lucide="user" class="w-4 h-4"></i>
</div>
<div class="flex-1 min-w-0">
<p class="sidebar-user-name text-xs font-bold text-white truncate">--</p>
<p class="sidebar-user-role text-[10px] text-slate-500 truncate">--</p>
</div>
<button onclick="logout()" class="text-slate-500 hover:text-slate-300 transition-colors" title="退出">
<i data-lucide="log-out" class="w-4 h-4"></i>
</button>
</div>
</aside>
<!-- Right: header + main -->
<div class="flex-1 flex flex-col overflow-y-auto custom-scrollbar bg-[#F8FAFC]">
<header class="sticky top-0 z-50 px-8 py-4 flex items-center justify-between shrink-0 bg-white/80 backdrop-blur-md border-b border-slate-100">
<div class="flex items-center gap-4">
<i data-lucide="book-open" class="w-5 h-5 text-primary"></i>
<h1 class="text-lg font-bold text-slate-900">情报百科</h1>
<span class="text-[10px] text-slate-400 bg-slate-100 px-2 py-0.5 rounded-full">DARPA Intelligence Wiki</span>
</div>
<div class="flex items-center gap-3">
<div onclick="openProfileModal()" class="header-user-avatar w-8 h-8 rounded-full bg-slate-200 flex items-center justify-center cursor-pointer shrink-0">
<i data-lucide="user" class="w-4 h-4 text-slate-500"></i>
</div>
</div>
</header>
<!-- Tab Navigation -->
<div class="px-8 pt-6 pb-0">
<div class="flex gap-1 bg-slate-100 rounded-xl p-1 w-fit" id="wikiTabs">
<button data-wiki-tab="tech" onclick="switchWikiTab('tech')" class="px-5 py-2.5 text-sm font-medium rounded-lg transition-all duration-200 bg-white text-slate-900 shadow-sm">
<i data-lucide="cpu" class="w-4 h-4 inline mr-1.5"></i>技术图谱
</button>
<button data-wiki-tab="milestone" onclick="switchWikiTab('milestone')" class="px-5 py-2.5 text-sm font-medium rounded-lg transition-all duration-200 text-slate-500 hover:text-slate-700">
<i data-lucide="clock" class="w-4 h-4 inline mr-1.5"></i>里程碑时间线
</button>
<button data-wiki-tab="office" onclick="switchWikiTab('office')" class="px-5 py-2.5 text-sm font-medium rounded-lg transition-all duration-200 text-slate-500 hover:text-slate-700">
<i data-lucide="landmark" class="w-4 h-4 inline mr-1.5"></i>DARPA 办公室
</button>
<button data-wiki-tab="manager" onclick="switchWikiTab('manager')" class="px-5 py-2.5 text-sm font-medium rounded-lg transition-all duration-200 text-slate-500 hover:text-slate-700">
<i data-lucide="users" class="w-4 h-4 inline mr-1.5"></i>关键人物
</button>
</div>
</div>
<!-- Tab Content -->
<main class="flex-1 px-8 py-6">
<!-- 技术图谱 Tab -->
<div id="wikiTabTech" class="wiki-tab-content">
<!-- Skeleton -->
<div id="wikiTechSkeleton" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
<div class="bg-white rounded-xl p-6 border border-slate-100 animate-pulse space-y-3" repeat="9">
<div class="h-4 bg-slate-100 rounded w-3/4"></div>
<div class="h-3 bg-slate-50 rounded w-full"></div>
<div class="h-3 bg-slate-50 rounded w-5/6"></div>
</div>
</div>
<div id="wikiTechContent" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5 hidden"></div>
<div id="wikiTechError" class="text-center py-16 text-red-400 hidden">数据加载失败,请检查后端服务</div>
</div>
<!-- 里程碑时间线 Tab -->
<div id="wikiTabMilestone" class="wiki-tab-content hidden">
<div id="wikiMsSkeleton" class="space-y-4">
<div class="bg-white rounded-xl p-6 border border-slate-100 animate-pulse space-y-3" repeat="6">
<div class="h-4 bg-slate-100 rounded w-1/4"></div>
<div class="h-3 bg-slate-50 rounded w-3/4"></div>
</div>
</div>
<div id="wikiMsContent" class="hidden">
<div class="flex flex-wrap gap-2 mb-6" id="wikiMsEraFilter"></div>
<div id="wikiMsTimeline" class="space-y-0"></div>
</div>
<div id="wikiMsError" class="text-center py-16 text-red-400 hidden">数据加载失败</div>
</div>
<!-- DARPA 办公室 Tab -->
<div id="wikiTabOffice" class="wiki-tab-content hidden">
<div id="wikiOfficeSkeleton" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
<div class="bg-white rounded-xl p-6 border border-slate-100 animate-pulse space-y-3" repeat="6">
<div class="h-4 bg-slate-100 rounded w-3/4"></div>
<div class="h-3 bg-slate-50 rounded w-full"></div>
</div>
</div>
<div id="wikiOfficeContent" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5 hidden"></div>
<div id="wikiOfficeError" class="text-center py-16 text-red-400 hidden">数据加载失败</div>
</div>
<!-- 关键人物 Tab -->
<div id="wikiTabManager" class="wiki-tab-content hidden">
<div id="wikiMgrSkeleton" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5">
<div class="bg-white rounded-xl p-6 border border-slate-100 animate-pulse space-y-3" repeat="12">
<div class="h-10 w-10 bg-slate-100 rounded-full mx-auto"></div>
<div class="h-4 bg-slate-100 rounded w-1/2 mx-auto"></div>
<div class="h-3 bg-slate-50 rounded w-3/4 mx-auto"></div>
</div>
</div>
<div id="wikiMgrContent" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5 hidden"></div>
<div id="wikiMgrError" class="text-center py-16 text-red-400 hidden">数据加载失败</div>
</div>
</main>
</div><!-- end right -->
</div><!-- end h-screen flex -->
</div><!-- end wikiPage -->

@ -0,0 +1,126 @@
/* =====================================================================
* [GLOBAL]
* ===================================================================== */
body { background-color: #F0F2F5; overflow: hidden; height: 100vh; }
.page { display: none; height: 100vh; }
.page.active { display: block; }
#loginPage.active { display: flex; flex-direction: column; overflow-y: auto; }
#dashboardPage.active { display: flex; }
#searchPage.active { display: flex; flex-direction: column; }
#graphPage.active { display: flex; flex-direction: column; }
#trendPage.active { display: flex; flex-direction: column; }
#governancePage.active { display: flex; flex-direction: column; }
#detailPage.active { display: flex; flex-direction: column; }
/* [GLOBAL] 公共组件 */
.custom-scrollbar::-webkit-scrollbar { width: 4px; }
.custom-scrollbar::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 10px; }
.glass-nav { background: rgba(255, 255, 255, 0.8); backdrop-filter: blur(10px); }
.menu-active { background: #1890FF !important; color: white !important; }
/* =====================================================================
* [MODULE: login] /
* ===================================================================== */
.login-page { background: radial-gradient(circle at 50% 50%, #002766 0%, #001529 100%); position: relative; }
.login-page::before { content: ""; position: absolute; inset: 0; background-image: url('https://www.transparenttextures.com/patterns/carbon-fibre.png'); opacity: 0.1; pointer-events: none; }
.glass-card { background: rgba(0, 21, 41, 0.7); backdrop-filter: blur(20px); border: 1px solid rgba(24, 144, 255, 0.2); box-shadow: 0 25px 50px -12px rgba(0,0,0,0.5); }
.input-focus-glow:focus { box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); border-color: #1890FF; }
.error-shake { animation: shake 0.5s cubic-bezier(.36,.07,.19,.97) both; border-color: #ff4d4f !important; }
@keyframes shake { 10%,90%{transform:translate3d(-1px,0,0)} 20%,80%{transform:translate3d(2px,0,0)} 30%,50%,70%{transform:translate3d(-4px,0,0)} 40%,60%{transform:translate3d(4px,0,0)} }
/* =====================================================================
* [MODULE: graph]
* ===================================================================== */
.graph-canvas-bg { background-image: radial-gradient(circle at 1px 1px, rgba(0,0,0,0.05) 1px, transparent 0); background-size: 40px 40px; }
.glass-panel { background: rgba(255, 255, 255, 0.88); backdrop-filter: blur(12px); border: 1px solid rgba(0, 0, 0, 0.08); }
/* =====================================================================
* [MODULE: detail]
* ===================================================================== */
.detail-glass-header { background: rgba(255, 255, 255, 0.85); backdrop-filter: blur(12px); border-bottom: 1px solid rgba(226, 232, 240, 0.8); }
.detail-card { background: #fff; border-radius: 16px; border: 1px solid #e2e8f0; box-shadow: 0 1px 3px rgba(0,0,0,0.02), 0 1px 2px rgba(0,0,0,0.04); }
.status-tag-in { background: #F6FFED; border: 1px solid #B7EB8F; color: #52C41A; }
.detail-timeline-dot::before { content: ''; position: absolute; left: -21px; top: 6px; width: 10px; height: 10px; border-radius: 50%; background: #1890FF; border: 2px solid #F8FAFC; box-shadow: 0 0 0 3px rgba(24,144,255,0.15); }
.detail-abstract-fade { background: linear-gradient(to top, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%); }
.line-clamp-4 { display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
/* =====================================================================
* [GLOBAL]
* ===================================================================== */
@keyframes skeleton-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
.skeleton-text {
display: inline-block;
min-width: 40px;
height: 1em;
border-radius: 4px;
background: #e2e8f0;
animation: skeleton-pulse 1.5s ease-in-out infinite;
}
.skeleton-text-sm {
display: inline-block;
min-width: 30px;
height: 0.75em;
border-radius: 3px;
background: #e2e8f0;
animation: skeleton-pulse 1.5s ease-in-out infinite;
}
/* =====================================================================
* [MODULE: profile] + hover
* ===================================================================== */
@keyframes modal-fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes modal-scale-in {
from { opacity: 0; transform: scale(0.92) translateY(8px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
#profileModal.active {
display: flex !important;
animation: modal-fade-in 0.2s ease-out;
}
#profileModal.active .profile-modal-inner {
animation: modal-scale-in 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}
.header-user-avatar {
transition: all 0.2s ease;
}
.header-user-avatar:hover {
background: #e2e8f0 !important;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.3);
transform: scale(1.05);
}
.sidebar-user-avatar {
transition: all 0.2s ease;
}
.sidebar-user-avatar:hover {
cursor: pointer;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}
.whitelist-tag {
display: inline-flex;
align-items: center;
gap: 2px;
padding: 2px 8px;
font-size: 11px;
font-weight: 500;
background: #e0f2fe;
color: #0369a1;
border-radius: 9999px;
transition: all 0.15s;
}
.whitelist-tag:hover {
background: #bae6fd;
}
.whitelist-tag button {
margin-left: 2px;
color: #0284c7;
cursor: pointer;
}
.whitelist-tag button:hover {
color: #dc2626;
}

@ -0,0 +1,40 @@
import { defineConfig } from 'vite';
import { createHtmlPlugin } from 'vite-plugin-html';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
// ESM 下兼容 __dirname
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// 读取页面片段的辅助函数
function readPage(name) {
return fs.readFileSync(
path.resolve(__dirname, `src/pages/${name}.html`),
'utf8'
);
}
export default defineConfig({
plugins: [
createHtmlPlugin({
inject: {
data: {
PAGE_LOGIN: readPage('login'),
PAGE_DASHBOARD: readPage('dashboard'),
PAGE_SEARCH: readPage('search'),
PAGE_GRAPH: readPage('graph'),
PAGE_TREND: readPage('trend'),
PAGE_WIKI: readPage('wiki'),
PAGE_GOVERNANCE: readPage('governance'),
PAGE_DETAIL: readPage('detail'),
},
},
}),
],
build: {
// 打包产物dist/index.html 可直接双击运行
outDir: 'dist',
},
});

Binary file not shown.
Loading…
Cancel
Save