finally finish all website check in.
This commit is contained in:
247
src/pages/report/ai-eda-paper-report/README.md
Normal file
247
src/pages/report/ai-eda-paper-report/README.md
Normal file
@@ -0,0 +1,247 @@
|
||||
# 交互式EDA/CAD学术发表指南
|
||||
|
||||
## 📋 概述
|
||||
|
||||
这是一个基于《学术发表的投稿难度与周期分析》报告构建的交互式指南页面,帮助研究人员制定最佳投稿策略。
|
||||
|
||||
## 🎯 功能特性
|
||||
|
||||
### 1. 智能筛选系统
|
||||
- **类型筛选**:会议 / 期刊
|
||||
- **难度等级筛选**:顶级 / 高 / 应用/其他
|
||||
- **评审速度筛选**:快速(<10周) / 中等(10-15周) / 慢速(>15周)
|
||||
- **一键重置**:快速清除所有筛选条件
|
||||
|
||||
### 2. 场所卡片展示
|
||||
包含7个主要发表场所:
|
||||
- **DAC** - Design Automation Conference (顶级会议)
|
||||
- **ICCAD** - International Conference on Computer-Aided Design (顶级会议)
|
||||
- **DATE** - Design, Automation and Test in Europe (高级会议)
|
||||
- **ASP-DAC** - Asia and South Pacific Design Automation Conference (高级会议)
|
||||
- **IEEE TCAD** - Transactions on Computer-Aided Design (顶级期刊)
|
||||
- **ACM TODAES** - Transactions on Design Automation of Electronic Systems (高级期刊)
|
||||
- **IEEE D&T** - Design & Test (应用期刊)
|
||||
|
||||
每个卡片显示:
|
||||
- 🏆 难度等级
|
||||
- 📊 接收率
|
||||
- ⏱️ 评审速度
|
||||
- ⭐ 关键指标
|
||||
|
||||
### 3. 交互式模态框
|
||||
- **GSAP动画**:卡片到模态框的流畅展开动画
|
||||
- **详细信息展示**:
|
||||
- 关键信息(难度、主办方、页数限制、投稿指南)
|
||||
- 评审过程特点
|
||||
- 可视化图表(Chart.js)
|
||||
- 典型发表时间线
|
||||
- **降级方案**:GSAP未加载时使用简化模态框
|
||||
|
||||
### 4. 投稿策略指南
|
||||
手风琴式折叠面板,包含:
|
||||
- 如何理解投稿难度?
|
||||
- 如何规划发表时间线?
|
||||
- 如何制定投稿策略?
|
||||
|
||||
## 🛠️ 技术栈
|
||||
|
||||
### 框架与组件
|
||||
- **Astro** - 主框架
|
||||
- **莫兰蒂蓝色系** - 主题色 `#2c4a6b`
|
||||
- **Container组件** - 玻璃态容器
|
||||
- **AnimatedElement组件** - 滚动动画
|
||||
|
||||
### 外部依赖
|
||||
- **Chart.js 4.4.1** - 数据可视化图表
|
||||
- **GSAP 3.13** - 模态框动画效果
|
||||
- **Tailwind CSS** - 样式框架
|
||||
|
||||
### 自定义脚本
|
||||
`./eda-venues-interactive.ts`(本地脚本)
|
||||
- TypeScript编写
|
||||
- 完整类型定义
|
||||
- 模块化设计
|
||||
- 降级兼容处理
|
||||
|
||||
## 📂 文件结构
|
||||
|
||||
```
|
||||
src/
|
||||
├── pages/report/ai-eda-paper-report/
|
||||
│ ├── index.astro # 主页面文件
|
||||
│ ├── eda-venues-interactive.ts # 交互逻辑脚本(页面专用)
|
||||
│ └── README.md # 文档说明
|
||||
└── components/
|
||||
├── Container.astro # 容器组件
|
||||
├── AnimatedElement.astro # 动画组件
|
||||
├── Header.astro # 页头组件
|
||||
└── Footer.astro # 页脚组件
|
||||
```
|
||||
|
||||
## 🎨 设计特点
|
||||
|
||||
### 1. 莫兰蒂蓝色系
|
||||
- 主色:`#2c4a6b`
|
||||
- 强调色:`#011a2d`(深蓝)
|
||||
- 辅助色:`#5b778e`(浅蓝)
|
||||
|
||||
### 2. 玻璃态效果
|
||||
```css
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(44, 74, 107, 0.1);
|
||||
```
|
||||
|
||||
### 3. 响应式布局
|
||||
- 桌面:3列网格
|
||||
- 平板:2列网格
|
||||
- 移动:单列网格
|
||||
|
||||
### 4. 动画时序
|
||||
- Hero区域:200ms
|
||||
- 筛选器:400ms
|
||||
- 场所卡片:600ms
|
||||
- 策略指南:800ms
|
||||
|
||||
## 🚀 使用方式
|
||||
|
||||
### 访问路径
|
||||
```
|
||||
/report/ai-eda-paper-report
|
||||
```
|
||||
|
||||
### 本地开发
|
||||
```bash
|
||||
npm run dev
|
||||
# 访问 http://localhost:4321/report/ai-eda-paper-report
|
||||
```
|
||||
|
||||
### 生产构建
|
||||
```bash
|
||||
npm run build
|
||||
npm run preview
|
||||
```
|
||||
|
||||
## 📊 数据结构
|
||||
|
||||
### VenueData接口
|
||||
```typescript
|
||||
interface VenueData {
|
||||
id: string;
|
||||
name: string;
|
||||
fullName: string;
|
||||
type: '会议' | '期刊';
|
||||
tier: '顶级' | '高' | '应用/其他';
|
||||
speed: 'fast' | 'medium' | 'slow';
|
||||
speedValue: number;
|
||||
acceptanceRate: string;
|
||||
acceptanceValue: number | null;
|
||||
keyMetric: string;
|
||||
pageLimit: string;
|
||||
sponsors: string;
|
||||
overview: string;
|
||||
reviewProcess: string[];
|
||||
timeline: TimelineStage[];
|
||||
guidelines: string;
|
||||
}
|
||||
```
|
||||
|
||||
### StrategyData接口
|
||||
```typescript
|
||||
interface StrategyData {
|
||||
title: string;
|
||||
content: string; // HTML内容
|
||||
}
|
||||
```
|
||||
|
||||
## 🔧 核心函数
|
||||
|
||||
### 主要功能函数
|
||||
- `renderVenues()` - 渲染场所卡片
|
||||
- `openModal(venueId, cardElement)` - 打开模态框(GSAP动画)
|
||||
- `openSimpleModal(venueId)` - 简化模态框(降级方案)
|
||||
- `closeModal()` - 关闭模态框
|
||||
- `renderStrategyAccordion()` - 渲染策略手风琴
|
||||
- `initEDAVenuesInteractive()` - 初始化所有交互
|
||||
|
||||
## ⚙️ 配置选项
|
||||
|
||||
### 模态框尺寸(响应式)
|
||||
```typescript
|
||||
// 大屏幕 (≥1024px)
|
||||
targetW = '70vw';
|
||||
targetH = '70vh';
|
||||
|
||||
// 中等屏幕
|
||||
targetW = '80vw';
|
||||
targetH = '75vh';
|
||||
|
||||
// 小屏幕 (≤640px)
|
||||
targetW = '92vw';
|
||||
targetH = '85vh';
|
||||
```
|
||||
|
||||
### 动画参数
|
||||
```typescript
|
||||
// GSAP Timeline
|
||||
duration: 0.5, // 模态框展开时长
|
||||
ease: 'expo.out' // 缓动函数
|
||||
```
|
||||
|
||||
## 🐛 错误处理
|
||||
|
||||
### Chart.js加载失败
|
||||
```typescript
|
||||
try {
|
||||
if (window.Chart && venue.acceptanceValue !== null) {
|
||||
// 渲染图表
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('绘制图表时出错:', err);
|
||||
}
|
||||
```
|
||||
|
||||
### GSAP加载失败
|
||||
```typescript
|
||||
if (!gsap) {
|
||||
console.warn('GSAP未加载,使用简化模态框');
|
||||
openSimpleModal(venueId);
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
## 📝 更新日志
|
||||
|
||||
### 2025-10-01
|
||||
- ✅ 完成页面从HTML到Astro的转换
|
||||
- ✅ 创建TypeScript交互脚本
|
||||
- ✅ 实现GSAP模态框动画
|
||||
- ✅ 添加Chart.js图表渲染
|
||||
- ✅ 实现筛选器功能
|
||||
- ✅ 添加策略指南手风琴
|
||||
- ✅ 实现降级兼容方案
|
||||
- ✅ 应用莫兰蒂蓝色系主题
|
||||
|
||||
## 🎯 未来优化方向
|
||||
|
||||
1. **性能优化**
|
||||
- 懒加载Chart.js和GSAP
|
||||
- 虚拟滚动大列表
|
||||
- 图片优化
|
||||
|
||||
2. **功能增强**
|
||||
- 添加搜索功能
|
||||
- 导出PDF报告
|
||||
- 个性化推荐
|
||||
|
||||
3. **数据扩展**
|
||||
- 更多会议期刊数据
|
||||
- 历史录取率趋势
|
||||
- 审稿人反馈统计
|
||||
|
||||
## 📚 相关文档
|
||||
|
||||
- [Astro文档](https://docs.astro.build/)
|
||||
- [GSAP文档](https://greensock.com/docs/)
|
||||
- [Chart.js文档](https://www.chartjs.org/docs/)
|
||||
- [报告模板文档](../template/README.md)
|
||||
739
src/pages/report/ai-eda-paper-report/eda-venues-interactive.ts
Normal file
739
src/pages/report/ai-eda-paper-report/eda-venues-interactive.ts
Normal file
@@ -0,0 +1,739 @@
|
||||
/**
|
||||
* EDA/CAD学术发表指南交互式功能
|
||||
* 包含场所卡片筛选、模态框动画、图表渲染等功能
|
||||
*/
|
||||
|
||||
// 场所数据类型定义
|
||||
interface TimelineStage {
|
||||
stage: string;
|
||||
date: string;
|
||||
}
|
||||
|
||||
interface VenueData {
|
||||
id: string;
|
||||
name: string;
|
||||
fullName: string;
|
||||
type: '会议' | '期刊';
|
||||
tier: '顶级' | '高' | '应用/其他';
|
||||
speed: 'fast' | 'medium' | 'slow';
|
||||
speedValue: number;
|
||||
acceptanceRate: string;
|
||||
acceptanceValue: number | null;
|
||||
keyMetric: string;
|
||||
pageLimit: string;
|
||||
sponsors: string;
|
||||
overview: string;
|
||||
reviewProcess: string[];
|
||||
timeline: TimelineStage[];
|
||||
guidelines: string;
|
||||
}
|
||||
|
||||
interface StrategyData {
|
||||
title: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
// 场所数据
|
||||
const venuesData: VenueData[] = [
|
||||
{
|
||||
id: 'dac',
|
||||
name: 'DAC',
|
||||
fullName: 'Design Automation Conference',
|
||||
type: '会议',
|
||||
tier: '顶级',
|
||||
speed: 'medium',
|
||||
speedValue: 14,
|
||||
acceptanceRate: '20-25%',
|
||||
acceptanceValue: 22.7,
|
||||
keyMetric: '会议排名顶级',
|
||||
pageLimit: '6页 + 1页参考文献',
|
||||
sponsors: 'IEEE/ACM',
|
||||
overview: 'EDA领域的顶级会议之一,由IEEE和ACM共同赞助,对电子行业的创新具有重要影响。',
|
||||
reviewProcess: [
|
||||
'研究论文采用双盲评审。',
|
||||
'投稿规则非常严格,包括作者身份保密、投稿数量限制、摘要具体要求等。',
|
||||
'严格的规则旨在确保评审的公正性、完整性,并管理利益冲突。'
|
||||
],
|
||||
timeline: [
|
||||
{ stage: '建议论文开始写作', date: '每年8月' },
|
||||
{ stage: '建议实验结束', date: '每年10月初' },
|
||||
{ stage: '建议论文完稿', date: '每年11月初' },
|
||||
{ stage: '摘要提交', date: '每年11月中旬' },
|
||||
{ stage: '全文提交', date: '每年11月下旬' },
|
||||
{ stage: '接收通知', date: '次年2月下旬' },
|
||||
{ stage: '会议召开', date: '次年6月下旬' },
|
||||
],
|
||||
guidelines: '稿件长度不超过6页(双栏,9或10号字体),参考文献可额外占用1页,需遵循IEEE模板。'
|
||||
},
|
||||
{
|
||||
id: 'iccad',
|
||||
name: 'ICCAD',
|
||||
fullName: 'International Conference on Computer-Aided Design',
|
||||
type: '会议',
|
||||
tier: '顶级',
|
||||
speed: 'fast',
|
||||
speedValue: 8,
|
||||
acceptanceRate: '~22%',
|
||||
acceptanceValue: 22,
|
||||
keyMetric: '会议排名顶级',
|
||||
pageLimit: '8页 + 1页参考文献',
|
||||
sponsors: 'IEEE/ACM',
|
||||
overview: 'EDA研究领域的另一个顶级论坛,同样由IEEE和ACM联合主办,专注于集成电路和系统的CAD技术。',
|
||||
reviewProcess: [
|
||||
'采用双盲评审。',
|
||||
'投稿分两阶段:先提交摘要,再提交全文。',
|
||||
'鼓励提交包含开源软件的论文,重视可复现性和实际应用价值。'
|
||||
],
|
||||
timeline: [
|
||||
{ stage: '建议论文开始写作', date: '每年1月' },
|
||||
{ stage: '建议实验结束', date: '每年3月初' },
|
||||
{ stage: '建议论文完稿', date: '每年4月初' },
|
||||
{ stage: '摘要提交', date: '每年4月中旬' },
|
||||
{ stage: '全文提交', date: '每年4月下旬' },
|
||||
{ stage: '接收通知', date: '同年6月下旬' },
|
||||
{ stage: '会议召开', date: '同年10月下旬' },
|
||||
],
|
||||
guidelines: '常规论文不超过8页(双栏,9或10号字体),参考文献可额外占用1页,需遵守ACM出版政策。'
|
||||
},
|
||||
{
|
||||
id: 'date',
|
||||
name: 'DATE',
|
||||
fullName: 'Design, Automation and Test in Europe',
|
||||
type: '会议',
|
||||
tier: '高',
|
||||
speed: 'fast',
|
||||
speedValue: 8,
|
||||
acceptanceRate: '~36%',
|
||||
acceptanceValue: 35.7,
|
||||
keyMetric: 'CORE Rank B',
|
||||
pageLimit: '需查阅具体征稿通知',
|
||||
sponsors: 'EDA/IEEE/ACM相关',
|
||||
overview: '欧洲在电子系统设计与测试领域的主要学术活动,涵盖硬件和软件,设有多个不同主题的轨道。',
|
||||
reviewProcess: [
|
||||
'论文经过同行评审。',
|
||||
'设有多个轨道(科学论文、应用设计、最新成果等),以适应不同类型的贡献。',
|
||||
'不同轨道的评审周期不同,为作者提供多样化的发表途径和速度选择。'
|
||||
],
|
||||
timeline: [
|
||||
{ stage: '建议论文开始写作', date: '每年6月' },
|
||||
{ stage: '建议实验结束', date: '每年8月初' },
|
||||
{ stage: '建议论文完稿', date: '每年9月初' },
|
||||
{ stage: '常规轨全文提交', date: '每年9月中旬' },
|
||||
{ stage: '常规轨接收通知', date: '同年11月中旬' },
|
||||
{ stage: '会议召开', date: '次年3月下旬' },
|
||||
],
|
||||
guidelines: '提及了音视频演示指南和海报格式要求。具体论文格式需参考当年征稿通知。'
|
||||
},
|
||||
{
|
||||
id: 'asp-dac',
|
||||
name: 'ASP-DAC',
|
||||
fullName: 'Asia and South Pacific Design Automation Conference',
|
||||
type: '会议',
|
||||
tier: '高',
|
||||
speed: 'fast',
|
||||
speedValue: 8,
|
||||
acceptanceRate: '~31%',
|
||||
acceptanceValue: 31,
|
||||
keyMetric: '区域顶级会议',
|
||||
pageLimit: '6页 + 1页参考文献',
|
||||
sponsors: 'IEEE/ACM相关',
|
||||
overview: '亚洲及南太平洋地区关于VLSI设计自动化的年度国际会议,近年来国际影响力日益提升。',
|
||||
reviewProcess: [
|
||||
'由技术程序委员会(TPC)进行严格、彻底的评审。',
|
||||
'通常召开TPC面对面会议进行最终论文筛选,注重审议和共识。',
|
||||
'采用两步流程:先注册摘要,再提交完整手稿。'
|
||||
],
|
||||
timeline: [
|
||||
{ stage: '建议论文开始写作', date: '每年4月' },
|
||||
{ stage: '建议实验结束', date: '每年5月下旬' },
|
||||
{ stage: '建议论文完稿', date: '每年6月下旬' },
|
||||
{ stage: '摘要/全文提交', date: '每年7月上旬' },
|
||||
{ stage: '接收通知', date: '同年9月上旬' },
|
||||
{ stage: '会议召开', date: '次年1月下旬' },
|
||||
],
|
||||
guidelines: '全文,双栏,最多6页,参考文献可额外占用1页,推荐使用ACM模板。'
|
||||
},
|
||||
{
|
||||
id: 'tcad',
|
||||
name: 'IEEE TCAD',
|
||||
fullName: 'Transactions on Computer-Aided Design of ICs and Systems',
|
||||
type: '期刊',
|
||||
tier: '顶级',
|
||||
speed: 'medium',
|
||||
speedValue: 10.1,
|
||||
acceptanceRate: '33-34%',
|
||||
acceptanceValue: 33.5,
|
||||
keyMetric: 'IF: 2.9 (2022)',
|
||||
pageLimit: '常规14页, 简报5页',
|
||||
sponsors: 'IEEE CEDA',
|
||||
overview: '月刊,同行评审,是集成电路与系统CAD领域的顶级期刊之一。全年滚动投稿。',
|
||||
reviewProcess: [
|
||||
'采用单盲评审(评审人匿名,作者身份公开)。',
|
||||
'通常邀请3位评审人,副编辑也可参与决策。',
|
||||
'设有"desk rejection"机制,快速处理不达标或不符范围的稿件。',
|
||||
'期刊正积极改善评审周期,缩短处理时间。'
|
||||
],
|
||||
timeline: [],
|
||||
guidelines: '常规论文14页,简报5页。通过Manuscript Central系统提交,需遵循IEEE格式。'
|
||||
},
|
||||
{
|
||||
id: 'todaes',
|
||||
name: 'ACM TODAES',
|
||||
fullName: 'Transactions on Design Automation of Electronic Systems',
|
||||
type: '期刊',
|
||||
tier: '高',
|
||||
speed: 'slow',
|
||||
speedValue: 16,
|
||||
acceptanceRate: '未明确',
|
||||
acceptanceValue: null,
|
||||
keyMetric: 'IF: 0.852',
|
||||
pageLimit: '视文章类型而定',
|
||||
sponsors: 'ACM',
|
||||
overview: 'ACM在电子系统设计自动化领域的旗舰期刊,季刊,侧重计算机科学/工程方向。全年滚动投稿。',
|
||||
reviewProcess: [
|
||||
'同行评审。',
|
||||
'作为季刊,总发表周期可能较长,尤其在需要修改的情况下。',
|
||||
'接收多种类型的稿件,包括常规研究、综述、教程等,为不同贡献提供空间。'
|
||||
],
|
||||
timeline: [],
|
||||
guidelines: '接收常规研究论文、主旨报告、综述、教程、设计者笔记等。通过Manuscript Central系统提交,遵循ACM规范。'
|
||||
},
|
||||
{
|
||||
id: 'd&t',
|
||||
name: 'IEEE D&T',
|
||||
fullName: 'IEEE Design & Test',
|
||||
type: '期刊',
|
||||
tier: '应用/其他',
|
||||
speed: 'fast',
|
||||
speedValue: 6,
|
||||
acceptanceRate: '未明确',
|
||||
acceptanceValue: null,
|
||||
keyMetric: 'IF: 1.5-1.9',
|
||||
pageLimit: '特稿<5000词',
|
||||
sponsors: 'IEEE',
|
||||
overview: '杂志型期刊,强调实践应用、教程和案例研究,面向实践者。全年滚动投稿。',
|
||||
reviewProcess: [
|
||||
'同行评审,至少两位独立评审人。',
|
||||
'评审侧重于论文的重要性、创新性、时下关注度、清晰度和实践相关性。',
|
||||
'稿件接收可能受即将出版期次的主题契合度影响。'
|
||||
],
|
||||
timeline: [],
|
||||
guidelines: '特稿文章不超过5000字,参考文献不超过12篇。专栏文章不超过2500字。强调清晰易懂的写作风格和教程性内容。'
|
||||
}
|
||||
];
|
||||
|
||||
// 策略指南数据
|
||||
const strategyData: StrategyData[] = [
|
||||
{
|
||||
title: '如何理解投稿难度?',
|
||||
content: `
|
||||
<p class="mb-2">学术出版物的"投稿难度"是一个多维度概念,不能仅看单一指标。主要考量:</p>
|
||||
<ul class="list-disc list-inside space-y-2">
|
||||
<li><strong>接收率 (Acceptance Rate):</strong> 接收率越低,通常意味着竞争越激烈、声望越高。但需要结合领域平均水平来看。</li>
|
||||
<li><strong>影响力指标 (Impact Metrics):</strong> 如期刊影响因子(IF)、CiteScore等,反映了期刊的学术影响力。Q1/Q2分区通常代表了高质量期刊。</li>
|
||||
<li><strong>同行评审 (Peer Review):</strong> 评审过程的严谨性是"难度"中一个难以量化的重要部分。严格的评审流程要求稿件具有更高的质量。</li>
|
||||
<li><strong>稿件质量与契合度:</strong> 稿件本身的创新性、严谨性,以及与发表场所范围的匹配度,是最根本的决定因素。</li>
|
||||
</ul>
|
||||
<p class="mt-4 text-sm text-slate-500"><strong>专家提示:</strong> 不要孤立地看待任何一个指标。一个接收率适中的Q1期刊,其投稿难度依然很高,因为它对稿件质量和潜在影响力有极高要求。</p>
|
||||
`
|
||||
},
|
||||
{
|
||||
title: '如何规划发表时间线?',
|
||||
content: `
|
||||
<p class="mb-2">从提交到见刊的周期受多种因素影响,关键时间节点包括:</p>
|
||||
<div class="space-y-3">
|
||||
<div><strong>初审 (Desk Review):</strong> 约1-2周。编辑部进行格式和范围检查,部分稿件在此阶段会被直接拒稿(desk rejection)。</div>
|
||||
<div><strong>同行评审 (Peer Review):</strong> 约1-3个月,变动很大。这是最主要的耗时环节,取决于评审人的效率。</div>
|
||||
<div><strong>修改与再审 (Revision):</strong> 时间不固定。作者修改速度和编辑/评审人的二审效率都会影响总时长。</div>
|
||||
<div><strong>制作与发表 (Production):</strong> 接收后约1-3个月。许多期刊提供在线预发表(Early Access),可以缩短成果传播时间。</div>
|
||||
</div>
|
||||
<p class="mt-4 text-sm text-slate-500"><strong>专家提示:</strong> 会议的发表周期通常比期刊更固定、更可预测。对于时间敏感的研究,优先考虑会议或快速发表期刊,并善用预印本服务器(如arXiv)。</p>
|
||||
`
|
||||
},
|
||||
{
|
||||
title: '如何制定投稿策略?',
|
||||
content: `
|
||||
<p class="mb-2">选择发表场所是一项战略性决策,需综合考量:</p>
|
||||
<ul class="list-disc list-inside space-y-2">
|
||||
<li><strong>研究性质:</strong>
|
||||
<ul class="list-['-_'] list-inside ml-4">
|
||||
<li><strong>开创性研究:</strong> 优先考虑顶级会议(DAC, ICCAD)或高影响力期刊(TCAD)。</li>
|
||||
<li><strong>应用型/案例研究:</strong> DATE的应用轨或IEEE D&T杂志可能更合适。</li>
|
||||
<li><strong>增量型研究:</strong> 可考虑区域性会议(ASP-DAC)或接收范围稍广的期刊。</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>职业目标:</strong>
|
||||
<ul class="list-['-_'] list-inside ml-4">
|
||||
<li><strong>博士生/早期学者:</strong> 在知名会议发表有助建立声誉和学术联系。</li>
|
||||
<li><strong>职称晋升:</strong> 通常更看重高影响力(Q1/Q2)期刊论文。</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>混合策略:</strong> EDA/CAD领域的常见做法是,先在顶级会议上快速发布核心创新成果,之后将工作深化、扩展,发表于档案型的顶级期刊。</li>
|
||||
</ul>
|
||||
`
|
||||
}
|
||||
];
|
||||
|
||||
// 全局变量
|
||||
let activeChart: any = null;
|
||||
let activeCardState: { top: number; left: number; width: number; height: number; id: string } | null = null;
|
||||
let isAnimating = false;
|
||||
|
||||
/**
|
||||
* 渲染场所卡片
|
||||
*/
|
||||
export function renderVenues(): void {
|
||||
const venueGrid = document.getElementById('venue-grid');
|
||||
const typeFilter = document.getElementById('type-filter') as HTMLSelectElement;
|
||||
const tierFilter = document.getElementById('tier-filter') as HTMLSelectElement;
|
||||
const speedFilter = document.getElementById('speed-filter') as HTMLSelectElement;
|
||||
const noResults = document.getElementById('no-results');
|
||||
|
||||
if (!venueGrid || !typeFilter || !tierFilter || !speedFilter || !noResults) return;
|
||||
|
||||
venueGrid.innerHTML = '';
|
||||
const type = typeFilter.value;
|
||||
const tier = tierFilter.value;
|
||||
const speed = speedFilter.value;
|
||||
|
||||
const filteredVenues = venuesData.filter(venue => {
|
||||
const typeMatch = type === 'all' || venue.type === type;
|
||||
const tierMatch = tier === 'all' || venue.tier === tier;
|
||||
const speedMatch = speed === 'all' || venue.speed === speed;
|
||||
return typeMatch && tierMatch && speedMatch;
|
||||
});
|
||||
|
||||
if (filteredVenues.length === 0) {
|
||||
noResults.classList.remove('hidden');
|
||||
} else {
|
||||
noResults.classList.add('hidden');
|
||||
}
|
||||
|
||||
filteredVenues.forEach(venue => {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'venue-card p-6 cursor-pointer flex flex-col';
|
||||
card.dataset.id = venue.id;
|
||||
card.innerHTML = `
|
||||
<div class="flex-grow">
|
||||
<div class="flex justify-between items-start">
|
||||
<h3 class="text-2xl font-bold text-gray-800">${venue.name}</h3>
|
||||
<span class="text-xs font-semibold ${venue.type === '会议' ? 'bg-sky-100 text-sky-800' : 'bg-amber-100 text-amber-800'} py-1 px-3 rounded-full">${venue.type}</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 mb-4">${venue.fullName}</p>
|
||||
<div class="space-y-3 text-sm">
|
||||
<div class="flex items-center">
|
||||
<span class="w-6 text-center mr-2">🏆</span>
|
||||
<span><strong>难度:</strong> ${venue.tier}</span>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<span class="w-6 text-center mr-2">📊</span>
|
||||
<span><strong>接收率:</strong> ${venue.acceptanceRate}</span>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<span class="w-6 text-center mr-2">⏱️</span>
|
||||
<span><strong>评审速度:</strong> ~${venue.speedValue} 周</span>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<span class="w-6 text-center mr-2">⭐</span>
|
||||
<span><strong>关键指标:</strong> ${venue.keyMetric}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="mt-6 w-full text-center bg-gray-100 text-gray-700 font-semibold py-2 rounded-lg hover:bg-gray-200 transition duration-300">查看详情</button>
|
||||
`;
|
||||
card.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
openModal(venue.id, card);
|
||||
});
|
||||
venueGrid.appendChild(card);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开模态框
|
||||
*/
|
||||
export function openModal(venueId: string, cardElement: HTMLElement): void {
|
||||
if (isAnimating) return;
|
||||
|
||||
// 检查是否有GSAP
|
||||
const gsap = (window as any).gsap;
|
||||
if (!gsap) {
|
||||
console.warn('GSAP未加载,使用简化模态框');
|
||||
openSimpleModal(venueId);
|
||||
return;
|
||||
}
|
||||
|
||||
isAnimating = true;
|
||||
|
||||
const venue = venuesData.find(v => v.id === venueId);
|
||||
if (!venue) {
|
||||
isAnimating = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const cardRect = cardElement.getBoundingClientRect();
|
||||
activeCardState = {
|
||||
top: cardRect.top,
|
||||
left: cardRect.left,
|
||||
width: cardRect.width,
|
||||
height: cardRect.height,
|
||||
id: venueId
|
||||
};
|
||||
|
||||
if (activeChart) {
|
||||
activeChart.destroy();
|
||||
}
|
||||
|
||||
const modal = document.getElementById('detail-modal');
|
||||
const modalOverlay = document.getElementById('modal-overlay');
|
||||
const modalContent = document.getElementById('modal-content');
|
||||
const modalContentWrapper = document.getElementById('modal-content-wrapper');
|
||||
|
||||
if (!modal || !modalOverlay || !modalContent || !modalContentWrapper) return;
|
||||
|
||||
// 生成时间线HTML
|
||||
let timelineHtml = '';
|
||||
if (venue.timeline.length > 0) {
|
||||
timelineHtml = `<div class="mt-6">
|
||||
<h4 class="text-lg font-semibold text-gray-800 mb-3">典型发表时间线 (${venue.type === '会议' ? '年度周期' : ''})</h4>
|
||||
<ol class="relative border-l border-gray-200">`;
|
||||
venue.timeline.forEach(item => {
|
||||
timelineHtml += `
|
||||
<li class="mb-6 ml-4">
|
||||
<div class="absolute w-3 h-3 bg-gray-300 rounded-full mt-1.5 -left-1.5 border border-white"></div>
|
||||
<time class="mb-1 text-sm font-normal leading-none text-gray-500">${item.date}</time>
|
||||
<h3 class="text-md font-semibold text-gray-900">${item.stage}</h3>
|
||||
</li>
|
||||
`;
|
||||
});
|
||||
timelineHtml += `</ol></div>`;
|
||||
}
|
||||
|
||||
modalContent.innerHTML = `
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<div>
|
||||
<h2 class="text-3xl font-bold text-gray-900">${venue.name}</h2>
|
||||
<p class="text-gray-600">${venue.fullName}</p>
|
||||
</div>
|
||||
<span class="text-sm font-semibold ${venue.type === '会议' ? 'bg-sky-100 text-sky-800' : 'bg-amber-100 text-amber-800'} py-1.5 px-4 rounded-full">${venue.type}</span>
|
||||
</div>
|
||||
|
||||
<div class="prose max-w-none text-gray-700 mb-6">
|
||||
<p>${venue.overview}</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
<div>
|
||||
<h4 class="text-lg font-semibold text-gray-800 mb-3">关键信息</h4>
|
||||
<ul class="space-y-2">
|
||||
<li class="flex justify-between p-2 bg-gray-50 rounded-md"><span><strong>难度等级:</strong></span> <span class="font-semibold">${venue.tier}</span></li>
|
||||
<li class="flex justify-between p-2 bg-gray-50 rounded-md"><span><strong>主办方:</strong></span> <span class="font-semibold">${venue.sponsors}</span></li>
|
||||
<li class="flex justify-between p-2 bg-gray-50 rounded-md"><span><strong>页数限制:</strong></span> <span class="font-semibold">${venue.pageLimit}</span></li>
|
||||
<li class="flex justify-between p-2 bg-gray-50 rounded-md"><span><strong>投稿指南:</strong></span> <span class="font-semibold">${venue.guidelines}</span></li>
|
||||
</ul>
|
||||
|
||||
<div class="mt-6">
|
||||
<h4 class="text-lg font-semibold text-gray-800 mb-3">评审过程特点</h4>
|
||||
<ul class="list-disc list-inside space-y-1 text-gray-600">
|
||||
${venue.reviewProcess.map(p => `<li>${p}</li>`).join('')}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="text-lg font-semibold text-gray-800 mb-3 text-center">指标概览</h4>
|
||||
<div class="chart-container">
|
||||
<canvas id="venueChart"></canvas>
|
||||
</div>
|
||||
${timelineHtml}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 渲染图表
|
||||
try {
|
||||
const Chart = (window as any).Chart;
|
||||
if (Chart && venue.acceptanceValue !== null) {
|
||||
const ctx = (document.getElementById('venueChart') as HTMLCanvasElement).getContext('2d');
|
||||
if (ctx) {
|
||||
activeChart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['接收率 (%)', '评审周期 (周)'],
|
||||
datasets: [{
|
||||
label: venue.name,
|
||||
data: [venue.acceptanceValue, venue.speedValue],
|
||||
backgroundColor: ['rgba(39, 121, 127, 0.6)', 'rgba(251, 191, 36, 0.6)'],
|
||||
borderColor: ['rgba(39, 121, 127, 1)', 'rgba(245, 158, 11, 1)'],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
indexAxis: 'y',
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: { legend: { display: false } }
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('绘制图表时出错:', err);
|
||||
}
|
||||
|
||||
// GSAP动画
|
||||
gsap.set(cardElement, { opacity: 0 });
|
||||
|
||||
modal.classList.remove('hidden');
|
||||
modalOverlay.classList.remove('hidden');
|
||||
|
||||
const tl = gsap.timeline({
|
||||
onComplete: () => { isAnimating = false; }
|
||||
});
|
||||
|
||||
const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
|
||||
let targetW = '80vw';
|
||||
let targetH = '75vh';
|
||||
if (vw >= 1024) {
|
||||
targetW = '70vw';
|
||||
targetH = '70vh';
|
||||
} else if (vw <= 640) {
|
||||
targetW = '92vw';
|
||||
targetH = '85vh';
|
||||
}
|
||||
|
||||
tl.set(modal, {
|
||||
top: activeCardState.top,
|
||||
left: activeCardState.left,
|
||||
width: activeCardState.width,
|
||||
height: activeCardState.height,
|
||||
})
|
||||
.to(modalOverlay, {
|
||||
opacity: 0.6,
|
||||
duration: 0.4
|
||||
}, 0)
|
||||
.to(modal, {
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
width: targetW,
|
||||
height: targetH,
|
||||
x: '-50%',
|
||||
y: '-50%',
|
||||
duration: 0.5,
|
||||
ease: 'expo.out'
|
||||
}, 0)
|
||||
.to(modalContentWrapper, {
|
||||
opacity: 1,
|
||||
visibility: 'visible',
|
||||
duration: 0.4,
|
||||
}, ">-0.2");
|
||||
}
|
||||
|
||||
/**
|
||||
* 简化模态框(无GSAP时使用)
|
||||
*/
|
||||
function openSimpleModal(venueId: string): void {
|
||||
const venue = venuesData.find(v => v.id === venueId);
|
||||
if (!venue) return;
|
||||
|
||||
const modal = document.getElementById('detail-modal');
|
||||
const modalOverlay = document.getElementById('modal-overlay');
|
||||
const modalContent = document.getElementById('modal-content');
|
||||
const modalContentWrapper = document.getElementById('modal-content-wrapper');
|
||||
|
||||
if (!modal || !modalOverlay || !modalContent || !modalContentWrapper) return;
|
||||
|
||||
// 直接显示,无动画
|
||||
modal.classList.remove('hidden');
|
||||
modalOverlay.classList.remove('hidden');
|
||||
modalContentWrapper.style.opacity = '1';
|
||||
modalContentWrapper.style.visibility = 'visible';
|
||||
|
||||
// 设置固定位置
|
||||
modal.style.top = '50%';
|
||||
modal.style.left = '50%';
|
||||
modal.style.transform = 'translate(-50%, -50%)';
|
||||
modal.style.width = '80vw';
|
||||
modal.style.height = '75vh';
|
||||
|
||||
// 生成内容(同上)
|
||||
let timelineHtml = '';
|
||||
if (venue.timeline.length > 0) {
|
||||
timelineHtml = `<div class="mt-6">
|
||||
<h4 class="text-lg font-semibold text-gray-800 mb-3">典型发表时间线</h4>
|
||||
<ol class="relative border-l border-gray-200">`;
|
||||
venue.timeline.forEach(item => {
|
||||
timelineHtml += `
|
||||
<li class="mb-6 ml-4">
|
||||
<div class="absolute w-3 h-3 bg-gray-300 rounded-full mt-1.5 -left-1.5 border border-white"></div>
|
||||
<time class="mb-1 text-sm font-normal leading-none text-gray-500">${item.date}</time>
|
||||
<h3 class="text-md font-semibold text-gray-900">${item.stage}</h3>
|
||||
</li>
|
||||
`;
|
||||
});
|
||||
timelineHtml += `</ol></div>`;
|
||||
}
|
||||
|
||||
modalContent.innerHTML = `
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<div>
|
||||
<h2 class="text-3xl font-bold text-gray-900">${venue.name}</h2>
|
||||
<p class="text-gray-600">${venue.fullName}</p>
|
||||
</div>
|
||||
<span class="text-sm font-semibold ${venue.type === '会议' ? 'bg-sky-100 text-sky-800' : 'bg-amber-100 text-amber-800'} py-1.5 px-4 rounded-full">${venue.type}</span>
|
||||
</div>
|
||||
|
||||
<div class="prose max-w-none text-gray-700 mb-6">
|
||||
<p>${venue.overview}</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
<div>
|
||||
<h4 class="text-lg font-semibold text-gray-800 mb-3">关键信息</h4>
|
||||
<ul class="space-y-2">
|
||||
<li class="flex justify-between p-2 bg-gray-50 rounded-md"><span><strong>难度等级:</strong></span> <span class="font-semibold">${venue.tier}</span></li>
|
||||
<li class="flex justify-between p-2 bg-gray-50 rounded-md"><span><strong>主办方:</strong></span> <span class="font-semibold">${venue.sponsors}</span></li>
|
||||
<li class="flex justify-between p-2 bg-gray-50 rounded-md"><span><strong>页数限制:</strong></span> <span class="font-semibold">${venue.pageLimit}</span></li>
|
||||
</ul>
|
||||
|
||||
<div class="mt-6">
|
||||
<h4 class="text-lg font-semibold text-gray-800 mb-3">评审过程特点</h4>
|
||||
<ul class="list-disc list-inside space-y-1 text-gray-600">
|
||||
${venue.reviewProcess.map(p => `<li>${p}</li>`).join('')}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
${timelineHtml}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭模态框
|
||||
*/
|
||||
export function closeModal(): void {
|
||||
const gsap = (window as any).gsap;
|
||||
|
||||
if (!gsap || !activeCardState) {
|
||||
// 简化关闭
|
||||
const modal = document.getElementById('detail-modal');
|
||||
const modalOverlay = document.getElementById('modal-overlay');
|
||||
if (modal && modalOverlay) {
|
||||
modal.classList.add('hidden');
|
||||
modalOverlay.classList.add('hidden');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAnimating) return;
|
||||
isAnimating = true;
|
||||
|
||||
const modal = document.getElementById('detail-modal');
|
||||
const modalOverlay = document.getElementById('modal-overlay');
|
||||
const modalContentWrapper = document.getElementById('modal-content-wrapper');
|
||||
const originalCard = document.querySelector(`[data-id='${activeCardState.id}']`) as HTMLElement;
|
||||
|
||||
if (!modal || !modalOverlay || !modalContentWrapper) return;
|
||||
|
||||
const tl = gsap.timeline({
|
||||
onComplete: () => {
|
||||
modal.classList.add('hidden');
|
||||
modalOverlay.classList.add('hidden');
|
||||
if (originalCard) {
|
||||
gsap.set(originalCard, { opacity: 1 });
|
||||
}
|
||||
activeCardState = null;
|
||||
isAnimating = false;
|
||||
}
|
||||
});
|
||||
|
||||
tl.to(modalContentWrapper, {
|
||||
opacity: 0,
|
||||
duration: 0.3,
|
||||
ease: 'power2.out'
|
||||
})
|
||||
.to(modal, {
|
||||
top: activeCardState.top,
|
||||
left: activeCardState.left,
|
||||
width: activeCardState.width,
|
||||
height: activeCardState.height,
|
||||
x: '0%',
|
||||
y: '0%',
|
||||
duration: 0.5,
|
||||
ease: 'expo.in'
|
||||
}, ">-0.05")
|
||||
.to(modalOverlay, {
|
||||
opacity: 0,
|
||||
duration: 0.4,
|
||||
ease: 'power2.inOut'
|
||||
}, "<")
|
||||
.set(modalContentWrapper, { visibility: 'hidden' });
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染策略指南手风琴
|
||||
*/
|
||||
export function renderStrategyAccordion(): void {
|
||||
const container = document.getElementById('accordion-container');
|
||||
if (!container) return;
|
||||
|
||||
strategyData.forEach((item, index) => {
|
||||
const div = document.createElement('div');
|
||||
div.className = "bg-white rounded-xl shadow-sm overflow-hidden border-l-4 border-transparent hover:border-[#27797f] transition-all";
|
||||
div.innerHTML = `
|
||||
<button class="accordion-header w-full flex justify-between items-center p-5 text-left font-semibold text-gray-800 hover:bg-gray-50 transition" data-index="${index}">
|
||||
<span>${item.title}</span>
|
||||
<svg class="accordion-icon w-6 h-6 transform transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
|
||||
</button>
|
||||
<div class="accordion-content hidden p-5 pt-0 prose max-w-none text-gray-600">
|
||||
${item.content}
|
||||
</div>
|
||||
`;
|
||||
container.appendChild(div);
|
||||
});
|
||||
|
||||
document.querySelectorAll('.accordion-header').forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
const content = button.nextElementSibling as HTMLElement;
|
||||
const icon = button.querySelector('.accordion-icon');
|
||||
|
||||
content.classList.toggle('hidden');
|
||||
icon?.classList.toggle('rotate-180');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化所有交互功能
|
||||
*/
|
||||
export function initEDAVenuesInteractive(): void {
|
||||
const typeFilter = document.getElementById('type-filter');
|
||||
const tierFilter = document.getElementById('tier-filter');
|
||||
const speedFilter = document.getElementById('speed-filter');
|
||||
const resetButton = document.getElementById('reset-filters');
|
||||
const closeModalBtn = document.getElementById('close-modal-btn');
|
||||
const modalOverlay = document.getElementById('modal-overlay');
|
||||
|
||||
// 筛选器事件
|
||||
typeFilter?.addEventListener('change', renderVenues);
|
||||
tierFilter?.addEventListener('change', renderVenues);
|
||||
speedFilter?.addEventListener('change', renderVenues);
|
||||
|
||||
resetButton?.addEventListener('click', () => {
|
||||
(typeFilter as HTMLSelectElement).value = 'all';
|
||||
(tierFilter as HTMLSelectElement).value = 'all';
|
||||
(speedFilter as HTMLSelectElement).value = 'all';
|
||||
renderVenues();
|
||||
});
|
||||
|
||||
// 模态框关闭事件
|
||||
closeModalBtn?.addEventListener('click', closeModal);
|
||||
modalOverlay?.addEventListener('click', closeModal);
|
||||
|
||||
// 渲染初始内容
|
||||
renderVenues();
|
||||
renderStrategyAccordion();
|
||||
|
||||
console.log('🎯 EDA学术发表指南交互功能已初始化');
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user