Compare commits

2 Commits
Author SHA1 Message Date
xuxin 5f4aab8d04 bug处理 2026-07-16 18:36:40 +08:00
xuxin 15971bffd9 友盟跟踪记录 2026-07-16 16:30:07 +08:00
19 changed files with 167 additions and 22 deletions
+10
View File
@@ -7,6 +7,16 @@
<title>Offer派 - 大学生AI求职平台 | 智能岗位匹配·一键自动网申·AI简历优化</title> <title>Offer派 - 大学生AI求职平台 | 智能岗位匹配·一键自动网申·AI简历优化</title>
<meta name="description" content="Offer派是专为大学生打造的AI求职平台,提供智能岗位匹配、一键自动网申、岗位定制简历、内推人脉直通等功能,让校招求职效率提升80%。" /> <meta name="description" content="Offer派是专为大学生打造的AI求职平台,提供智能岗位匹配、一键自动网申、岗位定制简历、内推人脉直通等功能,让校招求职效率提升80%。" />
<meta name="keywords" content="大学生求职,校招,AI求职,智能匹配,自动网申,简历优化,内推,Offer派" /> <meta name="keywords" content="大学生求职,校招,AI求职,智能匹配,自动网申,简历优化,内推,Offer派" />
<!-- 友盟统计 -->
<script>
var _czc = _czc || [];
(function () {
var um = document.createElement("script");
um.src = "https://v1.cnzz.com/z.js?id=1281490571&async=1";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(um, s);
})();
</script>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 211 KiB

