feat: 实现 PinnedProject 组件与父组件的双向交互

添加 PinnedProject 组件引用和 pin-changed 事件处理
在 Dashboard 和 Dashboard-AI 中同步 pin 状态
暴露 loadPinnedBids 方法供父组件调用
This commit is contained in:
dmy
2026-01-13 21:16:23 +08:00
parent feb18c01bb
commit f050d38140
3 changed files with 72 additions and 3 deletions

View File

@@ -7,7 +7,7 @@
获取 AI 推荐
</el-button>
</div>
<PinnedProject />
<PinnedProject ref="pinnedProjectRef" @pin-changed="handlePinChanged" />
<el-row :gutter="20">
<el-col :span="24">
<el-card class="box-card" shadow="hover">
@@ -328,6 +328,18 @@ const getConfidenceType = (confidence: number) => {
return 'info'
}
// PinnedProject 组件引用
const pinnedProjectRef = ref<any>(null)
// 处理 PinnedProject 组件的 pin 状态改变事件
const handlePinChanged = async (title: string) => {
// 更新对应推荐项目的 pin 状态
const rec = aiRecommendations.value.find(r => r.title === title)
if (rec) {
rec.pin = false
}
}
// 切换 AI 推荐项目的 Pin 状态
const togglePin = async (item: AIRecommendation) => {
try {
@@ -335,6 +347,10 @@ const togglePin = async (item: AIRecommendation) => {
await axios.patch(`/api/bids/${encodeURIComponent(item.title)}/pin`, { pin: newPinStatus })
item.pin = newPinStatus
ElMessage.success(newPinStatus ? '已置顶' : '已取消置顶')
// 刷新 PinnedProject 组件的数据
if (pinnedProjectRef.value) {
pinnedProjectRef.value.loadPinnedBids()
}
} catch (error) {
ElMessage.error('操作失败')
}

View File

@@ -7,7 +7,7 @@
立刻抓取
</el-button>
</div>
<PinnedProject />
<PinnedProject ref="pinnedProjectRef" @pin-changed="handlePinChanged" />
<el-divider />
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
<h3 style="margin: 0;">Today's Bids</h3>
@@ -48,6 +48,20 @@
</div>
</div>
<el-table :data="filteredTodayBids" v-loading="loading" style="width: 100%">
<el-table-column label="Pin" width="60" align="center">
<template #default="scope">
<el-icon
:style="{
color: scope.row.pin ? '#f56c6c' : '#909399',
cursor: 'pointer',
fontSize: '18px'
}"
@click="togglePin(scope.row)"
>
<Paperclip />
</el-icon>
</template>
</el-table-column>
<el-table-column prop="title" label="Title">
<template #default="scope">
<a :href="scope.row.url" target="_blank">{{ scope.row.title }}</a>
@@ -65,7 +79,7 @@
import { ref, computed, watch } from 'vue'
import axios from 'axios'
import { ElMessage } from 'element-plus'
import { Refresh, ArrowDown } from '@element-plus/icons-vue'
import { Refresh, ArrowDown, Paperclip } from '@element-plus/icons-vue'
import PinnedProject from './PinnedProject.vue'
interface Props {
@@ -271,6 +285,34 @@ const handleCrawl = async () => {
}
}
// PinnedProject 组件引用
const pinnedProjectRef = ref<any>(null)
// 处理 PinnedProject 组件的 pin 状态改变事件
const handlePinChanged = async (title: string) => {
// 更新 todayBids 中对应项目的 pin 状态
const bid = props.todayBids.find(b => b.title === title)
if (bid) {
bid.pin = false
}
}
// 切换 Today's Bids 的 Pin 状态
const togglePin = async (item: any) => {
try {
const newPinStatus = !item.pin
await axios.patch(`/api/bids/${encodeURIComponent(item.title)}/pin`, { pin: newPinStatus })
item.pin = newPinStatus
ElMessage.success(newPinStatus ? '已置顶' : '已取消置顶')
// 刷新 PinnedProject 组件的数据
if (pinnedProjectRef.value) {
pinnedProjectRef.value.loadPinnedBids()
}
} catch (error) {
ElMessage.error('操作失败')
}
}
// 初始化时加载保存的关键字和日期范围
loadSavedKeywords()
loadSavedDateRange()

View File

@@ -52,6 +52,10 @@ import axios from 'axios'
import { ElMessage } from 'element-plus'
import { Loading, InfoFilled, Paperclip } from '@element-plus/icons-vue'
const emit = defineEmits<{
pinChanged: [title: string]
}>()
const pinnedBids = ref<any[]>([])
const pinnedLoading = ref(false)
@@ -77,6 +81,8 @@ const togglePin = async (item: any) => {
pinnedBids.value.splice(index, 1)
}
ElMessage.success('已取消置顶')
// 通知父组件 pin 状态已改变,传递 title
emit('pinChanged', item.title)
} catch (error) {
ElMessage.error('操作失败')
}
@@ -96,6 +102,11 @@ const formatDate = (dateStr: string) => {
onMounted(() => {
loadPinnedBids()
})
// 暴露方法给父组件调用
defineExpose({
loadPinnedBids
})
</script>
<style scoped>