From f1bbb28b286416dad93dc01f31b66fd846eb3d43 Mon Sep 17 00:00:00 2001 From: psnci6hgk <1747918662@qq.com> Date: Wed, 24 Sep 2025 15:45:45 +0800 Subject: [PATCH] =?UTF-8?q?9.24=20ai=E9=83=A8=E7=BD=B2=E6=88=90=E5=8A=9F?= =?UTF-8?q?=20ai=E9=9A=8F=E6=9C=BA=E7=94=9F=E6=88=90=E4=BA=BA=E8=AE=BE?= =?UTF-8?q?=E4=BB=A5=E5=8F=8Aai=E5=AF=B9=E8=AF=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/oc-community-frontend/{api.env => .env} | 0 .../src/components/ChatWindow.vue | 50 ++-- .../src/components/OCCreationPage.vue | 260 +++++++++++++---- .../src/components/PhoneWidget.vue | 72 +++-- src/oc-community-frontend/开发日志.txt | 276 ++++++------------ 5 files changed, 378 insertions(+), 280 deletions(-) rename src/oc-community-frontend/{api.env => .env} (100%) diff --git a/src/oc-community-frontend/api.env b/src/oc-community-frontend/.env similarity index 100% rename from src/oc-community-frontend/api.env rename to src/oc-community-frontend/.env diff --git a/src/oc-community-frontend/src/components/ChatWindow.vue b/src/oc-community-frontend/src/components/ChatWindow.vue index 7f538c0..e1b5f33 100644 --- a/src/oc-community-frontend/src/components/ChatWindow.vue +++ b/src/oc-community-frontend/src/components/ChatWindow.vue @@ -86,7 +86,7 @@ onMounted(scrollToBottom) onUpdated(scrollToBottom) watch(messages, scrollToBottom, { deep: true }) -const handleSend = () => { +const handleSend = async () => { if (!canSend.value) return const userMsg = { senderId: props.selfId, @@ -102,7 +102,6 @@ const handleSend = () => { // AI回复 const API_KEY = import.meta.env.VITE_ZHIPU_API_KEY - // 可根据联系人id区分AI/真人,下面假设所有联系人都用AI回复 const aiMsg = { senderId: props.activeContact?.id || 'ai', text: 'AI思考中...', @@ -111,12 +110,21 @@ const handleSend = () => { nextMessages = [...messages.value, aiMsg] messages.value = nextMessages emit('update:modelValue', nextMessages) + if (!API_KEY) { + aiMsg.text = 'API_KEY未配置,请检查.env文件和重启项目' + messages.value = [...messages.value.slice(0, -1), aiMsg] + emit('update:modelValue', messages.value) + return + } try { - axios.post( + const res = await axios.post( 'https://open.bigmodel.cn/api/paas/v4/chat/completions', { - model: 'glm-4.5-air', - messages: [{ role: 'user', content: userText }] + model: 'glm-4-flash', + messages: [{ role: 'user', content: userText }], + thinking: { type: 'enabled' }, + max_tokens: 1024, + temperature: 0.6 }, { headers: { @@ -124,22 +132,26 @@ const handleSend = () => { 'Content-Type': 'application/json' } } - ).then(res => { - const reply = res.data.choices?.[0]?.message?.content || 'AI无回复' - aiMsg.text = reply - aiMsg.timestamp = Date.now() - // 更新最后一条AI消息 - messages.value = [...messages.value.slice(0, -1), aiMsg] - emit('update:modelValue', messages.value) - }).catch(() => { - aiMsg.text = 'AI接口调用失败' - messages.value = [...messages.value.slice(0, -1), aiMsg] - emit('update:modelValue', messages.value) - }) - } catch { - aiMsg.text = 'AI接口调用失败' + ) + const reply = res.data.choices?.[0]?.message?.content || 'AI无回复' + aiMsg.text = reply + aiMsg.timestamp = Date.now() + messages.value = [...messages.value.slice(0, -1), aiMsg] + emit('update:modelValue', messages.value) + } catch (err) { + let errMsg = 'AI接口调用失败' + if (err?.response?.data?.msg) { + errMsg += `: ${err.response.data.msg}` + } else if (err?.response?.data?.message) { + errMsg += `: ${err.response.data.message}` + } else if (err?.message) { + errMsg += `: ${err.message}` + } + aiMsg.text = errMsg messages.value = [...messages.value.slice(0, -1), aiMsg] emit('update:modelValue', messages.value) + // 可选:console详细错误 + // console.error('AI接口调用失败', err) } } diff --git a/src/oc-community-frontend/src/components/OCCreationPage.vue b/src/oc-community-frontend/src/components/OCCreationPage.vue index f651679..83dd2c0 100644 --- a/src/oc-community-frontend/src/components/OCCreationPage.vue +++ b/src/oc-community-frontend/src/components/OCCreationPage.vue @@ -7,53 +7,122 @@ - + + 基础信息 + - - - + + + + + 其他 + + + + + + + + + + + - - - - - - - - - - - - - - - + + + 外表形象 + + + + + + + + + + + + + + + + + + 性格与内心 + + + + + + + + + + + + + + + + + + + + + + + + 背景故事与关系 + + + + + + + + + + + + 喜好与日常 + + + + + + + + + + + + + + + + + + 社区角色期待 + + + + + + + + + + + + 头像 + - + { - console.log('AI生成OC') - // 模拟AI生成数据 - ocForm.name = '小' + Math.random().toString(36).substr(2, 4) - ocForm.personality = '活泼开朗,喜欢交朋友' - ocForm.occupation = '学生' - ocForm.birthday = '2000-01-01' - ocForm.hobbies = '音乐、绘画、运动' - ocForm.bio = '这是一个由AI生成的OC角色' - ocForm.avatar = `https://i.pravatar.cc/100?img=${Math.floor(Math.random() * 50) + 1}` - - ElMessage.success('AI生成完成!') +const handleAIGenerate = async () => { + ElMessage.info('AI生成中...') + const API_KEY = import.meta.env.VITE_ZHIPU_API_KEY + const prompt = `生成一个OC角色的JSON对象,字段有: +name, gender, genderOther, birthday, age, race, occupation, hair, eyeColor, height, clothes, feature, personality(数组), personalityOther, mbti, advantage, shortcoming, habit, catchphrase, growup, story, secret, hobbies(数组), foodLike, hate, life, weekend, communityActivity, relation(数组), relationOther, avatar。 +每个字段都要有合理虚构内容,必须为中文,不能留空、不能为[]、不能为null。 +只输出JSON对象本身,不要任何推理、解释、reasoning、注释、代码块、markdown标记或多余内容。`; + try { + const res = await axios.post( + 'https://open.bigmodel.cn/api/paas/v4/chat/completions', + { + model: 'glm-4-flash', + messages: [ + { role: 'user', content: prompt } + ], + temperature: 0.9, + max_tokens: 1024, + thinking: { type: 'enabled' } + }, + { + headers: { + 'Authorization': `Bearer ${API_KEY}`, + 'Content-Type': 'application/json' + } + } + ) + console.log('AI接口完整响应:', res.data) + let jsonStr = res.data.choices?.[0]?.message?.content || '' + // 兼容AI输出前后有markdown、代码块或多余解释 + jsonStr = jsonStr.replace(/^```json|```$/g, '').trim() + // 尝试只提取第一个合法JSON对象 + let data = {} + let parsed = false + try { + data = JSON.parse(jsonStr) + parsed = true + } catch {} + if (!parsed) { + // 尝试用正则提取第一个 {...} 内容 + const match = jsonStr.match(/\{[\s\S]*\}/) + if (match) { + try { + data = JSON.parse(match[0]) + parsed = true + } catch {} + } + } + // B方案:如content为空且reasoning_content存在,尝试从reasoning_content中提取JSON + if (!parsed && res.data.choices?.[0]?.message?.reasoning_content) { + const reasoning = res.data.choices[0].message.reasoning_content + const match = reasoning.match(/\{[\s\S]*\}/) + if (match) { + try { + data = JSON.parse(match[0]) + parsed = true + } catch {} + } + } + if (!parsed) { + ElMessage.error('AI生成内容解析失败,原始内容已打印到控制台') + console.error('AI原始内容:', jsonStr) + if (res.data.choices?.[0]?.message?.reasoning_content) { + console.error('AI reasoning_content:', res.data.choices[0].message.reasoning_content) + } + return + } + // 兼容AI输出的personality/relation为字符串或数组,增强类型兼容 + Object.keys(ocForm).forEach(k => { + if (data[k] !== undefined) { + if (Array.isArray(ocForm[k]) && typeof data[k] === 'string') { + ocForm[k] = data[k].split(/[,,]/).map(s => s.trim()).filter(Boolean) + } else if (typeof ocForm[k] === 'string' && typeof data[k] !== 'string') { + ocForm[k] = String(data[k]) + } else if (Array.isArray(ocForm[k]) && Array.isArray(data[k])) { + ocForm[k] = data[k].map(x => typeof x === 'string' ? x.trim() : String(x)) + } else { + ocForm[k] = data[k] + } + } + }) + console.log('AI同步到表单后的ocForm:', JSON.parse(JSON.stringify(ocForm))) + ElMessage.success('AI生成完成!') + } catch (err) { + let msg = 'AI生成失败' + if (err?.response?.data?.msg) msg += ': ' + err.response.data.msg + else if (err?.message) msg += ': ' + err.message + ElMessage.error(msg) + } } const handleSubmit = async () => { diff --git a/src/oc-community-frontend/src/components/PhoneWidget.vue b/src/oc-community-frontend/src/components/PhoneWidget.vue index 6aa6cf7..aff5295 100644 --- a/src/oc-community-frontend/src/components/PhoneWidget.vue +++ b/src/oc-community-frontend/src/components/PhoneWidget.vue @@ -58,6 +58,8 @@ import { computed, ref, watch } from 'vue' import ContactsList from './ContactsList.vue' import ChatWindow from './ChatWindow.vue' +import { ocList } from '../stores/ocStore' +import { currentUser } from '../stores/userStore' const props = defineProps({ modelValue: { @@ -73,28 +75,15 @@ const modelValueLocal = computed({ set: value => emit('update:modelValue', value) }) -// mock user and contacts -const selfId = 'me' -const selfAvatar = 'https://avatars.githubusercontent.com/u/9919?v=4' +// 使用当前用户OC作为联系人 +const selfId = currentUser.value.username || 'me' +const selfAvatar = currentUser.value.avatar || 'https://avatars.githubusercontent.com/u/9919?v=4' +const contacts = ocList -const contacts = ref([ - { id: 'u_alice', name: 'Alice', avatar: 'https://i.pravatar.cc/100?img=5', status: '在线', lastMessage: '好的', lastTime: Date.now() - 600000, unread: 0 }, - { id: 'u_bob', name: 'Bob', avatar: 'https://i.pravatar.cc/100?img=12', status: '离线', lastMessage: '明天见', lastTime: Date.now() - 3600000, unread: 2 }, - { id: 'u_carla', name: 'Carla', avatar: 'https://i.pravatar.cc/100?img=32', status: '在线', lastMessage: '在吗?', lastTime: Date.now() - 120000, unread: 1 } -]) +// 每个OC独立消息 +const messagesByContact = ref({}) -const messagesByContact = ref({ - u_alice: [ - { senderId: 'u_alice', text: '你好~', timestamp: Date.now() - 7200000 }, - { senderId: selfId, text: '嗨!', timestamp: Date.now() - 7100000 } - ], - u_bob: [ - { senderId: 'u_bob', text: '有空吗', timestamp: Date.now() - 5000000 } - ], - u_carla: [] -}) - -const activeContactId = ref('u_alice') +const activeContactId = ref(contacts.value.length > 0 ? contacts.value[0].id : '') const activeContact = computed(() => contacts.value.find(c => c.id === activeContactId.value) || null) const leftTab = ref('chat') @@ -126,7 +115,7 @@ const formatTime = (ts) => { } -const handleSend = ({ contact, message }) => { +const handleSend = async ({ contact, message }) => { const idx = contacts.value.findIndex(c => c.id === contact.id) if (idx !== -1) { contacts.value[idx] = { @@ -136,11 +125,46 @@ const handleSend = ({ contact, message }) => { } } - // mock auto-reply - setTimeout(() => { + // AI自动回复,参考OC性格 + setTimeout(async () => { + let personality = contact.bio || '' + if (Array.isArray(contact.hobbies) && contact.hobbies.length > 0) { + personality += ` 爱好:${contact.hobbies.join('、')}` + } + if (contact.occupation) { + personality += ` 职业:${contact.occupation}` + } + // 生成简洁轻快的AI回复 + const API_KEY = import.meta.env.VITE_ZHIPU_API_KEY + let aiText = 'AI思考中...' + if (API_KEY) { + try { + const prompt = `你是${contact.name},${personality}。请用简洁轻快的语气回复对方这句话:${message.text}` + const res = await (await import('axios')).default.post( + 'https://open.bigmodel.cn/api/paas/v4/chat/completions', + { + model: 'glm-4.5-air', + messages: [{ role: 'user', content: prompt }], + max_tokens: 128, + temperature: 0.7 + }, + { + headers: { + 'Authorization': `Bearer ${API_KEY}`, + 'Content-Type': 'application/json' + } + } + ) + aiText = res.data.choices?.[0]?.message?.content || '收到!' + } catch (e) { + aiText = 'AI接口异常,自动回复:收到!' + } + } else { + aiText = 'AI KEY未配置,自动回复:收到!' + } const reply = { senderId: contact.id, - text: '收到:' + message.text, + text: aiText, timestamp: Date.now() } const list = messagesByContact.value[contact.id] || [] diff --git a/src/oc-community-frontend/开发日志.txt b/src/oc-community-frontend/开发日志.txt index 6c81d3d..d0b2914 100644 --- a/src/oc-community-frontend/开发日志.txt +++ b/src/oc-community-frontend/开发日志.txt @@ -4,11 +4,89 @@ 创建oc 填写oc问卷或交给ai随机生成oc,上传oc图片或通过填写问卷ai生成图片作为当前oc的头像。 确定oc头像后,进入社区界面,用户可以自定义oc的日程表或者让ai根据填写的问卷生成日程表,游戏内时间需要与用户所处实际时间相同,oc会根据自己的日程表安排自己的活动。小屋中包含卧室,客厅,厨房,健身房,餐厅,超市,花店,体育馆,酒店等等可拓展性活动场所,所有oc都在社区里生活工作甚至学习上课,社区里也有一些aiNPC和用户的oc一起生活。 进入手机界面,用户可以给oc或已结识的NPC发消息进行交流,ai会根据oc自身日程表当前的活动方式决策是实时回复还是延时回复(比如oc当前正在休闲放松可以实时回复,若进行体育运动如游泳就要延时回复),NPC同理。 - + 社区地图 暂定包含以下地点:超市(主卖日常用品),饭店,电影院,商场(综合性),公寓,甜品店,植物园,公园,体育馆,娱乐休闲区(KTV,台球厅,电玩城等) + + + 我希望打开网站后首先出现登录注册页面,完成登录后直接显示社区界面,在当前界面右侧一排从上到下有三个按钮 依次是用户中心 oc列表 手机通信, 点击用户中心会出现用户中心弹窗,弹窗中包含用户头像,用户昵称和一些自我角色的个人信息,下拉最下方有退出登录按钮,点击后会回到登录注册页面。 点击oc列表出现oc列表界面弹窗,初始列表为空白,有一个“创建oc”按钮,点击按钮后出现oc问卷,用户完成问卷填写后点击提交,oc信息会交给ai进行模拟,出现oc头像选择窗口,用户可以选择上传本地图片或者使用ai根据表单提交的信息生成。头像选择完毕后点击确定。 回到用户列表,此时列表中会显示出刚创建的o头像及名称集成卡片,点击卡片会出现oc的信息界面,包含oc头像,oc名称,oc生日,oc喜好,oc职业,oc日程表,oc的社交圈,oc的成就等等,用户可以点击日程表进行修改,点击社交圈可以添加好友,点击成就可以查看自己或好友的成就。 + + + OC角色创建问卷 +欢迎来到OC创造者!请填写以下问卷,帮助我们了解你想要的OC角色。如果不想手动填写,可以点击“AI随机生成”按钮自动创建。 + +1. 基础信息 +角色名称:_________________________ + +性别:□ 男 □ 女 □ 其他 _______ + +生日:___月 ___日 + +年龄:_________________________ + +种族:(如:人类、精灵、兽人、恶魔、机器人等,可自定义)_________________________ + +职业:(如:学生、骑士、程序员、魔法师、偶像、侦探等)_________________________ + +2. 外表形象(用于AI生成图片和视觉想象) +发型与发色:(如:银色短发、金色长卷发、蓝色双马尾)_________________________ + +瞳色:(如:琥珀色、湛蓝色、异色瞳)_________________________ + +大致身高:_________________________ + +着装风格:(如:休闲运动、哥特礼服、未来科技、古典汉服、学院风)_________________________ + +标志性特征:(如:眼角的泪痣、总戴着兜帽、有一条机械臂、有猫耳和尾巴)_________________________ + +3. 性格与内心(这是AI对话和行为逻辑的核心) +核心性格:(请选择1-3项) +□ 开朗外向 □ 安静内向 □ 成熟稳重 □ 天真烂漫 □ 理性冷静 +□ 感性冲动 □ 温柔体贴 □ 傲娇冷淡 □ 幽默搞怪 □ 认真固执 +□ 悲观消极 □ 乐观积极 □ 腹黑 □ 忠犬 □ 其他 _______ + +MBTI人格类型(可选):_________________________ (e.g., INFP, ESTJ) + +最大的优点:_________________________ + +最大的缺点:_________________________ + +习惯性小动作:(如:思考时捻头发、紧张时会结巴、说谎时眼神飘忽)_________________________ + +口头禅:(如:“没问题!”、“让我想想…”、“真是无聊”)_________________________ + +4. 背景故事与关系(让角色更真实丰满) +成长环境:(如:繁华都市、宁静乡村、孤儿院长大、贵族世家、星际飞船)_________________________ + +一段简要的背景故事或重要经历: + +想要隐藏的秘密:(可选)_________________________ + +5. 喜好与日常(用于生成日程表和对话内容) +兴趣爱好:(如:阅读、健身、烹饪、打游戏、观星、写诗)_________________________ + +喜欢的食物:_________________________ + +讨厌的东西:_________________________ + +理想的生活方式:(如:悠闲度日、不断挑战自我、为社会做贡献、陪伴重要的人)_________________________ + +通常如何度过周末:_________________________ + +6. 社区角色期待(决定OC在社区中的行为) +在社区中,你希望TA主要从事什么活动?(如:在花店打工、在健身房锻炼、在图书馆学习、在广场闲逛) + +你希望与TA建立什么样的关系? +□ 亲密无间的朋友 □ 互相扶持的伙伴 □ 需要照顾的后辈 +□ 值得信赖的前辈 □ 略带距离感的熟人 □ 其他 _______ + +提交 | AI随机生成 | 清空重填 | 取消创建 + + + + 功能概述: @@ -19,19 +97,18 @@ 修改个人日程表:用户可自定义或调整自己的日常活动安排。 退出登录:用户可安全退出当前账号,返回登录页。 创建OC:用户可通过问卷或AI生成方式创建属于自己的OC角色。 -修改OC信息:用户可编辑已创建OC的详细资料。 -删除OC:用户可移除不再需要的OC角色。 +管理OC:用户可编辑或删除已创建OC的详细资料。 修改OC日程表:用户可为每个OC单独设定或调整日程安排。 -AI通信:用户可与OC或NPC通过AI进行智能对话。 +AI互动:用户可与OC或NPC通过AI进行智能对话。 可补充的功能及描述 好友系统:用户可添加其他用户为好友,建立社交关系。 社区动态/广场:用户和OC可在社区内发布动态、评论和点赞。 成就系统:用户和OC可通过完成特定任务获得成就徽章。 消息通知:系统可推送好友请求、活动提醒等通知。 -多社区/多世界切换:用户可创建或加入不同主题的社区世界。 -社区活动/事件:定期举办线上活动或社区事件,丰富互动体验。 -自定义社区场景:用户可自定义社区的外观、布局和活动场所。 +*多社区/多世界切换:用户可创建或加入不同主题的社区世界。 +*社区活动/事件:定期举办线上活动或社区事件,丰富互动体验。 +*自定义社区场景:用户可自定义社区的外观、布局和活动场所。 虚拟经济系统:引入虚拟货币,用于购买装饰、道具等。 商城系统:用户可在商城购买服饰、家具等虚拟物品。 排行榜/活跃榜:展示用户或OC的活跃度、成就排名。 @@ -41,7 +118,7 @@ AI通信:用户可与OC或NPC通过AI进行智能对话。 多语言支持:平台支持多种语言切换,适应不同用户群体。 夜间模式:支持界面夜间/白天主题切换。 API开放/插件扩展:为开发者提供API或插件接口,便于二次开发。 -新手引导/帮助中心:为新用户提供操作指引和常见问题解答。 +*新手引导/帮助中心:为新用户提供操作指引和常见问题解答。 数据统计与分析:为用户提供社区活跃度、OC成长等数据可视化。 @@ -50,7 +127,7 @@ API开放/插件扩展:为开发者提供API或插件接口,便于二次开 多个世界,多个社区,自定义社区场景和社区活动,自定义自然环境和社会背景(与实时性相悖?) 与时俱进 增加每日大事件和新闻功能 联机功能 邀请朋友加入自己的世界或加入朋友的世界 - + oc问卷内容 @@ -62,6 +139,7 @@ API开放/插件扩展:为开发者提供API或插件接口,便于二次开 版本问题 +--0.1目标:搭建平台雏形 0.0.1 按钮没有对其 oc创建后没有显示在列表中 @@ -83,7 +161,15 @@ oc创建后没有显示在列表中 要求用户注册后的信息可以正常登录并保存在用户中心中,可以随时修改或查看 联系人列表只要有联系人头像名称就好,不显示最近一次聊天内容和时间 -0.1.0--直至完成了整整意义上的平台雏形 +0.1.0--完成了整体意义上的平台雏形 +0.1.1 +成功调用api进行对话,将手机中的联系人替换成用户自己创建的oc,ai回复逻辑参考oc性格,回复语句模拟现实聊天简洁轻快 +oc问卷中,生日只要月日即可,不需要填写年份,且ai随机生成的内容并没有同步到表单中 + +0.1.2 +oc问卷ai随机生成成功实现,但创建oc数量好像有最大限制,超过4个后新创建的oc会覆盖掉最后一个 +--0.2目标:成功调用ai,搭建基本社区地图 + @@ -98,173 +184,3 @@ Terminal window irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex - - - - - - - - - -### **第一步:搭建你的开发环境 (第1天)** - -1. **安装 Node.js:** - * **是什么:** Node.js是JavaScript的运行环境,前端很多工具都依赖它。 - * **怎么做:** 访问 [Node.js 官网](https://nodejs.org/),下载并安装 **LTS(长期支持版)**。 - * **验证:** 安装完成后,打开命令行(Windows: CMD 或 PowerShell; Mac: Terminal),输入以下命令,能显示版本号即成功。 - ```bash - node -v - npm -v - ``` - -2. **安装代码编辑器 - Visual Studio Code (VS Code):** - * **是什么:** 目前最强大的免费前端开发编辑器。 - * **怎么做:** 访问 [VS Code 官网](https://code.visualstudio.com/),下载安装。 - * **安装必备插件:** 打开VS Code,在左侧扩展商店中搜索并安装: - * `Volar` (Vue 3官方推荐支持插件,**必装**) - * `Auto Rename Tag` (自动重命名配对的HTML标签) - * `ESLint` (代码格式检查) - * `Live Server` (右键一键启动本地服务器预览HTML页面) - * `Chinese (Simplified) Language Pack` (如果需要中文界面) - -3. **安装 Git:** - * **是什么:** 代码版本管理工具,团队协作核心。 - * **怎么做:** 访问 [Git 官网](https://git-scm.com/) 下载安装。 - * **配置:** 安装后,在命令行中设置你的用户名和邮箱(用于标识你的提交): - ```bash - git config --global user.name "你的名字" - git config --global user.email "你的邮箱@example.com" - ``` - ---- - -### **第二步:创建你的第一个Vue项目 (第1-2天)** - -我们使用Vue官方推荐的脚手架工具 `Vite` 来创建项目,它非常快! - -1. **在命令行中创建项目:** - 找一个你喜欢的文件夹,在地址栏输入 `cmd` 打开命令行,执行以下命令: - ```bash - # 使用 npm 创建项目,项目名为 `oc-community-frontend` - npm create vite@latest oc-community-frontend -- --template vue - - # 接下来按照提示操作 - cd oc-community-frontend # 进入项目目录 - npm install # 安装项目依赖(所有需要的代码库) - npm run dev # 启动开发服务器 - ``` -2. **查看效果:** - 执行 `npm run dev` 后,命令行会给出一个本地地址(通常是 `http://localhost:5173`)。用浏览器打开它,你会看到Vue的欢迎页面!恭喜你,项目成功运行了! - -3. **了解项目结构:** - 用VS Code打开你刚创建的 `oc-community-frontend` 文件夹,你会看到类似下面的结构: - ``` - oc-community-frontend - ├── node_modules/ # 所有安装的依赖包(不用动它) - ├── src/ # 源代码目录(主要在这里工作!) - │ ├── assets/ # 静态资源,如图片、字体 - │ ├── components/ # Vue组件目录(可复用的小模块) - │ ├── App.vue # 根组件(应用的主组件) - │ └── main.js # 项目的入口文件 - ├── index.html # 主HTML页面 - ├── package.json # 项目配置文件(记录了项目信息和依赖) - └── vite.config.js # Vite的配置文件 - ``` - ---- - -### **第三步:学习核心概念并开始修改 (第2-4周)** - -你的目标是实现页面,而不是从零造轮子。所以我们要**现学现用**。 - -1. **学习最低限度的Vue语法:** - * **单文件组件 (.vue文件)**:`