搜索、小助手推荐位
This commit is contained in:
@@ -71,7 +71,7 @@
|
||||
<img v-else src="@/assets/imgs/assistant.svg" alt="AI助手" class="welcome-avatar" />
|
||||
</div>
|
||||
<h2>你好!我是{{ agentConfig?.name || 'AI助手' }}</h2>
|
||||
<p>{{ agentConfig?.systemPrompt || '有什么可以帮助你的吗?' }}</p>
|
||||
<AIRecommend />
|
||||
</div>
|
||||
|
||||
<!-- 消息列表 -->
|
||||
@@ -189,6 +189,7 @@ import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { chatApi, chatHistoryApi, aiAgentConfigApi, fileUploadApi } from '@/apis/ai';
|
||||
import type { AiConversation, AiMessage, AiAgentConfig, AiUploadFile } from '@/types/ai';
|
||||
import { AIRecommend } from '@/views/public/ai';
|
||||
|
||||
interface AIAgentProps {
|
||||
agentId?: string;
|
||||
|
||||
271
schoolNewsWeb/src/views/public/ai/AIRecommend.vue
Normal file
271
schoolNewsWeb/src/views/public/ai/AIRecommend.vue
Normal file
@@ -0,0 +1,271 @@
|
||||
<template>
|
||||
<div class="ai-recommend">
|
||||
<div class="recommend-left">
|
||||
<div class="recommend-title">
|
||||
<span class="title-icon">✨</span>
|
||||
<span class="title-text">智能推荐</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="recommend-right">
|
||||
<!-- Tab选项卡,推荐top资源和思政资源5个 -->
|
||||
<el-tabs v-model="activeName" class="recommend-tabs" @tab-click="handleClick">
|
||||
<el-tab-pane label="推荐top资源" name="top"></el-tab-pane>
|
||||
<el-tab-pane label="思政资源" name="ideological"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="recommend-list">
|
||||
<div v-if="showData.length === 0" class="empty-state">
|
||||
<span class="empty-icon">📚</span>
|
||||
<p>暂无推荐内容</p>
|
||||
</div>
|
||||
<div v-else class="list-items">
|
||||
<div v-for="(item, index) in showData" :key="item.id" class="recommend-item">
|
||||
<span class="item-number">{{ index + 1 }}</span>
|
||||
<a :href="buildUrl(item)" class="item-link" target="_blank">
|
||||
<span class="item-title">{{ item.title }}</span>
|
||||
<span class="item-arrow">→</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { PageParam, type ResourceRecommendVO } from '@/types'
|
||||
import { resourceRecommendApi} from '@/apis/resource';
|
||||
import { PUBLIC_WEB_PATH } from '@/config'
|
||||
type TabName = 'top' | 'ideological'
|
||||
|
||||
const activeName = ref<TabName>('top')
|
||||
const handleClick = (tab: any, event: Event) => {
|
||||
console.log(tab, event)
|
||||
loadData()
|
||||
}
|
||||
const showData = ref<ResourceRecommendVO[]>([])
|
||||
|
||||
const limit = 5
|
||||
const tabMap: Record<TabName, number> = {top: 1, ideological: 2}
|
||||
|
||||
function buildUrl(item: ResourceRecommendVO) {
|
||||
return `${PUBLIC_WEB_PATH}/article/show?articleId=${item.resourceID}`;
|
||||
}
|
||||
|
||||
async function loadData(){
|
||||
resourceRecommendApi.getRecommendsByType(tabMap[activeName.value], limit).then((res) => {
|
||||
showData.value = res.dataList || []
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData().then(() => {
|
||||
console.log()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ai-recommend {
|
||||
width: 100%;
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||
|
||||
.recommend-left {
|
||||
min-width: 80px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.recommend-title {
|
||||
writing-mode: vertical-lr;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
letter-spacing: 4px;
|
||||
|
||||
.title-icon {
|
||||
font-size: 24px;
|
||||
animation: sparkle 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
padding: 10px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.recommend-right {
|
||||
flex: 1;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||||
|
||||
:deep(.recommend-tabs) {
|
||||
.el-tabs__header {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.el-tabs__nav-wrap::after {
|
||||
background-color: #e8eaed;
|
||||
}
|
||||
|
||||
.el-tabs__item {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: #606266;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
color: #409eff;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.el-tabs__active-bar {
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, #409eff 0%, #66b1ff 100%);
|
||||
}
|
||||
}
|
||||
|
||||
.recommend-list {
|
||||
min-height: 180px;
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 20px;
|
||||
color: #909399;
|
||||
|
||||
.empty-icon {
|
||||
font-size: 48px;
|
||||
margin-bottom: 16px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 15px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.list-items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
.recommend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 14px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
border-left: 3px solid transparent;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(90deg, #e3f2fd 0%, #f5f5f5 100%);
|
||||
border-left-color: #409eff;
|
||||
transform: translateX(4px);
|
||||
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.15);
|
||||
|
||||
.item-arrow {
|
||||
transform: translateX(4px);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.item-number {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #909399;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.item-link {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
text-decoration: none;
|
||||
color: #303133;
|
||||
gap: 12px;
|
||||
|
||||
.item-title {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
|
||||
.item-arrow {
|
||||
font-size: 16px;
|
||||
color: #409eff;
|
||||
opacity: 0;
|
||||
transition: all 0.3s ease;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sparkle {
|
||||
0%, 100% {
|
||||
transform: scale(1) rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.2) rotate(180deg);
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式设计
|
||||
@media (max-width: 768px) {
|
||||
.ai-recommend {
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
|
||||
.recommend-left {
|
||||
min-width: auto;
|
||||
|
||||
.recommend-title {
|
||||
writing-mode: horizontal-tb;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1 +1,2 @@
|
||||
export { default as AIAgent} from './AIAgent.vue';
|
||||
export { default as AIAgent} from './AIAgent.vue';
|
||||
export { default as AIRecommend} from './AIRecommend.vue';
|
||||
Reference in New Issue
Block a user