以下是app.js:
const { createApp } = Vue;
createApp({
data() {
return {
products: [],
isLoading: true,
// 冷知识轮播数据
dailyTrivias: [],
currentTriviaIndex: 0,
autoPlayInterval: null,
API_BASE: 'http://127.0.0.1:8000'
}
},
async mounted() {
await this.loadProducts();
await this.loadDailyTrivias();
this.startAutoPlay();
},
methods: {
async loadProducts() {
try {
const response = await fetch('http://127.0.0.1:8000/api/specialties/');
this.products = await response.json();
// 强制修改图片URL为绝对路径
this.products = this.products.map(product => {
if (product.main_image_url) {
product.main_image_url = 'http://127.0.0.1:8000' + product.main_image_url;
}
if (product.recipes) {
product.recipes = product.recipes.map(recipe => {
if (recipe.image_url) {
recipe.image_url = 'http://127.0.0.1:8000' + recipe.image_url;
}
return recipe;
});
}
return product;
});
} catch (error) {
console.error('加载特产失败:', error);
this.products = [];
} finally {
this.isLoading = false;
}
},
async loadDailyTrivias() {
try {
console.log('正在加载每日冷知识...');
const response = await fetch('http://127.0.0.1:8000/api/daily-trivias/');
if (response.ok) {
this.dailyTrivias = await response.json();
console.log('冷知识加载成功:', this.dailyTrivias);
} else {
console.warn('冷知识API请求失败,使用默认数据');
this.dailyTrivias = this.getDefaultTrivias();
}
} catch (error) {
console.error('加载冷知识失败:', error);
this.dailyTrivias = this.getDefaultTrivias();
}
},
getDefaultTrivias() {
// 默认冷知识数据
return [
{
icon: "🧂",
category: "闽清糟菜",
content: "非遗技艺:闽清糟菜采用传统陶缸发酵工艺,2017年列入福州非遗"
},
{
icon: "🤖",
category: "创新故事",
content: "机器人主厨:全国首家机器人制作闽清美食的数字化餐厅"
},
{
icon: "🌿",
category: "闽清糟菜",
content: "健康价值:富含乳酸菌和氨基酸,是天然的益生元食品"
}
];
},
nextTrivia() {
this.currentTriviaIndex = (this.currentTriviaIndex + 1) % this.dailyTrivias.length;
this.resetAutoPlay();
},
prevTrivia() {
this.currentTriviaIndex = (this.currentTriviaIndex - 1 + this.dailyTrivias.length) % this.dailyTrivias.length;
this.resetAutoPlay();
},
startAutoPlay() {
if (this.dailyTrivias.length > 1) {
this.autoPlayInterval = setInterval(() => {
this.nextTrivia();
}, 5000); // 5秒自动切换
}
},
resetAutoPlay() {
if (this.autoPlayInterval) {
clearInterval(this.autoPlayInterval);
this.startAutoPlay();
}
},
showDetail(product) {
window.location.href = `detail.html?id=${product.id}`;
},
closeModal() {
this.selectedProduct = null;
}
},
beforeUnmount() {
// 清理定时器
if (this.autoPlayInterval) {
clearInterval(this.autoPlayInterval);
}
}
}).mount('#app');
以下是index。html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>闽货优品 - 福建特产文化推广</title>
<link rel="stylesheet" href="style.css">
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
<!-- 顶部导航栏 -->
<nav class="main-nav">
<div class="container">
<a href="index.html" class="nav-logo">🍜 闽货优品</a>
<div class="nav-links">
<a href="index.html" class="nav-link active">首页</a>
<a href="products.html" class="nav-link">特产档案</a>
<a href="craftsmen.html" class="nav-link">匠人故事</a>
<a href="videos.html" class="nav-link">短视频</a>
<a href="cold-knowledge.html" class="nav-link">冷知识</a>
</div>
</div>
</nav>
<!-- 文化标语 -->
<section class="hero-banner">
<div class="container">
<h1 class="hero-title">味道,是故乡最深的记忆</h1>
<p class="hero-subtitle">探寻福建非遗美食,传承千年文化韵味</p>
</div>
</section>
<!-- 文化冷知识 -->
<!-- 在 index.html 的文化冷知识部分 -->
<section class="cultural-trivia-section">
<div class="container">
<div class="section-header">
<span class="section-icon">🎯</span>
<h2 class="section-title">每日文化冷知识</h2>
<p class="section-subtitle">每天发现闽清非遗的新鲜故事</p>
</div>
<!-- 冷知识轮播 -->
<!-- 冷知识轮播 -->
<div class="trivia-carousel">
<div class="carousel-container">
<div v-for="(trivia, index) in dailyTrivias"
:key="index"
:class="['carousel-item', { active: currentTriviaIndex === index }]">
<div class="trivia-content">
<!-- 图标和分类同行 -->
<div class="trivia-header">
<span class="trivia-icon">{{ trivia.icon }}</span>
<h3 class="trivia-category">{{ trivia.category }}</h3>
</div>
<p>{{ trivia.content }}</p>
</div>
</div>
</div>
<!-- 轮播指示器 -->
<div class="carousel-indicators" v-if="dailyTrivias.length > 1">
<button v-for="(_, index) in dailyTrivias"
:key="index"
:class="['indicator', { active: currentTriviaIndex === index }]"
@click="currentTriviaIndex = index">
</button>
</div>
<!-- 轮播控制按钮 -->
<button class="carousel-btn prev" @click="prevTrivia" v-if="dailyTrivias.length > 1">‹</button>
<button class="carousel-btn next" @click="nextTrivia" v-if="dailyTrivias.length > 1">›</button>
</div>
<!-- 特产档案 -->
<section class="products-section">
<div class="container">
<h2 class="section-title">🍜 特色美食档案</h2>
<!-- 加载状态 -->
<div v-if="isLoading" class="loading">
<p>正在加载特产数据...</p>
</div>
<!-- 产品网格 -->
<div v-else class="products-grid">
<div v-for="product in products" :key="product.id" class="product-card">
<!-- 添加产品主图 -->
<img v-if="product.main_image_url"
:src="'http://127.0.0.1:8000' + product.main_image_url"
:alt="product.product_name"
class="product-image">
<div class="product-header">
<h3>{{ product.product_name }}</h3>
<span class="category">{{ product.category }}</span>
</div>
<div class="product-origin">📍 {{ product.origin }}</div>
<div class="product-taste">👅 {{ product.taste_profile }}</div>
<button class="detail-btn" @click="showDetail(product)">查看详情</button>
</div>
</div>
<!-- 空状态 -->
<div v-if="!isLoading && products.length === 0" class="no-data">
<p>暂无特产数据</p>
</div>
<!-- 查看更多 -->
<div class="more-section">
<a href="products.html" class="btn-primary">浏览全部特产档案</a>
</div>
</div>
</section>
<footer class="footer">
<div class="container">
<p>闽货优品 - 传承福建美食文化 © 2024</p>
</div>
</footer>
</div>
<script src="app.js"></script>
</body>
</html>
以下是dedtail.js:
const { createApp } = Vue;
createApp({
data() {
return {
product: null,
isLoading: true,
activeTab: 'history',
tabs: [
{ id: 'history', name: '历史故事', icon: '📖' },
{ id: 'naming', name: '名字由来', icon: '🏷️' },
{ id: 'materials', name: '原料配方', icon: '🥬' },
{ id: 'process', name: '制作工艺', icon: '👨🍳' },
{ id: 'usage', name: '食用方法', icon: '🍽️' },
{ id: 'nutrition', name: '营养价值', icon: '📊' },
{ id: 'culture', name: '文化意义', icon: '❤️' },
{ id: 'recipes', name: '经典做法', icon: '🍳' }
],
recipes: [],
recipesLoading: false
};
},
computed: {
processSteps() {
if (!this.product || !this.product.production_process) return [];
return this.product.production_process.split(/[;。]/).filter(step => step.trim());
}
},
watch: {
activeTab(newTab) {
if (newTab === 'recipes' && this.recipes.length === 0 && !this.recipesLoading) {
this.loadRecipes();
}
}
},
async mounted() {
await this.loadProduct();
},
methods: {
async loadProduct() {
try {
const urlParams = new URLSearchParams(window.location.search);
const productId = urlParams.get('id') || 2;
const response = await fetch(`http://127.0.0.1:8000/api/specialties/${productId}/`);
if (!response.ok) {
throw new Error('产品不存在');
}
this.product = await response.json();
} catch (error) {
console.error('加载产品详情失败:', error);
} finally {
this.isLoading = false;
}
},
async loadRecipes() {
if (!this.product) return;
this.recipesLoading = true;
try {
const productId = this.product.id;
if (this.product.recipes && this.product.recipes.length > 0) {
this.recipes = this.product.recipes;
} else {
const response = await fetch(`http://127.0.0.1:8000/api/specialties/${productId}/recipes/`);
if (response.ok) {
this.recipes = await response.json();
}
}
} catch (error) {
console.error('加载菜谱失败:', error);
} finally {
this.recipesLoading = false;
}
},
getDifficultyText(difficulty) {
const difficultyMap = {
'easy': '简单',
'medium': '中等',
'hard': '困难',
'简单': '简单',
'中等': '中等',
'困难': '困难'
};
return difficultyMap[difficulty] || difficulty;
},
formatText(text) {
if (!text) return '';
return text.split('\n').filter(line => line.trim()).join('\n\n');
}
}
}).mount('#app');
以下是detail.html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>产品详情 - 闽货优品</title>
<link rel="stylesheet" href="style.css">
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
<!-- 导航栏 -->
<header class="header">
<div class="container">
<div class="nav-header">
<a href="index.html" class="back-btn">← 返回首页</a>
<h1 class="logo">🍜 闽货优品</h1>
</div>
</div>
</header>
<!-- 加载状态 -->
<div v-if="isLoading" class="loading">
<p>正在加载产品详情...</p>
</div>
<!-- 产品详情 -->
<div v-else-if="product" class="product-detail">
<div class="container">
<!-- 产品头部 -->
<section class="product-header">
<div class="product-hero">
<img v-if="product.main_image_url"
:src="product.main_image_url"
:alt="product.product_name"
class="hero-image">
<div class="product-basic-info">
<h1 class="product-title">{{ product.product_name }}</h1>
<div class="product-meta">
<span class="category">{{ product.category }}</span>
<span class="origin">📍 {{ product.origin }}</span>
</div>
<p class="product-taste">{{ product.taste_profile }}</p>
</div>
</section>
<!-- 标签页导航 -->
<nav class="tabs">
<button
v-for="tab in tabs"
:key="tab.id"
:class="['tab-btn', { active: activeTab === tab.id }]"
@click="activeTab = tab.id"
>
<span class="tab-icon">{{ tab.icon }}</span>
{{ tab.name }}
</button>
</nav>
<!-- 标签内容 -->
<div class="tab-content">
<!-- 历史故事 -->
<div v-if="activeTab === 'history'" class="tab-panel">
<h2>📖 历史故事</h2>
<div class="content-box">
<p>{{ product.history }}</p>
</div>
</div>
<!-- 名字由来 -->
<div v-if="activeTab === 'naming'" class="tab-panel">
<h2>🏷️ 名字由来</h2>
<div class="content-box">
<p>{{ product.naming_origin }}</p>
</div>
</div>
<!-- 原料配方 -->
<div v-if="activeTab === 'materials'" class="tab-panel">
<h2>🥬 原料配方</h2>
<div class="content-box">
<p>{{ product.raw_materials }}</p>
</div>
</div>
<!-- 制作工艺 -->
<div v-if="activeTab === 'process'" class="tab-panel">
<h2>👨🍳 制作工艺</h2>
<div class="content-box">
<div class="process-steps">
<div v-for="(step, index) in processSteps"
:key="index"
class="process-step">
<span class="step-number">{{ index + 1 }}</span>
<span class="step-text">{{ step }}</span>
</div>
</div>
</div>
</div>
<!-- 食用方法 -->
<div v-if="activeTab === 'usage'" class="tab-panel">
<h2>🍽️ 食用方法</h2>
<div class="content-box">
<p>{{ product.culinary_uses }}</p>
</div>
</div>
<!-- 营养价值 -->
<div v-if="activeTab === 'nutrition'" class="tab-panel">
<h2>📊 营养价值</h2>
<div class="content-box">
<p>{{ product.nutritional_value }}</p>
</div>
</div>
<!-- 文化意义 -->
<div v-if="activeTab === 'culture'" class="tab-panel">
<h2>❤️ 文化意义</h2>
<div class="content-box">
<p>{{ product.cultural_significance }}</p>
</div>
</div>
<!-- 经典做法 -->
<div v-if="activeTab === 'recipes'" class="tab-panel">
<h2>🍳 经典做法</h2>
<div class="content-box">
<div v-if="recipesLoading" class="loading-state">
<p>正在加载菜谱...</p>
</div>
<div v-else-if="recipes.length" class="recipes-list">
<div v-for="recipe in recipes" :key="recipe.id" class="recipe-card">
<!-- 添加菜谱图片 -->
<img v-if="recipe.image_url"
:src="recipe.image_url"
:alt="recipe.title"
class="recipe-image">
<h3 class="recipe-title">{{ recipe.title }}</h3>
<div class="recipe-meta">
<span class="difficulty">难度:{{ getDifficultyText(recipe.difficulty) }}</span>
<span class="cooking-time">时间:{{ recipe.cooking_time }}</span>
<span class="serving">份量:{{ recipe.serving }}</span>
</div>
<h3 class="recipe-title">{{ recipe.title }}</h3>
<div class="recipe-meta">
<span class="difficulty">难度:{{ getDifficultyText(recipe.difficulty) }}</span>
<span class="cooking-time">时间:{{ recipe.cooking_time }}</span>
<span class="serving">份量:{{ recipe.serving }}</span>
</div>
<div class="recipe-content">
<div class="ingredients">
<h4>📝 食材清单</h4>
<p>{{ formatText(recipe.ingredients) }}</p>
</div>
<div class="steps">
<h4>👩🍳 制作步骤</h4>
<p>{{ formatText(recipe.steps) }}</p>
</div>
<div v-if="recipe.tips" class="tips">
<h4>💡 小贴士</h4>
<p>{{ recipe.tips }}</p>
</div>
</div>
</div>
</div>
<div v-else class="no-data">
<p>暂无菜谱数据</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 错误状态 -->
<div v-else class="error-state">
<div class="container">
<p>产品不存在或加载失败</p>
<a href="index.html" class="btn-primary">返回首页</a>
</div>
</div>
<!-- 页脚 -->
<footer class="footer">
<div class="container">
<p>闽货优品 - 传承福建美食文化 © 2024</p>
</div>
</footer>
</div>
<script src="detail.js"></script>
</body>
</html>
请问我要如何解决刚刚的问题
最新发布