Files
offerpai_web/src/components/AgentTaskListDropdown.vue
T
2026-08-11 11:54:35 +08:00

214 lines
7.5 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>
<!-- 投递任务抽屉 从浏览器右侧弹出包含待投递和已完成两个tab -->
<Teleport to="body">
<Transition name="agent-task-drawer">
<div v-if="visible" class="agent-task-drawer-mask" @click.self="handleClose">
<div class="agent-task-drawer">
<!-- 顶部标题栏 -->
<div class="agent-task-drawer__header mb10">
<div class="agent-task-drawer__header-left">
<!-- 关闭按钮 -->
<div class="agent-task-drawer__close" @click="handleClose">
<svg viewBox="0 0 24 24" fill="none" class="agent-task-drawer__close-icon">
<path d="M18 6L6 18M6 6l12 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<span class="agent-task-drawer__title">投递任务</span>
</div>
</div>
<!-- Tab 切换按钮 -->
<div class="agent-task-drawer__tabs">
<button
class="agent-task-drawer__tab"
:class="{ 'agent-task-drawer__tab--active': activeTab === 'pending' }"
@click="switchTab('pending')"
>待投递 {{ pendingList.length }}</button>
<button
class="agent-task-drawer__tab"
:class="{ 'agent-task-drawer__tab--active': activeTab === 'completed' }"
@click="switchTab('completed')"
>已完成 {{ completedList.length }}</button>
</div>
<!-- 列表内容 -->
<div class="agent-task-drawer__body">
<!-- 待投递列表 -->
<template v-if="activeTab === 'pending'">
<div v-if="pendingLoading" class="agent-task-drawer__empty">加载中...</div>
<div v-else-if="pendingList.length === 0" class="agent-task-drawer__empty">暂无待投递岗位</div>
<div
v-for="job in pendingList"
:key="job.id"
class="agent-task-drawer__card"
>
<div class="agent-task-drawer__card-info">
<div class="agent-task-drawer__card-title">{{ job.title }}</div>
<div class="agent-task-drawer__card-company">
<img v-if="job.companyLogoUrl" :src="job.companyLogoUrl" class="agent-task-drawer__card-logo" :alt="job.companyShortName" />
<svg v-else class="agent-task-drawer__card-logo-placeholder" 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>
<span>{{ job.companyShortName || job.companyName }}</span>
</div>
</div>
<button
class="agent-task-drawer__remove-btn"
:disabled="removingIds.includes(job.id)"
@click="handleRemove(job)"
>移出任务</button>
</div>
</template>
<!-- 已完成列表 -->
<template v-else>
<div v-if="completedLoading" class="agent-task-drawer__empty">加载中...</div>
<div v-else-if="completedList.length === 0" class="agent-task-drawer__empty">暂无已完成岗位</div>
<div
v-for="job in completedList"
:key="job.id"
class="agent-task-drawer__card"
>
<div class="agent-task-drawer__card-info">
<div class="agent-task-drawer__card-title">{{ job.title }}</div>
<div class="agent-task-drawer__card-company">
<img v-if="job.companyLogoUrl" :src="job.companyLogoUrl" class="agent-task-drawer__card-logo" :alt="job.companyShortName" />
<svg v-else class="agent-task-drawer__card-logo-placeholder" 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>
<span>{{ job.companyShortName || job.companyName }}</span>
</div>
</div>
<!-- 已完成状态不显示移出按钮 -->
</div>
</template>
</div>
</div>
</div>
</Transition>
</Teleport>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { fetchAgentTaskList } from '@/api/jobs'
import { cancelApplyJob } from '@/api/agent'
import type { JobListItem } from '@/api/jobs'
// ==================== Props ====================
const props = defineProps<{
/** 是否显示抽屉 */
visible: boolean
}>()
// ==================== 事件 ====================
const emit = defineEmits<{
/** 关闭抽屉 */
(e: 'close'): void
/** 更新visible */
(e: 'update:visible', val: boolean): void
/** 移除岗位后通知父组件刷新列表 */
(e: 'removed', jobId: string): void
}>()
// ==================== 状态 ====================
/** 当前激活的 Tab */
const activeTab = ref<'pending' | 'completed'>('pending')
/** 待投递列表 */
const pendingList = ref<JobListItem[]>([])
/** 已完成列表 */
const completedList = ref<JobListItem[]>([])
/** 待投递加载状态 */
const pendingLoading = ref(false)
/** 已完成加载状态 */
const completedLoading = ref(false)
/** 正在移除中的岗位 ID 列表 */
const removingIds = ref<string[]>([])
// ==================== 监听 ====================
/** 打开时加载数据 */
watch(() => props.visible, (val) => {
if (val) {
loadPendingList()
loadCompletedList()
}
})
// ==================== 方法 ====================
/** 切换 Tab */
function switchTab(tab: 'pending' | 'completed') {
activeTab.value = tab
}
/** 加载待投递列表(pageSize=200 */
async function loadPendingList() {
pendingLoading.value = true
try {
const res = await fetchAgentTaskList({ pageNum: 1, pageSize: 200, tab: 1 })
if (res.code === '0' && res.data) {
pendingList.value = res.data.list || []
}
} catch {
console.error('[AgentTaskListDropdown] 加载待投递列表失败')
} finally {
pendingLoading.value = false
}
}
/** 加载已完成列表(pageSize=300 */
async function loadCompletedList() {
completedLoading.value = true
try {
const res = await fetchAgentTaskList({ pageNum: 1, pageSize: 300, tab: 2 })
if (res.code === '0' && res.data) {
completedList.value = res.data.list || []
}
} catch {
console.error('[AgentTaskListDropdown] 加载已完成列表失败')
} finally {
completedLoading.value = false
}
}
/** 移出岗位 */
async function handleRemove(job: JobListItem) {
if (removingIds.value.includes(job.id)) return
removingIds.value.push(job.id)
try {
await cancelApplyJob(job.id)
const idx = pendingList.value.findIndex(j => j.id === job.id)
if (idx !== -1) {
pendingList.value.splice(idx, 1)
}
emit('removed', job.id)
ElMessage.success('已移除')
} catch {
ElMessage.error('移除失败')
} finally {
removingIds.value = removingIds.value.filter(id => id !== job.id)
}
}
/** 关闭抽屉 */
function handleClose() {
emit('close')
emit('update:visible', false)
}
</script>
<style scoped lang="scss">
@use '../assets/styles/components/agent-task-list-dropdown';
</style>