From f90c8be2a9c5ca18dd1c1f71a8e2a3a5b7ce5aaf Mon Sep 17 00:00:00 2001 From: xuxin <15279969124@163.com> Date: Fri, 3 Jul 2026 19:55:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E5=B8=88=E7=9B=B8=E5=85=B3=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E6=8D=A2offer=E6=B4=BE=E6=8E=A5=E5=8F=A3=EF=BC=8C?= =?UTF-8?q?=E8=81=8C=E4=BD=8D=E5=88=97=E8=A1=A8=E5=92=8C=E8=81=8C=E4=BD=8D?= =?UTF-8?q?=E8=AF=A6=E6=83=85=EF=BC=8CNova=E8=81=8A=E5=A4=A9=E4=BE=A7?= =?UTF-8?q?=E8=BE=B9=E6=A0=8FUI=E9=87=8D=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/jobs.ts | 2 + src/api/mentor.ts | 14 +- src/assets/images/nova-logo.png | Bin 0 -> 3901 bytes src/assets/styles/auto.scss | 57 ++ src/assets/styles/components/ai-chat.scss | 340 +++++--- .../styles/components/job-page-header.scss | 32 +- .../components/profile-page-content.scss | 8 +- src/assets/styles/pages/job-detail.scss | 753 ++++++------------ src/assets/styles/pages/jobs.scss | 27 +- src/assets/styles/pages/mentor.scss | 4 + src/assets/styles/variables.scss | 2 +- src/components/AiChat.vue | 156 ++-- src/components/JobPageHeader.vue | 38 +- src/components/JobResumeCustomDialog.vue | 61 +- src/components/ProfilePageContent.vue | 8 +- src/components/tools/IndustrySelector.vue | 8 +- src/components/tools/JobCategorySelector.vue | 8 +- src/components/tools/RegionSelector.vue | 8 +- src/plugins/remAdapt.ts | 2 +- src/stores/index.ts | 15 + src/utils/aiRequest.ts | 3 +- src/views/JobDetail.vue | 400 +++------- src/views/Jobs.vue | 64 +- src/views/Mentor.vue | 5 +- src/views/Profile.vue | 2 + vite.config.ts | 8 +- 26 files changed, 896 insertions(+), 1129 deletions(-) create mode 100644 src/assets/images/nova-logo.png diff --git a/src/api/jobs.ts b/src/api/jobs.ts index f5cb894..c2b94d3 100644 --- a/src/api/jobs.ts +++ b/src/api/jobs.ts @@ -49,6 +49,8 @@ export interface JobListItem { matchDetail: MatchDetail /** 招聘分类:0=社招 1=校招 2=实习 */ recruitCategory?: number + /** 学历要求 0=不限 1=大专 2=本科 3=硕士 4=博士 */ + education?: number } // ==================== 分页结构 ==================== diff --git a/src/api/mentor.ts b/src/api/mentor.ts index ad5c706..8ede6af 100644 --- a/src/api/mentor.ts +++ b/src/api/mentor.ts @@ -1,4 +1,4 @@ -import jianshiRequest from '@/utils/jianshiRequest' +import request from '@/utils/request' /** * 分页查询导师列表请求参数 @@ -81,10 +81,10 @@ export interface MentorPageResult { /** * 分页查询导师列表 - * POST /public/website/pageSelectMentor + * POST /public/mentor/page(offerpai 后端) */ export function fetchMentorList(params: MentorListParams): Promise { - return jianshiRequest.post('/public/website/pageSelectMentor', params) + return request.post('/public/mentor/page', params) } // ==================== 导师详情接口 ==================== @@ -189,16 +189,16 @@ export interface MentorTalk { /** * 获取导师详情信息 - * GET /public/website/selectMentorFullInfo?mentorId=xxx + * GET /public/mentor/info?mentorId=xxx(offerpai 后端) */ export function fetchMentorFullInfo(mentorId: string): Promise { - return jianshiRequest.get('/public/website/selectMentorFullInfo', { params: { mentorId } }) + return request.get('/public/mentor/info', { params: { mentorId } }) } /** * 获取导师话题列表 - * GET /public/website/selectTalk?teacherId=xxx + * GET /public/mentor/talk?teacherId=xxx(offerpai 后端) */ export function fetchMentorTalks(teacherId: string): Promise { - return jianshiRequest.get('/public/website/selectTalk', { params: { teacherId } }) + return request.get('/public/mentor/talk', { params: { teacherId } }) } diff --git a/src/assets/images/nova-logo.png b/src/assets/images/nova-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..407641ea51f05f56533bf0ec4f00c54c0a09cee5 GIT binary patch literal 3901 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 LNkvXXu0mjf>62cE literal 0 HcmV?d00001 diff --git a/src/assets/styles/auto.scss b/src/assets/styles/auto.scss index 33ae898..e2492a6 100644 --- a/src/assets/styles/auto.scss +++ b/src/assets/styles/auto.scss @@ -3,10 +3,67 @@ html{ font-size: 100px; } +// 全局滚动条美化(必须在 body 包裹外,才能作用到 body/html 自身的滚动条) +::-webkit-scrollbar { + width: 4px; + height: 4px; +} +::-webkit-scrollbar-thumb { + background: #D4D4D4; + border-radius: 4px; +} +::-webkit-scrollbar-track { + background: transparent; +} +::-webkit-scrollbar-button { + display: none; + width: 0; + height: 0; +} +::-webkit-scrollbar-corner { + background: transparent; +} +html, body { + scrollbar-width: thin; + scrollbar-color: #D4D4D4 transparent; +} + +// body 滚动条在缩放模式下会被 transform scale 放大变丑,强制隐藏 +body { + &::-webkit-scrollbar { + width: 0 !important; + display: none !important; + } + -ms-overflow-style: none; + scrollbar-width: none; +} + // 用 body:not(#_) 包裹,提升选择器权重到 id 级别,确保工具类优先级最高 // :not(#_) 永远为 true,不影响匹配,只提升权重 body:not(#_) { +// 统一细滚动条工具类(4px 宽、圆角、无按钮) +.scrollbar-thin { + &::-webkit-scrollbar { + width: 4px; + height: 4px; + } + &::-webkit-scrollbar-thumb { + background: #D4D4D4; + border-radius: 4px; + } + &::-webkit-scrollbar-track { + background: transparent; + } + &::-webkit-scrollbar-button { + display: none; + width: 0; + height: 0; + } + scrollbar-width: thin; + scrollbar-color: #D4D4D4 transparent; +} + //组件定制样式 .box-shadow-head{ box-shadow: 0px 6px 16px rgba(0, 0, 0, 0.08), 0px 3px 6px -4px rgba(0, 0, 0, 0.12), 0px -3px 6px -4px rgba(0, 0, 0, 0.12); diff --git a/src/assets/styles/components/ai-chat.scss b/src/assets/styles/components/ai-chat.scss index 139379f..0e8a06e 100644 --- a/src/assets/styles/components/ai-chat.scss +++ b/src/assets/styles/components/ai-chat.scss @@ -1,84 +1,119 @@ -// 颜色变量已移至全局 variables.scss @use '../variables' as *; .ai-chat { - width: var(--chat-width, 4.0rem); - max-width: 4.0rem; - min-width: 1.5rem; + font-size: 0.14rem; + width: var(--chat-width, 3.6rem); height: var(--app-height, 100vh); - background: #f3f4f6; - display: flex; - flex-direction: column; - box-sizing: border-box; + background: $bg-white; position: fixed; right: 0; top: 0; - border-left: 1px solid #e5e7eb; - - &__banner { - display: flex; - align-items: center; - justify-content: space-between; - background: #0F172B; - color: #fff; - padding: 0.12rem 0.14rem; - font-size: 0.14rem; - font-weight: 600; - cursor: pointer; - border-radius: 0.2rem; - margin: 0.15rem; - height: 0.41rem; - } - - &__banner-arrow { - font-size: 0.16rem; - padding-bottom: 0.05rem; - box-sizing: border-box; - } + display: flex; + flex-direction: column; + box-sizing: border-box; + // ==================== 顶部头部区域 ==================== &__header { display: flex; align-items: center; - gap: 0.1rem; + justify-content: space-between; padding: 0.16rem; - border-bottom: 1px solid #e5e7eb; + height: 0.80rem; + box-sizing: border-box; + } + + &__header-left { + display: flex; + align-items: center; + gap: 0.12rem; } &__avatar { - width: 0.4rem; - height: 0.4rem; + width: 0.44rem; + height: 0.44rem; border-radius: 50%; - background: #e5e7eb; - display: flex; - align-items: center; - justify-content: center; - font-size: 0.2rem; + object-fit: cover; } &__info { - flex: 1; + display: flex; + flex-direction: column; } &__name { - font-size: 0.16rem; - font-weight: 600; - color: #1a1a2e; + font-size: 0.15rem; + font-weight: 520; + line-height: 0.22rem; + color: $text-dark; } &__desc { font-size: 0.12rem; - color: #6b7280; - margin-top: 0.02rem; + font-weight: 330; + line-height: 0.18rem; + color: #99A1AF; } + // 在线状态标签 + &__online-tag { + display: flex; + align-items: center; + justify-content: center; + padding: 0.04rem 0.08rem; + gap: 0.04rem; + background: #52CAD1; + border-radius: 0.12rem; + font-size: 0.12rem; + font-weight: 330; + line-height: 0.16rem; + color: $bg-white; + } + + &__online-dot { + width: 0.06rem; + height: 0.06rem; + background: $bg-white; + border-radius: 50%; + } + + // ==================== 聊天消息区域 ==================== &__messages { flex: 1; overflow-y: auto; - padding: 0.16rem; + padding: 0 0.16rem; + padding-bottom: 0.16rem; } + // 欢迎气泡 + &__welcome-bubble { + display: flex; + flex-direction: column; + align-items: flex-start; + padding: 0.16rem; + gap: 0.08rem; + background: #F4FBFB; + border: 1px solid #AEE6EA; + border-radius: 0.12rem; + margin-bottom: 0.17rem; + } + + &__welcome-title { + font-size: 0.14rem; + font-weight: 520; + line-height: 0.16rem; + color: $text-dark; + } + + &__welcome-text { + font-size: 0.12rem; + font-weight: 330; + line-height: 0.18rem; + color: #99A1AF; + } + + // ==================== 消息气泡 ==================== &__msg { - margin-bottom: 0.12rem; + margin-bottom: 0.17rem; display: flex; &--ai { @@ -91,13 +126,14 @@ } &__msg-bubble { - border-radius: 0.1rem; - padding: 0.12rem 0.14rem; - font-size: 0.13rem; - line-height: 1.6; - max-width: 85%; + max-width: 2.8rem; + padding: 0.08rem 0.12rem; + font-size: 0.14rem; + font-weight: 330; + line-height: 0.24rem; + box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.04); - // ===== Markdown 渲染样式 ===== + // Markdown 渲染样式 p { margin: 0 0 0.08rem; &:last-child { margin-bottom: 0; } @@ -174,123 +210,183 @@ background: #f8fafc; font-weight: 600; } - - tr:nth-child(even) { - background: #fafbfc; - } - } - - hr { - border: none; - border-top: 1px solid #e5e7eb; - margin: 0.1rem 0; } } - &__msg--ai &__msg-bubble { - background: #fff; - border: 1px solid #e5e7eb; - color: #374151; - } - + // 用户消息气泡 — 品牌色背景,右上圆角小 &__msg--user &__msg-bubble { - background: #fff; - color: #1a1a2e; + background: #52CAD1; + color: $bg-white; + border-radius: 0.12rem 0.04rem 0.12rem 0.12rem; } - &__msg-title { - font-weight: 600; - font-size: 0.14rem; - margin-bottom: 0.06rem; - color: #1a1a2e; + // AI 消息气泡 — 白色背景绿色边框,左上圆角小 + &__msg--ai &__msg-bubble { + background: $bg-white; + color: $text-dark; + border: 1px solid #AEE6EA; + box-shadow: 0px 2px 4px rgba(82, 202, 209, 0.1); + border-radius: 0.04rem 0.12rem 0.12rem 0.12rem; } - &__msg-text { - color: #6b7280; - font-size: 0.12rem; + // ==================== 三点等待动效 ==================== + &__typing-indicator { + display: flex; + align-items: center; + padding: 0.14rem 0.12rem; + gap: 0.06rem; + background: $bg-white; + border: 1px solid #AEE6EA; + box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.04); + border-radius: 0.04rem 0.12rem 0.12rem 0.12rem; } - &__quick-questions { + &__typing-dot { + width: 0.06rem; + height: 0.06rem; + border-radius: 50%; + background: #AEE6EA; + animation: typingBounce 1.4s infinite ease-in-out both; + + &:nth-child(1) { + animation-delay: 0s; + } + &:nth-child(2) { + animation-delay: 0.2s; + background: rgba(174, 230, 234, 0.6); + } + &:nth-child(3) { + animation-delay: 0.4s; + background: rgba(174, 230, 234, 0.4); + } + } + + @keyframes typingBounce { + 0%, 80%, 100% { + transform: scale(1); + opacity: 0.6; + } + 40% { + transform: scale(1.3); + opacity: 1; + } + } + + // ==================== 话题推荐模块 ==================== + &__topics { display: flex; flex-direction: column; - gap: 0.08rem; - margin-top: 0.12rem; + align-items: flex-start; + padding: 0.16rem 0.16rem 0.16rem 0.16rem; + gap: 0.12rem; + background: linear-gradient(180deg, #EDF9FA 0%, #FFFFFF 20.63%); + border: 1px solid #AEE6EA; + border-radius: 0.12rem; + margin: 0 0.16rem; margin-bottom: 0.12rem; } - &__quick-item { - background: #fff; - border: 1px solid #e5e7eb; + &__topics-header { + display: flex; + align-items: center; + gap: 0.04rem; + } + + &__topics-icon { + width: 0.16rem; + height: 0.16rem; + } + + &__topics-title { + font-size: 0.14rem; + font-weight: 520; + line-height: 0.19rem; + color: #52CAD1; + } + + &__topic-btn { + display: flex; + align-items: center; + padding: 0.08rem 0.12rem; + background: $bg-white; + border: 1px solid #F0F0F0; border-radius: 0.08rem; - padding: 0.1rem 0.14rem; - color: $text-middle; font-size: 0.12rem; + font-weight: 330; + line-height: 0.16rem; + color: $text-middle; cursor: pointer; transition: background 0.2s; - max-width: 80%; &:hover { - background: #f9fafb; - color: #374151; + background: $accent; + color: #fff; + } - /* AI 提问靠左 */ - &--ai { - align-self: flex-start; - } + // 第一个按钮用品牌色 + &--primary { + background: #52CAD1; + border-color: #52CAD1; + color: $bg-white; - /* 用户提问靠右 */ - &--user { - align-self: flex-end; - background: #f0f3f6; - border-color: #e0e3e6; + &:hover { + background: #47b8bf; + } } } + // ==================== 底部输入框 ==================== &__input-area { display: flex; align-items: center; + justify-content: space-between; + padding: 0.08rem 0.12rem; gap: 0.08rem; - padding: 0.12rem 0.16rem; - border-top: 1px solid #e5e7eb; - background: #fff; + margin: 0 0.16rem; + margin-bottom: 0.16rem; + background: rgba(255, 255, 255, 0.95); + border: 1px solid #AEE6EA; + border-radius: 0.08rem; + backdrop-filter: blur(12px); + box-sizing: border-box; } &__input { flex: 1; - background: #f3f4f6; - border: 1px solid #e5e7eb; - border-radius: 0.06rem; - padding: 0.1rem 0.12rem; - color: #1a1a2e; - font-size: 0.12rem; + border: none; outline: none; + background: transparent; + font-size: 0.12rem; + font-weight: 400; + line-height: 0.15rem; + color: $text-dark; &::placeholder { - color: #9ca3af; - } - - &:focus { - border-color: #9ca3af; + color: #99A1AF; } } &__send-btn { - width: 0.36rem; - height: 0.36rem; - border-radius: 50%; - background: #1a1a2e; - border: none; - color: #fff; - font-size: 0.16rem; - cursor: pointer; display: flex; align-items: center; justify-content: center; + width: 0.32rem; + height: 0.32rem; + background: #52CAD1; + border-radius: 0.08rem; + border: none; + cursor: pointer; + flex-shrink: 0; transition: background 0.2s; &:hover { - background: #2e3142; + background: #47b8bf; + } + + &:disabled { + opacity: 0.6; + cursor: not-allowed; } } } diff --git a/src/assets/styles/components/job-page-header.scss b/src/assets/styles/components/job-page-header.scss index bbfe2f1..93fde55 100644 --- a/src/assets/styles/components/job-page-header.scss +++ b/src/assets/styles/components/job-page-header.scss @@ -1,10 +1,10 @@ @use '../variables' as *; .job-page-header { - margin-bottom: 0; + &__title { - font-size: 0.24rem; + font-size: 0.18rem; font-weight: 700; color: $text-dark; margin: 0 !important; @@ -15,8 +15,6 @@ &__subtitle { font-size: 0.13rem; color: $text-light; - margin: 0.02rem 0 0 0 !important; - padding: 0; } &__tabs { @@ -24,7 +22,6 @@ justify-content: flex-start; align-items: center; gap: 0.04rem; - margin: 0.1rem 0 0.16rem 0; background: $bg-white; border-radius: 0.22rem; padding: 0.04rem; @@ -51,13 +48,16 @@ &__tab { font-size: 0.13rem; - color: $text-light; + color: $text-middle; cursor: pointer; - padding: 0.06rem 0.16rem; - border-radius: 0.18rem; + padding: 0.06rem 0.20rem; + border-radius: 0.08rem; transition: all 0.25s ease; user-select: none; font-weight: 500; + display: flex; + align-items: center; + gap: 0.06rem; &:hover { color: $text-dark; @@ -76,4 +76,20 @@ } } } + + /* 计数圆形徽章 */ + &__tab-badge { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 0.20rem; + height: 0.20rem; + padding: 0 0.05rem; + border-radius: 50%; + background: #F3F4F6; + font-size: 0.11rem; + font-weight: 500; + color: $text-middle; + line-height: 1; + } } diff --git a/src/assets/styles/components/profile-page-content.scss b/src/assets/styles/components/profile-page-content.scss index 1d84a7a..66beec2 100644 --- a/src/assets/styles/components/profile-page-content.scss +++ b/src/assets/styles/components/profile-page-content.scss @@ -224,15 +224,15 @@ &__portfolio-link { font-size: 0.13rem; line-height: 1.6; - color: $accent; + color: $text-middle; word-break: break-all; - text-decoration: none; + text-decoration: underline; transition: color 0.2s; display: inline-block; + vertical-align: text-bottom; &:hover { - color: $accent-hover; - text-decoration: underline; + } } diff --git a/src/assets/styles/pages/job-detail.scss b/src/assets/styles/pages/job-detail.scss index 7f2b284..7316687 100644 --- a/src/assets/styles/pages/job-detail.scss +++ b/src/assets/styles/pages/job-detail.scss @@ -4,9 +4,8 @@ .job-detail { &__content { margin-left: 2rem; - margin-right: var(--chat-width, 4.0rem); + margin-right: var(--chat-width, 3.6rem); flex: 1; - padding: 0.12rem 0.12rem 0.12rem 0.12rem; height: var(--app-height, 100vh); box-sizing: border-box; overflow: hidden; @@ -14,155 +13,168 @@ display: flex; flex-direction: column; font-size: 0.14rem; - - // 手动包裹的两层 div,需要撑满剩余高度并允许内部滚动 - > .bg-white { - flex: 1; - min-height: 0; - display: flex; - flex-direction: column; - overflow: hidden; - - > .bg-main { - flex: 1; - min-height: 0; - display: flex; - flex-direction: column; - overflow: hidden; - } - } } - // ---- 页面标题 ---- - &__header { - margin-bottom: 0; + // ---- 主内容卡片 ---- + &__main-card { + flex: 1; + min-height: 0; + margin: 0.16rem 0.24rem; + background: $bg-white; + border: 1px solid #F0F0F0; + box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.04); + border-radius: 0.08rem; + display: flex; + flex-direction: column; + overflow: hidden; } - &__page-title { - font-size: 0.24rem; - font-weight: 700; - color: $text-dark; - margin: 0; - line-height: 1.1; + // ---- 返回按钮 ---- + &__back-row { + padding: 0.24rem 0.32rem 0; } - &__page-subtitle { - font-size: 0.13rem; - color: $text-light; - margin: 0.02rem 0 0 0; - } - - // ---- Tab 切换 ---- - &__tabs { - display: inline-flex; + &__back-btn { + display: flex; align-items: center; gap: 0.04rem; - margin: 0.1rem 0 0.16rem 0; - background: $bg-white; - border-radius: 0.22rem; - padding: 0.04rem; - } - - &__tab { - font-size: 0.13rem; - color: $text-light; + background: none; + border: none; cursor: pointer; - padding: 0.06rem 0.22rem; - border-radius: 0.18rem; - transition: all 0.25s ease; - user-select: none; - font-weight: 500; + color: $text-middle; + font-size: 0.14rem; + line-height: 0.19rem; + padding: 0; &:hover { color: $text-dark; - background: $theme-color; + } + } + + &__back-icon { + width: 0.16rem; + height: 0.16rem; + } + + // ---- 内容区域(可滚动) ---- + &__body { + flex: 1; + overflow-y: auto; + padding: 0.24rem 0.32rem 0.4rem; + } + + // ---- 岗位头部信息区域 ---- + &__header-section { + display: flex; + align-items: flex-start; + justify-content: space-between; + margin-bottom: 0.24rem; + } + + // ---- 左侧基本信息 ---- + &__basic-info { + flex: 1; + min-width: 0; + } + + &__title-row { + display: flex; + align-items: center; + gap: 0.12rem; + margin-bottom: 0.08rem; + } + + &__job-title { + font-size: 0.24rem; + font-weight: 600; + line-height: 0.32rem; + color: $text-dark; + margin: 0; + } + + &__fav-btn { + background: none; + border: none; + cursor: pointer; + padding: 0; + display: flex; + align-items: center; + justify-content: center; + width: 0.2rem; + height: 0.2rem; + flex-shrink: 0; + color: #8C8C8C; + transition: color 0.2s; + + &:hover { + color: $danger; } &--active { - background: $accent; - color: $bg-white; - font-weight: 600; - box-shadow: 0 0.02rem 0.08rem rgba(79, 194, 201, 0.3); + color: $danger; - &:hover { - background: $accent-hover; - color: $bg-white; + .job-detail__fav-icon path { + fill: currentColor; } } } - // ---- 顶部操作栏 ---- - &__toolbar { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 0.14rem; + &__fav-icon { + width: 0.18rem; + height: 0.18rem; } - &__close-btn { - width: 0.32rem; - height: 0.32rem; - border-radius: 50%; - border: 1px solid $border-color; - background: $bg-white; - color: $text-dark; - cursor: pointer; + &__meta-row { + font-size: 0.12rem; + line-height: 0.16rem; + color: $text-middle; + margin-bottom: 0.12rem; + } + + &__meta-dot { + margin: 0 0.06rem; + color: $text-middle; + } + + // ---- 操作按钮 ---- + &__action-btns { + display: flex; + align-items: center; + gap: 0.16rem; + } + + &__nova-btn { display: flex; align-items: center; justify-content: center; + padding: 0.08rem 0.16rem; + border: 1px solid $accent; + border-radius: 0.08rem; + background: $bg-white; + color: $accent; + font-size: 0.14rem; + font-weight: 600; + line-height: 0.19rem; + cursor: pointer; transition: all 0.2s; &:hover { background: $theme-color; - border-color: $accent; - color: $accent; } } - &__close-icon { - width: 0.14rem; - height: 0.14rem; - } - - &__toolbar-right { - display: flex; - align-items: center; - gap: 0.1rem; - } - - &__tool-btn { - width: 0.32rem; - height: 0.32rem; - border-radius: 50%; - border: 1px solid $border-color; - background: $bg-white; - color: $text-light; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.2s; - - &:hover { - color: $accent; - border-color: $accent; - background: $theme-color; - } - } - - &__tool-icon { - width: 0.14rem; - height: 0.14rem; - } - &__apply-btn { + display: flex; + align-items: center; + justify-content: center; + padding: 0.08rem 0.16rem; background: $accent; + border: 1px solid $accent; + border-radius: 0.08rem; color: $bg-white; - border: none; - border-radius: 0.2rem; - padding: 0.07rem 0.22rem; - font-size: 0.13rem; - font-weight: 500; + font-size: 0.14rem; + font-weight: 600; + line-height: 0.19rem; cursor: pointer; transition: background 0.2s; @@ -171,225 +183,59 @@ } } - // ---- 内容区域 ---- - &__body { - flex: 1; - overflow-y: auto; - display: flex; - flex-direction: column; - gap: 0.14rem; - padding-bottom: 0.4rem; - padding-right: 0.05rem; - } - - // ---- 导航 Tab ---- - &__nav-tabs { - display: flex; - align-items: center; - gap: 0.2rem; - margin-bottom: 0.04rem; - } - - &__nav-tab { - font-size: 0.16rem; - font-weight: 600; - color: $text-light; - cursor: pointer; - padding-bottom: 0.06rem; - border-bottom: 2px solid transparent; - transition: all 0.2s; - - &:hover { - color: $text-dark; - } - - &--active { - color: $text-dark; - border-bottom-color: $text-dark; - } - } - - &__nav-tab-right { - margin-left: auto; - display: flex; - align-items: center; - gap: 0.16rem; - padding-right: 0.05rem; - } - - &__link-btn { - font-size: 0.12rem; - color: $text-light; - cursor: pointer; - transition: color 0.2s; - - &:hover { - color: $accent; - } - } - - // ---- 卡片 ---- - &__card { - background: $bg-white; - border-radius: 0.12rem; - padding: 0.22rem 0.24rem; - } - - &__card-top { - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: 0.3rem; - } - - &__card-left { - flex: 1; - min-width: 0; - } - - // ---- 公司 & 职位头部 ---- - &__company-row { - display: flex; - align-items: center; - gap: 0.1rem; - margin-bottom: 0.1rem; - } - - &__company-icon { - width: 0.36rem; - height: 0.36rem; + // ---- 右侧匹配度卡片 ---- + &__match-card { + flex-shrink: 0; + width: 2.06rem; + background: #FBFDF7; + border: 1px solid #9FD051; border-radius: 0.08rem; - background: $theme-color; + padding: 0.16rem 0.24rem; + } + + &__match-top { display: flex; - align-items: center; - justify-content: center; - border: 1px solid $border-color; - flex-shrink: 0; - } - - &__company-svg { - width: 0.2rem; - height: 0.2rem; - color: $accent; - } - - &__company-name { - font-size: 0.15rem; - font-weight: 600; - color: $text-dark; - } - - &__job-title { - font-size: 0.2rem; - font-weight: 700; - color: $text-dark; - margin: 0 0 0.1rem 0; - } - - &__job-meta { - display: flex; - align-items: center; - gap: 0.2rem; - flex-wrap: wrap; - } - - &__meta-item { - display: flex; - align-items: center; - gap: 0.05rem; - font-size: 0.12rem; - color: $text-light; - } - - &__meta-icon { - width: 0.14rem; - height: 0.14rem; - color: $text-light; - flex-shrink: 0; - } - - // ---- 匹配度 ---- - &__match-area { - display: flex; - flex-direction: column; - align-items: center; - flex-shrink: 0; - } - - &__match-ring { - position: relative; - width: 0.72rem; - height: 0.72rem; - display: flex; - align-items: center; - justify-content: center; - } - - &__ring-svg { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; + align-items: baseline; + gap: 0.08rem; + margin-bottom: 0.2rem; } &__match-score { - font-size: 0.18rem; - font-weight: 700; - color: $accent-hover; - position: relative; - z-index: 1; + font-size: 0.3rem; + font-weight: 630; + line-height: 0.4rem; + color: #9FD051; } &__match-label { - font-size: 0.1rem; - color: $text-light; - margin-top: 0.04rem; + font-size: 0.13rem; + font-weight: 520; + line-height: 0.17rem; + color: #9FD051; } - &__match-details { - display: flex; - align-items: center; - gap: 0.12rem; - margin-top: 0.12rem; - } - - &__match-item { + &__match-list { display: flex; flex-direction: column; - align-items: center; - gap: 0.03rem; + gap: 0.12rem; } - &__match-mini-ring { - position: relative; - width: 0.4rem; - height: 0.4rem; + &__match-row { display: flex; align-items: center; - justify-content: center; + justify-content: space-between; } - &__mini-ring-svg { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; + &__match-row-label { + font-size: 0.12rem; + line-height: 0.16rem; + color: #6B7280; } - &__mini-score { - font-size: 0.1rem; - font-weight: 600; + &__match-row-score { + font-size: 0.12rem; + line-height: 0.16rem; color: $text-dark; - position: relative; - z-index: 1; - } - - &__match-item-label { - font-size: 0.09rem; - color: $text-light; - white-space: nowrap; } // ---- 优化简历提示条 ---- @@ -397,93 +243,70 @@ display: flex; align-items: center; justify-content: space-between; - background: linear-gradient(90deg, #94EF9E , #53D9C8 ); - color: $bg-white; - border-radius: 0.1rem; - padding: 0.14rem 0.2rem; - font-size: 0.13rem; + background: linear-gradient(270deg, rgba(159, 208, 81, 0.1) 0%, rgba(82, 202, 209, 0.1) 62.02%); + border-radius: 0.08rem; + padding: 0.12rem 0.24rem; + margin-bottom: 0.32rem; + } + + &__optimize-text { + font-size: 0.16rem; + font-weight: 600; + line-height: 0.21rem; + color: $text-dark; } &__optimize-btn { - background: $bg-white; - color: $text-dark; + display: flex; + align-items: center; + justify-content: center; + padding: 0.08rem 0.16rem; + background: #52CAD1; border: none; - border-radius: 0.06rem; - padding: 0.07rem 0.18rem; - font-size: 0.12rem; - font-weight: 500; + border-radius: 0.08rem; + color: $bg-white; + font-size: 0.14rem; + font-weight: 600; + line-height: 0.19rem; cursor: pointer; - transition: all 0.2s; white-space: nowrap; + transition: background 0.2s; &:hover { - background: $theme-color; - color: $accent-hover; + background: $btn-dark-hover; } } - // ---- 描述文本 ---- - &__desc-text { - font-size: 0.13rem; - color: $text-dark; - line-height: 1.8; - margin: 0 0 0.12rem 0; + // ---- 内容区块 ---- + &__section { + margin-bottom: 0.32rem; } - // ---- 标签 ---- - &__tag-list { - display: flex; - flex-wrap: wrap; - gap: 0.08rem; - } - - &__tag { - font-size: 0.12rem; - color: $text-dark; - background: $bg-main; - border: 1px solid $border-color; - border-radius: 0.04rem; - padding: 0.04rem 0.14rem; - transition: all 0.2s; - - &:hover { - border-color: $accent; - color: $accent; - background: $theme-color; - } - } - - // ---- 区块标题 ---- &__section-title { - font-size: 0.17rem; - font-weight: 700; + font-size: 0.18rem; + font-weight: 600; + line-height: 0.24rem; color: $text-dark; - margin: 0 0 0.14rem 0; + margin: 0 0 0.16rem 0; } - &__section-header { + &__section-list { display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 0.14rem; - - .job-detail__section-title { - margin-bottom: 0; - } + flex-direction: column; + gap: 0.12rem; } - &__skill-hint { - display: flex; - align-items: center; - gap: 0.04rem; - font-size: 0.11rem; - color: $text-light; + &__section-item { + font-size: 0.14rem; + line-height: 0.19rem; + color: $text-middle; } - &__hint-icon { - width: 0.12rem; - height: 0.12rem; - flex-shrink: 0; + &__bonus-item { + font-size: 0.14rem; + line-height: 0.19rem; + color: $text-dark; + margin-top: 0.12rem; } // ---- 技能标签 ---- @@ -491,161 +314,81 @@ display: flex; flex-wrap: wrap; gap: 0.08rem; - margin-bottom: 0.16rem; + margin-bottom: 0.12rem; } &__skill-tag { - display: inline-flex; + display: flex; align-items: center; - gap: 0.04rem; + justify-content: center; + padding: 0.04rem 0.06rem; font-size: 0.12rem; - color: $text-dark; - background: $bg-main; - border: 1px solid $border-color; - border-radius: 0.2rem; - padding: 0.05rem 0.14rem; - transition: all 0.2s; + line-height: 0.18rem; + color: $text-middle; + background: #F3F4F6; + border-radius: 0.04rem; &--matched { background: $theme-color; - border-color: $accent; - color: $accent-hover; + color: $accent; } } - &__skill-close { - width: 0.1rem; - height: 0.1rem; - color: $accent; - cursor: pointer; - } - - // ---- 列表 ---- - &__list { - font-size: 0.13rem; - color: $text-dark; - line-height: 2; - margin: 0; - padding-left: 0.2rem; - - li { - padding-left: 0.04rem; - } - } - - // ---- 公司信息 ---- - &__company-info { - display: flex; - gap: 0.4rem; - } - - &__company-info-left { - flex: 1; - min-width: 0; - } - - &__company-header { + // ---- 公司概况 ---- + &__company-head { display: flex; align-items: center; - gap: 0.1rem; + gap: 0.12rem; margin-bottom: 0.12rem; } &__company-logo { - width: 0.36rem; - height: 0.36rem; - border-radius: 50%; - background: $bg-main; + width: 0.48rem; + height: 0.48rem; + border-radius: 0.08rem; + background: #EDF9FA; display: flex; align-items: center; justify-content: center; - border: 1px solid $border-color; flex-shrink: 0; } - &__company-info-name { - font-size: 0.16rem; + &__company-logo-img { + width: 100%; + height: 100%; + object-fit: cover; + border-radius: 0.08rem; + } + + &__company-svg { + width: 0.32rem; + height: 0.32rem; + color: #52CAD1; + } + + &__company-name-info { + display: flex; + flex-direction: column; + gap: 0.06rem; + } + + &__company-name { + font-size: 0.18rem; font-weight: 600; + line-height: 0.24rem; color: $text-dark; } + &__company-sub { + font-size: 0.14rem; + line-height: 0.19rem; + color: $text-middle; + } + &__company-desc { - font-size: 0.12rem; - color: $text-dark; - line-height: 1.8; - margin: 0; - } - - &__company-info-right { - flex-shrink: 0; - display: flex; - flex-direction: column; - gap: 0.08rem; - max-width: 45%; - } - - &__company-meta-item { - font-size: 0.12rem; - color: $text-dark; - line-height: 1.6; - } - - &__meta-label { - color: $text-light; - } - - &__company-link { - color: $accent; - text-decoration: none; - transition: color 0.2s; - - &:hover { - color: $accent-hover; - text-decoration: underline; - } - } - - // ---- 融资 ---- - &__funding-label { - font-weight: 600; - color: $text-dark; - } - - // ---- 最新动态 ---- - &__news-list { - display: flex; - gap: 0.14rem; - } - - &__news-item { - flex: 1; - background: $bg-main; - border: 1px solid $border-color; - border-radius: 0.08rem; - padding: 0.14rem 0.16rem; - transition: all 0.2s; - - &:hover { - border-color: $accent; - background: $theme-color; - } - } - - &__news-title { - font-size: 0.13rem; - font-weight: 600; - color: $text-dark; - margin: 0 0 0.06rem 0; - } - - &__news-desc { - font-size: 0.11rem; + font-size: 0.14rem; + line-height: 0.24rem; color: $text-middle; - line-height: 1.6; margin: 0; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; } } diff --git a/src/assets/styles/pages/jobs.scss b/src/assets/styles/pages/jobs.scss index f33c483..1c94697 100644 --- a/src/assets/styles/pages/jobs.scss +++ b/src/assets/styles/pages/jobs.scss @@ -3,11 +3,13 @@ @use '../variables' as *; .jobs-page { + display: flex; + &__content { margin-left: 2rem; - margin-right: var(--chat-width, 4.0rem); + margin-right: var(--chat-width, 3.6rem); flex: 1; - padding: 0.12rem 0.18rem; + padding-bottom: 0.18rem; height: var(--app-height, 100vh); box-sizing: border-box; overflow: hidden; @@ -79,10 +81,8 @@ // 筛选条件外层白色背景条 &__filters-bar { - background: $bg-white; border-radius: 0.12rem; - padding: 0.14rem 0.18rem; - margin-bottom: 0.2rem; + margin: 0 0.24rem 0.2rem 0.24rem; } // 筛选条件 @@ -103,11 +103,11 @@ display: flex; align-items: center; gap: 0.04rem; - background: $bg-main; + background: #fff; border: 1px solid #E8E8E8; - border-radius: 0.2rem; - padding: 0.05rem 0.14rem; - color: $text-dark; + border-radius: 0.08rem; + padding: 0.15rem 0.12rem; + color: $text-middle; font-size: 0.12rem; cursor: pointer; transition: all 0.2s ease; @@ -116,9 +116,11 @@ height: 0.234rem; &:hover { - border-color: $accent; - color: $accent; - background: $theme-color; + color: #fff; + background: $btn-dark; + svg{ + color: #fff; + } } } @@ -207,6 +209,7 @@ flex: 1; overflow-y: auto; padding-bottom: 0.2rem; + margin: 0 0.24rem; // 列表中每张卡片间距用 margin-bottom 替代 gap & > .jobs-page__job-card { diff --git a/src/assets/styles/pages/mentor.scss b/src/assets/styles/pages/mentor.scss index ed48640..aafc233 100644 --- a/src/assets/styles/pages/mentor.scss +++ b/src/assets/styles/pages/mentor.scss @@ -303,6 +303,10 @@ // 查看详情按钮 &__detail-btn { + display: flex; + justify-content: center; + gap: 0.06rem; + align-items: center; height: 0.32rem; line-height: 0.32rem; width: 0.92rem; diff --git a/src/assets/styles/variables.scss b/src/assets/styles/variables.scss index 33e8a25..60bd7b7 100644 --- a/src/assets/styles/variables.scss +++ b/src/assets/styles/variables.scss @@ -9,7 +9,7 @@ $theme-color: #F6FCFC; $selected-color: #F6FCFC; // 页面主背景色 -$bg-main: #F3F4F5; +$bg-main: #F3F4F6; // 页面中间色景色(用于页面主题色背景和白色背景分隔,用于某些模块组件的组件外层背景等) $bg-middle: #E6E6E6; diff --git a/src/components/AiChat.vue b/src/components/AiChat.vue index c43eafb..26ae1e0 100644 --- a/src/components/AiChat.vue +++ b/src/components/AiChat.vue @@ -1,40 +1,32 @@ @@ -75,8 +92,6 @@ import { ref, computed, watch, nextTick, onMounted } from 'vue' import { useRoute } from 'vue-router' import { useStore } from 'vuex' import markdownit from 'markdown-it' -import MemberDialog from '@/components/MemberDialog.vue' -import AiThinkingIndicator from '@/components/tools/AiThinkingIndicator.vue' import { sendNovaChat } from '@/utils/aiRequest' import type { NovaChatHistoryItem } from '@/utils/aiRequest' import { fetchResumeList } from '@/api/resume' @@ -85,9 +100,9 @@ import { fetchResumeList } from '@/api/resume' /** markdown-it 实例,用于将 AI 回复的 Markdown 文本渲染为 HTML */ const md = markdownit({ - html: false, // 禁止原始 HTML(防 XSS) - breaks: true, // 将换行符转为
- linkify: true, // 自动识别链接 + html: false, + breaks: true, + linkify: true, }) // ==================== Props ==================== @@ -98,23 +113,16 @@ const props = defineProps<{ jobId?: string }>() -/** 当前路由(用于判断是否在岗位详情页) */ +/** 当前路由 */ const currentRoute = useRoute() const store = useStore() - -/** 用户昵称 — 从全局 store 读取 */ -const nickName = computed(() => store.state.userInfo?.nick || '') - // ==================== 状态 ==================== -/** 会员购买弹窗的显示状态 */ -const showMemberDialog = ref(false) - /** 输入框内容 */ const inputText = ref('') -/** 消息列表容器 DOM 引用(用于滚动控制) */ +/** 消息列表容器 DOM 引用 */ const messagesRef = ref() /** AI 是否正在请求中 */ @@ -123,13 +131,20 @@ const aiLoading = ref(false) /** 默认简历 ID */ const defaultResumeId = ref('') +// ==================== 话题推荐列表 ==================== + +/** 固定话题推荐(始终显示) */ +const topicList = [ + '我适合投哪些岗位?', + '帮我看看我的简历可以怎么优化?', + '近期有哪些岗位值得投?', +] + // ==================== 类型定义 ==================== /** 聊天消息类型 */ interface ChatMsg { - /** 角色:assistant-AI助手 user-用户 */ role: 'assistant' | 'user' - /** 消息内容 */ content: string } @@ -137,8 +152,6 @@ interface ChatMsg { /** 获取当前用户的缓存 key */ function getCacheKey(): string { - // 用 sessionStorage 中的登录状态 + 一个简单标识区分用户 - // 如果有更精确的用户 ID 可以替换 const userId = sessionStorage.getItem('userId') || 'anonymous' return `nova_chat_${userId}` } @@ -175,19 +188,6 @@ const messages = ref([]) /** 是否在岗位详情页 */ const isJobDetailPage = computed(() => currentRoute.name === 'JobDetail' || currentRoute.path.startsWith('/jobs/')) -/** 快捷问题列表(仅岗位详情页显示的 3 个用户提问) */ -const quickQuestions = computed(() => { - if (!isJobDetailPage.value) return [] - return [ - '告诉我这个工作为什么适合我?', - '我想修改这个岗位,怎么优化简历?', - '帮我针对这个岗位生成一份面试攻略', - ] -}) - -/** 用户提问列表(等同于 quickQuestions) */ -const userQuestions = computed(() => quickQuestions.value) - // ==================== 内容格式化 ==================== /** 将消息内容通过 markdown-it 渲染为 HTML */ @@ -208,7 +208,7 @@ function scrollToBottom() { // ==================== 加载默认简历 ID ==================== -/** 加载默认简历 ID(用于 Nova 对话接口) */ +/** 加载默认简历 ID */ async function loadDefaultResumeId() { try { const res = await fetchResumeList() @@ -223,13 +223,13 @@ async function loadDefaultResumeId() { // ==================== 事件处理 ==================== -/** 点击快捷问题,填入输入框并发送 */ +/** 点击话题推荐,填入输入框并发送 */ function sendQuickQuestion(question: string) { inputText.value = question sendMessage() } -/** 发送消息(回车或点击发送按钮触发) */ +/** 发送消息 */ async function sendMessage() { if (!inputText.value.trim() || aiLoading.value) return @@ -256,8 +256,8 @@ async function sendMessage() { jobId: props.jobId || undefined, history, }) - // 添加 AI 回复消息 - const aiReply = res?.data?.message || res?.message || '抱歉,我暂时无法回答这个问题。' + // 从 res.data.message 取 AI 回复(接口返回结构:{ code, msg, data: { message } }) + const aiReply = res?.data?.message || '抱歉,我暂时无法回答这个问题。' messages.value.push({ role: 'assistant', content: aiReply }) } catch (e) { console.error('Nova 对话请求失败', e) @@ -269,8 +269,6 @@ async function sendMessage() { } } -// ==================== 动态宽度:小屏缩放时逐渐缩小 ==================== - // ==================== 生命周期 ==================== onMounted(() => { @@ -285,13 +283,23 @@ onMounted(() => { } }) -// 监听 jobId 变化(Jobs 页面点击"问助手"按钮时触发),自动插入 AI 提问消息 +// 监听 jobId 变化 watch(() => props.jobId, (newId, oldId) => { if (newId && newId !== oldId && !isJobDetailPage.value) { - // Jobs 页面:以 AI 身份插入提问到对话记录 messages.value.push({ role: 'assistant', content: '你想知道关于这个岗位的什么信息?' }) saveChatToCache() scrollToBottom() } }) + +// ==================== 对外暴露方法 ==================== + +/** 触发"问Nova"交互:推送提示消息并聚焦输入框 */ +function triggerAsk() { + messages.value.push({ role: 'assistant', content: '你想知道关于这个岗位的什么信息?' }) + saveChatToCache() + scrollToBottom() +} + +defineExpose({ triggerAsk }) diff --git a/src/components/JobPageHeader.vue b/src/components/JobPageHeader.vue index aa3f4f3..796a604 100644 --- a/src/components/JobPageHeader.vue +++ b/src/components/JobPageHeader.vue @@ -1,21 +1,23 @@ @@ -46,11 +48,11 @@ const route = useRoute() // ==================== 常量数据 ==================== -/** Tab 选项列表 */ +/** Tab 选项列表,count 用于显示圆形徽章计数 */ const tabs = computed(() => [ - { key: 'recommend', label: '推荐' }, - { key: 'collected', label: `收藏(${props.favoriteCount ?? 0})` }, - { key: 'applied', label: `投递(${props.applyCount ?? 0})` }, + { key: 'recommend', label: '推荐', count: undefined }, + { key: 'collected', label: '收藏', count: props.favoriteCount ?? 0 }, + { key: 'applied', label: '已投递', count: props.applyCount ?? 0 }, ]) // ==================== 事件处理 ==================== diff --git a/src/components/JobResumeCustomDialog.vue b/src/components/JobResumeCustomDialog.vue index b6bd562..24fc480 100644 --- a/src/components/JobResumeCustomDialog.vue +++ b/src/components/JobResumeCustomDialog.vue @@ -1,49 +1,10 @@ diff --git a/src/components/tools/IndustrySelector.vue b/src/components/tools/IndustrySelector.vue index e809982..7bca178 100644 --- a/src/components/tools/IndustrySelector.vue +++ b/src/components/tools/IndustrySelector.vue @@ -3,11 +3,12 @@
-
+
{{ displayText }} @@ -147,6 +148,8 @@ const props = withDefaults( level?: 1 | 2 /** 父组件传入的触发按钮自定义样式,用于在不同场景下覆盖默认外观 */ triggerStyle?: Record + /** 父组件传入的触发按钮 hover 时的自定义样式 */ + hoverStyle?: Record /** 父组件传入的显示文字自定义样式,用于覆盖 max-width 等默认样式 */ displayStyle?: Record }>(), @@ -170,6 +173,9 @@ const selectorRef = ref(null) /** 下拉面板是否可见 */ const visible = ref(false) +/** 触发按钮是否处于 hover 状态 */ +const isHovered = ref(false) + /** 搜索关键词 */ const searchText = ref('') diff --git a/src/components/tools/JobCategorySelector.vue b/src/components/tools/JobCategorySelector.vue index 8c8cffe..4a8b3f1 100644 --- a/src/components/tools/JobCategorySelector.vue +++ b/src/components/tools/JobCategorySelector.vue @@ -3,11 +3,12 @@
-
+
{{ displayText }} @@ -170,6 +171,8 @@ const props = withDefaults( level?: 1 | 2 | 3 /** 父组件传入的触发按钮自定义样式,用于在不同场景下覆盖默认外观 */ triggerStyle?: Record + /** 父组件传入的触发按钮 hover 时的自定义样式 */ + hoverStyle?: Record /** 父组件传入的显示文字自定义样式,用于覆盖 max-width 等默认样式 */ displayStyle?: Record }>(), @@ -193,6 +196,9 @@ const selectorRef = ref(null) /** 下拉面板是否可见 */ const visible = ref(false) +/** 触发按钮是否处于 hover 状态 */ +const isHovered = ref(false) + /** 搜索关键词 */ const searchText = ref('') diff --git a/src/components/tools/RegionSelector.vue b/src/components/tools/RegionSelector.vue index 23972a5..51b9db0 100644 --- a/src/components/tools/RegionSelector.vue +++ b/src/components/tools/RegionSelector.vue @@ -3,11 +3,12 @@
-
+
{{ displayText }} @@ -157,6 +158,8 @@ const props = withDefaults( maxSelect?: number /** 父组件传入的触发按钮自定义样式,用于在不同场景下覆盖默认外观 */ triggerStyle?: Record + /** 父组件传入的触发按钮 hover 时的自定义样式 */ + hoverStyle?: Record /** 父组件传入的显示文字自定义样式,用于覆盖 max-width 等默认样式 */ displayStyle?: Record }>(), @@ -179,6 +182,9 @@ const selectorRef = ref(null) /** 下拉面板是否可见 */ const visible = ref(false) +/** 触发按钮是否处于 hover 状态 */ +const isHovered = ref(false) + /** 搜索关键词 */ const searchText = ref('') diff --git a/src/plugins/remAdapt.ts b/src/plugins/remAdapt.ts index 5bcc4e7..611cb19 100644 --- a/src/plugins/remAdapt.ts +++ b/src/plugins/remAdapt.ts @@ -74,7 +74,7 @@ const remAdaptPlugin: Plugin = { docEl.style.height = '' docEl.style.overflow = '' docEl.style.setProperty('--app-height', '100vh') - docEl.style.setProperty('--chat-width', '4rem') + docEl.style.setProperty('--chat-width', '3.6rem') } } diff --git a/src/stores/index.ts b/src/stores/index.ts index 884b263..21da158 100644 --- a/src/stores/index.ts +++ b/src/stores/index.ts @@ -29,6 +29,21 @@ export function formatEmploymentType(type: number | undefined | null): string { return JOB_TYPE_MAP[type] ?? '' } +/** 学历要求映射:数字 → 中文标签(0=不限 1=大专 2=本科 3=硕士 4=博士) */ +export const EDUCATION_MAP: Record = { + 0: '不限', + 1: '大专', + 2: '本科', + 3: '硕士', + 4: '博士', +} + +/** 根据 education 值获取中文标签,未匹配返回空字符串 */ +export function formatEducation(edu: number | undefined | null): string { + if (edu === undefined || edu === null) return '' + return EDUCATION_MAP[edu] ?? '' +} + /** 职位列表页缓存数据(从详情页返回时恢复用) */ export interface JobListCache { /** 缓存的职位列表 */ diff --git a/src/utils/aiRequest.ts b/src/utils/aiRequest.ts index bc085a0..8af1af1 100644 --- a/src/utils/aiRequest.ts +++ b/src/utils/aiRequest.ts @@ -105,9 +105,10 @@ export interface NovaChatResponse { * Nova AI 对话 * POST /nova-chat/chat * @param params 对话参数 + * @returns 完整响应体 { code, msg, data: { message } } */ export function sendNovaChat(params: NovaChatParams) { - return aiService.post('/nova-chat/chat', params, { + return aiService.post>('/nova-chat/chat', params, { headers: { Token: DEFAULT_TOKEN, }, diff --git a/src/views/JobDetail.vue b/src/views/JobDetail.vue index bb20c31..847deff 100644 --- a/src/views/JobDetail.vue +++ b/src/views/JobDetail.vue @@ -4,275 +4,128 @@
-
-
- -
- -
- - - + +
+ +
+ +
+ + +
+ +
+ +
+ +
+

{{ job.title }}

+ +
+ +
+ {{ job.location }} + · + {{ job.experience }} + · + {{ job.education }} + · + {{ job.salary }} +
+ +
+ + +
+
+ + +
+
+ {{ job.matchScore }}% + 高匹配度 +
+
+
+ {{ m.label }} + {{ m.score }}% +
+
- -
- -
-
岗位详情
-
公司概况
-
- 问题反馈 - 原链接 -
+ +
+ 优化简历大幅提升面试成功率 + +
+ + +
+

岗位职责

+
+
{{ item }}
+
- - - - + +

{{ job.companyInfo.description }}

+
-
- - - - - - - + @@ -287,15 +140,13 @@