+1 -1
View File
@@ -344,7 +344,7 @@
&__quote-avatar { &__quote-avatar {
width: 0.38rem; width: 0.38rem;
height: 0.38rem; height: 0.38rem;
background: #D9E3EA; //background: #D9E3EA;
border-radius: 50%; border-radius: 50%;
flex-shrink: 0; flex-shrink: 0;
} }
+1 -1
View File
@@ -445,7 +445,7 @@
} }
.login-view__sms-status--error { .login-view__sms-status--error {
color: #E85635; color: #EF4444;
} }
/* ==================== 状态按钮(步骤二) ==================== */ /* ==================== 状态按钮(步骤二) ==================== */
+7
View File
@@ -92,6 +92,13 @@
&:hover { &:hover {
background: #EDF9FA; background: #EDF9FA;
} }
// 小屏(视口宽度 < 1440px)只显示第一个标签
@media (max-width: 1439px) {
& ~ & {
display: none;
}
}
} }
// 搜索框 // 搜索框
+6
View File
@@ -172,4 +172,10 @@ router.beforeEach(async (to, _from, next) => {
next() next()
}) })
// 友盟统计 - SPA 路由切换上报页面浏览(PV)
router.afterEach((to) => {
const _czc = (window as any)._czc || []
_czc.push(['_trackPageview', to.fullPath, document.referrer])
})
export default router export default router
+2 -1
View File
@@ -45,7 +45,8 @@
* ------------------------------------------------------------ * ------------------------------------------------------------
* | 数据名(name) | 中文名称 | 说明 | * | 数据名(name) | 中文名称 | 说明 |
* | ----------------------------- | -------------- | --------------------------------- | * | ----------------------------- | -------------- | --------------------------------- |
* | offerpieBrowserPlugUsage | 插件使用状态 | 标识插件正在运行 { usage: string } | * * | offerpieBrowserPlugUsage | 插件使用状态 | 标识插件正在运行 { usage: string, version: string } |
* * | offerpaiDeliveryLinkList | 投递链接列表 | 记录要投递职位的来源链接,目前用于解决投递网站的重定向 { linkList: string[] },useCsl:true |
* ============================================================ * ============================================================
*/ */
+1 -1
View File
@@ -102,7 +102,7 @@ export function exportResumeWord(element: HTMLElement, fileName: string) {
const blob = new Blob([fullHtml], { type: 'application/msword' }) const blob = new Blob([fullHtml], { type: 'application/msword' })
const link = document.createElement('a') const link = document.createElement('a')
link.href = URL.createObjectURL(blob) link.href = URL.createObjectURL(blob)
link.download = `${fileName}.doc` link.download = `${fileName}.docx`
document.body.appendChild(link) document.body.appendChild(link)
link.click() link.click()
document.body.removeChild(link) document.body.removeChild(link)
+7
View File
@@ -262,10 +262,17 @@ import { fetchResumeList } from '@/api/resume'
import { fetchMemberStatus } from '@/api/member' import { fetchMemberStatus } from '@/api/member'
import JobGoalDialog from '@/components/JobGoalDialog.vue' import JobGoalDialog from '@/components/JobGoalDialog.vue'
// ==================== 路由 & Store ==================== // ==================== 路由 & Store ====================
const router = useRouter() const router = useRouter()
const store = useStore() const store = useStore()
// 声明友盟统计 _czc 对象
const _czc: any[] = (window as any)._czc || [];
(window as any)._czc = _czc;
// 绑定 siteid,请用您的 siteid 替换下方 "XXXXXXXX" 部分
_czc.push(["_setAccount", "1281490571"]);
// ==================== sessionStorage 缓存 key ==================== // ==================== sessionStorage 缓存 key ====================
const STORAGE_KEY = 'agent_apply_progress_list' const STORAGE_KEY = 'agent_apply_progress_list'
const COMPLETED_STORAGE_KEY = 'agent_completed_apply_list' const COMPLETED_STORAGE_KEY = 'agent_completed_apply_list'
+6
View File
@@ -506,6 +506,12 @@ const router = useRouter()
/** Vuex 状态管理实例 */ /** Vuex 状态管理实例 */
const store = useStore() const store = useStore()
// 声明友盟统计 _czc 对象
const _czc: any[] = (window as any)._czc || [];
(window as any)._czc = _czc;
// 绑定 siteid,请用您的 siteid 替换下方 "XXXXXXXX" 部分
_czc.push(["_setAccount", "1281490571"]);
/** 页面是否已向下滚动超过 20px — 用于导航栏背景切换 */ /** 页面是否已向下滚动超过 20px — 用于导航栏背景切换 */
const isScrolled = ref(false) const isScrolled = ref(false)
+50 -2
View File
@@ -99,7 +99,7 @@
"真没想到校招居然可以这么轻松高效!一周就收到了3个面试邀约。" "真没想到校招居然可以这么轻松高效!一周就收到了3个面试邀约。"
</p> </p>
<div class="home-mobile__quote-author"> <div class="home-mobile__quote-author">
<div class="home-mobile__quote-avatar"></div> <div class="home-mobile__quote-avatar"><img class="w45 h45 " src="@/assets/images/home/student-avatar-0.png" alt=""></div>
<div class="home-mobile__quote-info"> <div class="home-mobile__quote-info">
<span class="home-mobile__quote-name">李同学</span> <span class="home-mobile__quote-name">李同学</span>
<span class="home-mobile__quote-school">西安交通大学</span> <span class="home-mobile__quote-school">西安交通大学</span>
@@ -170,9 +170,57 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref, onMounted, onUnmounted } from 'vue'
import { getDailyJobCount } from '@/utils/dailyJobCount' import { getDailyJobCount } from '@/utils/dailyJobCount'
// ==================== 移动端缩放重置 ====================
/**
* 确保 HomeMobile 页面不受全局 transform scale 缩放影响
* 部分浏览器中 remAdapt 插件的 recalc 在路由切换后未及时重新执行,
* 导致 body 上仍残留 PC 端 scale 样式,这里在组件挂载时主动重置
*/
function resetMobileScale() {
const docEl = document.documentElement
const body = document.body
const clientWidth = docEl.clientWidth || window.innerWidth
// 移动端首页 1rem = 视口宽度 / 3.90(设计稿 390px
const mobileFontSize = clientWidth / 3.90
docEl.style.fontSize = mobileFontSize + 'px'
// 清除 scale 缩放相关样式
body.style.width = ''
body.style.height = ''
body.style.minHeight = ''
body.style.overflowY = ''
body.style.transform = ''
body.style.transformOrigin = ''
docEl.style.height = ''
docEl.style.overflow = ''
docEl.style.setProperty('--app-height', '100vh')
docEl.style.setProperty('--chat-width', '100%')
}
/** 窗口 resize 时重新执行重置 */
function onResize() {
resetMobileScale()
}
onMounted(() => {
resetMobileScale()
window.addEventListener('resize', onResize)
window.addEventListener('orientationchange', onResize)
})
onUnmounted(() => {
window.removeEventListener('resize', onResize)
window.removeEventListener('orientationchange', onResize)
})
// 声明友盟统计 _czc 对象
const _czc: any[] = (window as any)._czc || [];
(window as any)._czc = _czc;
// 绑定 siteid,请用您的 siteid 替换下方 "XXXXXXXX" 部分
_czc.push(["_setAccount", "1281490571"]);
/** 今日更新岗位数量 */ /** 今日更新岗位数量 */
const dailyJobCount = getDailyJobCount() const dailyJobCount = getDailyJobCount()
+23 -10
View File
@@ -200,15 +200,24 @@ import FullscreenLoading from '@/components/FullscreenLoading.vue'
import MemberDialog from '@/components/MemberDialog.vue' import MemberDialog from '@/components/MemberDialog.vue'
import StepProgressOverlay from '@/components/StepProgressOverlay.vue' import StepProgressOverlay from '@/components/StepProgressOverlay.vue'
import { fetchJobDetail, toggleJobFavorite, removeJobFavorite, fetchSkillGap } from '@/api/jobs' import { fetchJobDetail, toggleJobFavorite, removeJobFavorite, fetchSkillGap } from '@/api/jobs'
import { fetchMemberStatus } from '@/api/member'
import type { JobDetailData, SkillGapData } from '@/api/jobs' import type { JobDetailData, SkillGapData } from '@/api/jobs'
// ==================== 路由相关 ==================== // ==================== 路由相关 ====================
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
const store = useStore() const store = useStore()
// 声明友盟统计 _czc 对象
const _czc: any[] = (window as any)._czc || [];
(window as any)._czc = _czc;
// 绑定 siteid,请用您的 siteid 替换下方 "XXXXXXXX" 部分
_czc.push(["_setAccount", "1281490571"]);
// ==================== 全屏加载状态 ==================== // ==================== 全屏加载状态 ====================
/** 全屏加载是否显示 */ /** 全屏加载是否显示 */
const fullLoading = ref(false) const fullLoading = ref(false)
@@ -482,16 +491,20 @@ const resumeCustomJobInfo = computed(() => ({
/** 生成岗位专属简历 — 先检查会员状态,非会员弹权限拦截弹窗 */ /** 生成岗位专属简历 — 先检查会员状态,非会员弹权限拦截弹窗 */
async function handleGenerateResume() { async function handleGenerateResume() {
// 先检查会员状态 // 优先从 vuex store 读取会员状态,没有则请求接口
try { let isMember = store.state.memberStatus?.isMember
const statusRes = await fetchMemberStatus() if (isMember === undefined || isMember === null) {
if (statusRes.code === '0' && statusRes.data && !statusRes.data.isMember) { try {
// 非会员 — 弹出会员权限拦截弹窗 await store.dispatch('loadMemberStatus')
showMemberAccessDialog.value = true isMember = store.state.memberStatus?.isMember
return } catch {
// 接口异常时不阻断,继续执行
} }
} catch { }
// 接口异常时不阻断,继续执行 if (!isMember) {
// 非会员 — 弹出会员权限拦截弹窗
showMemberAccessDialog.value = true
return
} }
// 显示步骤进度遮罩 // 显示步骤进度遮罩
+8
View File
@@ -390,6 +390,7 @@ import JobResumeTemplate from '@/components/JobResumeTemplate.vue'
import type { ResumeTemplateData } from '@/components/JobResumeTemplate.vue' import type { ResumeTemplateData } from '@/components/JobResumeTemplate.vue'
// 2. 注意:这里的字符串不需要再手动转义双引号了 // 2. 注意:这里的字符串不需要再手动转义双引号了
const paymentFormHtml = ref(` const paymentFormHtml = ref(`
<form name="punchout_form" method="post" action="https://openapi-sandbox.dl.alipaydev.com/gateway.do?charset=UTF-8&method=alipay.trade.page.pay&sign=o8MQ7cEAh4yrf6ri5iT9gXbtR%2BTncX36p9JNZf8nmXxEp1WKO6dF1HDC6DPF8nxJbus6OG9E5UPSoiHgqrEiu3aeOs4LMcYzXXZP0UQzG%2F6pXyZrvlL70G8uwpnV6MgQojzhKheG0vYIJgSPaGsHKjwcp%2BT8yOZg3eEDIgFYEBf2a3c7kANc7%2FuOOGCSD9Ip9zqwX9LQ3b433NPH3AbGQkFSLsdGOTY62I7yI8hEF7EM7nNm%2BYryieqju21yN76JrV4k%2BgIGHn83I5oT3y7zurzdTqHLD4UawpPWdJ5B7p6wnJ4cN4uzO8JgRpNqogYqqKBPcHIlB9o4uax3bcRqhg%3D%3D&notify_url=http%3A%2F%2F39.108.134.218%3A10106%2Fapi%2F%2Fpublic%2FalipayNotify%2Fpay&version=1.0&app_id=2018062160374941&sign_type=RSA2&timestamp=2026-05-20+15%3A29%3A21&alipay_sdk=alipay-sdk-java-4.40.791.ALL&format=json"> <form name="punchout_form" method="post" action="https://openapi-sandbox.dl.alipaydev.com/gateway.do?charset=UTF-8&method=alipay.trade.page.pay&sign=o8MQ7cEAh4yrf6ri5iT9gXbtR%2BTncX36p9JNZf8nmXxEp1WKO6dF1HDC6DPF8nxJbus6OG9E5UPSoiHgqrEiu3aeOs4LMcYzXXZP0UQzG%2F6pXyZrvlL70G8uwpnV6MgQojzhKheG0vYIJgSPaGsHKjwcp%2BT8yOZg3eEDIgFYEBf2a3c7kANc7%2FuOOGCSD9Ip9zqwX9LQ3b433NPH3AbGQkFSLsdGOTY62I7yI8hEF7EM7nNm%2BYryieqju21yN76JrV4k%2BgIGHn83I5oT3y7zurzdTqHLD4UawpPWdJ5B7p6wnJ4cN4uzO8JgRpNqogYqqKBPcHIlB9o4uax3bcRqhg%3D%3D&notify_url=http%3A%2F%2F39.108.134.218%3A10106%2Fapi%2F%2Fpublic%2FalipayNotify%2Fpay&version=1.0&app_id=2018062160374941&sign_type=RSA2&timestamp=2026-05-20+15%3A29%3A21&alipay_sdk=alipay-sdk-java-4.40.791.ALL&format=json">
@@ -405,6 +406,13 @@ const router = useRouter()
const route = useRoute() const route = useRoute()
const store = useStore() const store = useStore()
// 声明友盟统计 _czc 对象
const _czc: any[] = (window as any)._czc || [];
(window as any)._czc = _czc;
// 绑定 siteid,请用您的 siteid 替换下方 "XXXXXXXX" 部分
_czc.push(["_setAccount", "1281490571"]);
/** 招聘分类标签背景色:校招=#3AC6E5,社招=#B95DDD,实习=#50D3B5 */ /** 招聘分类标签背景色:校招=#3AC6E5,社招=#B95DDD,实习=#50D3B5 */
function recruitCategoryColor(category: number | undefined | null): string { function recruitCategoryColor(category: number | undefined | null): string {
if (category === 1) return '#3AC6E5' // 校招 if (category === 1) return '#3AC6E5' // 校招
+14 -4
View File
@@ -60,7 +60,7 @@
<input v-model="phone" type="tel" class="login-view__phone-input" placeholder="请输入手机号码" maxlength="11" /> <input v-model="phone" type="tel" class="login-view__phone-input" placeholder="请输入手机号码" maxlength="11" />
</div> </div>
<!-- 发送验证码按钮 --> <!-- 发送验证码按钮 -->
<button class="login-view__send-btn" :disabled="!canSend" @click="handleSendCode">发送验证码</button> <button class="login-view__send-btn " :disabled="!canSend" @click="handleSendCode">发送验证码</button>
</template> </template>
<!-- 步骤二输入验证码登录 --> <!-- 步骤二输入验证码登录 -->
@@ -76,7 +76,7 @@
<span v-else-if="idx === otpValue.length && !isLoggingIn" class="login-view__otp-cursor"></span> <span v-else-if="idx === otpValue.length && !isLoggingIn" class="login-view__otp-cursor"></span>
</div> </div>
</div> </div>
<p v-if="smsStatusMsg" class="login-view__sms-status" :class="{ 'login-view__sms-status--error': smsStatusIsError }">{{ smsStatusMsg }}</p> <p v-if="smsStatusMsg" class="login-view__sms-status tal" :class="{ 'login-view__sms-status--error': smsStatusIsError }">{{ smsStatusMsg }}</p>
<button class="login-view__status-btn" :disabled="isLoggingIn || countdown > 0" @click="handleResendCode"> <button class="login-view__status-btn" :disabled="isLoggingIn || countdown > 0" @click="handleResendCode">
<template v-if="isLoggingIn"><span class="login-view__spinner"></span><span>登录中</span></template> <template v-if="isLoggingIn"><span class="login-view__spinner"></span><span>登录中</span></template>
<template v-else-if="countdown > 0">{{ countdown }} 秒后可继续发送</template> <template v-else-if="countdown > 0">{{ countdown }} 秒后可继续发送</template>
@@ -291,6 +291,13 @@ const store = useStore()
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
// 声明友盟统计 _czc 对象
const _czc: any[] = (window as any)._czc || [];
(window as any)._czc = _czc;
// 绑定 siteid,请用您的 siteid 替换下方 "XXXXXXXX" 部分
_czc.push(["_setAccount", "1281490571"]);
// ==================== 左侧动画面板 ==================== // ==================== 左侧动画面板 ====================
/** 舞台引用 */ /** 舞台引用 */
const stageRef = ref<HTMLDivElement | null>(null) const stageRef = ref<HTMLDivElement | null>(null)
@@ -506,7 +513,9 @@ async function handleLogin() {
try { try {
const res = await smsLogin(phone.value, otpValue.value) const res = await smsLogin(phone.value, otpValue.value)
if (res.code !== '0') { if (res.code !== '0') {
ElMessage.error('登录失败请核对验证码') // 验证码错误或已过期 — 显示行内错误提示
smsStatusMsg.value = '验证码有误,请重新输入'
smsStatusIsError.value = true
otpValue.value = '' otpValue.value = ''
isLoggingIn.value = false isLoggingIn.value = false
nextTick(() => focusOtpInput()) nextTick(() => focusOtpInput())
@@ -539,7 +548,8 @@ async function handleLogin() {
// 有个人资料,直接跳转 // 有个人资料,直接跳转
router.replace(loginRedirect) router.replace(loginRedirect)
} catch { } catch {
ElMessage.error('登录失败请核对验证码') smsStatusMsg.value = '验证码有误,请重新输入'
smsStatusIsError.value = true
otpValue.value = '' otpValue.value = ''
isLoggingIn.value = false isLoggingIn.value = false
nextTick(() => focusOtpInput()) nextTick(() => focusOtpInput())
+7 -2
View File
@@ -12,7 +12,6 @@
<!-- <span class="mentor-page__title-icon"></span>--> <!-- <span class="mentor-page__title-icon"></span>-->
<div class=" "> <div class=" ">
<div class="mentor-page__title dib mr10">导师推荐</div> <div class="mentor-page__title dib mr10">导师推荐</div>
<div class="mentor-page__subtitle dib">自有合作导师真实在职身份全部实名认证</div>
</div> </div>
</div> </div>
<div class="dflex-end aliite-c flex-warp"> <div class="dflex-end aliite-c flex-warp">
@@ -20,7 +19,7 @@
<div class="mentor-page__quick-tags"> <div class="mentor-page__quick-tags">
<span class="mentor-page__quick-label">推荐搜索</span> <span class="mentor-page__quick-label">推荐搜索</span>
<span <span
v-for="tag in quickSearchTags" v-for="(tag,index) in quickSearchTags"
:key="tag" :key="tag"
class="mentor-page__quick-tag" class="mentor-page__quick-tag"
@click="handleQuickSearch(tag)" @click="handleQuickSearch(tag)"
@@ -164,6 +163,12 @@ import { toOssUrl } from '@/utils/image'
const router = useRouter() const router = useRouter()
const store = useStore() const store = useStore()
// 声明友盟统计 _czc 对象
const _czc: any[] = (window as any)._czc || [];
(window as any)._czc = _czc;
// 绑定 siteid,请用您的 siteid 替换下方 "XXXXXXXX" 部分
_czc.push(["_setAccount", "1281490571"]);
/** 行业 Tab 标签列表 */ /** 行业 Tab 标签列表 */
const industryTabs = ['推荐', '互联网', '金融', '快消', '咨询', '央国企', '硬科技', '生涯规划', '名校导师', '心理咨询', '其他'] const industryTabs = ['推荐', '互联网', '金融', '快消', '咨询', '央国企', '硬科技', '生涯规划', '名校导师', '心理咨询', '其他']
+6
View File
@@ -125,6 +125,12 @@ import MentorQrCodeDialog from '@/components/MentorQrCodeDialog.vue'
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
// 声明友盟统计 _czc 对象
const _czc: any[] = (window as any)._czc || [];
(window as any)._czc = _czc;
// 绑定 siteid,请用您的 siteid 替换下方 "XXXXXXXX" 部分
_czc.push(["_setAccount", "1281490571"]);
/** 导师 ID,从路由参数获取(字符串,避免大数精度丢失) */ /** 导师 ID,从路由参数获取(字符串,避免大数精度丢失) */
const mentorId = route.params.id as string const mentorId = route.params.id as string
+6
View File
@@ -55,6 +55,12 @@ import type { SaveEducationItem, SaveWorkItem, SaveProjectItem, SaveCompetitionI
const router = useRouter() const router = useRouter()
const store = useStore() const store = useStore()
// 声明友盟统计 _czc 对象
const _czc: any[] = (window as any)._czc || [];
(window as any)._czc = _czc;
// 绑定 siteid,请用您的 siteid 替换下方 "XXXXXXXX" 部分
_czc.push(["_setAccount", "1281490571"]);
// ==================== 全屏加载状态 ==================== // ==================== 全屏加载状态 ====================
/** 全屏加载是否显示 */ /** 全屏加载是否显示 */
const fullLoading = ref(false) const fullLoading = ref(false)
+6
View File
@@ -142,6 +142,12 @@ import StepProgressOverlay from '@/components/StepProgressOverlay.vue'
const router = useRouter() const router = useRouter()
// 声明友盟统计 _czc 对象
const _czc: any[] = (window as any)._czc || [];
(window as any)._czc = _czc;
// 绑定 siteid,请用您的 siteid 替换下方 "XXXXXXXX" 部分
_czc.push(["_setAccount", "1281490571"]);
// ==================== 全屏加载状态 ==================== // ==================== 全屏加载状态 ====================
/** 全屏加载是否显示 */ /** 全屏加载是否显示 */
const fullLoading = ref(false) const fullLoading = ref(false)
+6
View File
@@ -639,6 +639,12 @@ import StepProgressOverlay from '@/components/StepProgressOverlay.vue'
// ==================== Store 实例 ==================== // ==================== Store 实例 ====================
const store = useStore() const store = useStore()
// 声明友盟统计 _czc 对象
const _czc: any[] = (window as any)._czc || [];
(window as any)._czc = _czc;
// 绑定 siteid,请用您的 siteid 替换下方 "XXXXXXXX" 部分
_czc.push(["_setAccount", "1281490571"]);
// ==================== Tab 导航栏相关 ==================== // ==================== Tab 导航栏相关 ====================
/** 简历详情 Tab 导航列表 */ /** 简历详情 Tab 导航列表 */