前端
This commit is contained in:
16
frontend/app/web-gold/src/views/trends/Copywriting.vue
Normal file
16
frontend/app/web-gold/src/views/trends/Copywriting.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<h2 class="text-xl font-bold">热点-文案创作</h2>
|
||||
<p class="text-gray-600 text-sm">入口参数预填自热度/预测面板。</p>
|
||||
<div class="bg-white p-4 rounded shadow">结果编辑器与模块一共享逻辑。</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
642
frontend/app/web-gold/src/views/trends/Forecast.vue
Normal file
642
frontend/app/web-gold/src/views/trends/Forecast.vue
Normal file
@@ -0,0 +1,642 @@
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import TikhubService, { InterfaceType, MethodType, ParamType } from '@/api/tikhub'
|
||||
|
||||
// 定义组件名称
|
||||
defineOptions({
|
||||
name: 'ForecastView'
|
||||
})
|
||||
|
||||
// 平台列表
|
||||
// const platforms = [
|
||||
// { id: 'douyin', name: '抖音', color: '#FE2C55' }
|
||||
// ]
|
||||
|
||||
// const activePlatform = ref('douyin')
|
||||
|
||||
// 搜索关键词
|
||||
const searchKeyword = ref('')
|
||||
|
||||
// 加载状态
|
||||
const isLoading = ref(false)
|
||||
|
||||
// 热点列表数据(模拟数据)
|
||||
const hotTopics = ref([])
|
||||
|
||||
// 选中的热点
|
||||
const selectedTopic = ref(null)
|
||||
|
||||
// 右侧详细信息
|
||||
const topicDetails = reactive({
|
||||
title: '',
|
||||
copywriting: '',
|
||||
stylePrompt: ''
|
||||
})
|
||||
|
||||
// 点击创作按钮
|
||||
const handleCreate = (topic) => {
|
||||
selectedTopic.value = topic.id
|
||||
topicDetails.title = topic.title
|
||||
topicDetails.copywriting = ''
|
||||
topicDetails.stylePrompt = ''
|
||||
}
|
||||
|
||||
// 立即生成
|
||||
const handleGenerate = () => {
|
||||
console.log('生成内容', topicDetails)
|
||||
// TODO: 调用生成API
|
||||
}
|
||||
|
||||
// 切换平台
|
||||
// const switchPlatform = (platformId) => {
|
||||
// activePlatform.value = platformId
|
||||
// selectedTopic.value = null
|
||||
// topicDetails.title = ''
|
||||
// topicDetails.copywriting = ''
|
||||
// topicDetails.stylePrompt = ''
|
||||
// }
|
||||
|
||||
// 搜索热点
|
||||
const handleSearch = async () => {
|
||||
if (!searchKeyword.value.trim()) {
|
||||
message.warning('请输入搜索关键词')
|
||||
return
|
||||
}
|
||||
|
||||
isLoading.value = true
|
||||
try {
|
||||
const response = await TikhubService.postTikHup(
|
||||
{
|
||||
type: InterfaceType.DOUYIN_SEARCH_GENERAL_SEARCH, // 使用网页端通用搜索结果接口
|
||||
methodType: MethodType.POST,
|
||||
urlParams: {
|
||||
keyword: searchKeyword.value.trim(),
|
||||
sort_type: '1',
|
||||
offset: 0,
|
||||
count: 20,
|
||||
publish_time: 7
|
||||
},
|
||||
paramType: ParamType.JSON
|
||||
}
|
||||
)
|
||||
// 处理搜索结果
|
||||
const searchResults = response.data.data.map(el => el.aweme_info).filter(el => el).map((item, index) => ({
|
||||
id: hotTopics.value.length + index + 1,
|
||||
title: item.desc || '无标题',
|
||||
videoId: item.aweme_id,
|
||||
videoUrl: `https://www.douyin.com/video/${item.aweme_id}`, // 视频链接
|
||||
author: item.author.nickname,
|
||||
// 统计数据
|
||||
playCount: item.statistics?.play_count || 0, // 播放量
|
||||
diggCount: item.statistics?.digg_count || 0, // 点赞量(喜欢)
|
||||
commentCount: item.statistics?.comment_count || 0, // 评论数
|
||||
shareCount: item.statistics?.share_count || 0, // 分享数
|
||||
collectCount: item.statistics?.collect_count || 0, // 收藏数
|
||||
}))
|
||||
|
||||
// 将搜索结果添加到列表顶部
|
||||
hotTopics.value = [...searchResults, ...hotTopics.value]
|
||||
message.success(`找到 ${searchResults.length} 个结果`)
|
||||
|
||||
} catch (error) {
|
||||
console.error('搜索失败:', error)
|
||||
message.error(error?.message || '搜索失败,请稍后重试')
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 回车搜索
|
||||
const handleSearchKeypress = (event) => {
|
||||
if (event.key === 'Enter' && !isLoading.value) {
|
||||
handleSearch()
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化数字,将大数字转换为万等单位
|
||||
const formatNumber = (num) => {
|
||||
if (!num) return '0'
|
||||
if (num >= 10000) {
|
||||
return (num / 10000).toFixed(1) + 'w'
|
||||
}
|
||||
return num.toString()
|
||||
}
|
||||
|
||||
// 打开视频
|
||||
const openVideo = (topic, event) => {
|
||||
event.stopPropagation() // 阻止事件冒泡,避免触发热点选择
|
||||
if (topic.videoUrl) {
|
||||
window.open(topic.videoUrl, '_blank')
|
||||
}
|
||||
}
|
||||
|
||||
// 截断标题,限制最大长度
|
||||
const truncateTitle = (title, maxLength = 30) => {
|
||||
if (!title) return ''
|
||||
if (title.length <= maxLength) return title
|
||||
return title.substring(0, maxLength) + '...'
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="fc-page">
|
||||
<div class="fc-grid">
|
||||
<!-- 左侧:平台栏目和热点列表 -->
|
||||
<section class="fc-left">
|
||||
<div class="fc-title">热点预测</div>
|
||||
|
||||
<!-- 平台选择 -->
|
||||
<!-- <div class="platform-tabs">
|
||||
<div class="flex space-x-2">
|
||||
<button
|
||||
v-for="platform in platforms"
|
||||
:key="platform.id"
|
||||
@click="switchPlatform(platform.id)"
|
||||
:class="['platform-tab', activePlatform === platform.id ? 'platform-tab--active' : 'platform-tab--inactive']"
|
||||
:style="activePlatform === platform.id ? { background: platform.color } : {}"
|
||||
>
|
||||
{{ platform.name }}
|
||||
</button>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- 搜索框 -->
|
||||
<div class="search-box">
|
||||
<div class="search-input-wrapper">
|
||||
<input v-model="searchKeyword" type="text" placeholder="输入关键词搜索抖音热点..." class="search-input"
|
||||
:disabled="isLoading" @keypress="handleSearchKeypress" />
|
||||
<button @click="handleSearch" :disabled="isLoading || !searchKeyword.trim()" class="search-btn"
|
||||
:class="{ 'search-btn--loading': isLoading }">
|
||||
<svg v-if="!isLoading" class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
<svg v-else class="w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 热点列表 -->
|
||||
<div class="topic-list">
|
||||
<div class="p-2">
|
||||
<!-- 空状态 -->
|
||||
<div v-if="hotTopics.length === 0" class="empty-state">
|
||||
<svg class="empty-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
||||
<circle cx="9" cy="9" r="3"></circle>
|
||||
</svg>
|
||||
<p class="empty-text">搜索抖音热点内容</p>
|
||||
<p class="empty-hint">输入关键词,开始搜索热门内容</p>
|
||||
</div>
|
||||
|
||||
<!-- 热点列表 -->
|
||||
<div v-for="topic in hotTopics" :key="topic.id" @click="handleCreate(topic)" class="topic-item"
|
||||
:class="{ 'topic-item--selected': selectedTopic === topic.id }">
|
||||
<div class="flex flex-col flex-1 min-w-0">
|
||||
<div class="flex items-center mb-2">
|
||||
<span class="topic-number">{{ topic.id }}</span>
|
||||
<span
|
||||
v-if="topic.videoUrl"
|
||||
@click="openVideo(topic, $event)"
|
||||
class="flex-1 topic-title topic-title--clickable"
|
||||
:title="topic.title"
|
||||
>
|
||||
{{ truncateTitle(topic.title) }}
|
||||
</span>
|
||||
<span v-else class="flex-1 topic-title" :title="topic.title">
|
||||
{{ truncateTitle(topic.title) }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- 统计信息 -->
|
||||
<div v-if="topic.diggCount || topic.playCount || topic.commentCount || topic.collectCount || topic.shareCount" class="flex flex-wrap items-center gap-4 text-xs text-gray-500 topic-stats">
|
||||
<span v-if="topic.playCount" class="stat-item">
|
||||
<svg class="inline w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" />
|
||||
</svg>
|
||||
播放 {{ formatNumber(topic.playCount) }}
|
||||
</span>
|
||||
<span v-if="topic.diggCount" class="stat-item">
|
||||
<svg class="inline w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M2 10.5a1.5 1.5 0 113 0v6a1.5 1.5 0 01-3 0v-6zM6 10.333v5.834a1 1 0 001.555.832L12 13.202a5 5 0 001.196-.599l.707-.707a1 1 0 00.293-.707V8.465a1 1 0 00-1.707-.707L12 8.465V5a2 2 0 00-2-2H7a1 1 0 000 2h3v3z" />
|
||||
</svg>
|
||||
点赞 {{ formatNumber(topic.diggCount) }}
|
||||
</span>
|
||||
<span v-if="topic.commentCount" class="stat-item">
|
||||
<svg class="inline w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M18 10c0 3.866-3.582 7-8 7a8.841 8.841 0 01-4.083-.98L2 17l1.338-3.123C2.493 12.767 2 11.434 2 10c0-3.866 3.582-7 8-7s8 3.134 8 7zM7 9H5v2h2V9zm8 0h-2v2h2V9zM9 9h2v2H9V9z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
评论 {{ formatNumber(topic.commentCount) }}
|
||||
</span>
|
||||
<span v-if="topic.collectCount" class="stat-item">
|
||||
<svg class="inline w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M3.172 5.172a4 4 0 015.656 0L10 6.343l1.172-1.171a4 4 0 115.656 5.656L10 17.657l-6.828-6.829a4 4 0 010-5.656z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
收藏 {{ formatNumber(topic.collectCount) }}
|
||||
</span>
|
||||
<span v-if="topic.shareCount" class="stat-item">
|
||||
<svg class="inline w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M15 8a3 3 0 10-2.977-2.63l-4.94 2.47a3 3 0 100 4.319l4.94 2.47a3 3 0 10.895-1.789l-4.94-2.47a3.027 3.027 0 000-.74l4.94-2.47C13.456 7.68 14.19 8 15 8z" />
|
||||
</svg>
|
||||
分享 {{ formatNumber(topic.shareCount) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<button @click.stop="handleCreate(topic)" class="create-btn">
|
||||
创作
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 右侧:详细信息 -->
|
||||
<section class="fc-right">
|
||||
<div class="fc-title">创作详情</div>
|
||||
|
||||
<div class="detail-content">
|
||||
<!-- 热点标题 -->
|
||||
<div>
|
||||
<label class="form-label">热点标题</label>
|
||||
<input v-model="topicDetails.title" type="text" placeholder="选择左侧热点或手动输入标题" class="form-input" />
|
||||
</div>
|
||||
|
||||
<!-- 文案 -->
|
||||
<div>
|
||||
<label class="form-label">文案</label>
|
||||
<textarea v-model="topicDetails.copywriting" rows="5" placeholder="输入或AI生成文案内容"
|
||||
class="form-textarea"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- 风格提示词 -->
|
||||
<div>
|
||||
<label class="form-label">风格提示词</label>
|
||||
<input v-model="topicDetails.stylePrompt" type="text" placeholder="例如:专业、权威、温暖、幽默等" class="form-input" />
|
||||
</div>
|
||||
|
||||
<!-- 立即生成按钮 -->
|
||||
<div class="pt-2">
|
||||
<button @click="handleGenerate" class="generate-btn">
|
||||
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd"
|
||||
d="M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10A1 1 0 018 18v-5H4a1 1 0 01-.82-1.573l7-10a1 1 0 011.12-.38z"
|
||||
clip-rule="evenodd" />
|
||||
</svg>
|
||||
立即生成
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.fc-page {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.fc-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.fc-grid {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.fc-left,
|
||||
.fc-right {
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-card);
|
||||
box-shadow: var(--shadow-inset-card);
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.fc-title {
|
||||
font-size: 14px;
|
||||
color: var(--color-text-secondary);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* 平台标签区域 */
|
||||
.platform-tabs {
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.platform-tab {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
border-radius: 8px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.platform-tab--active {
|
||||
color: white;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.platform-tab--inactive {
|
||||
background: transparent;
|
||||
color: var(--color-text-secondary);
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.platform-tab--inactive:hover {
|
||||
background: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* 搜索框 */
|
||||
.search-box {
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.search-input-wrapper {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
font-size: 14px;
|
||||
color: var(--color-text);
|
||||
background: var(--color-bg);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 6px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-primary);
|
||||
box-shadow: 0 0 0 3px rgba(0, 176, 48, 0.1);
|
||||
}
|
||||
|
||||
.search-input:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.search-input::placeholder {
|
||||
color: var(--color-text-secondary);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
padding: 8px 16px;
|
||||
background: var(--color-primary);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s;
|
||||
min-width: 48px;
|
||||
}
|
||||
|
||||
.search-btn:hover:not(:disabled) {
|
||||
background: var(--color-primary);
|
||||
filter: brightness(1.1);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.search-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.search-btn--loading {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* 热点列表 */
|
||||
.topic-list {
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.topic-list::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.topic-list::-webkit-scrollbar-track {
|
||||
background: var(--color-bg);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.topic-list::-webkit-scrollbar-thumb {
|
||||
background: var(--color-border);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.topic-list::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 80px 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
color: var(--color-text-secondary);
|
||||
opacity: 0.4;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.empty-hint {
|
||||
font-size: 14px;
|
||||
color: var(--color-text-secondary);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* 热点项 */
|
||||
.topic-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
padding: 12px;
|
||||
margin-bottom: 8px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.topic-item:hover {
|
||||
background: var(--color-bg);
|
||||
}
|
||||
|
||||
.topic-item--selected {
|
||||
background: var(--color-bg);
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.topic-number {
|
||||
flex-shrink: 0;
|
||||
margin-right: 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.topic-title {
|
||||
font-size: 14px;
|
||||
color: var(--color-text);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.topic-title--clickable {
|
||||
cursor: pointer;
|
||||
color: #1890ff;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.topic-title--clickable:hover {
|
||||
text-decoration: underline;
|
||||
color: #40a9ff;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* 统计信息 */
|
||||
.topic-stats {
|
||||
padding-left: 32px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.stat-item svg {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* 创作按钮 */
|
||||
.create-btn {
|
||||
margin-left: auto;
|
||||
padding: 6px 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: white;
|
||||
background: var(--color-primary);
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 8px rgba(0, 176, 48, 0.2);
|
||||
transition: all 0.2s;
|
||||
flex-shrink: 0;
|
||||
align-self: flex-start;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.create-btn:hover {
|
||||
box-shadow: 0 0 12px rgba(0, 176, 48, 0.5);
|
||||
filter: brightness(1.1);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* 详情内容 */
|
||||
.detail-content {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.form-input,
|
||||
.form-textarea {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
color: var(--color-text);
|
||||
background: var(--color-bg);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 6px;
|
||||
transition: all 0.2s;
|
||||
font-size: 14px;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.form-input::placeholder,
|
||||
.form-textarea::placeholder {
|
||||
color: var(--color-text-secondary);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.form-input:focus,
|
||||
.form-textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-primary);
|
||||
box-shadow: 0 0 0 3px rgba(0, 176, 48, 0.1);
|
||||
}
|
||||
|
||||
.form-textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.generate-btn {
|
||||
width: 100%;
|
||||
padding: 8px 24px;
|
||||
background: var(--color-primary);
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 8px rgba(0, 176, 48, 0.3);
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.generate-btn:hover {
|
||||
box-shadow: 0 0 12px rgba(0, 176, 48, 0.4);
|
||||
filter: brightness(1.05);
|
||||
transform: scale(1.01);
|
||||
}
|
||||
</style>
|
||||
217
frontend/app/web-gold/src/views/trends/Heat.vue
Normal file
217
frontend/app/web-gold/src/views/trends/Heat.vue
Normal file
@@ -0,0 +1,217 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
// 定义组件名称
|
||||
defineOptions({
|
||||
name: 'HeatAnalysis'
|
||||
})
|
||||
|
||||
const keywords = ref('')
|
||||
const platform = ref('')
|
||||
const timeWindow = ref('')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="min-h-screen bg-gray-50 p-6">
|
||||
<div class="max-w-7xl mx-auto space-y-6">
|
||||
<!-- 页面标题 -->
|
||||
<div class="text-center">
|
||||
<h1 class="text-3xl font-bold text-gray-900 mb-2">热度趋势分析</h1>
|
||||
<p class="text-gray-600">实时监控关键词在各大平台的热度变化</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<!-- 查询参数面板 -->
|
||||
<section class="lg:col-span-1">
|
||||
<div class="bg-white rounded-xl shadow-lg p-6 border border-gray-100">
|
||||
<div class="mb-4">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-4 flex items-center">
|
||||
<svg class="w-5 h-5 mr-2 text-purple-600" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
查询设置
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- 关键词输入 -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">关键词</label>
|
||||
<div class="relative">
|
||||
<input
|
||||
v-model="keywords"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-3 text-gray-900 placeholder-gray-500 focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-all duration-200 bg-gray-50 hover:bg-white"
|
||||
placeholder="输入关键词,多个用逗号分隔"
|
||||
type="text"
|
||||
/>
|
||||
<div class="absolute inset-y-0 right-0 flex items-center pr-3">
|
||||
<svg class="w-5 h-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500 mt-1">支持多个关键词,用逗号分隔</p>
|
||||
</div>
|
||||
|
||||
<!-- 平台和时间选择 -->
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">平台选择</label>
|
||||
<select
|
||||
v-model="platform"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-3 text-gray-900 focus:ring-2 focus:ring-purple-500 focus:border-transparent transition-all duration-200 bg-gray-50 hover:bg-white"
|
||||
>
|
||||
<option value="">请选择平台</option>
|
||||
<option value="weibo">微博</option>
|
||||
<option value="douyin">抖音</option>
|
||||
<option value="xiaohongshu">小红书</option>
|
||||
<option value="zhihu">知乎</option>
|
||||
<option value="toutiao">今日头条</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">时间窗口</label>
|
||||
<select
|
||||
v-model="timeWindow"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-3 text-gray-900 focus:ring-2 Focus:ring-purple-500 focus:border-transparent transition-all duration-200 bg-gray-50 hover:bg-white"
|
||||
>
|
||||
<option value="">请选择时间范围</option>
|
||||
<option value="1h">最近1小时</option>
|
||||
<option value="6h">最近6小时</option>
|
||||
<option value="24h">最近24小时</option>
|
||||
<option value="7d">最近7天</option>
|
||||
<option value="30d">最近30天</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 查询按钮 -->
|
||||
<button class="w-full bg-gradient-to-r from-purple-600 to-purple-700 hover:from-purple-700 hover:to-purple-800 text-white font-semibold py-3 px-6 rounded-lg shadow-md hover:shadow-lg transform hover:scale-[1.02] transition-all duration-200 flex items-center justify-center">
|
||||
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
开始分析
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 分析结果面板 -->
|
||||
<section class="lg:col-span-2">
|
||||
<div class="bg-white rounded-xl shadow-lg border border-gray-100">
|
||||
<!-- 看板头部 -->
|
||||
<div class="px-6 py-4 border-b border-gray-100">
|
||||
<h3 class="text-lg font-semibold text-gray-900 flex items-center">
|
||||
<svg class="w-5 h-5 mr-2 text-purple-600" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M2 11a1 1 0 011-1h2a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1v-5zM8 7a1 1 0 011-1h2a1 1 0 011 1v9a1 1 0 01-1 1H9a1 1 0 01-1-1V7zM14 4a1 1 0 011-1h2a1 1 0 011 1v12a1 1 0 01-1 1h-2a1 1 0 01-1-1V4z" />
|
||||
</svg>
|
||||
热度趋势看板
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<!-- 图表内容区域 -->
|
||||
<div class="p-6">
|
||||
<!-- 占位内容 -->
|
||||
<div class="flex items-center justify-center h-96 border-2 border-dashed border-gray-300 rounded-lg bg-gray-50">
|
||||
<div class="text-center">
|
||||
<svg class="w-16 h-16 text-gray-400 mx-auto mb-4" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M3 4a1 1 0 011-1h12a1 1 0 011 1v16a1 1 0 01-1 1h-3a1 1 0 01-1-1v-6a1 1 0 00-1-1H9a1 1 0 00-1 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1V4zm2 1v14h2v-6a1 1 0 011-1h4a1 1 0 011 1v6h2V5H5z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
<p class="text-lg font-medium text-gray-900 mb-2">正在准备数据...</p>
|
||||
<p class="text-gray-600">请先设置查询参数,然后点击"开始分析"查看趋势图表</p>
|
||||
<div class="mt-4 space-y-2">
|
||||
<p class="text-sm text-gray-500">📈 热度折线图</p>
|
||||
<p class="text-sm text-gray-500">📊 相关话题分布</p>
|
||||
<p class="text-sm text-gray-500">🏆 热门排行榜</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 功能特性提示 -->
|
||||
<div class="mt-6 grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div class="text-center p-4 bg-purple-50 rounded-lg">
|
||||
<div class="w-8 h-8 bg-purple-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||||
<svg class="w-4 h-4 text-purple-600" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M2 11a1 1 0 011-1h2a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1v-5zM8 7a1 1 0 011-1h2a1 1 0 011 1v9a1 1 0 01-1 1H9a1 1 0 01-1-1V7zM14 4a1 1 0 011-1h2a1 1 0 011 1v12a1 1 0 01-1 1h-2a1 1 0 01-1-1V4z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h4 class="font-medium text-gray-900">趋势分析</h4>
|
||||
<p class="text-xs text-gray-600">实时跟踪关键词热度变化</p>
|
||||
</div>
|
||||
<div class="text-center p-4 bg-blue-50 rounded-lg">
|
||||
<div class="w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||||
<svg class="w-4 h-4 text-blue-600" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M9 2a1 1 0 000 2h2a1 1 0 100-2H9z" />
|
||||
<path fill-rule="evenodd" d="M4 5a2 2 0 012-2v1a1 1 0 102 0V3a2 2 0 012 2v6a2 2 0 01-2 2H6a2 2 0 01-2-2V5zm3 4a1 1 0 000 2h.01a1 1 0 100-2H7zm3 0a1 1 0 000 2h3a1 1 0 100-2h-3z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<h4 class="font-medium text-gray-900">智能预测</h4>
|
||||
<p class="text-xs text-gray-600">AI预测未来热度走势</p>
|
||||
</div>
|
||||
<div class="text-center p-4 bg-green-50 rounded-lg">
|
||||
<div class="w-8 h-8 bg-green-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||||
<svg class="w-4 h-4 text-green-600" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M3 17a1 1 0 011-1h12a1 1 0 011 1v.5a1.5 1.5 0 01-1.5 1.5h-11A1.5 1.5 0 012 17.5V17zm1.5-2A1.5 1.5 0 003 16.5v.5h14v-.5a1.5 1.5 0 00-1.5-1.5h-11z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<h4 class="font-medium text-gray-900">多维分析</h4>
|
||||
<p class="text-xs text-gray-600">跨平台数据对比分析</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* 自定义滚动条样式 */
|
||||
.scrollbar-thin::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.scrollbar-thin::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.scrollbar-thin::-webkit-scrollbar-thumb {
|
||||
background: #c1c1c1;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.scrollbar-thin::-webkit-scrollbar-thumb:hover {
|
||||
background: #a8a8a8;
|
||||
}
|
||||
|
||||
/* 平滑过渡效果 */
|
||||
.fade-in {
|
||||
animation: fadeIn 0.5s ease-in;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮悬停效果增强 */
|
||||
button:hover {
|
||||
box-shadow: 0 10px 25px -2px rgba(147, 51, 234, 0.5);
|
||||
}
|
||||
|
||||
/* 输入框焦点效果 */
|
||||
input:focus, select:focus {
|
||||
box-shadow: 0 0 0 3px rgba(147, 51, 234, 0.1);
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user