Compare commits
2 Commits
bfc0ee4233
...
b4a101d4fe
| Author | SHA1 | Date |
|---|---|---|
|
|
b4a101d4fe | |
|
|
20f6b188e3 |
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="three-panel">
|
||||
<div class="two-panel">
|
||||
|
||||
<!-- ── 左栏:公司列表 ── -->
|
||||
<aside class="panel-left">
|
||||
|
|
@ -59,35 +59,33 @@
|
|||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- ── 中栏:岗位列表 ── -->
|
||||
<section class="panel-mid">
|
||||
<div class="mid-header">
|
||||
<span v-if="selectedOrg" class="mid-title">
|
||||
<span class="mid-title-org">{{ selectedOrg.name }}</span>
|
||||
<span class="mid-title-sep"> · </span>职位列表
|
||||
</span>
|
||||
<span v-else class="mid-title muted">← 请选择企业</span>
|
||||
<span v-if="jobs.length" class="mid-count">{{ jobs.length }} 个</span>
|
||||
<!-- ── 右栏:岗位列表 ── -->
|
||||
<section class="panel-right">
|
||||
<div class="right-header">
|
||||
<span class="right-title">职位列表</span>
|
||||
<span v-if="jobs.length" class="right-count">{{ jobs.length }} 个</span>
|
||||
</div>
|
||||
<div class="mid-body">
|
||||
<div class="right-body">
|
||||
<template v-if="jobsLoading">
|
||||
<div v-for="i in 4" :key="i" class="skeleton-row" />
|
||||
</template>
|
||||
<template v-else-if="jobsError">
|
||||
<div class="state-tip">加载失败,请刷新重试</div>
|
||||
</template>
|
||||
<template v-else-if="jobs.length === 0 && selectedOrg">
|
||||
<div class="state-tip">暂无在招职位</div>
|
||||
<template v-else-if="jobs.length === 0">
|
||||
<div class="state-tip">请选择企业查看职位</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div
|
||||
v-for="job in jobs"
|
||||
:key="job.id"
|
||||
class="job-row"
|
||||
:class="{ active: selectedJob?.id === job.id }"
|
||||
@click="selectJob(job)"
|
||||
@click="goToJobDetail(job)"
|
||||
>
|
||||
<div class="job-row-title">{{ job.title }}</div>
|
||||
<div class="job-row-meta">
|
||||
<span class="job-org">{{ job.organization?.name }}</span>
|
||||
</div>
|
||||
<div class="job-row-tags">
|
||||
<span class="tag tag-loc">{{ job.location }}</span>
|
||||
<span class="tag tag-sal">{{ job.salary }}</span>
|
||||
|
|
@ -99,138 +97,6 @@
|
|||
</section>
|
||||
|
||||
<!-- ── 右栏:岗位详情 ── -->
|
||||
<section class="panel-right">
|
||||
<!-- 加载 -->
|
||||
<template v-if="detailLoading">
|
||||
<div class="detail-loading">
|
||||
<div v-for="i in 6" :key="i" class="skeleton-row" style="margin-bottom:12px" />
|
||||
</div>
|
||||
</template>
|
||||
<!-- 错误 -->
|
||||
<template v-else-if="detailError">
|
||||
<div class="state-tip full-tip">加载失败,请刷新重试</div>
|
||||
</template>
|
||||
<!-- 详情 -->
|
||||
<template v-else-if="selectedJob">
|
||||
<!-- Banner -->
|
||||
<div class="detail-banner">
|
||||
<div class="banner-deco"></div>
|
||||
<div class="banner-content">
|
||||
<div class="banner-left">
|
||||
<div class="banner-category">{{ selectedJob.category }}</div>
|
||||
<h2 class="banner-title">{{ selectedJob.title }}</h2>
|
||||
<div class="banner-salary">{{ selectedJob.salary }}</div>
|
||||
<div class="banner-meta">
|
||||
<span class="bmeta-item">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>
|
||||
{{ selectedJob.location }}
|
||||
</span>
|
||||
<span class="bmeta-sep">|</span>
|
||||
<span class="bmeta-item">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
|
||||
{{ selectedJob.organization?.name }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="banner-right">
|
||||
<div class="banner-date">发布于 {{ formatDate(selectedJob.created_at) }}</div>
|
||||
<div class="banner-btns">
|
||||
<button class="btn-collect" @click="handleCollect">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>
|
||||
{{ collected ? '已收藏' : '收藏' }}
|
||||
</button>
|
||||
<button class="btn-apply" :class="{ loading: applying }" @click="handleApply">
|
||||
{{ applying ? '提交中…' : '立即投递' }}
|
||||
</button>
|
||||
</div>
|
||||
<p class="banner-hint" v-if="!auth.isLoggedIn">登录后才能投递</p>
|
||||
<p class="banner-hint success" v-if="applied">✓ 投递成功,可在「我的投递」查看</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主体 -->
|
||||
<div class="detail-main">
|
||||
<div class="detail-left">
|
||||
<!-- 信息格 -->
|
||||
<div class="info-grid">
|
||||
<div class="info-cell">
|
||||
<span class="info-label">职位类别</span>
|
||||
<span class="info-value">{{ selectedJob.category || '未填写' }}</span>
|
||||
</div>
|
||||
<div class="info-cell">
|
||||
<span class="info-label">工作地点</span>
|
||||
<span class="info-value">{{ selectedJob.location }}</span>
|
||||
</div>
|
||||
<div class="info-cell">
|
||||
<span class="info-label">薪资范围</span>
|
||||
<span class="info-value red-val">{{ selectedJob.salary }}</span>
|
||||
</div>
|
||||
<div class="info-cell">
|
||||
<span class="info-label">发布时间</span>
|
||||
<span class="info-value">{{ formatDate(selectedJob.created_at) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-divider"></div>
|
||||
|
||||
<!-- 职位介绍 -->
|
||||
<div class="content-section">
|
||||
<div class="section-heading"><span class="heading-bar"></span>职位介绍</div>
|
||||
<div class="desc-text" v-html="selectedJob.description"></div>
|
||||
</div>
|
||||
|
||||
<div class="section-divider"></div>
|
||||
|
||||
<!-- 工作地点 -->
|
||||
<div class="content-section">
|
||||
<div class="section-heading"><span class="heading-bar"></span>工作地点</div>
|
||||
<div class="location-row">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="2"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>
|
||||
{{ selectedJob.location }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 公司卡片 -->
|
||||
<div class="detail-right">
|
||||
<div class="company-card">
|
||||
<div class="company-card-label">招聘单位</div>
|
||||
<div class="company-card-top">
|
||||
<div class="cc-logo">
|
||||
<img v-if="selectedJob.organization?.logo" :src="selectedJob.organization.logo" alt="" />
|
||||
<span v-else>{{ selectedJob.organization?.name?.[0] }}</span>
|
||||
</div>
|
||||
<div class="cc-info">
|
||||
<div class="cc-name">{{ selectedJob.organization?.name }}</div>
|
||||
<div class="cc-desc" v-if="selectedJob.organization?.description">
|
||||
{{ selectedJob.organization.description.slice(0, 50) }}{{ selectedJob.organization.description.length > 50 ? '…' : '' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cc-divider"></div>
|
||||
<div class="cc-contact" v-if="selectedJob.organization?.email">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="2"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>
|
||||
{{ selectedJob.organization.email }}
|
||||
</div>
|
||||
<button class="btn-apply-card" :class="{ loading: applying }" @click="handleApply">
|
||||
{{ applying ? '提交中…' : '立即投递' }}
|
||||
</button>
|
||||
<p class="apply-success" v-if="applied">✓ 投递成功</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 空状态 -->
|
||||
<template v-else>
|
||||
<div class="state-tip full-tip">
|
||||
<div class="empty-icon">
|
||||
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#D4A95D" stroke-width="1.5"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
|
||||
</div>
|
||||
<p>请从左侧选择企业及职位</p>
|
||||
</div>
|
||||
</template>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -240,8 +106,7 @@ import { useRouter } from 'vue-router'
|
|||
import { useAuthStore } from '@/stores/auth'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { getOrganizations } from '@/api/organizations'
|
||||
import { getJobs, getJob, toggleFavorite } from '@/api/jobs'
|
||||
import { applyJob } from '@/api/applications'
|
||||
import { getJobs } from '@/api/jobs'
|
||||
|
||||
const router = useRouter()
|
||||
const auth = useAuthStore()
|
||||
|
|
@ -255,12 +120,6 @@ const jobs = ref([])
|
|||
const jobsLoading = ref(false)
|
||||
const jobsError = ref(false)
|
||||
|
||||
const selectedJob = ref(null)
|
||||
const detailLoading = ref(false)
|
||||
const detailError = ref(false)
|
||||
const applying = ref(false)
|
||||
const applied = ref(false)
|
||||
const collected = ref(false)
|
||||
|
||||
const totalOrgs = computed(() => {
|
||||
return orgs.value.reduce((n, o) => n + 1 + (o.children?.length || 0), 0)
|
||||
|
|
@ -284,39 +143,8 @@ async function selectOrg(org) {
|
|||
finally { jobsLoading.value = false }
|
||||
}
|
||||
|
||||
async function selectJob(job) {
|
||||
detailError.value = false
|
||||
detailLoading.value = true
|
||||
selectedJob.value = null
|
||||
applied.value = false
|
||||
collected.value = false
|
||||
try {
|
||||
const { data } = await getJob(job.id)
|
||||
selectedJob.value = data
|
||||
} catch { detailError.value = true }
|
||||
finally { detailLoading.value = false }
|
||||
}
|
||||
|
||||
async function handleCollect() {
|
||||
if (!auth.isLoggedIn) return router.push({ name: 'Login' })
|
||||
if (!auth.isSeeker) return ElMessage.warning('管理员账号无法收藏职位')
|
||||
const { data } = await toggleFavorite(selectedJob.value.id)
|
||||
collected.value = data.collected
|
||||
ElMessage.success(collected.value ? '已收藏,可在「关注职位」中查看' : '已取消收藏')
|
||||
}
|
||||
|
||||
async function handleApply() {
|
||||
if (!auth.isLoggedIn) return router.push({ name: 'Login' })
|
||||
if (!auth.isSeeker) return ElMessage.warning('管理员账号无法投递职位')
|
||||
applying.value = true
|
||||
try {
|
||||
await applyJob(selectedJob.value.id)
|
||||
applied.value = true
|
||||
ElMessage.success('投递成功!')
|
||||
} catch (e) {
|
||||
if (e.response?.status === 400) ElMessage.warning(e.response.data?.detail || '您已投递过该职位')
|
||||
else ElMessage.error('投递失败,请先完善简历')
|
||||
} finally { applying.value = false }
|
||||
function goToJobDetail(job) {
|
||||
router.push({ name: 'JobDetail', params: { id: job.id } })
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
|
|
@ -332,15 +160,15 @@ onMounted(async () => {
|
|||
|
||||
<style scoped>
|
||||
/* ── 变量 ── */
|
||||
.three-panel {
|
||||
--red: #FFFFFF;
|
||||
--dark: #F5F5F5;
|
||||
--gold: #FFFFFF;
|
||||
--gold-lt: #FFFFFF;
|
||||
--cream: #FFFFFF;
|
||||
--border: #EFEFEF;
|
||||
--text: #333333;
|
||||
--muted: #999999;
|
||||
.two-panel {
|
||||
--red: #B8860B;
|
||||
--dark: #1A1A1A;
|
||||
--gold: #B8860B;
|
||||
--gold-lt: #D4AF37;
|
||||
--cream: #FAFAFA;
|
||||
--border: #D3D3D3;
|
||||
--text: #2A1A1A;
|
||||
--muted: #3A3A3A;
|
||||
|
||||
display: flex;
|
||||
height: calc(100vh - 220px);
|
||||
|
|
@ -348,7 +176,7 @@ onMounted(async () => {
|
|||
overflow: hidden;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--border);
|
||||
box-shadow: 0 4px 24px rgba(0,0,0,0.05);
|
||||
box-shadow: 0 4px 24px rgba(0,0,0,0.12);
|
||||
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||
}
|
||||
|
||||
|
|
@ -366,13 +194,13 @@ onMounted(async () => {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #EFEFEF;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.08);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.left-title {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
color: #333333;
|
||||
color: rgba(255,255,255,0.9);
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
.left-count {
|
||||
|
|
@ -388,7 +216,7 @@ onMounted(async () => {
|
|||
.left-body { flex: 1; overflow-y: auto; }
|
||||
.left-body::-webkit-scrollbar { width: 4px; }
|
||||
.left-body::-webkit-scrollbar-track { background: transparent; }
|
||||
.left-body::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.1); border-radius: 2px; }
|
||||
.left-body::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.12); border-radius: 2px; }
|
||||
|
||||
/* 公司行 */
|
||||
.org-row {
|
||||
|
|
@ -397,19 +225,19 @@ onMounted(async () => {
|
|||
gap: 10px;
|
||||
padding: 10px 16px;
|
||||
border-left: 3px solid transparent;
|
||||
border-bottom: 1px solid #EFEFEF;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.05);
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.org-row:hover { background: #EBEBEB; }
|
||||
.org-row:hover { background: rgba(255,255,255,0.06); }
|
||||
.org-row.active {
|
||||
border-left-color: var(--red);
|
||||
background: #FFF5F5;
|
||||
border-left-color: var(--gold);
|
||||
background: rgba(184,134,11,0.1);
|
||||
}
|
||||
.org-avatar {
|
||||
width: 34px; height: 34px;
|
||||
border-radius: 6px;
|
||||
background: linear-gradient(135deg, #C8973A, #9A6E28);
|
||||
background: linear-gradient(135deg, #B8860B, #8B6407);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 15px; font-weight: 900; color: #fff;
|
||||
flex-shrink: 0; overflow: hidden;
|
||||
|
|
@ -417,76 +245,73 @@ onMounted(async () => {
|
|||
.org-avatar img { width: 100%; height: 100%; object-fit: cover; }
|
||||
.child-avatar {
|
||||
width: 28px; height: 28px; font-size: 12px;
|
||||
background: linear-gradient(135deg, #C8A080, #9A7860);
|
||||
background: linear-gradient(135deg, #A67C07, #7D5A05);
|
||||
}
|
||||
.org-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
|
||||
.org-name {
|
||||
font-size: 13px; font-weight: 600;
|
||||
color: #333333;
|
||||
color: rgba(255,255,255,0.88);
|
||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||
}
|
||||
.child-name { font-size: 12px; color: #666666; }
|
||||
.org-row.active .org-name { color: var(--red); }
|
||||
.org-stat { font-size: 11px; color: #999999; }
|
||||
.org-stat em { font-style: normal; color: var(--red); font-weight: 700; }
|
||||
.child-name { font-size: 12px; color: rgba(255,255,255,0.7); }
|
||||
.org-row.active .org-name { color: var(--gold-lt); }
|
||||
.org-stat { font-size: 11px; color: rgba(255,255,255,0.38); }
|
||||
.org-stat em { font-style: normal; color: var(--gold); font-weight: 700; }
|
||||
|
||||
/* 子公司缩进 */
|
||||
.org-child { padding-left: 12px; background: #FAFAFA; }
|
||||
.org-child { padding-left: 12px; background: rgba(0,0,0,0.12); }
|
||||
.child-indent {
|
||||
display: flex; align-items: center; flex-shrink: 0;
|
||||
padding-left: 6px;
|
||||
}
|
||||
.child-line {
|
||||
display: block; width: 10px; height: 1px;
|
||||
background: #FFFFFF;
|
||||
background: rgba(184,134,11,0.35);
|
||||
}
|
||||
|
||||
/* ── 中栏 ── */
|
||||
.panel-mid {
|
||||
width: 268px;
|
||||
/* ── 右栏 (职位列表) ── */
|
||||
.panel-right {
|
||||
flex: 1;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #FFFFFF;
|
||||
border-right: 1px solid #EFEFEF;
|
||||
background: var(--cream);
|
||||
border-left: 1px solid var(--border);
|
||||
}
|
||||
.mid-header {
|
||||
.right-header {
|
||||
padding: 14px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 2px solid #EFEFEF;
|
||||
border-bottom: 2px solid var(--border);
|
||||
flex-shrink: 0;
|
||||
background: #fff;
|
||||
}
|
||||
.mid-title { font-size: 13px; font-weight: 600; color: var(--text); }
|
||||
.mid-title-org { color: var(--red); }
|
||||
.mid-title.muted { color: var(--muted); font-weight: 400; }
|
||||
.mid-count {
|
||||
font-size: 11px; color: #999999;
|
||||
background: #F5F5F5; border-radius: 10px; padding: 1px 8px;
|
||||
.right-title { font-size: 13px; font-weight: 600; color: var(--text); }
|
||||
.right-count {
|
||||
font-size: 11px; color: var(--muted);
|
||||
background: #F0F0F0; border-radius: 10px; padding: 1px 8px;
|
||||
}
|
||||
.mid-body { flex: 1; overflow-y: auto; }
|
||||
.right-body { flex: 1; overflow-y: auto; }
|
||||
|
||||
/* 岗位行 */
|
||||
.job-row {
|
||||
padding: 13px 16px;
|
||||
border-left: 3px solid transparent;
|
||||
border-bottom: 1px solid #EFEFEF;
|
||||
border-bottom: 1px solid var(--border);
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
background: #fff;
|
||||
}
|
||||
.job-row:hover { background: #FAFAFA; }
|
||||
.job-row.active {
|
||||
border-left-color: var(--red);
|
||||
background: #FFF5F5;
|
||||
}
|
||||
.job-row:hover { background: #F8F8F8; }
|
||||
.job-row-title {
|
||||
font-size: 13px; font-weight: 600;
|
||||
color: var(--text); margin-bottom: 7px;
|
||||
color: var(--text); margin-bottom: 5px;
|
||||
}
|
||||
.job-row.active .job-row-title { color: var(--red); }
|
||||
.job-row-meta {
|
||||
font-size: 11px; color: var(--muted); margin-bottom: 6px;
|
||||
}
|
||||
.job-org { color: var(--red); }
|
||||
.job-row-tags { display: flex; gap: 5px; flex-wrap: wrap; }
|
||||
.tag {
|
||||
font-size: 11px; padding: 2px 7px;
|
||||
|
|
@ -496,190 +321,6 @@ onMounted(async () => {
|
|||
.tag-sal { background: #FFF3E0; color: #B7610A; }
|
||||
.tag-cat { background: #E8F5E9; color: #2E7D32; }
|
||||
|
||||
/* ── 右栏 ── */
|
||||
.panel-right {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
background: #FFFFFF;
|
||||
}
|
||||
|
||||
/* Banner */
|
||||
.detail-banner {
|
||||
position: relative;
|
||||
background: linear-gradient(135deg, #8B4545 0%, #A85555 50%, #9A4C4C 100%);
|
||||
overflow: hidden;
|
||||
}
|
||||
.banner-deco {
|
||||
position: absolute; inset: 0;
|
||||
background:
|
||||
repeating-linear-gradient(45deg, transparent, transparent 20px, rgba(212,169,93,0.03) 20px, rgba(212,169,93,0.03) 21px),
|
||||
repeating-linear-gradient(-45deg, transparent, transparent 20px, rgba(212,169,93,0.03) 20px, rgba(212,169,93,0.03) 21px);
|
||||
}
|
||||
.banner-content {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 20px;
|
||||
padding: 28px 32px;
|
||||
}
|
||||
.banner-left { flex: 1; }
|
||||
.banner-category {
|
||||
display: inline-block;
|
||||
padding: 3px 12px;
|
||||
background: rgba(212,169,93,0.15);
|
||||
border: 1px solid rgba(212,169,93,0.35);
|
||||
color: var(--gold-lt);
|
||||
font-size: 11px; letter-spacing: 0.1em;
|
||||
border-radius: 2px; margin-bottom: 10px;
|
||||
}
|
||||
.banner-title {
|
||||
font-size: 22px; font-weight: 800;
|
||||
color: #fff; letter-spacing: 0.05em;
|
||||
margin: 0 0 8px;
|
||||
text-shadow: 0 2px 8px rgba(0,0,0,0.3);
|
||||
}
|
||||
.banner-salary {
|
||||
font-size: 18px; font-weight: 700;
|
||||
color: #CCCCCC; margin-bottom: 12px;
|
||||
}
|
||||
.banner-meta { display: flex; align-items: center; gap: 8px; }
|
||||
.bmeta-item {
|
||||
display: flex; align-items: center; gap: 4px;
|
||||
font-size: 13px; color: rgba(255,255,255,0.6);
|
||||
}
|
||||
.bmeta-sep { color: rgba(255,255,255,0.2); }
|
||||
|
||||
.banner-right { text-align: right; flex-shrink: 0; }
|
||||
.banner-date { font-size: 12px; color: rgba(255,255,255,0.38); margin-bottom: 14px; }
|
||||
.banner-btns { display: flex; gap: 10px; justify-content: flex-end; }
|
||||
.btn-collect {
|
||||
display: flex; align-items: center; gap: 6px;
|
||||
padding: 9px 18px;
|
||||
background: transparent;
|
||||
border: 1px solid rgba(212,169,93,0.5);
|
||||
color: var(--gold-lt);
|
||||
border-radius: 3px; font-size: 13px;
|
||||
cursor: pointer; transition: all 0.2s;
|
||||
font-family: inherit;
|
||||
}
|
||||
.btn-collect:hover { background: rgba(212,169,93,0.1); border-color: var(--gold); }
|
||||
.btn-apply {
|
||||
padding: 9px 24px;
|
||||
background: var(--red);
|
||||
border: none; color: #fff;
|
||||
border-radius: 3px; font-size: 13px; font-weight: 700;
|
||||
cursor: pointer; transition: all 0.2s;
|
||||
letter-spacing: 0.05em;
|
||||
font-family: inherit;
|
||||
box-shadow: 0 4px 16px rgba(200,200,200,0.2);
|
||||
}
|
||||
.btn-apply:hover { background: #F0F0F0; box-shadow: 0 6px 20px rgba(200,200,200,0.2); }
|
||||
.btn-apply.loading { opacity: 0.7; cursor: not-allowed; }
|
||||
.banner-hint { font-size: 12px; color: rgba(255,255,255,0.4); margin-top: 8px; }
|
||||
.banner-hint.success { color: #6FCF97; }
|
||||
|
||||
/* 主体 */
|
||||
.detail-main {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
padding: 24px 28px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.detail-left {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
padding: 24px 28px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
|
||||
border: 1px solid #EFEFEF;
|
||||
}
|
||||
.detail-right { width: 224px; flex-shrink: 0; }
|
||||
|
||||
/* 信息格 */
|
||||
.info-grid {
|
||||
display: grid; grid-template-columns: 1fr 1fr; gap: 16px 24px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.info-cell { display: flex; flex-direction: column; gap: 4px; }
|
||||
.info-label {
|
||||
font-size: 11px; color: var(--muted); letter-spacing: 0.05em;
|
||||
display: flex; align-items: center; gap: 5px;
|
||||
}
|
||||
.info-label::before {
|
||||
content: ''; width: 5px; height: 5px;
|
||||
background: var(--red); border-radius: 50%;
|
||||
}
|
||||
.info-value { font-size: 14px; font-weight: 600; color: var(--text); }
|
||||
.red-val { color: var(--red); }
|
||||
|
||||
.section-divider {
|
||||
height: 1px; background: #EFEFEF;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
/* 内容区块 */
|
||||
.content-section { }
|
||||
.section-heading {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
font-size: 15px; font-weight: 700; color: var(--text);
|
||||
margin-bottom: 14px; letter-spacing: 0.05em;
|
||||
}
|
||||
.heading-bar {
|
||||
display: block; width: 4px; height: 16px;
|
||||
background: var(--red); border-radius: 2px;
|
||||
}
|
||||
.desc-text {
|
||||
font-size: 13px; line-height: 2;
|
||||
color: #3A3A4A; white-space: pre-wrap;
|
||||
}
|
||||
.location-row {
|
||||
display: flex; align-items: center; gap: 6px;
|
||||
font-size: 13px; color: #3A3A4A;
|
||||
}
|
||||
|
||||
/* 公司卡片 */
|
||||
.company-card {
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
padding: 18px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
|
||||
border: 1px solid #EFEFEF;
|
||||
}
|
||||
.company-card-label {
|
||||
font-size: 11px; font-weight: 700;
|
||||
color: var(--muted); letter-spacing: 0.15em;
|
||||
margin-bottom: 14px; text-transform: uppercase;
|
||||
}
|
||||
.company-card-top { display: flex; gap: 12px; align-items: flex-start; margin-bottom: 14px; }
|
||||
.cc-logo {
|
||||
width: 48px; height: 48px;
|
||||
border-radius: 8px; overflow: hidden; flex-shrink: 0;
|
||||
background: linear-gradient(135deg, #D4A95D, #B08C3A);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 20px; font-weight: 900; color: #fff;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
.cc-logo img { width: 100%; height: 100%; object-fit: cover; }
|
||||
.cc-name { font-size: 14px; font-weight: 700; color: var(--text); margin-bottom: 4px; }
|
||||
.cc-desc { font-size: 11px; color: var(--muted); line-height: 1.6; }
|
||||
.cc-divider { height: 1px; background: #EFEFEF; margin-bottom: 12px; }
|
||||
.cc-contact {
|
||||
display: flex; align-items: center; gap: 6px;
|
||||
font-size: 12px; color: var(--muted); word-break: break-all;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.btn-apply-card {
|
||||
width: 100%; padding: 10px;
|
||||
background: var(--red); border: none;
|
||||
color: #fff; font-size: 13px; font-weight: 700;
|
||||
border-radius: 3px; cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
font-family: inherit; letter-spacing: 0.05em;
|
||||
}
|
||||
.btn-apply-card:hover { background: #F0F0F0; }
|
||||
.btn-apply-card.loading { opacity: 0.7; cursor: not-allowed; }
|
||||
.apply-success { text-align: center; font-size: 12px; color: #27AE60; margin-top: 8px; }
|
||||
|
||||
/* 空状态 / 骨架 */
|
||||
.state-tip {
|
||||
|
|
@ -691,7 +332,7 @@ onMounted(async () => {
|
|||
.empty-icon { opacity: 0.5; }
|
||||
.detail-loading { padding: 24px 28px; }
|
||||
.skeleton-row {
|
||||
height: 14px; background: linear-gradient(90deg, #EDE3DE 25%, #F5EDED 50%, #EDE3DE 75%);
|
||||
height: 14px; background: linear-gradient(90deg, #E8E8E8 25%, #F0F0F0 50%, #E8E8E8 75%);
|
||||
background-size: 200% 100%;
|
||||
border-radius: 3px; margin-bottom: 10px;
|
||||
animation: shimmer 1.5s infinite;
|
||||
|
|
|
|||
Loading…
Reference in New Issue