临时保存2
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -94,6 +94,11 @@ def meal_planning_page():
|
||||
"""饭菜规划页面"""
|
||||
return render_template('meal_planning.html')
|
||||
|
||||
@meal_planning_bp.route('/meal-planning/mobile', methods=['GET'])
|
||||
def meal_planning_mobile_page():
|
||||
"""饭菜规划移动端页面"""
|
||||
return render_template('meal_planning_mobile.html')
|
||||
|
||||
@meal_planning_bp.route('/meal-planning/history', methods=['GET'])
|
||||
def meal_planning_history():
|
||||
"""饭菜规划历史页面"""
|
||||
|
||||
55
src/flask_prompt_master/static/manifest.json
Normal file
55
src/flask_prompt_master/static/manifest.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "智能饭菜规划",
|
||||
"short_name": "饭菜规划",
|
||||
"description": "AI驱动的个性化饭菜清单规划师",
|
||||
"start_url": "/meal-planning/mobile",
|
||||
"display": "standalone",
|
||||
"background_color": "#ffffff",
|
||||
"theme_color": "#667eea",
|
||||
"orientation": "portrait",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/static/icons/icon-72x72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/static/icons/icon-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/static/icons/icon-128x128.png",
|
||||
"sizes": "128x128",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/static/icons/icon-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/static/icons/icon-152x152.png",
|
||||
"sizes": "152x152",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/static/icons/icon-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/static/icons/icon-384x384.png",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/static/icons/icon-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"categories": ["food", "lifestyle", "productivity"],
|
||||
"lang": "zh-CN",
|
||||
"dir": "ltr"
|
||||
}
|
||||
125
src/flask_prompt_master/static/sw.js
Normal file
125
src/flask_prompt_master/static/sw.js
Normal file
@@ -0,0 +1,125 @@
|
||||
// Service Worker for 智能饭菜规划 PWA
|
||||
const CACHE_NAME = 'meal-planning-v1';
|
||||
const urlsToCache = [
|
||||
'/meal-planning/mobile',
|
||||
'/static/css/bootstrap.min.css',
|
||||
'/static/js/bootstrap.bundle.min.js',
|
||||
'/static/css/font-awesome.min.css',
|
||||
'/api/meal-planning/generate',
|
||||
'/api/meal-planning/save'
|
||||
];
|
||||
|
||||
// 安装事件
|
||||
self.addEventListener('install', function(event) {
|
||||
event.waitUntil(
|
||||
caches.open(CACHE_NAME)
|
||||
.then(function(cache) {
|
||||
console.log('Opened cache');
|
||||
return cache.addAll(urlsToCache);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// 激活事件
|
||||
self.addEventListener('activate', function(event) {
|
||||
event.waitUntil(
|
||||
caches.keys().then(function(cacheNames) {
|
||||
return Promise.all(
|
||||
cacheNames.map(function(cacheName) {
|
||||
if (cacheName !== CACHE_NAME) {
|
||||
console.log('Deleting old cache:', cacheName);
|
||||
return caches.delete(cacheName);
|
||||
}
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// 拦截请求
|
||||
self.addEventListener('fetch', function(event) {
|
||||
event.respondWith(
|
||||
caches.match(event.request)
|
||||
.then(function(response) {
|
||||
// 缓存命中 - 返回缓存的版本
|
||||
if (response) {
|
||||
return response;
|
||||
}
|
||||
|
||||
// 克隆请求
|
||||
var fetchRequest = event.request.clone();
|
||||
|
||||
return fetch(fetchRequest).then(
|
||||
function(response) {
|
||||
// 检查是否收到有效响应
|
||||
if(!response || response.status !== 200 || response.type !== 'basic') {
|
||||
return response;
|
||||
}
|
||||
|
||||
// 克隆响应
|
||||
var responseToCache = response.clone();
|
||||
|
||||
caches.open(CACHE_NAME)
|
||||
.then(function(cache) {
|
||||
cache.put(event.request, responseToCache);
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// 后台同步
|
||||
self.addEventListener('sync', function(event) {
|
||||
if (event.tag === 'background-sync') {
|
||||
event.waitUntil(doBackgroundSync());
|
||||
}
|
||||
});
|
||||
|
||||
function doBackgroundSync() {
|
||||
// 处理离线时的数据同步
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// 推送通知
|
||||
self.addEventListener('push', function(event) {
|
||||
const options = {
|
||||
body: event.data ? event.data.text() : '您有新的饭菜规划建议!',
|
||||
icon: '/static/icons/icon-192x192.png',
|
||||
badge: '/static/icons/icon-72x72.png',
|
||||
vibrate: [100, 50, 100],
|
||||
data: {
|
||||
dateOfArrival: Date.now(),
|
||||
primaryKey: 1
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
action: 'explore',
|
||||
title: '查看详情',
|
||||
icon: '/static/icons/icon-72x72.png'
|
||||
},
|
||||
{
|
||||
action: 'close',
|
||||
title: '关闭',
|
||||
icon: '/static/icons/icon-72x72.png'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
event.waitUntil(
|
||||
self.registration.showNotification('智能饭菜规划', options)
|
||||
);
|
||||
});
|
||||
|
||||
// 通知点击事件
|
||||
self.addEventListener('notificationclick', function(event) {
|
||||
event.notification.close();
|
||||
|
||||
if (event.action === 'explore') {
|
||||
event.waitUntil(
|
||||
clients.openWindow('/meal-planning/mobile')
|
||||
);
|
||||
}
|
||||
});
|
||||
498
src/flask_prompt_master/templates/meal_planning_mobile.html
Normal file
498
src/flask_prompt_master/templates/meal_planning_mobile.html
Normal file
@@ -0,0 +1,498 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}智能饭菜规划 - 提示词大师{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<!-- 移动端优化的页面标题 -->
|
||||
<div class="page-header-mobile">
|
||||
<h1 class="page-title-mobile">
|
||||
<i class="fas fa-utensils"></i>
|
||||
智能饭菜规划
|
||||
</h1>
|
||||
<p class="page-subtitle-mobile">AI驱动的个性化饭菜清单规划师</p>
|
||||
</div>
|
||||
|
||||
<!-- 移动端优化的表单区域 -->
|
||||
<div class="mobile-form-container">
|
||||
<div class="card mobile-card">
|
||||
<div class="card-header mobile-card-header">
|
||||
<h5 class="card-title-mobile">
|
||||
<i class="fas fa-cog"></i>
|
||||
规划参数
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body mobile-card-body">
|
||||
<form id="mealPlanningFormMobile">
|
||||
<!-- 地区类型 -->
|
||||
<div class="form-group-mobile mb-3">
|
||||
<label for="regionType" class="form-label-mobile">地区类型</label>
|
||||
<select class="form-select-mobile" id="regionType" name="region_type">
|
||||
<option value="全国">全国</option>
|
||||
<option value="北方">北方</option>
|
||||
<option value="南方">南方</option>
|
||||
<option value="川菜">川菜</option>
|
||||
<option value="粤菜">粤菜</option>
|
||||
<option value="鲁菜">鲁菜</option>
|
||||
<option value="苏菜">苏菜</option>
|
||||
<option value="浙菜">浙菜</option>
|
||||
<option value="闽菜">闽菜</option>
|
||||
<option value="湘菜">湘菜</option>
|
||||
<option value="徽菜">徽菜</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 就餐人数 -->
|
||||
<div class="form-group-mobile mb-3">
|
||||
<label for="dinerCount" class="form-label-mobile">就餐人数</label>
|
||||
<select class="form-select-mobile" id="dinerCount" name="diner_count">
|
||||
<option value="1">1人</option>
|
||||
<option value="2" selected>2人</option>
|
||||
<option value="3">3人</option>
|
||||
<option value="4">4人</option>
|
||||
<option value="5">5人</option>
|
||||
<option value="6">6人</option>
|
||||
<option value="8">8人</option>
|
||||
<option value="10">10人</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 用餐类型 -->
|
||||
<div class="form-group-mobile mb-3">
|
||||
<label for="mealType" class="form-label-mobile">用餐类型</label>
|
||||
<select class="form-select-mobile" id="mealType" name="meal_type">
|
||||
<option value="早餐">早餐</option>
|
||||
<option value="午餐" selected>午餐</option>
|
||||
<option value="晚餐">晚餐</option>
|
||||
<option value="全天">全天</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 用餐者家乡 -->
|
||||
<div class="form-group-mobile mb-3">
|
||||
<label for="hometown" class="form-label-mobile">用餐者家乡 <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control-mobile" id="hometown" name="hometown"
|
||||
placeholder="如:四川成都" required>
|
||||
</div>
|
||||
|
||||
<!-- 个人喜好 -->
|
||||
<div class="form-group-mobile mb-3">
|
||||
<label for="preferences" class="form-label-mobile">个人喜好</label>
|
||||
<textarea class="form-control-mobile" id="preferences" name="preferences" rows="3"
|
||||
placeholder="如:喜欢辣味、偏爱素食、喜欢海鲜等"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- 饮食禁忌 -->
|
||||
<div class="form-group-mobile mb-3">
|
||||
<label for="dietaryRestrictions" class="form-label-mobile">饮食禁忌</label>
|
||||
<textarea class="form-control-mobile" id="dietaryRestrictions" name="dietary_restrictions" rows="3"
|
||||
placeholder="如:不吃猪肉、对花生过敏、素食主义等"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- 预算范围 -->
|
||||
<div class="form-group-mobile mb-3">
|
||||
<label for="budget" class="form-label-mobile">预算范围(元)</label>
|
||||
<select class="form-select-mobile" id="budget" name="budget">
|
||||
<option value="50">50元以下</option>
|
||||
<option value="100" selected>50-100元</option>
|
||||
<option value="150">100-150元</option>
|
||||
<option value="200">150-200元</option>
|
||||
<option value="300">200-300元</option>
|
||||
<option value="500">300-500元</option>
|
||||
<option value="1000">500元以上</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 生成按钮 -->
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary-mobile btn-lg" id="generateBtnMobile">
|
||||
<i class="fas fa-magic"></i>
|
||||
生成饭菜规划
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 移动端优化的结果展示区域 -->
|
||||
<div class="mobile-result-container" id="resultContainerMobile" style="display: none;">
|
||||
<div class="card mobile-card">
|
||||
<div class="card-header mobile-card-header">
|
||||
<h5 class="card-title-mobile">
|
||||
<i class="fas fa-clipboard-list"></i>
|
||||
饭菜规划结果
|
||||
</h5>
|
||||
<div class="card-actions-mobile">
|
||||
<button class="btn btn-sm btn-outline-primary-mobile" id="copyBtnMobile">
|
||||
<i class="fas fa-copy"></i>
|
||||
复制
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-success-mobile" id="saveBtnMobile">
|
||||
<i class="fas fa-save"></i>
|
||||
保存
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body mobile-card-body">
|
||||
<div class="meal-plan-content-mobile" id="mealPlanContentMobile">
|
||||
<!-- 结果内容将在这里显示 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 移动端优化的加载动画 -->
|
||||
<div class="modal fade" id="loadingModalMobile" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content mobile-modal-content">
|
||||
<div class="modal-body text-center py-4">
|
||||
<div class="spinner-border text-primary mb-3" role="status">
|
||||
<span class="visually-hidden">生成中...</span>
|
||||
</div>
|
||||
<h5>正在生成饭菜规划...</h5>
|
||||
<p class="text-muted">AI正在为您制定个性化的饭菜清单,请稍候</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* 移动端专用样式 */
|
||||
@media (max-width: 768px) {
|
||||
.page-header-mobile {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 1.5rem 1rem;
|
||||
margin: -1rem -1rem 1.5rem -1rem;
|
||||
border-radius: 0 0 20px 20px;
|
||||
}
|
||||
|
||||
.page-title-mobile {
|
||||
font-size: 1.8rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.page-subtitle-mobile {
|
||||
font-size: 1rem;
|
||||
opacity: 0.9;
|
||||
margin-bottom: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mobile-form-container {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.mobile-card {
|
||||
border: none;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 15px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.mobile-card-header {
|
||||
background: #f8f9fa;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
border-radius: 15px 15px 0 0 !important;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.card-title-mobile {
|
||||
margin-bottom: 0;
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.mobile-card-body {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.form-group-mobile {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-label-mobile {
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.form-control-mobile, .form-select-mobile {
|
||||
border-radius: 10px;
|
||||
border: 1px solid #ced4da;
|
||||
padding: 0.75rem;
|
||||
font-size: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-control-mobile:focus, .form-select-mobile:focus {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
|
||||
}
|
||||
|
||||
.btn-primary-mobile {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
padding: 1rem 1.5rem;
|
||||
font-weight: 600;
|
||||
font-size: 1.1rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.btn-primary-mobile:hover {
|
||||
background: linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 8px rgba(102, 126, 234, 0.3);
|
||||
}
|
||||
|
||||
.mobile-result-container {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.card-actions-mobile {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.btn-outline-primary-mobile, .btn-outline-success-mobile {
|
||||
border-radius: 8px;
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.9rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.meal-plan-content-mobile {
|
||||
background: #f8f9fa;
|
||||
border-radius: 10px;
|
||||
padding: 1rem;
|
||||
border-left: 4px solid #667eea;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.meal-plan-content-mobile h1,
|
||||
.meal-plan-content-mobile h2,
|
||||
.meal-plan-content-mobile h3 {
|
||||
color: #495057;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.meal-plan-content-mobile h1:first-child,
|
||||
.meal-plan-content-mobile h2:first-child,
|
||||
.meal-plan-content-mobile h3:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.meal-plan-content-mobile ul,
|
||||
.meal-plan-content-mobile ol {
|
||||
padding-left: 1.2rem;
|
||||
}
|
||||
|
||||
.meal-plan-content-mobile li {
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
.meal-plan-content-mobile strong {
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
.mobile-modal-content {
|
||||
border-radius: 15px;
|
||||
border: none;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* 触摸优化 */
|
||||
.btn, .form-control, .form-select {
|
||||
min-height: 44px; /* iOS推荐的最小触摸目标 */
|
||||
}
|
||||
|
||||
/* 防止双击缩放 */
|
||||
input, select, textarea, button {
|
||||
touch-action: manipulation;
|
||||
}
|
||||
}
|
||||
|
||||
/* 超小屏幕优化 */
|
||||
@media (max-width: 480px) {
|
||||
.page-title-mobile {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.mobile-card-body {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.form-control-mobile, .form-select-mobile {
|
||||
padding: 0.6rem;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.btn-primary-mobile {
|
||||
padding: 0.8rem 1rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const form = document.getElementById('mealPlanningFormMobile');
|
||||
const generateBtn = document.getElementById('generateBtnMobile');
|
||||
const resultContainer = document.getElementById('resultContainerMobile');
|
||||
const copyBtn = document.getElementById('copyBtnMobile');
|
||||
const saveBtn = document.getElementById('saveBtnMobile');
|
||||
const loadingModal = new bootstrap.Modal(document.getElementById('loadingModalMobile'));
|
||||
|
||||
// 表单提交处理
|
||||
form.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// 验证必填字段
|
||||
const hometown = document.getElementById('hometown').value.trim();
|
||||
if (!hometown) {
|
||||
showAlert('请输入用餐者家乡', 'danger');
|
||||
return;
|
||||
}
|
||||
|
||||
// 收集表单数据
|
||||
const formData = new FormData(form);
|
||||
const data = Object.fromEntries(formData.entries());
|
||||
|
||||
// 显示加载动画
|
||||
loadingModal.show();
|
||||
generateBtn.disabled = true;
|
||||
|
||||
// 发送请求
|
||||
fetch('/api/meal-planning/generate', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
loadingModal.hide();
|
||||
generateBtn.disabled = false;
|
||||
|
||||
if (result.success) {
|
||||
displayResult(result.data.meal_plan);
|
||||
resultContainer.style.display = 'block';
|
||||
showAlert('饭菜规划生成成功!', 'success');
|
||||
|
||||
// 滚动到结果区域
|
||||
resultContainer.scrollIntoView({ behavior: 'smooth' });
|
||||
} else {
|
||||
showAlert(result.message || '生成失败,请重试', 'danger');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
loadingModal.hide();
|
||||
generateBtn.disabled = false;
|
||||
console.error('Error:', error);
|
||||
showAlert('网络错误,请检查网络连接后重试', 'danger');
|
||||
});
|
||||
});
|
||||
|
||||
// 显示结果
|
||||
function displayResult(mealPlan) {
|
||||
// 简单的Markdown转HTML函数
|
||||
function simpleMarkdownToHtml(text) {
|
||||
return text
|
||||
.replace(/^### (.*$)/gim, '<h3>$1</h3>')
|
||||
.replace(/^## (.*$)/gim, '<h2>$1</h2>')
|
||||
.replace(/^# (.*$)/gim, '<h1>$1</h1>')
|
||||
.replace(/\*\*(.*)\*\*/gim, '<strong>$1</strong>')
|
||||
.replace(/\*(.*)\*/gim, '<em>$1</em>')
|
||||
.replace(/^\* (.*$)/gim, '<li>$1</li>')
|
||||
.replace(/^\d+\. (.*$)/gim, '<li>$1</li>')
|
||||
.replace(/\n\n/gim, '</p><p>')
|
||||
.replace(/\n/gim, '<br>')
|
||||
.replace(/^(.*)$/gim, '<p>$1</p>');
|
||||
}
|
||||
|
||||
document.getElementById('mealPlanContentMobile').innerHTML = simpleMarkdownToHtml(mealPlan);
|
||||
}
|
||||
|
||||
// 复制功能
|
||||
copyBtn.addEventListener('click', function() {
|
||||
const content = document.getElementById('mealPlanContentMobile').textContent;
|
||||
navigator.clipboard.writeText(content).then(() => {
|
||||
showAlert('饭菜规划已复制到剪贴板', 'success');
|
||||
}).catch(() => {
|
||||
showAlert('复制失败,请手动复制', 'danger');
|
||||
});
|
||||
});
|
||||
|
||||
// 保存功能
|
||||
saveBtn.addEventListener('click', function() {
|
||||
const content = document.getElementById('mealPlanContentMobile').textContent;
|
||||
|
||||
// 获取当前表单参数
|
||||
const formData = {
|
||||
meal_plan_content: content,
|
||||
region_type: document.getElementById('regionType').value,
|
||||
diner_count: document.getElementById('dinerCount').value,
|
||||
meal_type: document.getElementById('mealType').value,
|
||||
hometown: document.getElementById('hometown').value,
|
||||
preferences: document.getElementById('preferences').value,
|
||||
dietary_restrictions: document.getElementById('dietaryRestrictions').value,
|
||||
budget: document.getElementById('budget').value
|
||||
};
|
||||
|
||||
fetch('/api/meal-planning/save', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(formData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.success) {
|
||||
showAlert('饭菜规划保存成功!', 'success');
|
||||
console.log('保存成功,规划ID:', result.data.meal_plan_id);
|
||||
} else {
|
||||
showAlert(result.message || '保存失败', 'danger');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showAlert('保存失败,请重试', 'danger');
|
||||
});
|
||||
});
|
||||
|
||||
// 显示提示信息
|
||||
function showAlert(message, type) {
|
||||
const alertDiv = document.createElement('div');
|
||||
alertDiv.className = `alert alert-${type} alert-dismissible fade show`;
|
||||
alertDiv.innerHTML = `
|
||||
${message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
`;
|
||||
|
||||
// 插入到页面顶部
|
||||
const container = document.querySelector('.container-fluid');
|
||||
container.insertBefore(alertDiv, container.firstChild);
|
||||
|
||||
// 自动消失
|
||||
setTimeout(() => {
|
||||
if (alertDiv.parentNode) {
|
||||
alertDiv.remove();
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user