导师列表和导师详情

This commit is contained in:
2026-07-03 11:55:44 +08:00
parent 51be3e5585
commit a1a27073e4
22 changed files with 2007 additions and 346 deletions
+88 -12
View File
@@ -17,16 +17,77 @@
:class="{ 'side-nav__item--active': isActive(item.name) }"
@click="handleNav(item)"
>
<img class="side-nav__item-icon" :src="item.iconImg" :alt="item.label" />
<!-- SVG图标通过v-html渲染以支持currentColor继承颜色 -->
<span class="side-nav__item-icon" v-html="item.iconImg"></span>
<span class="side-nav__item-label">{{ item.label }}</span>
<span v-if="item.badge" class="side-nav__badge">{{ item.badge }}</span>
</a>
</nav>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_151_276)">
<path fill="currentColor" stroke="currentColor" stroke-width="0.2" d="M7.66664 2.16675C6.78388 2.16681 5.91411 2.37934 5.13081 2.7864C4.34751 3.19346 3.6737 3.78309 3.16631 4.50545C2.65891 5.22782 2.33285 6.0617 2.21567 6.93664C2.09849 7.81158 2.19362 8.70188 2.49305 9.5323C2.79247 10.3627 3.28738 11.1089 3.93596 11.7077C4.58454 12.3065 5.36773 12.7405 6.21936 12.9728C7.07099 13.2052 7.96603 13.2291 8.82886 13.0426C9.6917 12.8561 10.497 12.4647 11.1766 11.9014L12.962 13.6867C13.0568 13.7751 13.1821 13.8232 13.3117 13.8209C13.4412 13.8186 13.5648 13.7661 13.6564 13.6745C13.748 13.5829 13.8005 13.4593 13.8028 13.3298C13.805 13.2002 13.757 13.0749 13.6686 12.9801L11.8853 11.1961C12.5567 10.3936 12.9853 9.41624 13.1208 8.37872C13.2562 7.34121 13.0929 6.28658 12.65 5.33862C12.2071 4.39066 11.503 3.58871 10.6203 3.02688C9.73759 2.46506 8.71296 2.16667 7.66664 2.16675Z" />
</g>
<defs>
<clipPath id="clip0_151_276">
<rect width="16" height="16" fill="none"/>
</clipPath>
</defs>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_151_281)">
<path fill="currentColor" stroke="currentColor" stroke-width="0.2" d="M10.5 8.66675C10.5 8.53414 10.4473 8.40696 10.3536 8.31319C10.2598 8.21943 10.1326 8.16675 10 8.16675H6C5.86739 8.16675 5.74022 8.21943 5.64645 8.31319C5.55268 8.40696 5.5 8.53414 5.5 8.66675C5.5 8.79936 5.55268 8.92653 5.64645 9.0203C5.74022 9.11407 5.86739 9.16675 6 9.16675H10C10.1326 9.16675 10.2598 9.11407 10.3536 9.0203C10.4473 8.92653 10.5 8.79936 10.5 8.66675ZM10.5 11.3334C10.5 11.2008 10.4473 11.0736 10.3536 10.9799C10.2598 10.8861 10.1326 10.8334 10 10.8334H6C5.86739 10.8334 5.74022 10.8861 5.64645 10.9799C5.55268 11.0736 5.5 11.2008 5.5 11.3334C5.5 11.466 5.55268 11.5932 5.64645 11.687C5.74022 11.7807 5.86739 11.8334 6 11.8334H10C10.1326 11.8334 10.2598 11.7807 10.3536 11.687C10.4473 11.5932 10.5 11.466 10.5 11.3334Z"/>
<path fill="currentColor" stroke="currentColor" stroke-width="0.1" fill-rule="evenodd" clip-rule="evenodd" d="M4.66671 1.5C4.18048 1.5 3.71416 1.69315 3.37034 2.03697C3.02653 2.38079 2.83337 2.8471 2.83337 3.33333V12.6667C2.83337 13.1529 3.02653 13.6192 3.37034 13.963C3.71416 14.3068 4.18048 14.5 4.66671 14.5H11.3334C11.8196 14.5 12.2859 14.3068 12.6297 13.963C12.9736 13.6192 13.1667 13.1529 13.1667 12.6667V5.312C13.1667 5.058 13.084 4.81133 12.9307 4.60867L10.932 1.96333C10.8233 1.81941 10.6827 1.70267 10.5212 1.62227C10.3597 1.54188 10.1818 1.50002 10.0014 1.5H4.66671ZM3.83337 3.33333C3.83337 2.87333 4.20671 2.5 4.66671 2.5H9.50004V5.43133C9.50004 5.70733 9.72404 5.93133 10 5.93133H12.1667V12.6667C12.1667 13.1267 11.7934 13.5 11.3334 13.5H4.66671C4.20671 13.5 3.83337 13.1267 3.83337 12.6667V3.33333Z" />
</g>
<defs>
<clipPath id="clip0_151_281">
<rect width="16" height="16" fill="currentColor"/>
</clipPath>
</defs>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_151_287)">
<path fill="currentColor" stroke="currentColor" stroke-width="0.2" d="M13.8087 5.41874L13.6447 5.79607C13.6191 5.85751 13.5758 5.91 13.5204 5.94692C13.465 5.98384 13.4 6.00354 13.3334 6.00354C13.2668 6.00354 13.2017 5.98384 13.1463 5.94692C13.0909 5.91 13.0477 5.85751 13.022 5.79607L12.858 5.41874C12.5697 4.75122 12.0416 4.21602 11.378 3.91874L10.872 3.69274C10.8107 3.6645 10.7586 3.61925 10.7222 3.56236C10.6857 3.50546 10.6664 3.43931 10.6664 3.37174C10.6664 3.30417 10.6857 3.23801 10.7222 3.18112C10.7586 3.12422 10.8107 3.07897 10.872 3.05074L11.35 2.83807C12.0303 2.53232 12.5674 1.97732 12.8507 1.2874L13.0194 0.88007C13.0441 0.816972 13.0874 0.762802 13.1434 0.72462C13.1994 0.686438 13.2656 0.666016 13.3334 0.666016C13.4012 0.666016 13.4674 0.686438 13.5234 0.72462C13.5794 0.762802 13.6226 0.816972 13.6474 0.88007L13.816 1.28674C14.099 1.97679 14.6359 2.53202 15.316 2.83807L15.7947 3.0514C15.8559 3.07972 15.9077 3.12496 15.944 3.18179C15.9804 3.23861 15.9997 3.30463 15.9997 3.37207C15.9997 3.43951 15.9804 3.50553 15.944 3.56235C15.9077 3.61917 15.8559 3.66442 15.7947 3.69274L15.288 3.91807C14.6246 4.21565 14.0968 4.75109 13.8087 5.41874ZM6.66671 2.00007H9.33337V3.3334H6.66671C5.60584 3.3334 4.58843 3.75483 3.83828 4.50498C3.08813 5.25512 2.66671 6.27254 2.66671 7.3334C2.66671 9.74007 4.30804 11.3107 8.00004 12.9867V11.3334H9.33337C10.3942 11.3334 11.4117 10.912 12.1618 10.1618C12.9119 9.41168 13.3334 8.39427 13.3334 7.3334H14.6667C14.6667 8.74789 14.1048 10.1044 13.1046 11.1046C12.1044 12.1048 10.7479 12.6667 9.33337 12.6667V15.0001C6.00004 13.6667 1.33337 11.6667 1.33337 7.3334C1.33337 5.91892 1.89528 4.56236 2.89547 3.56217C3.89567 2.56197 5.25222 2.00007 6.66671 2.00007Z"/>
</g>
<defs>
<clipPath id="clip0_151_287">
<rect width="16" height="16" fill="currentColor"/>
</clipPath>
</defs>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_151_292)">
<path fill="none" stroke="currentColor" stroke-width="0.2" d="M14.3333 5.29864V10.7013C14.3328 11.0668 14.2604 11.4286 14.1189 11.7656C13.9775 12.1027 13.7705 12.4083 13.51 12.6646C12.982 13.1846 12.2666 13.478 11.52 13.478H4.48063C3.7362 13.4788 3.02136 13.1866 2.49063 12.6646C1.96329 12.144 1.66663 11.438 1.66663 10.7013V5.29864C1.66704 4.93317 1.74003 4.57143 1.88137 4.23439C2.0227 3.89736 2.22957 3.59175 2.48996 3.33531C3.02069 2.8133 3.73554 2.52113 4.47996 2.52197H11.5193C12.2637 2.52113 12.9786 2.8133 13.5093 3.33531C13.7698 3.5917 13.9768 3.89728 14.1182 4.23432C14.2597 4.57135 14.3328 4.93313 14.3333 5.29864Z" stroke-linecap="round" stroke-linejoin="round"/>
<path fill="none" stroke="currentColor" stroke-width="0.2" d="M7.75534 10.6454C7.75534 10.1041 7.53934 9.5854 7.15401 9.20207C6.76801 8.81817 6.24574 8.60267 5.70134 8.60267C5.15694 8.60267 4.63467 8.81817 4.24867 9.20207C4.05815 9.39107 3.90693 9.6159 3.80372 9.86362C3.70052 10.1113 3.64737 10.377 3.64734 10.6454M9.71201 5.94607H12.108M9.71201 8.00007H10.7387M9.71201 10.0541H12.108M5.70134 8.0934C6.06451 8.0934 6.4128 7.94914 6.6696 7.69234C6.9264 7.43554 7.07067 7.08724 7.07067 6.72407C7.07067 6.3609 6.9264 6.01261 6.6696 5.75581C6.4128 5.49901 6.06451 5.35474 5.70134 5.35474C5.33817 5.35474 4.98987 5.49901 4.73307 5.75581C4.47627 6.01261 4.33201 6.3609 4.33201 6.72407C4.33201 7.08724 4.47627 7.43554 4.73307 7.69234C4.98987 7.94914 5.33817 8.0934 5.70134 8.0934Z" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_151_292">
<rect width="16" height="16" fill="currentColor"/>
</clipPath>
</defs>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_151_299)">
<path fill="currentColor" stroke="currentColor" stroke-width="0.2" d="M6.07128 3.63192C6.46995 2.46525 8.08195 2.42992 8.55461 3.52592L8.59461 3.63259L9.13262 5.20592C9.25591 5.56674 9.45515 5.89693 9.7169 6.1742C9.97865 6.45148 10.2968 6.66939 10.6499 6.81325L10.7946 6.86725L12.3679 7.40459C13.5346 7.80325 13.5699 9.41525 12.4746 9.88792L12.3679 9.92792L10.7946 10.4659C10.4337 10.5891 10.1034 10.7883 9.82596 11.0501C9.54856 11.3118 9.33055 11.6301 9.18661 11.9833L9.13262 12.1273L8.59528 13.7013C8.19661 14.8679 6.58461 14.9033 6.11261 13.8079L6.07128 13.7013L5.53395 12.1279C5.41073 11.767 5.21153 11.4367 4.94978 11.1593C4.68802 10.8819 4.36981 10.6638 4.01661 10.5199L3.87261 10.4659L2.29928 9.92859C1.13195 9.52992 1.09661 7.91792 2.19261 7.44592L2.29928 7.40459L3.87261 6.86725C4.23344 6.74396 4.56362 6.54471 4.8409 6.28297C5.11817 6.02122 5.33609 5.70305 5.47995 5.34992L5.53395 5.20592L6.07128 3.63192ZM7.33328 4.06259L6.79595 5.63592C6.60821 6.18612 6.30279 6.68879 5.90097 7.10892C5.49915 7.52904 5.01058 7.85654 4.46928 8.06859L4.30261 8.12925L2.72928 8.66659L4.30261 9.20392C4.85282 9.39166 5.35548 9.69707 5.77561 10.0989C6.19574 10.5007 6.52323 10.9893 6.73528 11.5306L6.79595 11.6973L7.33328 13.2706L7.87061 11.6973C8.05835 11.147 8.36377 10.6444 8.76559 10.2243C9.16741 9.80413 9.65598 9.47664 10.1973 9.26459L10.3639 9.20459L11.9373 8.66659L10.3639 8.12925C9.81375 7.94151 9.31108 7.6361 8.89095 7.23428C8.47082 6.83245 8.14333 6.34388 7.93128 5.80259L7.87128 5.63592L7.33328 4.06259ZM12.6666 1.33325C12.7913 1.33325 12.9136 1.36824 13.0194 1.43423C13.1252 1.50023 13.2104 1.59459 13.2653 1.70659L13.2973 1.78459L13.5306 2.46859L14.2153 2.70192C14.3403 2.74438 14.4498 2.823 14.5301 2.9278C14.6104 3.0326 14.6577 3.15886 14.6661 3.2906C14.6746 3.42233 14.6437 3.55361 14.5774 3.66778C14.5112 3.78195 14.4125 3.87388 14.2939 3.93192L14.2153 3.96392L13.5313 4.19725L13.2979 4.88192C13.2554 5.00687 13.1767 5.11638 13.0719 5.19658C12.9671 5.27678 12.8408 5.32405 12.709 5.3324C12.5773 5.34075 12.4461 5.30981 12.3319 5.2435C12.2178 5.17719 12.1259 5.0785 12.0679 4.95992L12.0359 4.88192L11.8026 4.19792L11.1179 3.96459C10.993 3.92212 10.8834 3.84351 10.8031 3.73871C10.7229 3.63391 10.6755 3.50764 10.6671 3.37591C10.6587 3.24417 10.6895 3.1129 10.7558 2.99873C10.8221 2.88456 10.9207 2.79263 11.0393 2.73459L11.1179 2.70259L11.8019 2.46925L12.0353 1.78459C12.0802 1.65287 12.1653 1.53852 12.2785 1.45758C12.3917 1.37664 12.5274 1.33317 12.6666 1.33325Z"/>
</g>
<defs>
<clipPath id="clip0_151_299">
<rect width="16" height="16" fill="currentColor"/>
</clipPath>
</defs>
</svg>
<!-- 底部菜单 -->
<div class="side-nav__footer">
<div class="side-nav__item" v-for="item in footerMenus" :key="item.label" @click="item.action?.()">
<img class="side-nav__item-icon" :src="item.iconImg" :alt="item.label" />
<span class="side-nav__item-label">{{ item.label }}</span>
<span v-if="item.badge" class="side-nav__badge">{{ item.badge }}</span>
</div>
@@ -150,6 +211,8 @@ import navMessageIcon from '@/assets/images/nav/nav-message-icon.png'
import navSettingIcon from '@/assets/images/nav/nav-setting-icon.png'
import navFeedbackIcon from '@/assets/images/nav/nav-feedback-icon.png'
import navShareIcon from '@/assets/images/nav/nav-share-icon.png'
// 导师页图标(暂用 profile 图标占位,有设计稿后替换为专属图标)
import navMentorIcon from '@/assets/images/nav/nav-profile-icon.png'
const route = useRoute()
const router = useRouter()
@@ -168,9 +231,8 @@ interface MenuItem {
}
/**
* 图标映射表
* 后端 meta.icon 返回的是字符串 key,这里映射到实际的图片资源
* 【新增图标时】在这里加一条即可
* 图标映射表(兼容旧版字符串 key,新版后端直接返回 SVG 字符串)
* 如果 meta.icon 是一个已知的 key,则使用对应图片;否则直接当作 SVG 字符串使用
*/
const iconMap: Record<string, string> = {
'nav-jobs-icon': navJobsIcon,
@@ -178,6 +240,20 @@ const iconMap: Record<string, string> = {
'nav-profile-icon': navProfileIcon,
'nav-agent-icon': navAgentIcon,
'nav-setting-icon': navSettingIcon,
'nav-mentor-icon': navMentorIcon,
}
/**
* 解析图标:如果是已知的 key 则返回 img 标签,如果是 SVG 字符串则直接返回
*/
function resolveIcon(iconValue: string | undefined): string {
if (!iconValue) return ''
// 如果在映射表中找到了,说明是旧版 key,包装成 img 标签
if (iconMap[iconValue]) {
return `<img src="${iconMap[iconValue]}" alt="" />`
}
// 否则认为是 SVG 字符串,直接返回
return iconValue
}
/**
@@ -186,7 +262,7 @@ const iconMap: Record<string, string> = {
* sortOrder 设为 0 确保在未获取到后端数据时也能正常显示
*/
const staticMenus: MenuItem[] = [
{ name: 'Jobs', path: '/jobs', iconImg: navJobsIcon, label: '职位', sortOrder: 0, accessible: true },
{ name: 'Jobs', path: '/jobs', iconImg: `<img src="${navJobsIcon}" alt="" />`, label: '职位', sortOrder: 0, accessible: true },
]
/**
@@ -201,7 +277,7 @@ const dynamicMenuItems = computed<MenuItem[]>(() => {
.map((item: any) => ({
name: item.name,
path: item.path,
iconImg: iconMap[item.meta?.icon] || '',
iconImg: resolveIcon(item.meta?.icon),
label: item.meta?.label || item.name,
badge: item.meta?.badge,
sortOrder: item.sortOrder ?? 99,
@@ -405,19 +481,19 @@ const settingsMenu = computed(() => {
const item = store.state.dynamicMenus.find((m: any) => m.meta?.position === 'footer')
if (item) {
return {
iconImg: iconMap[item.meta?.icon] || navSettingIcon,
iconImg: resolveIcon(item.meta?.icon) || `<img src="${navSettingIcon}" alt="" />`,
label: item.meta?.label || '设置',
path: item.path,
}
}
return { iconImg: navSettingIcon, label: '设置', path: '/settings' }
return { iconImg: `<img src="${navSettingIcon}" alt="" />`, label: '设置', path: '/settings' }
})
const footerMenus = computed(() => [
{ iconImg: navShareIcon, label: '分享送会员', action: () => { showShareDialog.value = true } },
{ iconImg: navMessageIcon, label: '消息通知', badge: unreadCount.value > 0 ? 'NEW' : '', action: () => { showMessageDialog.value = true } },
{ iconImg: `<img src="${navShareIcon}" alt="" />`, label: '分享送会员', action: () => { showShareDialog.value = true } },
{ iconImg: `<img src="${navMessageIcon}" alt="" />`, label: '消息通知', badge: unreadCount.value > 0 ? 'NEW' : '', action: () => { showMessageDialog.value = true } },
{ iconImg: settingsMenu.value.iconImg, label: settingsMenu.value.label, action: () => { handleSettingsNav() } },
{ iconImg: navFeedbackIcon, label: '反馈', action: () => { showFeedbackDialog.value = true } },
{ iconImg: `<img src="${navFeedbackIcon}" alt="" />`, label: '反馈', action: () => { showFeedbackDialog.value = true } },
])
/**