import { createApp, reactive, ref, computed, watch, onMounted, nextTick } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'; import QQApp from './apps/QQApp.js'; import SettingsApp from './apps/SettingsApp.js'; const app = createApp({ components: { 'qq-app': QQApp, 'settings-app': SettingsApp }, setup() { // === 1. 数据定义 (恢复原来的数据结构) === const defaultData = { wallpaper: 'https://images.unsplash.com/photo-1550684848-fac1c5b4e853?q=80&w=1000&auto=format&fit=crop', avatar: { img: '', frame: 'frame-pink' }, profile: { name: '小手机 <3', bio1: 'Welcome to my world', bio2: '点击下方图标开始聊天' }, colors: { app: '#5D4037', widget: '#5D4037', header: '#5D4037' }, photos: [ 'https://images.unsplash.com/photo-1516961642265-531546e84af2?q=80&w=400&auto=format&fit=crop', 'https://images.unsplash.com/photo-1529333166437-7750a6dd5a70?q=80&w=400&auto=format&fit=crop' ], // 桌面上的APP desktopApps: { qq: { icon: '🐧', name: 'QQ', img: '' }, world: { icon: '📕', name: '世界书', img: '' }, phone: { icon: '📱', name: '查手机', img: '' }, game: { icon: '🎮', name: '小游戏', img: '' }, }, // 底部 Dock 栏的 APP dockApps: { settings: { icon: '⚙️', name: '设置', img: '' }, storage: { icon: '💾', name: '储存', img: '' }, font: { icon: '🔤', name: '字体', img: '' }, theme: { icon: '🎨', name: '美化', img: '' }, }, textWidgets: [ { title: '状态', desc: '心情美美哒 ✨', align: 'center' }, { title: '备忘', desc: '记得喝水哦 🥛', align: 'center' } ], apiConfig: { endpoint: '', key: '', model: '' } }; // 响应式状态 const wallpaper = ref(defaultData.wallpaper); const avatar = reactive({ ...defaultData.avatar }); const profile = reactive({ ...defaultData.profile }); const colors = reactive({ ...defaultData.colors }); const photos = reactive([...defaultData.photos]); const desktopApps = reactive(JSON.parse(JSON.stringify(defaultData.desktopApps))); const dockApps = reactive(JSON.parse(JSON.stringify(defaultData.dockApps))); const textWidgets = reactive(JSON.parse(JSON.stringify(defaultData.textWidgets))); const apiConfig = reactive({ ...defaultData.apiConfig }); // 计算属性 const allApps = computed(() => ({ ...desktopApps, ...dockApps })); // 窗口控制状态 const windows = reactive({ qq: false, settings: false, beautify: false, // 美化中心 world: false }); // 弹窗控制状态 const activeModal = ref(null); const uploadTargetType = ref(''); const uploadTargetIndex = ref(null); const fileInput = ref(null); const tempText = reactive({ title: '', desc: '', align: 'left', index: null }); const tempInputVal = ref(''); const editTargetKey = ref(''); const editTargetLabel = ref(''); // === 2. 核心逻辑 === // 存储逻辑 const STORAGE_KEY = 'my_ai_phone_system_v1'; const loadData = () => { const saved = localStorage.getItem(STORAGE_KEY); if (saved) { try { const data = JSON.parse(saved); if(data.wallpaper) wallpaper.value = data.wallpaper; if(data.avatar) Object.assign(avatar, data.avatar); if(data.profile) Object.assign(profile, data.profile); if(data.colors) Object.assign(colors, data.colors); if(data.photos) photos.splice(0, photos.length, ...data.photos); if(data.desktopApps) Object.assign(desktopApps, data.desktopApps); if(data.dockApps) Object.assign(dockApps, data.dockApps); if(data.textWidgets) textWidgets.splice(0, textWidgets.length, ...data.textWidgets); if(data.apiConfig) Object.assign(apiConfig, data.apiConfig); } catch (e) { console.error("读取存档失败", e); } } }; // 自动保存 watch([wallpaper, avatar, profile, colors, photos, desktopApps, dockApps, textWidgets, apiConfig], () => { const dataToSave = { wallpaper: wallpaper.value, avatar, profile, colors, photos, desktopApps, dockApps, textWidgets, apiConfig }; localStorage.setItem(STORAGE_KEY, JSON.stringify(dataToSave)); }, { deep: true }); onMounted(() => loadData()); // 图片处理工具 const compressImage = (file) => { return new Promise((resolve) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = (e) => { const img = new Image(); img.src = e.target.result; img.onload = () => { const canvas = document.createElement('canvas'); let w = img.width, h = img.height; const max = 800; if (w > h) { if (w > max) { h *= max / w; w = max; } } else { if (h > max) { w *= max / h; h = max; } } canvas.width = w; canvas.height = h; canvas.getContext('2d').drawImage(img, 0, 0, w, h); resolve(canvas.toDataURL('image/jpeg', 0.6)); }; }; }); }; // === 3. 交互逻辑 === const handleAppClick = (key) => { if (key === 'qq') windows.qq = true; else if (key === 'settings') windows.settings = true; else if (key === 'theme') windows.beautify = true; else if (key === 'world') alert("世界书开发中..."); else if (key === 'game') alert("小游戏开发中..."); else if (key === 'phone') alert("查手机功能开发中..."); else if (key === 'storage' || key === 'font') alert("该功能暂未开放"); }; // 文件上传相关 const triggerFileUpload = (type) => { uploadTargetType.value = type; fileInput.value.click(); }; const handleFileChange = async (e) => { const file = e.target.files[0]; if (file) { const url = await compressImage(file); applyUpload(url); } e.target.value = ''; }; const handleLinkUpload = (type) => { uploadTargetType.value = type || uploadTargetType.value; activeModal.value = null; setTimeout(() => { const url = prompt("请输入图片链接:"); if (url && url.trim()) applyUpload(url); }, 100); }; const applyUpload = (url) => { if (uploadTargetType.value === 'avatar') avatar.img = url; else if (uploadTargetType.value === 'wallpaper') wallpaper.value = url; else if (uploadTargetType.value === 'photo') photos[uploadTargetIndex.value] = url; else if (uploadTargetType.value === 'icon') { const key = uploadTargetIndex.value; if (desktopApps[key]) desktopApps[key].img = url; if (dockApps[key]) dockApps[key].img = url; } activeModal.value = null; }; // 各种弹窗逻辑 const openImageModal = (type, index) => { uploadTargetType.value = type; uploadTargetIndex.value = index; activeModal.value = 'image'; }; const openSingleEdit = (key, label) => { editTargetKey.value = key; editTargetLabel.value = label; tempInputVal.value = profile[key]; activeModal.value = 'singleEdit'; }; const saveSingleEdit = () => { if (editTargetKey.value) profile[editTargetKey.value] = tempInputVal.value; activeModal.value = null; }; const openTextEdit = (index) => { const w = textWidgets[index]; tempText.title = w.title; tempText.desc = w.desc; tempText.align = w.align || 'left'; tempText.index = index; activeModal.value = 'textEdit'; }; const saveTextEdit = () => { const i = tempText.index; textWidgets[i].title = tempText.title; textWidgets[i].desc = tempText.desc; textWidgets[i].align = tempText.align; activeModal.value = null; }; const openIconModal = (key) => { uploadTargetType.value = 'icon'; uploadTargetIndex.value = key; activeModal.value = 'icon'; }; const setFrame = (f) => { avatar.frame = f; activeModal.value = null; }; const resetBeautify = () => { if(confirm("重置美化?")) localStorage.removeItem(STORAGE_KEY); location.reload(); }; const getFlexAlign = (a) => a === 'center' ? 'center' : (a === 'right' ? 'flex-end' : 'flex-start'); const getCurrentIconName = () => (allApps.value[uploadTargetIndex.value] || {}).name; return { // 数据 wallpaper, avatar, profile, colors, photos, desktopApps, dockApps, allApps, textWidgets, apiConfig, windows, activeModal, tempText, tempInputVal, editTargetLabel, fileInput, // 方法 handleAppClick, triggerFileUpload, handleFileChange, handleLinkUpload, openImageModal, openSingleEdit, saveSingleEdit, openTextEdit, saveTextEdit, openIconModal, setFrame, resetBeautify, getFlexAlign, getCurrentIconName, uploadTargetType // 必须返回这个,HTML里用到了 }; } }); app.mount('#app');