Compare commits

..

2 Commits

5 changed files with 705 additions and 515 deletions

View File

@ -24,6 +24,7 @@
"agentation": "^2.2.0", "agentation": "^2.2.0",
"axios": "^1.13.2", "axios": "^1.13.2",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"echarts": "^5.5.0",
"nprogress": "catalog:frontend", "nprogress": "catalog:frontend",
"pinia": "catalog:frontend", "pinia": "catalog:frontend",
"react": "^19.2.4", "react": "^19.2.4",

File diff suppressed because it is too large Load Diff

View File

@ -83,6 +83,11 @@ const locationInfo = computed(() => {
: { address: '山东省东营市...', details: '老校区历史悠久...' } : { address: '山东省东营市...', details: '老校区历史悠久...' }
}) })
const schoolName = '中国石油大学(华东)'
const mapQuery = computed(() => `${schoolName} ${activeLocationTab.value} ${locationInfo.value.address}`)
const mapEmbedUrl = computed(() => `https://map.baidu.com/?newmap=1&ie=utf-8&wd=${encodeURIComponent(mapQuery.value)}`)
const mapDetailUrl = computed(() => `https://map.baidu.com/?newmap=1&ie=utf-8&wd=${encodeURIComponent(mapQuery.value)}`)
const currentCampusFacilities = computed(() => { const currentCampusFacilities = computed(() => {
return campusFacilities.value.find(c => c.name === selectedCampus.value) return campusFacilities.value.find(c => c.name === selectedCampus.value)
}) })
@ -135,13 +140,24 @@ const currentCampusFacilities = computed(() => {
</button> </button>
</div> </div>
<div class="h-64 flex flex-col md:flex-row"> <div class="h-64 flex flex-col md:flex-row">
<!-- 模拟地图 --> <!-- 地图 -->
<div class="group relative w-full flex items-center justify-center bg-blue-50 md:w-1/2 dark:bg-slate-900"> <div class="group relative w-full overflow-hidden bg-blue-50 md:w-1/2 dark:bg-slate-900">
<span class="text-4xl text-blue-300">MAP</span> <iframe
class="absolute inset-0 h-full w-full"
:src="mapEmbedUrl"
title="Baidu Map"
loading="lazy"
referrerpolicy="no-referrer-when-downgrade"
></iframe>
<div class="absolute inset-0 bg-black/5 transition dark:bg-white/5 group-hover:bg-transparent" /> <div class="absolute inset-0 bg-black/5 transition dark:bg-white/5 group-hover:bg-transparent" />
<div class="absolute bottom-2 right-2 rounded bg-white px-2 py-1 text-xs shadow dark:bg-slate-700"> <a
:href="mapDetailUrl"
target="_blank"
rel="noopener"
class="absolute bottom-2 right-2 rounded bg-white px-2 py-1 text-xs shadow dark:bg-slate-700"
>
地图详情 > 地图详情 >
</div> </a>
</div> </div>
<!-- 地址详情 --> <!-- 地址详情 -->
<div class="w-full flex flex-col justify-center p-4 md:w-1/2"> <div class="w-full flex flex-col justify-center p-4 md:w-1/2">

View File

@ -1,38 +1,37 @@
<template> <template>
<div class="min-h-screen bg-gray-50 p-4 md:p-8 font-sans text-gray-700"> <div class="mx-auto max-w-7xl px-4 lg:px-8 sm:px-6">
<div class="max-w-6xl mx-auto space-y-4"> <div class="space-y-4">
<!-- 头部卡片: 专业标题与关注 --> <!-- 头部卡片: 专业标题与关注 -->
<div class="bg-white rounded shadow-sm p-6 flex flex-col md:flex-row items-start md:items-center justify-between gap-4"> <div class="bg-white rounded shadow-sm p-6 mt-8 flex flex-col md:flex-row items-start md:items-center justify-between gap-4 dark:bg-slate-800">
<div class="flex items-start gap-4"> <div class="flex items-center gap-4">
<!-- 图标 --> <!-- 图标 -->
<div class="w-16 h-16 rounded-full bg-blue-100 flex items-center justify-center flex-shrink-0"> <div class="w-16 h-16 rounded-full bg-blue-100 flex items-center justify-center flex-shrink-0">
<svg class="w-8 h-8 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.384-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"></path></svg> <svg class="w-8 h-8 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.384-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"></path></svg>
</div> </div>
<div> <div>
<h1 class="text-2xl font-bold text-gray-900 mb-2">产品设计</h1> <h1 class="text-2xl font-bold text-gray-900 mb-2 dark:text-white">产品设计</h1>
<div class="flex flex-wrap gap-2 text-sm"> <div class="flex flex-wrap gap-2 text-sm">
<span class="px-2 py-0.5 bg-gray-100 text-gray-600 rounded">本科</span> <span class="px-2 py-0.5 bg-gray-100 text-gray-600 rounded dark:bg-slate-700 dark:text-slate-200">本科</span>
<span class="px-2 py-0.5 bg-gray-100 text-gray-600 rounded">4</span> <span class="px-2 py-0.5 bg-gray-100 text-gray-600 rounded dark:bg-slate-700 dark:text-slate-200">4</span>
<span class="px-2 py-0.5 bg-gray-100 text-gray-600 rounded">艺术学学士</span> <span class="px-2 py-0.5 bg-gray-100 text-gray-600 rounded dark:bg-slate-700 dark:text-slate-200">艺术学学士</span>
</div> </div>
<div class="mt-2 text-sm text-gray-500">设计学类</div> <div class="mt-2 text-sm text-gray-500 dark:text-slate-400">设计学类</div>
</div> </div>
</div> </div>
<button class="px-4 py-1.5 border border-gray-300 rounded text-gray-600 hover:bg-gray-50 transition text-sm"> <button class="px-4 py-1.5 border border-gray-300 rounded text-gray-600 hover:bg-gray-50 transition text-sm dark:border-slate-600 dark:text-slate-200 dark:hover:bg-slate-700">
+ 关注 + 关注
</button> </button>
</div> </div>
<!-- 导航栏 --> <!-- 导航栏 -->
<div class="bg-white rounded shadow-sm border-b border-gray-100"> <div class="bg-white rounded shadow-sm border-b border-gray-100 dark:bg-slate-800 dark:border-slate-700">
<div class="flex px-6 gap-8"> <div class="flex px-6 gap-8">
<button <button
v-for="tab in tabs" v-for="tab in tabs"
:key="tab.id" :key="tab.id"
@click="currentTab = tab.id" @click="currentTab = tab.id"
class="py-4 text-sm font-medium border-b-2 transition-colors relative" class="py-4 text-sm font-medium border-b-2 transition-colors relative"
:class="currentTab === tab.id ? 'border-orange-500 text-orange-500' : 'border-transparent text-gray-600 hover:text-gray-900'" :class="currentTab === tab.id ? 'border-orange-500 text-orange-500' : 'border-transparent text-gray-600 hover:text-gray-900 dark:text-slate-300 dark:hover:text-white'"
> >
{{ tab.name }} {{ tab.name }}
</button> </button>
@ -40,48 +39,69 @@
</div> </div>
<!-- 内容区域 --> <!-- 内容区域 -->
<div class="bg-white rounded shadow-sm p-6 min-h-[500px]"> <div class="bg-white rounded shadow-sm p-6 min-h-[500px] dark:bg-slate-800">
<!-- Panel 1: 基本介绍 --> <!-- Panel 1: 基本介绍 -->
<div v-if="currentTab === 'intro'" class="space-y-8"> <div v-if="currentTab === 'intro'" class="space-y-6">
<ExpandableSection title="专业概括"> <div class="rounded-lg border border-gray-100 bg-gray-50 p-1 dark:border-slate-700 dark:bg-slate-700/40">
<div class="space-y-4"> <button
class="w-full flex items-center justify-between gap-4 rounded-lg px-4 py-3 text-left text-sm font-semibold text-gray-900 transition hover:bg-white dark:text-white dark:hover:bg-slate-700"
@click="toggleIntroSection('summary')"
>
专业概括
<span class="text-gray-400 transition-transform" :class="openIntroSection === 'summary' ? 'rotate-180' : ''"></span>
</button>
<div v-show="openIntroSection === 'summary'" class="space-y-4 px-4 pb-4 pt-4 text-left text-sm text-gray-600 dark:text-slate-300">
<div> <div>
<span class="font-bold text-gray-900">是什么</span> <span class="font-bold text-gray-900 dark:text-white">是什么</span>
产品设计主要研究艺术学设计学计算机技术等方面的基本知识和技能进行工业设计外观设计结构设计造型设计以及交互设计等例如勺子杯子的造型设计衣柜橱柜的结构设计软件界面的设计等关键词杯子 衣柜 软件界面 计算机 产品设计主要研究艺术学设计学计算机技术等方面的基本知识和技能进行工业设计外观设计结构设计造型设计以及交互设计等例如勺子杯子的造型设计衣柜橱柜的结构设计软件界面的设计等关键词杯子 衣柜 软件界面 计算机
</div> </div>
<div> <div>
<span class="font-bold text-gray-900">学什么</span> <span class="font-bold text-gray-900 dark:text-white">学什么</span>
工业美术史工业设计史设计手绘色彩传达产品结构设计产品造型设计产品创新设计产品造型材料工艺产品语义设计计算机辅助设计 部分高校按以下专业方向培养服装设计家具设计数字设计应用设计纺织品设计产品造型设计珠宝首饰设计鞋类与工程鞋类与皮具设计 工业美术史工业设计史设计手绘色彩传达产品结构设计产品造型设计产品创新设计产品造型材料工艺产品语义设计计算机辅助设计 部分高校按以下专业方向培养服装设计家具设计数字设计应用设计纺织品设计产品造型设计珠宝首饰设计鞋类与工程鞋类与皮具设计
</div> </div>
</div> </div>
</ExpandableSection> </div>
<ExpandableSection title="培养方向"> <div class="rounded-lg border border-gray-100 bg-gray-50 p-1 dark:border-slate-700 dark:bg-slate-700/40">
<div class="space-y-4"> <button
class="w-full flex items-center justify-between gap-4 rounded-lg px-4 py-3 text-left text-sm font-semibold text-gray-900 transition hover:bg-white dark:text-white dark:hover:bg-slate-700"
@click="toggleIntroSection('training')"
>
培养方向
<span class="text-gray-400 transition-transform" :class="openIntroSection === 'training' ? 'rotate-180' : ''"></span>
</button>
<div v-show="openIntroSection === 'training'" class="space-y-4 px-4 pb-4 pt-4 text-left text-sm text-gray-600 dark:text-slate-300">
<div> <div>
<span class="font-bold text-gray-900">培养目标</span> <span class="font-bold text-gray-900 dark:text-white">培养目标</span>
本专业培养具有厚基础宽口径重能力知识能力素质协调发展具有扎实的工业设计基础理论知识及产品造型能力良好的职业技能和职业素质能在企事业单位专业设计部门教学科研单位从事以产品创新为重点的设计管理科研或教学工作也能从事与产品设计相关的视觉传达设计信息设计环境设施设计或展示设计工作的应用型研究型人才 本专业培养具有厚基础宽口径重能力知识能力素质协调发展具有扎实的工业设计基础理论知识及产品造型能力良好的职业技能和职业素质能在企事业单位专业设计部门教学科研单位从事以产品创新为重点的设计管理科研或教学工作也能从事与产品设计相关的视觉传达设计信息设计环境设施设计或展示设计工作的应用型研究型人才
</div> </div>
<div> <div>
<span class="font-bold text-gray-900">培养要求</span> <span class="font-bold text-gray-900 dark:text-white">培养要求</span>
本专业在能力结构方面要求学生应具有一定的设计创新思维意识初步具备综合运用所学知识分析和解决工业产品造型设计过程中遇到的研究开发设计等方面问题的能力能清晰地表达设计思想熟悉产品设计的程序与方法 本专业在能力结构方面要求学生应具有一定的设计创新思维意识初步具备综合运用所学知识分析和解决工业产品造型设计过程中遇到的研究开发设计等方面问题的能力能清晰地表达设计思想熟悉产品设计的程序与方法
</div> </div>
</div> </div>
</ExpandableSection> </div>
<ExpandableSection title="主要课程"> <div class="rounded-lg border border-gray-100 bg-gray-50 p-1 dark:border-slate-700 dark:bg-slate-700/40">
<div class="space-y-4"> <button
class="w-full flex items-center justify-between gap-4 rounded-lg px-4 py-3 text-left text-sm font-semibold text-gray-900 transition hover:bg-white dark:text-white dark:hover:bg-slate-700"
@click="toggleIntroSection('courses')"
>
主要课程
<span class="text-gray-400 transition-transform" :class="openIntroSection === 'courses' ? 'rotate-180' : ''"></span>
</button>
<div v-show="openIntroSection === 'courses'" class="space-y-4 px-4 pb-4 pt-4 text-left text-sm text-gray-600 dark:text-slate-300">
<div> <div>
<span class="font-bold text-gray-900">主干学科</span> <span class="font-bold text-gray-900 dark:text-white">主干学科</span>
产品设计方法学人机工程学材料与工艺学 产品设计方法学人机工程学材料与工艺学
</div> </div>
<div> <div>
<span class="font-bold text-gray-900">核心课程</span> <span class="font-bold text-gray-900 dark:text-white">核心课程</span>
工业设计史产品设计方法学产品设计效果图表现技法人机工程学制图模型制作与工艺产品调研方法产品设计报告书制作数字化产品设计及产品设计相关软件等基础理论知识以及基本方法中外工艺美术史设计学美学心理学公关关系学造型基础构成平面色彩立体构成世界工业设计发展史等相关课程等 工业设计史产品设计方法学产品设计效果图表现技法人机工程学制图模型制作与工艺产品调研方法产品设计报告书制作数字化产品设计及产品设计相关软件等基础理论知识以及基本方法中外工艺美术史设计学美学心理学公关关系学造型基础构成平面色彩立体构成世界工业设计发展史等相关课程等
</div> </div>
</div> </div>
</ExpandableSection> </div>
</div> </div>
<!-- Panel 2: 就业分析 --> <!-- Panel 2: 就业分析 -->
@ -89,23 +109,19 @@
<!-- 职业分布 --> <!-- 职业分布 -->
<div> <div>
<h3 class="font-bold text-gray-900 mb-6">职业分布</h3> <h3 class="font-bold text-gray-900 mb-6 dark:text-white">职业分布</h3>
<div class="flex flex-col md:flex-row gap-8 items-center bg-gray-50 p-6 rounded-lg"> <div class="flex flex-col md:flex-row gap-8 items-center bg-gray-50 p-6 rounded-lg dark:bg-slate-700/40">
<!-- CSS 模拟饼图 --> <div ref="jobPieRef" class="w-48 h-48 flex-shrink-0"></div>
<div class="w-48 h-48 rounded-full relative flex-shrink-0"
style="background: conic-gradient(#f97316 0% 35%, #84cc16 35% 75%, #06b6d4 75% 85%, #ef4444 85% 100%);">
<div class="absolute inset-8 bg-gray-50 rounded-full"></div>
</div>
<div class="flex-1"> <div class="flex-1">
<h4 class="font-bold mb-2">其他</h4> <h4 class="font-bold mb-2 dark:text-white">{{ selectedJob.name }}</h4>
<p class="text-sm text-gray-600 leading-relaxed"> <p class="text-sm text-gray-600 leading-relaxed dark:text-slate-300">
资深产品经理资深产品设计师产品创意设计主管ID工程师产品专家UI/UX Designer and Researcher 交互界面/体验设计师及研究员高级能开发产品规划经理市场部市场技术开发专员 {{ selectedJob.description }}
</p> </p>
<div class="flex flex-wrap gap-4 mt-4 text-xs"> <div class="flex flex-wrap gap-4 mt-4 text-xs">
<div class="flex items-center gap-1"><span class="w-3 h-3 bg-orange-500 rounded-sm"></span>其他</div> <div v-for="item in jobDistribution" :key="item.name" class="flex items-center gap-1">
<div class="flex items-center gap-1"><span class="w-3 h-3 bg-lime-500 rounded-sm"></span>艺术设计</div> <span class="w-3 h-3 rounded-sm" :style="{ backgroundColor: item.color }"></span>
<div class="flex items-center gap-1"><span class="w-3 h-3 bg-cyan-500 rounded-sm"></span>装饰装修</div> {{ item.name }}
<div class="flex items-center gap-1"><span class="w-3 h-3 bg-red-500 rounded-sm"></span>市场</div> </div>
</div> </div>
</div> </div>
</div> </div>
@ -113,10 +129,10 @@
<!-- 薪资分布 --> <!-- 薪资分布 -->
<div> <div>
<h3 class="font-bold text-gray-900 mb-6">薪资分布</h3> <h3 class="font-bold text-gray-900 mb-6 dark:text-white">薪资分布</h3>
<div class="overflow-x-auto border border-gray-100 rounded-lg"> <div class="overflow-x-auto border border-gray-100 rounded-lg dark:border-slate-700">
<table class="w-full text-sm text-left"> <table class="w-full text-sm text-left">
<thead class="bg-gray-50 text-gray-900 font-medium"> <thead class="bg-gray-50 text-gray-900 font-medium dark:bg-slate-700 dark:text-white">
<tr> <tr>
<th class="px-6 py-4">岗位</th> <th class="px-6 py-4">岗位</th>
<th class="px-6 py-4">应届生月薪</th> <th class="px-6 py-4">应届生月薪</th>
@ -124,7 +140,7 @@
<th class="px-6 py-4">毕业3-5年月薪</th> <th class="px-6 py-4">毕业3-5年月薪</th>
</tr> </tr>
</thead> </thead>
<tbody class="divide-y divide-gray-100"> <tbody class="divide-y divide-gray-100 dark:divide-slate-700">
<tr> <tr>
<td class="px-6 py-4">家具 (家居用品设计)</td> <td class="px-6 py-4">家具 (家居用品设计)</td>
<td class="px-6 py-4">6547~10881</td> <td class="px-6 py-4">6547~10881</td>
@ -144,19 +160,19 @@
<!-- 地区去向 --> <!-- 地区去向 -->
<div> <div>
<h3 class="font-bold text-gray-900 mb-6">地区去向</h3> <h3 class="font-bold text-gray-900 mb-6 dark:text-white">地区去向</h3>
<div class="flex flex-col md:flex-row gap-12 items-center"> <div class="flex flex-col md:flex-row gap-12 items-center">
<div class="w-32 h-32 rounded-full border-8 border-orange-400 flex items-center justify-center flex-col text-center"> <div class="w-32 h-32 rounded-full border-8 border-orange-400 flex items-center justify-center flex-col text-center">
<span class="text-xs text-gray-500">去北上广深比例</span> <span class="text-xs text-gray-500 dark:text-slate-400">去北上广深比例</span>
<span class="text-xl font-bold text-gray-900">70%</span> <span class="text-xl font-bold text-gray-900 dark:text-white">70%</span>
</div> </div>
<div class="flex-1 w-full space-y-3"> <div class="flex-1 w-full space-y-3">
<div v-for="city in cities" :key="city.name" class="flex items-center text-sm"> <div v-for="city in cities" :key="city.name" class="flex items-center text-sm">
<span class="w-12 text-gray-600">{{ city.name }}</span> <span class="w-12 text-gray-600 dark:text-slate-300">{{ city.name }}</span>
<div class="flex-1 h-2 bg-gray-100 rounded-full overflow-hidden mx-3"> <div class="flex-1 h-2 bg-gray-100 rounded-full overflow-hidden mx-3 dark:bg-slate-700">
<div class="h-full bg-orange-500 rounded-full" :style="{ width: city.percent + '%' }"></div> <div class="h-full bg-orange-500 rounded-full" :style="{ width: city.percent + '%' }"></div>
</div> </div>
<span class="w-8 text-right text-gray-900">{{ city.percent }}%</span> <span class="w-8 text-right text-gray-900 dark:text-white">{{ city.percent }}%</span>
</div> </div>
</div> </div>
</div> </div>
@ -166,32 +182,32 @@
<!-- Panel 3: 开设院校 --> <!-- Panel 3: 开设院校 -->
<div v-if="currentTab === 'school'" class="space-y-6"> <div v-if="currentTab === 'school'" class="space-y-6">
<div v-for="school in schools" :key="school.name" class="flex items-center justify-between border-b border-gray-100 pb-6 last:border-0"> <div v-for="school in schools" :key="school.name" class="flex items-center justify-between border-b border-gray-100 pb-6 last:border-0 dark:border-slate-700">
<div class="flex gap-4"> <div class="flex gap-4">
<img :src="school.logo" class="w-14 h-14 rounded-full border border-gray-200 object-cover" alt="logo" /> <img :src="school.logo" class="w-14 h-14 rounded-full border border-gray-200 object-cover" alt="logo" />
<div> <div>
<h3 class="font-bold text-lg text-gray-900 mb-1">{{ school.name }}</h3> <h3 class="font-bold text-lg text-gray-900 mb-1 dark:text-white">{{ school.name }}</h3>
<div class="flex gap-2 mb-2"> <div class="flex gap-2 mb-2">
<span v-for="tag in school.tags" :key="tag" class="px-1.5 py-0.5 bg-gray-100 text-xs text-gray-500 rounded">{{ tag }}</span> <span v-for="tag in school.tags" :key="tag" class="px-1.5 py-0.5 bg-gray-100 text-xs text-gray-500 rounded dark:bg-slate-700 dark:text-slate-200">{{ tag }}</span>
</div> </div>
<div class="text-sm text-gray-500">{{ school.location }}</div> <div class="text-sm text-gray-500 dark:text-slate-400">{{ school.location }}</div>
</div> </div>
</div> </div>
<div class="text-right"> <div class="text-right">
<div class="text-sm text-gray-500 mb-1">排名: <span class="font-medium text-gray-900">{{ school.rank }}</span></div> <div class="text-sm text-gray-500 mb-1 dark:text-slate-400">排名: <span class="font-medium text-gray-900 dark:text-white">{{ school.rank }}</span></div>
<div class="text-sm text-gray-500">专业学科评级 <span class="text-orange-500 font-bold">{{ school.grade }}</span></div> <div class="text-sm text-gray-500 dark:text-slate-400">专业学科评级 <span class="text-orange-500 font-bold">{{ school.grade }}</span></div>
</div> </div>
</div> </div>
<!-- 分页 --> <!-- 分页 -->
<div class="flex justify-center gap-2 mt-8"> <div class="flex justify-center gap-2 mt-8">
<button class="w-8 h-8 border border-gray-300 rounded hover:border-orange-500 hover:text-orange-500 transition text-sm">&lt;</button> <button class="w-8 h-8 border border-gray-300 rounded hover:border-orange-500 hover:text-orange-500 transition text-sm dark:border-slate-600 dark:text-slate-200 dark:hover:text-orange-400">&lt;</button>
<button class="w-8 h-8 bg-orange-500 text-white rounded text-sm">1</button> <button class="w-8 h-8 bg-orange-500 text-white rounded text-sm">1</button>
<button class="w-8 h-8 border border-gray-300 rounded hover:border-orange-500 hover:text-orange-500 transition text-sm">2</button> <button class="w-8 h-8 border border-gray-300 rounded hover:border-orange-500 hover:text-orange-500 transition text-sm dark:border-slate-600 dark:text-slate-200 dark:hover:text-orange-400">2</button>
<button class="w-8 h-8 border border-gray-300 rounded hover:border-orange-500 hover:text-orange-500 transition text-sm">3</button> <button class="w-8 h-8 border border-gray-300 rounded hover:border-orange-500 hover:text-orange-500 transition text-sm dark:border-slate-600 dark:text-slate-200 dark:hover:text-orange-400">3</button>
<span class="leading-8 text-gray-400">...</span> <span class="leading-8 text-gray-400 dark:text-slate-500">...</span>
<button class="w-8 h-8 border border-gray-300 rounded hover:border-orange-500 hover:text-orange-500 transition text-sm">42</button> <button class="w-8 h-8 border border-gray-300 rounded hover:border-orange-500 hover:text-orange-500 transition text-sm dark:border-slate-600 dark:text-slate-200 dark:hover:text-orange-400">42</button>
<button class="w-8 h-8 border border-gray-300 rounded hover:border-orange-500 hover:text-orange-500 transition text-sm">&gt;</button> <button class="w-8 h-8 border border-gray-300 rounded hover:border-orange-500 hover:text-orange-500 transition text-sm dark:border-slate-600 dark:text-slate-200 dark:hover:text-orange-400">&gt;</button>
</div> </div>
</div> </div>
@ -201,7 +217,7 @@
</template> </template>
<script setup> <script setup>
import { ref } from 'vue'; import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
// --- Tab Logic --- // --- Tab Logic ---
const currentTab = ref('intro'); const currentTab = ref('intro');
@ -211,6 +227,145 @@ const tabs = [
{ id: 'school', name: '开设院校' } { id: 'school', name: '开设院校' }
]; ];
const openIntroSection = ref('summary');
const toggleIntroSection = (section) => {
openIntroSection.value = openIntroSection.value === section ? '' : section;
};
const jobDistribution = [
{
name: '其他',
value: 35,
color: '#f97316',
description: '资深产品经理、资深产品设计师、产品创意设计主管、ID 工程师、产品专家、UI/UX 设计师及研究员等岗位。',
},
{
name: '艺术设计',
value: 40,
color: '#84cc16',
description: '偏向视觉与品牌方向:视觉设计、平面设计、品牌设计、插画与多媒体设计等岗位。',
},
{
name: '装饰装修',
value: 10,
color: '#06b6d4',
description: '偏向空间与工程方向:室内设计、展示设计、软装设计与施工协调等岗位。',
},
{
name: '市场',
value: 15,
color: '#ef4444',
description: '偏向商业与增长方向:市场策划、产品运营、用户研究、市场拓展等岗位。',
},
];
const jobPieRef = ref(null);
let jobPieChart;
let echartsModule;
const selectedJob = ref(jobDistribution[0]);
const defaultJobName = jobDistribution[0].name;
const pinnedJobName = ref(null);
const loadEcharts = async () => {
if (!echartsModule)
echartsModule = await import('echarts');
return echartsModule;
};
const renderJobPie = async () => {
if (currentTab.value !== 'job')
return;
await nextTick();
if (currentTab.value !== 'job')
return;
if (!jobPieRef.value)
return;
if (jobPieChart)
jobPieChart.dispose();
const echarts = await loadEcharts();
if (currentTab.value !== 'job' || !jobPieRef.value)
return;
jobPieChart = echarts.init(jobPieRef.value);
jobPieChart.setOption({
tooltip: {
trigger: 'item',
formatter: '{b}: {d}%',
},
series: [
{
type: 'pie',
radius: ['55%', '80%'],
center: ['50%', '50%'],
label: { show: false },
labelLine: { show: false },
data: jobDistribution.map(item => ({
name: item.name,
value: item.value,
itemStyle: { color: item.color },
})),
},
],
});
jobPieChart.on('mouseover', (params) => {
if (pinnedJobName.value)
return;
const target = jobDistribution.find(item => item.name === params.name);
if (target)
selectedJob.value = target;
});
jobPieChart.on('mouseout', () => {
const target = jobDistribution.find(item => item.name === (pinnedJobName.value || defaultJobName));
if (target)
selectedJob.value = target;
});
jobPieChart.on('click', (params) => {
const target = jobDistribution.find(item => item.name === params.name);
if (!target)
return;
pinnedJobName.value = pinnedJobName.value === target.name ? null : target.name;
selectedJob.value = target;
});
};
const handleJobPieResize = () => {
if (jobPieChart)
jobPieChart.resize();
};
watch(currentTab, (value) => {
if (value === 'job') {
renderJobPie();
return;
}
if (jobPieChart) {
jobPieChart.dispose();
jobPieChart = null;
}
});
onMounted(() => {
if (currentTab.value === 'job')
renderJobPie();
window.addEventListener('resize', handleJobPieResize);
});
onBeforeUnmount(() => {
window.removeEventListener('resize', handleJobPieResize);
if (jobPieChart) {
jobPieChart.dispose();
jobPieChart = null;
}
});
// --- Data for School List --- // --- Data for School List ---
const schools = [ const schools = [
{ {

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, onMounted, onUnmounted } from 'vue' import { computed, ref, onMounted, onUnmounted, nextTick } from 'vue'
// //
import SchoolOverview from '~/components/school/SchoolOverview.vue' import SchoolOverview from '~/components/school/SchoolOverview.vue'
@ -27,6 +27,15 @@ const schoolCode = ref('')
const activeLocationTab = ref('唐岛湾校区') const activeLocationTab = ref('唐岛湾校区')
const activeNavTab = ref('学校概况') const activeNavTab = ref('学校概况')
const tabs = [
{ id: '学校概况', name: '学校概况' },
{ id: '历年分数', name: '历年分数' },
{ id: '招生计划', name: '招生计划' },
{ id: '开设专业', name: '开设专业' },
{ id: '录取预测', name: '录取预测' },
];
// //
const currentSlide = ref(0) const currentSlide = ref(0)
const carouselInterval = ref<number | null>(null) const carouselInterval = ref<number | null>(null)
@ -54,6 +63,14 @@ const rankings: Ranking[] = [
{ label: '人气值排名', value: 70 }, { label: '人气值排名', value: 70 },
] ]
const quickStats = [
{ label: '建校时间', value: '1953年', icon: '🕒', color: 'text-orange-500' },
{ label: '占地面积', value: '5000亩', icon: '⛳', color: 'text-purple-500' },
{ label: '主管部门', value: '教育部', icon: '🎓', color: 'text-blue-500' },
{ label: '联系电话', value: '0532-86983086', icon: '📞', color: 'text-blue-500' },
{ label: '邮箱', value: 'zhaosheng@upc.edu.cn', icon: '📧', color: 'text-blue-500' },
]
// () // ()
const departments: Major[] = [ const departments: Major[] = [
{ college: '地球科学与技术学院', majors: ['勘查技术与工程', '地质学', '资源勘查工程', '地球物理学'] }, { college: '地球科学与技术学院', majors: ['勘查技术与工程', '地质学', '资源勘查工程', '地球物理学'] },
@ -124,12 +141,34 @@ const handleCompare = () => {
// TODO: // TODO:
} }
const navRef = ref<HTMLElement | null>(null)
const navPlaceholderHeight = ref(0)
const isNavSticky = ref(false)
const stickyTrigger = 220
const updateNavHeight = () => {
if (navRef.value)
navPlaceholderHeight.value = navRef.value.getBoundingClientRect().height
}
const updateNavSticky = () => {
isNavSticky.value = window.scrollY >= stickyTrigger
}
onMounted(() => { onMounted(() => {
startCarousel() startCarousel()
updateNavSticky()
nextTick(() => {
updateNavHeight()
})
window.addEventListener('scroll', updateNavSticky, { passive: true })
window.addEventListener('resize', updateNavHeight)
}) })
onUnmounted(() => { onUnmounted(() => {
stopCarousel() stopCarousel()
window.removeEventListener('scroll', updateNavSticky)
window.removeEventListener('resize', updateNavHeight)
}) })
watchEffect(() => { watchEffect(() => {
@ -141,10 +180,10 @@ useHead({
</script> </script>
<template> <template>
<div class="mx-auto max-w-7xl min-h-screen bg-gray-50 px-4 transition-colors duration-300 dark:bg-slate-900 lg:px-8 sm:px-6"> <div class="mx-auto max-w-7xl px-4 lg:px-8 sm:px-6">
<!-- 顶部导航 & Header sticky --> <!-- 顶部导航 & Header sticky -->
<header class="top-0 z-50 shadow-sm"> <header class="top-0 z-50">
<div class="mb-8 mt-8 rounded-lg bg-white dark:bg-slate-800"> <div class="mb-4 mt-8 rounded-lg bg-white pl-4 pr-4 dark:bg-slate-800">
<div class="h-20 flex items-center justify-between"> <div class="h-20 flex items-center justify-between">
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<div class="h-16 w-16 flex items-center justify-center rounded-full bg-blue-900 text-sm text-white font-bold"> <div class="h-16 w-16 flex items-center justify-center rounded-full bg-blue-900 text-sm text-white font-bold">
@ -187,42 +226,25 @@ useHead({
</div> </div>
</div> </div>
</div>
<div v-show="isNavSticky" :style="{ height: `${navPlaceholderHeight}px` }"></div>
<div
class="w-full transition"
:class="isNavSticky
? 'fixed top-0 left-0 right-0 z-50 bg-white/95 shadow-sm backdrop-blur dark:bg-slate-800/95'
: 'mb-8 rounded-lg bg-white shadow-sm dark:bg-slate-800'"
>
<!-- 导航菜单 --> <!-- 导航菜单 -->
<nav class="scrollbar-hide flex overflow-x-auto pt-4 pb-2 text-base text-gray-500 font-medium space-x-8 sm:pb-0 dark:text-gray-400"> <nav
<button ref="navRef"
class="scrollbar-hide mx-auto flex w-full max-w-7xl overflow-x-auto px-4 pt-4 pb-2 text-base text-gray-500 font-medium space-x-8 sm:px-6 sm:pb-0 lg:px-8 dark:text-gray-400"
>
<button v-for="(item, index) in tabs" :key="index"
class="whitespace-nowrap border-b-2 pb-3 transition-colors" class="whitespace-nowrap border-b-2 pb-3 transition-colors"
:class="activeNavTab === '学校概况' ? 'border-orange-500 text-orange-600 dark:text-orange-400' : 'border-transparent hover:text-gray-700 dark:hover:text-gray-200'" :class="activeNavTab === item.id ? 'border-orange-500 text-orange-600 dark:text-orange-400' : 'border-transparent hover:text-gray-700 dark:hover:text-gray-200'"
@click="activeNavTab = '学校概况'" @click="activeNavTab = item.id"
> >
学校概况 {{item.name}}
</button>
<button
class="whitespace-nowrap border-b-2 pb-3 transition-colors"
:class="activeNavTab === '历年分数' ? 'border-orange-500 text-orange-600 dark:text-orange-400' : 'border-transparent hover:text-gray-700 dark:hover:text-gray-200'"
@click="activeNavTab = '历年分数'"
>
历年分数
</button>
<button
class="whitespace-nowrap border-b-2 pb-3 transition-colors"
:class="activeNavTab === '招生计划' ? 'border-orange-500 text-orange-600 dark:text-orange-400' : 'border-transparent hover:text-gray-700 dark:hover:text-gray-200'"
@click="activeNavTab = '招生计划'"
>
招生计划
</button>
<button
class="whitespace-nowrap border-b-2 pb-3 transition-colors"
:class="activeNavTab === '开设专业' ? 'border-orange-500 text-orange-600 dark:text-orange-400' : 'border-transparent hover:text-gray-700 dark:hover:text-gray-200'"
@click="activeNavTab = '开设专业'"
>
开设专业
</button>
<button
class="whitespace-nowrap border-b-2 pb-3 transition-colors"
:class="activeNavTab === '录取预测' ? 'border-orange-500 text-orange-600 dark:text-orange-400' : 'border-transparent hover:text-gray-700 dark:hover:text-gray-200'"
@click="activeNavTab = '录取预测'"
>
录取预测
</button> </button>
</nav> </nav>
</div> </div>
@ -239,15 +261,11 @@ useHead({
<button <button
class="absolute left-2 top-1/2 -translate-y-1/2 rounded-full bg-black/30 p-2 text-white backdrop-blur-sm transition hover:bg-black/50" class="absolute left-2 top-1/2 -translate-y-1/2 rounded-full bg-black/30 p-2 text-white backdrop-blur-sm transition hover:bg-black/50"
@click="prevSlide" @click="prevSlide"
> ><</button>
</button>
<button <button
class="absolute right-2 top-1/2 -translate-y-1/2 rounded-full bg-black/30 p-2 text-white backdrop-blur-sm transition hover:bg-black/50" class="absolute right-2 top-1/2 -translate-y-1/2 rounded-full bg-black/30 p-2 text-white backdrop-blur-sm transition hover:bg-black/50"
@click="nextSlide" @click="nextSlide"
> >></button>
</button>
<!-- 轮播指示器 --> <!-- 轮播指示器 -->
<div class="absolute bottom-4 left-1/2 flex -translate-x-1/2 gap-2"> <div class="absolute bottom-4 left-1/2 flex -translate-x-1/2 gap-2">
@ -273,68 +291,16 @@ useHead({
<!-- 快速统计信息栏 --> <!-- 快速统计信息栏 -->
<div class="grid grid-cols-2 gap-4 border-b border-gray-100 p-3 md:grid-cols-5 sm:grid-cols-4 dark:border-slate-700"> <div class="grid grid-cols-2 gap-4 border-b border-gray-100 p-3 md:grid-cols-5 sm:grid-cols-4 dark:border-slate-700">
<div class="flex items-start gap-2"> <div v-for="stat in quickStats" :key="stat.label" class="flex items-start gap-2">
<div class="text-xl text-orange-500"> <div class="text-xl" :class="stat.color">
🕒 {{ stat.icon }}
</div> </div>
<div> <div>
<p class="text-xs text-gray-500 dark:text-gray-400"> <p class="text-xs text-gray-500 dark:text-gray-400">
建校时间 {{ stat.label }}
</p> </p>
<p class="text-gray-900 font-medium dark:text-white"> <p class="text-gray-900 font-medium dark:text-white">
1953 {{ stat.value }}
</p>
</div>
</div>
<div class="flex items-start gap-2">
<div class="text-xl text-purple-500">
</div>
<div>
<p class="text-xs text-gray-500 dark:text-gray-400">
占地面积
</p>
<p class="text-gray-900 font-medium dark:text-white">
5000
</p>
</div>
</div>
<div class="flex items-start gap-2">
<div class="text-xl text-blue-500">
🎓
</div>
<div>
<p class="text-xs text-gray-500 dark:text-gray-400">
主管部门
</p>
<p class="text-gray-900 font-medium dark:text-white">
教育部
</p>
</div>
</div>
<div class="flex items-start gap-2">
<div class="text-xl text-blue-500">
📞
</div>
<div>
<p class="text-xs text-gray-500 dark:text-gray-400">
联系电话
</p>
<p class="text-gray-900 font-medium dark:text-white">
0532-86983086
</p>
</div>
</div>
<div class="flex items-start gap-2">
<div class="text-xl text-blue-500">
📧
</div>
<div>
<p class="text-xs text-gray-500 dark:text-gray-400">
邮箱
</p>
<p class="text-gray-900 font-medium dark:text-white">
zhaosheng@upc.edu.cn
</p> </p>
</div> </div>
</div> </div>
@ -344,7 +310,7 @@ useHead({
<!-- 网格布局左侧主内容右侧简单侧边栏(可选) --> <!-- 网格布局左侧主内容右侧简单侧边栏(可选) -->
<div class="grid grid-cols-1 gap-6 lg:grid-cols-4"> <div class="grid grid-cols-1 gap-6 lg:grid-cols-4">
<!-- 左侧/主体内容 (占3份宽度) --> <!-- 左侧/主体内容 (占3份宽度) -->
<div class="lg:col-span-3 space-y-6"> <div class="lg:col-span-3">
<!-- 子页面组件 --> <!-- 子页面组件 -->
<SchoolOverview v-show="activeNavTab === '学校概况'" /> <SchoolOverview v-show="activeNavTab === '学校概况'" />
<HistoricalScores v-show="activeNavTab === '历年分数'" /> <HistoricalScores v-show="activeNavTab === '历年分数'" />