Files
offerpai_web/src/components/AgentPendingJobListPanel.vue
T

189 lines
6.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<!-- 待投递岗位列表面板 右侧面板显示全部待投递岗位滚动分页 -->
<div class="agent-pending-job-list-panel">
<!-- 顶部标题栏 -->
<div class="agent-pending-job-list-panel__header">
<span class="agent-pending-job-list-panel__title">待投递岗位列表</span>
<!-- 关闭按钮 -->
<button class="agent-pending-job-list-panel__close-btn" @click="emit('close')">
<svg viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="12" r="10" fill="#1A1A2E" />
<path d="M8 8l8 8M16 8l-8 8" stroke="#fff" stroke-width="1.5" stroke-linecap="round" />
</svg>
</button>
</div>
<!-- 列表内容可滚动触底加载更多 -->
<div ref="listRef" class="agent-pending-job-list-panel__list" @scroll="handleScroll">
<!-- 岗位项 -->
<div
v-for="job in jobList"
:key="job.id"
class="agent-pending-job-list-panel__item"
>
<!-- 左侧信息区域 -->
<div class="agent-pending-job-list-panel__info">
<!-- 公司 Logo -->
<div class="agent-pending-job-list-panel__logo">
<svg viewBox="0 0 24 24" fill="none">
<rect x="3" y="7" width="18" height="14" rx="2" stroke="currentColor" stroke-width="1.5"/>
<path d="M7 7V5a2 2 0 012-2h6a2 2 0 012 2v2" stroke="currentColor" stroke-width="1.5"/>
</svg>
</div>
<!-- 岗位详情 -->
<div class="agent-pending-job-list-panel__detail">
<div class="agent-pending-job-list-panel__company">{{ job.companyShortName || job.companyName }}</div>
<div class="agent-pending-job-list-panel__position">{{ job.title }}</div>
<!-- 标签 -->
<div class="agent-pending-job-list-panel__tags">
<span v-if="job.regionName" class="agent-pending-job-list-panel__tag">{{ job.regionName }}</span>
<span v-if="job.categoryName" class="agent-pending-job-list-panel__tag">{{ job.categoryName }}</span>
<span v-for="tag in (job.tags || []).slice(0, 2)" :key="tag" class="agent-pending-job-list-panel__tag">{{ tag }}</span>
</div>
</div>
</div>
<!-- 右侧匹配度 + 移出按钮 -->
<div class="agent-pending-job-list-panel__right">
<!-- 匹配度环形 -->
<div class="agent-pending-job-list-panel__score">
<svg class="agent-pending-job-list-panel__ring" viewBox="0 0 44 44">
<circle cx="22" cy="22" r="18" fill="none" stroke="#E8E8E8" stroke-width="3" />
<circle
cx="22" cy="22" r="18" fill="none"
stroke="#4FC2C9" stroke-width="3"
stroke-linecap="round"
:stroke-dasharray="2 * Math.PI * 18"
:stroke-dashoffset="2 * Math.PI * 18 * (1 - (job.matchScore || 0) / 100)"
transform="rotate(-90 22 22)"
/>
</svg>
<span class="agent-pending-job-list-panel__score-text">{{ job.matchScore || 0 }}%</span>
</div>
<!-- 移出按钮 -->
<button
class="agent-pending-job-list-panel__remove-btn"
:disabled="removingIds.includes(job.id)"
@click="handleRemove(job)"
>移出</button>
</div>
</div>
<!-- 加载更多提示 -->
<div v-if="loadingMore" class="agent-pending-job-list-panel__loading">加载中...</div>
<!-- 没有更多数据 -->
<div v-if="noMore && jobList.length > 0" class="agent-pending-job-list-panel__no-more">暂无更多数据</div>
<!-- 空状态 -->
<div v-if="!loading && jobList.length === 0" class="agent-pending-job-list-panel__empty">暂无待投递岗位</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { fetchAgentTaskList } from '@/api/jobs'
import { cancelApplyJob } from '@/api/agent'
import type { JobListItem } from '@/api/jobs'
/** 事件 */
const emit = defineEmits<{
/** 关闭面板 */
(e: 'close'): void
/** 移除岗位后通知父组件 */
(e: 'removed', jobId: string): void
}>()
/** 岗位列表数据 */
const jobList = ref<JobListItem[]>([])
/** 当前页码 */
const currentPage = ref(1)
/** 每页条数 */
const pageSize = 30
/** 是否正在加载首页 */
const loading = ref(false)
/** 是否正在加载更多 */
const loadingMore = ref(false)
/** 是否没有更多数据 */
const noMore = ref(false)
/** 正在移除中的岗位 ID 列表 */
const removingIds = ref<string[]>([])
/** 列表容器 ref */
const listRef = ref<HTMLElement | null>(null)
/** 加载待投递列表 */
async function loadList(page: number) {
if (page === 1) {
loading.value = true
} else {
loadingMore.value = true
}
try {
const res = await fetchAgentTaskList({ pageNum: page, pageSize, tab: 1 })
if (res.code === '0' && res.data) {
const list = res.data.list || []
if (page === 1) {
jobList.value = list
} else {
jobList.value.push(...list)
}
/* 判断是否还有更多数据 */
const total = Number(res.data.total || 0)
if (jobList.value.length >= total || list.length < pageSize) {
noMore.value = true
}
}
} catch {
console.error('[AgentPendingJobListPanel] 加载待投递列表失败')
} finally {
loading.value = false
loadingMore.value = false
}
}
/** 滚动触底加载更多 */
function handleScroll() {
if (!listRef.value || loadingMore.value || noMore.value) return
const { scrollTop, scrollHeight, clientHeight } = listRef.value
/* 距离底部 50px 时触发加载 */
if (scrollTop + clientHeight >= scrollHeight - 50) {
currentPage.value++
loadList(currentPage.value)
}
}
/** 移出岗位 */
async function handleRemove(job: JobListItem) {
if (removingIds.value.includes(job.id)) return
removingIds.value.push(job.id)
try {
await cancelApplyJob(job.id)
/* 从列表中移除 */
const idx = jobList.value.findIndex(j => j.id === job.id)
if (idx !== -1) {
jobList.value.splice(idx, 1)
}
emit('removed', job.id)
ElMessage.success('已移除')
} catch {
ElMessage.error('移除失败,请重试')
} finally {
removingIds.value = removingIds.value.filter(id => id !== job.id)
}
}
onMounted(() => {
loadList(1)
})
</script>
<style scoped lang="scss">
@use '../assets/styles/components/agent-pending-job-list-panel';
</style>