【应用程序】基于 Spring Boot + Spring AI的虚拟宠物Web 应用(二)
前端技术细节前端实现与后端大模型交互实现:async interact(action, message = '') { if (this.loading) return; this.loading = true; try { const controller = new AbortController(); const timeout = setTimeout(() = controller.abort(), 30000); const res = await fetch('/api/interact', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action, message, conversationId: this.conversationId }), signal: controller.signal }); clearTimeout(timeout); if (!res.ok) { throw new Error(`HTTP error! status: ${res.status}`); } const data = await res.json(); this.hunger = data.hunger ?? this.hunger; this.happiness = data.happiness ?? this.happiness; this.addMessage(true, data.reply || '喵呜...我忘记要说什么了 😿'); } catch (e) { if (e.name === 'AbortError') { this.addMessage(true, '喵呜...等太久了,你是不是不要我了 😿'); } else { this.addMessage(true, '网络好像断了...等我一下下喵 😿'); } } finally { this.loading = false; this.inputText = ''; } },如下图所示:完整前端页面代码:!DOCTYPEhtmlhtmllang="zh-CN"headmetacharset="UTF-8"metaname="viewport"content="width=device-width, initial-scale=1.0, user-scalable=yes"title小N · AI虚拟宠物 | 智能陪伴小猫/titlescriptsrc="https://unpkg.com/alpinejs@3.14.3/dist/cdn.min.js"defer/scriptstyle/* ========== 基础重置 自定义样式(不依赖Tailwind) ========== */*{margin:0;padding:0;box-sizing:border-box;}[x-cloak]{display:none!important;}body{font-family:system-ui,'Segoe UI','Inter','PingFang SC',Roboto,'Helvetica Neue',sans-serif;background:linear-gradient(135deg,#111827 0%,#1f2937 50%,#111827 100%);min-height:100vh;padding:1rem;display:flex;align-items:center;justify-content:center;}/* 主卡片 */.pet-card{width:100%;max-width:600px;background:rgba(31,41,55,0.7);backdrop-filter:blur(14px);border-radius:1.5rem;border:1px solidrgba(129,140,248,0.3);padding:1.5rem;box-shadow:0 25px 45px -12pxrgba(0,0,0,0.5);transition:all 0.2s ease;}@media(max-width:640px){.pet-card{padding:1rem;}}/* 头部区域 */.header{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:0.75rem;margin-bottom:1.5rem;}.header-left{display:flex;align-items:center;gap:1rem;}.avatar{width:4rem;height:4rem;border-radius:9999px;box-shadow:0 4px 6px -1pxrgba(0,0,0,0.3);ring:2px solidrgba(129,140,248,0.5);object-fit:cover;animation:bounce-soft 3s ease-in-out infinite;}@media(min-width:768px){.avatar{width:4.5rem;height:4.5rem;}}@keyframesbounce-soft{0%, 100%{transform:translateY(0px)scale(1);}50%{transform:translateY(-6px)scale(1.02);}}.title{font-size:1.5rem;font-weight:800;background:linear-gradient(135deg,#a5b4fc,#c084fc);-webkit-background-clip:text;background-clip:text;color:transparent;}.subtitle{font-size:0.75rem;color:rgba(156,163,175,0.8);margin-top:0.125rem;}/* 重置按钮 */.reset-btn{padding:0.5rem 1rem;background:rgba(244,63,94,0.15);border:1px solidrgba(244,63,94,0.3);border-radius:0.75rem;color:#fecdd3;font-size:0.875rem;font-weight:500;cursor:pointer;transition:all 0.2s;}.reset-btn:hover{background:rgba(244,63,94,0.3);transform:translateY(-1px);}/* 状态卡片网格 */.stats-grid{display:grid;grid-template-columns:1fr 1fr;gap:1rem;margin-bottom:1.5rem;}.stat-card{background:rgba(0,0,0,0.2);border-radius:1rem;padding:0.875rem;border:1px solidrgba(255,255,255,0.05);}.stat-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:0.5rem;}.stat-label{font-size:0.875rem;font-weight:600;display:flex;align-items:center;gap:0.375rem;}.stat-value{font-size:0.875rem;font-weight:700;background:rgba(0,0,0,0.4);padding:0.125rem 0.5rem;border-radius:9999px;}.progress-bar{background:rgba(75,85,99,0.7);border-radius:9999px;height:0.75rem;overflow:hidden;}.progress-fill{height:100%;border-radius:9999px;transition:width 0.5s ease-out;}.progress-fill.hunger{background:linear-gradient(90deg,#fb923c,#ef4444);}.progress-fill.happiness{background:linear-gradient(90deg,#c084fc,#a855f7);}/* 情绪面板 */.mood-panel{display:flex;align-items:center;justify-content:space-between;background:rgba(0,0,0,0.2);border-radius:0.75rem;padding:0.75rem;margin-bottom:1.25rem;border:1px solidrgba(129,140,248,0.2);}.mood-left{display:flex;align-items:center;gap:0.75rem