<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>0寻漫 - 全景文创智能设计工作台</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;700;900&family=Roboto:wght@300;400;700&display=swap" rel="stylesheet">
<style>
:root {
--primary-accent: #eab308;
--secondary-accent: #1f2937;
}
body { background-color: #f3f4f6; font-family: 'Roboto', 'Noto Serif SC', sans-serif; overflow-x: hidden; }
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 3px; }
.preview-container { transform: scale(0.65); transform-origin: top left; width: 875px; }
.postcard { width: 875px; height: 550px; background: #fff; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); position: relative; overflow: hidden; border-radius: 4px; transition: all 0.3s ease; }
.front-bg { background: linear-gradient(to bottom, rgba(0,0,0,0.1), rgba(0,0,0,0.85)), url('https://images.unsplash.com/photo-1541888049100-34e81561fbe2?ixlib=rb-4.0.3&auto=format&fit=crop&w=1600&q=80') center/cover; height: 100%; width: 100%; transition: opacity 0.3s ease; }
.qr-bg { background: url('https://upload.wikimedia.org/wikipedia/commons/d/d0/QR_code_for_mobile_English_Wikipedia.svg') center/cover; }
.post-stamp-box { width: 80px; height: 90px; border: 2px solid #ccc; display: flex; align-items: center; justify-content: center; color: #ccc; font-size: 14px; font-family: sans-serif; }
.address-line { border-bottom: 1px solid #aaa; height: 40px; width: 100%; }
.zip-box { width: 25px; height: 30px; border: 1px solid #ff4d4f; display: inline-block; margin-right: 2px; }
[contenteditable="true"]:hover { background-color: rgba(255, 255, 255, 0.2); outline: 1px dashed #ccc; border-radius: 4px; cursor: text; }
[contenteditable="true"]:focus { background-color: rgba(255, 255, 255, 0.4); outline: 2px solid #3b82f6; border-radius: 4px; }
.text-dark-editable[contenteditable="true"]:hover { background-color: rgba(0, 0, 0, 0.05); outline: 1px dashed #666; }
.text-dark-editable[contenteditable="true"]:focus { background-color: rgba(0, 0, 0, 0.05); outline: 2px solid #3b82f6; }
.dynamic-border { border-color: var(--primary-accent) !important; }
.dynamic-text { color: var(--primary-accent) !important; }
.dynamic-bg { background-color: var(--secondary-accent) !important; }
.tab-active { border-bottom: 3px solid #3b82f6; color: #1d4ed8; font-weight: bold; }
.tab-inactive { color: #6b7280; font-weight: normal; }
.tab-inactive:hover { color: #374151; }
</style>
</head>
<body class="h-screen flex flex-col">
<header class="bg-gray-900 text-white shadow-md z-10 flex-shrink-0">
<div class="container mx-auto px-6 py-4 flex justify-between items-center">
<div class="flex items-center space-x-3">
<div class="w-8 h-8 bg-blue-500 rounded flex items-center justify-center font-bold text-xl">0</div>
<h1 class="text-xl font-bold tracking-widest">0寻漫 <span class="font-light text-gray-400 text-sm ml-2">全景文创智能设计台</span></h1>
</div>
<div class="flex space-x-6">
<button onclick="switchTab('workspace')" id="tab-workspace" class="pb-1 tab-active transition">创作台</button>
<button onclick="switchTab('gallery')" id="tab-gallery" class="pb-1 tab-inactive transition">成品展厅</button>
</div>
</div>
</header>
<main class="flex-1 overflow-hidden relative">
<div id="view-workspace" class="absolute inset-0 flex w-full h-full">
<div class="w-[450px] bg-white border-r border-gray-200 flex flex-col h-full shadow-lg z-10 overflow-y-auto">
<div class="p-6 space-y-8">
<section>
<h2 class="text-lg font-bold text-gray-800 border-l-4 border-blue-500 pl-2 mb-4">1. 基础信息与智能策划</h2>
<div class="space-y-4">
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">拍摄场景名称:</label>
<input id="ai-location" type="text" value="绿岛大创工场" class="w-full px-3 py-2 bg-gray-50 border border-gray-300 rounded focus:ring-2 focus:ring-blue-500 focus:outline-none text-sm">
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">期望视觉风格:</label>
<select id="ai-style" class="w-full px-3 py-2 bg-gray-50 border border-gray-300 rounded focus:ring-2 focus:ring-blue-500 focus:outline-none text-sm">
<option value="科技前沿、现代感、硬核">科技硬核风 (适合大创工场/实验室)</option>
<option value="文艺清新、高级留白、诗意">文艺清新风 (适合美术馆/书屋)</option>
<option value="历史沉淀、古典人文、厚重">历史人文风 (适合古建筑/图书馆)</option>
</select>
</div>
<div class="flex gap-2">
<button id="btn-ai-copy" onclick="generateAICopy()" class="flex-1 bg-blue-600 hover:bg-blue-700 text-white py-2 rounded text-sm font-bold shadow transition flex justify-center items-center">
✨ AI 写文案
</button>
<button id="btn-ai-color" onclick="generateAIColor()" class="flex-1 bg-yellow-500 hover:bg-yellow-600 text-yellow-900 py-2 rounded text-sm font-bold shadow transition flex justify-center items-center">
🎨 AI 算配色
</button>
</div>
<p class="text-xs text-gray-400 mt-1">* 提示:右侧预览区的文字可直接点击进行手动修改。</p>
</div>
</section>
<section>
<h2 class="text-lg font-bold text-gray-800 border-l-4 border-blue-500 pl-2 mb-4">2. 本地素材装载</h2>
<div class="space-y-4">
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">上传品牌/学校 Logo (透明PNG佳):</label>
<input type="file" id="upload-logo" accept="image/*" class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100">
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">上传全景正面海报图 (主视觉):</label>
<input type="file" id="upload-bg" accept="image/*" class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100">
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">上传全景漫游二维码:</label>
<input type="file" id="upload-qr" accept="image/*" class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100">
</div>
</div>
</section>
<section class="bg-blue-50 p-4 rounded-lg border border-blue-100">
<h2 class="text-lg font-bold text-blue-800 mb-3">3. 结课作品交付区</h2>
<div class="space-y-3">
<div>
<label class="block text-xs font-semibold text-blue-800 mb-1">1. 提交印刷级 JPG 效果图:</label>
<input type="file" id="submit-jpg" accept=".jpg,.jpeg,.png" class="block w-full text-xs">
</div>
<div>
<label class="block text-xs font-semibold text-blue-800 mb-1">2. 提交 PSD 完整源文件:</label>
<input type="file" id="submit-psd" accept=".psd,.zip" class="block w-full text-xs">
</div>
<button id="btn-submit-work" onclick="submitProject()" class="w-full mt-2 bg-green-600 hover:bg-green-700 text-white py-2 rounded text-sm font-bold shadow transition">
📤 提交作品并发布至展厅
</button>
</div>
</section>
</div>
</div>
<div class="flex-1 bg-gray-200 overflow-y-auto p-10 flex flex-col items-center">
<div class="text-center mb-6">
<p class="text-gray-500 text-sm font-bold">👀 实时设计预览区 (175mm × 110mm 比例)</p>
</div>
<div class="preview-container space-y-12 pb-20">
<div class="postcard flex flex-col justify-end p-8 relative group" id="front-card">
<div id="front-bg-layer" class="front-bg absolute inset-0 z-0"></div>
<div class="z-10 relative">
<div class="absolute -top-[380px] left-0 flex items-center space-x-3">
<img id="preview-logo" src="https://via.placeholder.com/150?text=LOGO" alt="Logo" class="w-14 h-14 rounded-full bg-white p-1 shadow-lg object-contain">
<div id="preview-school-name" contenteditable="true" class="text-white/90 font-sans tracking-widest text-sm border-l-2 pl-3 dynamic-border">
沈阳城市学院<br>Shenyang City University
</div>
</div>
<div class="border-l-4 pl-4 dynamic-border">
<h2 id="front-title" contenteditable="true" class="text-5xl font-black text-white tracking-widest mb-1 shadow-sm inline-block">绿岛大创工场</h2>
<br>
<p id="front-slogan" contenteditable="true" class="font-sans tracking-[0.25em] uppercase text-sm font-bold inline-block mt-2 dynamic-text">Innovation Space • AR Tour</p>
</div>
<p id="front-desc" contenteditable="true" class="text-white/90 mt-4 font-sans text-sm tracking-wider font-light max-w-lg leading-relaxed drop-shadow-md">
思想的火花在这里碰撞,创新的梦想在这里起航。用全景技术记录每一个改变未来的瞬间。
</p>
</div>
</div>
<div class="postcard p-8 relative bg-[#fdfbf7]">
<div class="absolute top-8 left-8">
<div class="zip-box"></div><div class="zip-box"></div><div class="zip-box"></div><div class="zip-box"></div><div class="zip-box"></div><div class="zip-box"></div>
</div>
<div class="absolute top-8 right-8 post-stamp-box">贴邮票处</div>
<div class="flex h-full w-full pt-16">
<div class="w-1/2 pr-8 flex flex-col justify-between">
<div>
<h3 id="back-title" contenteditable="true" class="text-xl font-bold text-gray-800 mb-2 font-sans tracking-wide text-dark-editable">全景探索视界</h3>
<p id="back-desc" contenteditable="true" class="text-gray-600 text-xs leading-relaxed text-justify mb-4 text-dark-editable">
绿岛大创工场是青年创客的摇篮。扫描下方二维码,跨越物理空间的限制,720度沉浸式漫游各大创新实验室,感受科技与灵感交织的魅力。
</p>
</div>
<div class="flex items-center bg-white p-3 rounded shadow-sm border border-gray-200">
<div class="w-20 h-20 rounded-sm flex items-center justify-center p-1 dynamic-bg">
<div id="preview-qr" class="w-full h-full qr-bg bg-white"></div>
</div>
<div class="ml-4">
<p class="text-sm font-bold text-gray-800 font-sans">扫码开启 720° 漫游</p>
<p class="text-xs text-gray-500 font-sans mt-1">Scan to start VR Tour</p>
<p class="text-[10px] text-blue-500 font-sans mt-1">Powered by 0寻漫</p>
</div>
</div>
</div>
<div class="w-[1px] h-full bg-gray-300"></div>
<div class="w-1/2 pl-8 flex flex-col pt-10">
<p class="text-gray-400 font-sans text-sm mb-4 italic">To __________,</p>
<div class="flex-1"></div>
<div class="w-full mb-8">
<div class="address-line"></div>
<div class="address-line"></div>
<div class="address-line"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="view-gallery" class="absolute inset-0 bg-gray-100 hidden overflow-y-auto p-10">
<div class="max-w-6xl mx-auto">
<div class="flex justify-between items-end mb-8">
<div>
<h2 class="text-3xl font-bold text-gray-800">优秀作品展厅</h2>
<p class="text-gray-500 mt-2">2026级 虚拟现实技术专业 结课项目成果库</p>
</div>
<div class="text-sm text-gray-400">Powered by 0寻漫工作室</div>
</div>
<div id="gallery-grid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-xl transition">
<div class="h-48 bg-[url('https://images.unsplash.com/photo-1541888049100-34e81561fbe2?ixlib=rb-4.0.3&w=800&q=80')] bg-cover bg-center"></div>
<div class="p-5">
<h3 class="font-bold text-lg text-gray-800">绿岛图书馆</h3>
<p class="text-xs text-blue-500 mb-3">#历史人文风</p>
<p class="text-sm text-gray-600 line-clamp-2">书香浸润岁月,光影镌刻时光。利用全景影像技术,将知识的殿堂折叠于掌心之间。</p>
<div class="mt-4 pt-4 border-t border-gray-100 flex justify-between items-center">
<span class="text-xs text-gray-400">已包含 JPG & PSD</span>
<button class="text-blue-600 text-sm font-semibold hover:underline">查看详情</button>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
<div id="global-loader" class="fixed inset-0 bg-black/70 z-50 hidden flex-col items-center justify-center text-white">
<svg class="animate-spin h-10 w-10 mb-4" xmlns="http://www.w3.org/2000/svg" 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>
<p id="loader-text" class="text-lg font-bold tracking-widest">文件打包并上传至服务器中...</p>
</div>
<script>
// ==========================================
// 核心修改:将请求地址指向我们上传的 PHP 代理文件
// ==========================================
const apiUrl = "/gemini-proxy.php";
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url, options);
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return await response.json();
} catch (error) {
if (i === maxRetries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1500));
}
}
}
function switchTab(tab) {
const wsView = document.getElementById('view-workspace');
const glView = document.getElementById('view-gallery');
const wsTab = document.getElementById('tab-workspace');
const glTab = document.getElementById('tab-gallery');
if (tab === 'workspace') {
wsView.classList.remove('hidden'); glView.classList.add('hidden');
wsTab.className = "pb-1 tab-active transition"; glTab.className = "pb-1 tab-inactive transition";
} else {
wsView.classList.add('hidden'); glView.classList.remove('hidden');
wsTab.className = "pb-1 tab-inactive transition"; glTab.className = "pb-1 tab-active transition";
}
}
function handleImageUpload(inputId, targetCallback) {
document.getElementById(inputId).addEventListener('change', function(e) {
const file = e.target.files[0];
if (file) {
const url = URL.createObjectURL(file);
targetCallback(url);
}
});
}
handleImageUpload('upload-logo', (url) => {
const img = document.getElementById('preview-logo');
img.src = url; img.classList.remove('bg-white', 'p-1');
});
handleImageUpload('upload-bg', (url) => {
document.getElementById('front-bg-layer').style.backgroundImage = `linear-gradient(to bottom, rgba(0,0,0,0.1), rgba(0,0,0,0.85)), url('${url}')`;
window.currentBgUrl = url;
});
handleImageUpload('upload-qr', (url) => {
document.getElementById('preview-qr').style.backgroundImage = `url('${url}')`;
});
function setButtonLoading(btnId, isLoading, originalText) {
const btn = document.getElementById(btnId);
if (isLoading) {
btn.innerHTML = `<svg class="animate-spin -ml-1 mr-2 h-4 w-4 text-white inline-block" xmlns="http://www.w3.org/2000/svg" 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> 思考中...`;
btn.disabled = true; btn.classList.add('opacity-70');
} else {
btn.innerHTML = originalText; btn.disabled = false; btn.classList.remove('opacity-70');
}
}
async function generateAICopy() {
const location = document.getElementById('ai-location').value || '全景风光';
const style = document.getElementById('ai-style').value;
const originalText = "✨ AI 写文案";
setButtonLoading('btn-ai-copy', true, originalText);
const promptText = `你是一名文创策划大师。正在制作全景明信片。场景:【${location}】。风格:【${style}】。请务必以纯JSON格式返回,不要包含任何markdown标记(如\`\`\`json)。格式如下:{"frontTitle": "正面短标题", "frontSlogan": "英文副标题", "backDescription": "背面80字中文介绍", "frontDesc": "正面30字介绍"}`;
const payload = {
contents: [{ parts: [{ text: promptText }] }]
};
try {
const data = await fetchWithRetry(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) });
let rawText = data.candidates[0].content.parts[0].text;
// 去除可能存在的 markdown 代码块包裹
rawText = rawText.replace(/```json/g, '').replace(/```/g, '').trim();
const aiContent = JSON.parse(rawText);
document.getElementById('front-title').innerText = aiContent.frontTitle;
document.getElementById('front-slogan').innerText = aiContent.frontSlogan;
document.getElementById('back-desc').innerText = aiContent.backDescription;
document.getElementById('back-title').innerText = "云游 " + aiContent.frontTitle;
document.getElementById('front-desc').innerText = aiContent.frontDesc;
} catch (error) {
alert("生成文案失败,请确保您的服务器能够顺畅连接外网。");
console.error(error);
} finally { setButtonLoading('btn-ai-copy', false, originalText); }
}
async function generateAIColor() {
const location = document.getElementById('ai-location').value;
const style = document.getElementById('ai-style').value;
const originalText = "🎨 AI 算配色";
setButtonLoading('btn-ai-color', true, originalText);
const promptText = `作为排版设计师,为【${location}】的明信片推荐配色。风格:【${style}】。请务必以纯JSON格式返回,不要包含任何markdown标记。格式如下:{"primaryHex": "#eab308", "secondaryHex": "#1f2937"}`;
const payload = {
contents: [{ parts: [{ text: promptText }] }]
};
try {
const data = await fetchWithRetry(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) });
let rawText = data.candidates[0].content.parts[0].text;
rawText = rawText.replace(/```json/g, '').replace(/```/g, '').trim();
const aiContent = JSON.parse(rawText);
document.documentElement.style.setProperty('--primary-accent', aiContent.primaryHex);
document.documentElement.style.setProperty('--secondary-accent', aiContent.secondaryHex);
} catch (error) {
alert("配色计算失败,请检查网络。");
console.error(error);
} finally { setButtonLoading('btn-ai-color', false, originalText); }
}
function submitProject() {
const jpgInput = document.getElementById('submit-jpg');
const psdInput = document.getElementById('submit-psd');
if (!jpgInput.files.length || !psdInput.files.length) {
alert("⚠️ 请先上传您本地输出好的 JPG效果图 和 PSD源文件!\n\n(注:当前为前端模拟展示,实际教学中请让学生将源文件打包发送至您的指定云盘/邮箱)");
return;
}
const title = document.getElementById('front-title').innerText;
const desc = document.getElementById('front-desc').innerText;
const styleText = document.getElementById('ai-style').options[document.getElementById('ai-style').selectedIndex].text;
const bgUrl = window.currentBgUrl || 'https://images.unsplash.com/photo-1541888049100-34e81561fbe2?ixlib=rb-4.0.3&w=800&q=80';
const loader = document.getElementById('global-loader');
loader.classList.remove('hidden');
loader.classList.add('flex');
setTimeout(() => {
loader.classList.add('hidden');
loader.classList.remove('flex');
const cardHtml = `
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-xl transition border-t-4 border-green-500">
<div class="h-48 bg-cover bg-center" style="background-image: url('${bgUrl}')"></div>
<div class="p-5">
<h3 class="font-bold text-lg text-gray-800">${title} <span class="text-xs bg-green-100 text-green-700 px-2 py-1 rounded ml-2">最新上传</span></h3>
<p class="text-xs text-blue-500 mb-3">#${styleText.split(' ')[0]}</p>
<p class="text-sm text-gray-600 line-clamp-2">${desc}</p>
<div class="mt-4 pt-4 border-t border-gray-100 flex justify-between items-center">
<span class="text-xs text-green-600 font-bold flex items-center"><svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>展示更新成功</span>
</div>
</div>
</div>
`;
const galleryGrid = document.getElementById('gallery-grid');
galleryGrid.insertAdjacentHTML('afterbegin', cardHtml);
jpgInput.value = '';
psdInput.value = '';
alert("🎉 恭喜!前台作品展厅已更新。(注:源文件请学生通过云盘上交)");
switchTab('gallery');
}, 2000);
}
</script>
</body>
</html>