commit 888f8d9939be6f557675e76876623c3a03d2bb7b Author: 宋凯 <18937831187@189.cn> Date: Sun Sep 28 17:07:09 2025 +0800 first diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..115cc02 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,31 @@ +/* + * Eslint config file + * Documentation: https://eslint.org/docs/user-guide/configuring/ + * Install the Eslint extension before using this feature. + */ +module.exports = { + env: { + es6: true, + browser: true, + node: true, + }, + ecmaFeatures: { + modules: true, + }, + parserOptions: { + ecmaVersion: 2018, + sourceType: 'module', + }, + globals: { + wx: true, + App: true, + Page: true, + getCurrentPages: true, + getApp: true, + Component: true, + requirePlugin: true, + requireMiniProgram: true, + }, + // extends: 'eslint:recommended', + rules: {}, +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..14ea590 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Windows +[Dd]esktop.ini +Thumbs.db +$RECYCLE.BIN/ + +# macOS +.DS_Store +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes + +# Node.js +node_modules/ diff --git a/app.js b/app.js new file mode 100644 index 0000000..4af33be --- /dev/null +++ b/app.js @@ -0,0 +1,2 @@ +// app.js +App({}) diff --git a/app.json b/app.json new file mode 100644 index 0000000..2207ca5 --- /dev/null +++ b/app.json @@ -0,0 +1,57 @@ +{ + "pages": [ + "pages/index/index", + "pages/index2/index2", + "pages/record/record", + "pages/detail/detail", + "pages/history/history" + ], + "window": { + "backgroundTextStyle": "light", + "navigationBarBackgroundColor": "#4a6fa5", + "navigationBarTitleText": "梦境日记", + "navigationBarTextStyle": "white" + }, + "tabBar": { + "color": "#7A7E83", + "selectedColor": "#4a6fa5", + "borderStyle": "black", + "list": [ + { + "pagePath": "pages/index/index", + "text": "首页", + "iconPath": "images/home.png", + "selectedIconPath": "images/home-active.png" + }, + { + "pagePath": "pages/index2/index2", + "text": "首页2", + "iconPath": "images/home.png", + "selectedIconPath": "images/home-active.png" + }, + { + "pagePath": "pages/record/record", + "text": "记录", + "iconPath": "images/add.png", + "selectedIconPath": "images/add-active.png" + }, + { + "pagePath": "pages/history/history", + "text": "历史", + "iconPath": "images/history.png", + "selectedIconPath": "images/history-active.png" + } + ] + }, + "style": "v2", + "sitemapLocation": "sitemap.json", + "permission": { + "scope.userLocation": { + "desc": "用于加载本地视频资源" + } + }, + "networkTimeout": { + "downloadFile": 10000 + }, + "lazyCodeLoading": "requiredComponents" +} diff --git a/app.wxss b/app.wxss new file mode 100644 index 0000000..06c6fc9 --- /dev/null +++ b/app.wxss @@ -0,0 +1,10 @@ +/**app.wxss**/ +.container { + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-between; + padding: 200rpx 0; + box-sizing: border-box; +} diff --git a/components/navigation-bar/navigation-bar.js b/components/navigation-bar/navigation-bar.js new file mode 100644 index 0000000..eb1770e --- /dev/null +++ b/components/navigation-bar/navigation-bar.js @@ -0,0 +1,102 @@ +Component({ + options: { + multipleSlots: true // 在组件定义时的选项中启用多slot支持 + }, + /** + * 组件的属性列表 + */ + properties: { + extClass: { + type: String, + value: '' + }, + title: { + type: String, + value: '' + }, + background: { + type: String, + value: '' + }, + color: { + type: String, + value: '' + }, + back: { + type: Boolean, + value: true + }, + loading: { + type: Boolean, + value: false + }, + homeButton: { + type: Boolean, + value: false, + }, + animated: { + // 显示隐藏的时候opacity动画效果 + type: Boolean, + value: true + }, + show: { + // 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在 + type: Boolean, + value: true, + observer: '_showChange' + }, + // back为true的时候,返回的页面深度 + delta: { + type: Number, + value: 1 + }, + }, + /** + * 组件的初始数据 + */ + data: { + displayStyle: '' + }, + lifetimes: { + attached() { + const rect = wx.getMenuButtonBoundingClientRect() + const platform = (wx.getDeviceInfo() || wx.getSystemInfoSync()).platform + const isAndroid = platform === 'android' + const isDevtools = platform === 'devtools' + const { windowWidth, safeArea: { top = 0, bottom = 0 } = {} } = wx.getWindowInfo() || wx.getSystemInfoSync() + this.setData({ + ios: !isAndroid, + innerPaddingRight: `padding-right: ${windowWidth - rect.left}px`, + leftWidth: `width: ${windowWidth - rect.left}px`, + safeAreaTop: isDevtools || isAndroid ? `height: calc(var(--height) + ${top}px); padding-top: ${top}px` : `` + }) + }, + }, + /** + * 组件的方法列表 + */ + methods: { + _showChange(show) { + const animated = this.data.animated + let displayStyle = '' + if (animated) { + displayStyle = `opacity: ${show ? '1' : '0' + };transition:opacity 0.5s;` + } else { + displayStyle = `display: ${show ? '' : 'none'}` + } + this.setData({ + displayStyle + }) + }, + back() { + const data = this.data + if (data.delta) { + wx.navigateBack({ + delta: data.delta + }) + } + this.triggerEvent('back', { delta: data.delta }, {}) + } + }, +}) diff --git a/components/navigation-bar/navigation-bar.json b/components/navigation-bar/navigation-bar.json new file mode 100644 index 0000000..4a20f17 --- /dev/null +++ b/components/navigation-bar/navigation-bar.json @@ -0,0 +1,5 @@ +{ + "component": true, + "styleIsolation": "apply-shared", + "usingComponents": {} +} \ No newline at end of file diff --git a/components/navigation-bar/navigation-bar.wxml b/components/navigation-bar/navigation-bar.wxml new file mode 100644 index 0000000..be9a663 --- /dev/null +++ b/components/navigation-bar/navigation-bar.wxml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{title}} + + + + + + + + + + + + diff --git a/components/navigation-bar/navigation-bar.wxss b/components/navigation-bar/navigation-bar.wxss new file mode 100644 index 0000000..8bd379e --- /dev/null +++ b/components/navigation-bar/navigation-bar.wxss @@ -0,0 +1,96 @@ +.weui-navigation-bar { + --weui-FG-0:rgba(0,0,0,.9); + --height: 44px; + --left: 16px; +} +.weui-navigation-bar .android { + --height: 48px; +} + +.weui-navigation-bar { + overflow: hidden; + color: var(--weui-FG-0); + flex: none; +} + +.weui-navigation-bar__inner { + position: relative; + top: 0; + left: 0; + height: calc(var(--height) + env(safe-area-inset-top)); + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + padding-top: env(safe-area-inset-top); + width: 100%; + box-sizing: border-box; +} + +.weui-navigation-bar__left { + position: relative; + padding-left: var(--left); + display: flex; + flex-direction: row; + align-items: flex-start; + height: 100%; + box-sizing: border-box; +} + +.weui-navigation-bar__btn_goback_wrapper { + padding: 11px 18px 11px 16px; + margin: -11px -18px -11px -16px; +} + +.weui-navigation-bar__btn_goback_wrapper.weui-active { + opacity: 0.5; +} + +.weui-navigation-bar__btn_goback { + font-size: 12px; + width: 12px; + height: 24px; + -webkit-mask: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='24' viewBox='0 0 12 24'%3E %3Cpath fill-opacity='.9' fill-rule='evenodd' d='M10 19.438L8.955 20.5l-7.666-7.79a1.02 1.02 0 0 1 0-1.42L8.955 3.5 10 4.563 2.682 12 10 19.438z'/%3E%3C/svg%3E") no-repeat 50% 50%; + mask: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='24' viewBox='0 0 12 24'%3E %3Cpath fill-opacity='.9' fill-rule='evenodd' d='M10 19.438L8.955 20.5l-7.666-7.79a1.02 1.02 0 0 1 0-1.42L8.955 3.5 10 4.563 2.682 12 10 19.438z'/%3E%3C/svg%3E") no-repeat 50% 50%; + -webkit-mask-size: cover; + mask-size: cover; + background-color: var(--weui-FG-0); +} + +.weui-navigation-bar__center { + font-size: 17px; + text-align: center; + position: relative; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + font-weight: bold; + flex: 1; + height: 100%; +} + +.weui-navigation-bar__loading { + margin-right: 4px; + align-items: center; +} + +.weui-loading { + font-size: 16px; + width: 16px; + height: 16px; + display: block; + background: transparent url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8'%3F%3E%3Csvg width='80px' height='80px' viewBox='0 0 80 80' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Ctitle%3Eloading%3C/title%3E%3Cdefs%3E%3ClinearGradient x1='94.0869141%25' y1='0%25' x2='94.0869141%25' y2='90.559082%25' id='linearGradient-1'%3E%3Cstop stop-color='%23606060' stop-opacity='0' offset='0%25'%3E%3C/stop%3E%3Cstop stop-color='%23606060' stop-opacity='0.3' offset='100%25'%3E%3C/stop%3E%3C/linearGradient%3E%3ClinearGradient x1='100%25' y1='8.67370605%25' x2='100%25' y2='90.6286621%25' id='linearGradient-2'%3E%3Cstop stop-color='%23606060' offset='0%25'%3E%3C/stop%3E%3Cstop stop-color='%23606060' stop-opacity='0.3' offset='100%25'%3E%3C/stop%3E%3C/linearGradient%3E%3C/defs%3E%3Cg stroke='none' stroke-width='1' fill='none' fill-rule='evenodd' opacity='0.9'%3E%3Cg%3E%3Cpath d='M40,0 C62.09139,0 80,17.90861 80,40 C80,62.09139 62.09139,80 40,80 L40,73 C58.2253967,73 73,58.2253967 73,40 C73,21.7746033 58.2253967,7 40,7 L40,0 Z' fill='url(%23linearGradient-1)'%3E%3C/path%3E%3Cpath d='M40,0 L40,7 C21.7746033,7 7,21.7746033 7,40 C7,58.2253967 21.7746033,73 40,73 L40,80 C17.90861,80 0,62.09139 0,40 C0,17.90861 17.90861,0 40,0 Z' fill='url(%23linearGradient-2)'%3E%3C/path%3E%3Ccircle id='Oval' fill='%23606060' cx='40.5' cy='3.5' r='3.5'%3E%3C/circle%3E%3C/g%3E%3C/g%3E%3C/svg%3E%0A") no-repeat; + background-size: 100%; + margin-left: 0; + animation: loading linear infinite 1s; +} + +@keyframes loading { + from { + transform: rotate(0); + } + to { + transform: rotate(360deg); + } +} diff --git a/images/add-active.png b/images/add-active.png new file mode 100644 index 0000000..ad5e338 Binary files /dev/null and b/images/add-active.png differ diff --git a/images/add.png b/images/add.png new file mode 100644 index 0000000..c0eccc2 Binary files /dev/null and b/images/add.png differ diff --git a/images/history-active.png b/images/history-active.png new file mode 100644 index 0000000..718fb33 Binary files /dev/null and b/images/history-active.png differ diff --git a/images/history.png b/images/history.png new file mode 100644 index 0000000..325583b Binary files /dev/null and b/images/history.png differ diff --git a/images/home-active.png b/images/home-active.png new file mode 100644 index 0000000..72f3cdd Binary files /dev/null and b/images/home-active.png differ diff --git a/images/home.png b/images/home.png new file mode 100644 index 0000000..4555e7a Binary files /dev/null and b/images/home.png differ diff --git a/pages/detail/detail.js b/pages/detail/detail.js new file mode 100644 index 0000000..d156783 --- /dev/null +++ b/pages/detail/detail.js @@ -0,0 +1,107 @@ +Page({ + data: { + dream: {}, + dreamId: '', + emotions: [ + { name: '开心', value: 'happy', icon: 'smile' }, + { name: '害怕', value: 'scared', icon: 'warn' }, + { name: '治愈', value: 'healing', icon: 'like' }, + { name: '怪异', value: 'strange', icon: 'question' }, + { name: '悲伤', value: 'sad', icon: 'cry' }, + { name: '愤怒', value: 'angry', icon: 'no' }, + { name: '紧张', value: 'nervous', icon: 'waiting' }, + { name: '平静', value: 'calm', icon: 'sleep' } + ] + }, + + onLoad(options) { + const id = options.id; + this.setData({ + dreamId: id + }); + this.loadDreamDetail(id); + }, + + // 加载梦境详情 + loadDreamDetail(id) { + wx.getStorage({ + key: 'dreamRecords', + success: (res) => { + const records = res.data || []; + const dream = records.find(record => record.id === id); + + if (dream) { + this.setData({ + dream + }); + } else { + wx.showToast({ + title: '未找到记录', + icon: 'none' + }); + setTimeout(() => { + wx.navigateBack(); + }, 1500); + } + } + }); + }, + + // 获取情绪图标 + getEmotionIcon(emotion) { + const emotionObj = this.data.emotions.find(item => item.value === emotion); + return emotionObj ? emotionObj.icon : 'info'; + }, + + // 获取情绪名称 + getEmotionName(emotion) { + const emotionObj = this.data.emotions.find(item => item.value === emotion); + return emotionObj ? emotionObj.name : ''; + }, + + // 删除记录 + deleteRecord() { + const that = this; + wx.showModal({ + title: '确认删除', + content: '确定要删除这条梦境记录吗?', + success(res) { + if (res.confirm) { + wx.getStorage({ + key: 'dreamRecords', + success: (res) => { + let records = res.data || []; + records = records.filter(record => record.id !== that.data.dreamId); + + wx.setStorage({ + key: 'dreamRecords', + data: records, + success: () => { + wx.showToast({ + title: '删除成功', + icon: 'success', + duration: 2000 + }); + + setTimeout(() => { + wx.navigateBack(); + }, 1500); + } + }); + } + }); + } + } + }); + }, + + // 编辑记录 + editRecord() { + // 在实际应用中,这里应该跳转到编辑页面 + // 并传递当前记录的数据 + wx.showToast({ + title: '编辑功能开发中', + icon: 'none' + }); + } +}); diff --git a/pages/detail/detail.json b/pages/detail/detail.json new file mode 100644 index 0000000..8835af0 --- /dev/null +++ b/pages/detail/detail.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/detail/detail.wxml b/pages/detail/detail.wxml new file mode 100644 index 0000000..4610062 --- /dev/null +++ b/pages/detail/detail.wxml @@ -0,0 +1,82 @@ + + + {{dream.title}} + {{dream.date}} + + + + + {{getEmotionName(dream.emotion)}} + + + + + + {{item}} + + + + + + + + + + + 场景 + + {{dream.scene}} + + + + + + + 人物 + + {{dream.characters}} + + + + + + + 情节 + + {{dream.plot}} + + + + + + + 其他细节 + + {{dream.details}} + + + + + + + + + diff --git a/pages/detail/detail.wxss b/pages/detail/detail.wxss new file mode 100644 index 0000000..91973ea --- /dev/null +++ b/pages/detail/detail.wxss @@ -0,0 +1 @@ +/* pages/detail/detail.wxss */ \ No newline at end of file diff --git a/pages/history/history.js b/pages/history/history.js new file mode 100644 index 0000000..d174af8 --- /dev/null +++ b/pages/history/history.js @@ -0,0 +1,129 @@ +Page({ + data: { + records: [], + filteredRecords: [], + allTags: [], + selectedFilterTag: '', + searchKeyword: '' + }, + + onLoad() { + this.loadDreamRecords(); + }, + + onShow() { + // 每次页面显示时重新加载数据 + this.loadDreamRecords(); + }, + + // 加载梦境记录 + loadDreamRecords() { + wx.getStorage({ + key: 'dreamRecords', + success: (res) => { + const records = res.data || []; + const allTags = this.extractAllTags(records); + + this.setData({ + records, + filteredRecords: records, + allTags + }); + } + }); + }, + + // 提取所有标签 + extractAllTags(records) { + const tagSet = new Set(); + + records.forEach(record => { + record.tags.forEach(tag => { + tagSet.add(tag); + }); + }); + + return Array.from(tagSet); + }, + + // 搜索功能 + onSearchChange(e) { + const keyword = e.detail.value.trim().toLowerCase(); + this.setData({ + searchKeyword: keyword + }); + this.filterRecords(keyword, this.data.selectedFilterTag); + }, + + // 选择筛选标签 + selectFilterTag(e) { + const tag = e.currentTarget.dataset.tag; + this.setData({ + selectedFilterTag: tag + }); + this.filterRecords(this.data.searchKeyword, tag); + }, + + // 筛选记录 + filterRecords(keyword, tag) { + let filtered = [...this.data.records]; + + // 按标签筛选 + if (tag) { + filtered = filtered.filter(record => + record.tags.includes(tag) + ); + } + + // 按关键词搜索 + if (keyword) { + filtered = filtered.filter(record => { + const textToSearch = [ + record.title, + record.scene, + record.characters, + record.plot, + record.details, + ...record.tags + ].join(' ').toLowerCase(); + + return textToSearch.includes(keyword); + }); + } + + this.setData({ + filteredRecords: filtered + }); + }, + + // 获取情绪对应的图标 + getEmotionIcon(emotion) { + const emotionMap = { + 'happy': 'smile', + 'scared': 'warn', + 'healing': 'like', + 'strange': 'question', + 'sad': 'cry', + 'angry': 'no', + 'nervous': 'waiting', + 'calm': 'sleep' + }; + + return emotionMap[emotion] || 'info'; + }, + + // 跳转到记录页面 + navigateToRecord() { + wx.navigateTo({ + url: '/pages/record/record' + }); + }, + + // 跳转到详情页面 + navigateToDetail(e) { + const id = e.currentTarget.dataset.id; + wx.navigateTo({ + url: `/pages/detail/detail?id=${id}` + }); + } +}); diff --git a/pages/history/history.json b/pages/history/history.json new file mode 100644 index 0000000..8835af0 --- /dev/null +++ b/pages/history/history.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/history/history.wxml b/pages/history/history.wxml new file mode 100644 index 0000000..f88fb66 --- /dev/null +++ b/pages/history/history.wxml @@ -0,0 +1,90 @@ + + + 我的梦境记录 + {{records.length}} 条记录 + + + + + + + + + + + + + 全部 + + + {{item}} + + + + + + + + + 还没有记录呢 + 快去记录你的第一个梦境吧 + + + + + + {{item.title}} + {{item.date}} + + + + + {{item.plot.length > 50 ? item.plot.substring(0, 50) + '...' : item.plot || '点击查看详情'}} + + + + + + {{item}} + + + + + + + + + diff --git a/pages/history/history.wxss b/pages/history/history.wxss new file mode 100644 index 0000000..e3b28f6 --- /dev/null +++ b/pages/history/history.wxss @@ -0,0 +1 @@ +/* pages/history/history.wxss */ \ No newline at end of file diff --git a/pages/index/index.js b/pages/index/index.js new file mode 100644 index 0000000..3146157 --- /dev/null +++ b/pages/index/index.js @@ -0,0 +1,82 @@ +Page({ + data: { + animationFrame: null // 用于保存定时器ID + }, + + onReady() { + // 获取Canvas上下文 + const query = wx.createSelectorQuery() + + // 获取Canvas宽高 + query.select('.starry-canvas') + .fields({ node: true, size: true }) + .exec((res) => { + const canvas = res[0].node + const ctx = canvas.getContext('2d') + + const dpr = wx.getSystemInfoSync().pixelRatio + canvas.width = res[0].width * dpr + canvas.height = res[0].height * dpr + ctx.scale(dpr, dpr) + + // 绘制星空 + this.drawStars(canvas, ctx) + }) + }, + + // 绘制动态星空 + drawStars(canvas, ctx) { + const width = canvas.width / wx.getSystemInfoSync().pixelRatio + const height = canvas.height / wx.getSystemInfoSync().pixelRatio + + // 创建星星数组 + const stars = [] + const starCount = 200 // 星星数量 + + // 初始化星星 + for (let i = 0; i < starCount; i++) { + stars.push({ + x: Math.random() * width, + y: Math.random() * height, + radius: Math.random() * 1.5 + 0.5, // 星星大小 + opacity: Math.random(), // 透明度 + speed: Math.random() * 0.5 + 0.1 // 移动速度 + }) + } + + // 动画循环 - 使用setInterval替代requestAnimationFrame + const animate = () => { + // 清空画布 + ctx.clearRect(0, 0, width, height) + + // 绘制每颗星星 + stars.forEach(star => { + // 更新星星位置(向上移动) + star.y -= star.speed + if (star.y < 0) { + star.y = height // 星星移出屏幕后重新从底部出现 + } + + // 随机闪烁效果 + star.opacity += (Math.random() - 0.5) * 0.02 + star.opacity = Math.max(0.1, Math.min(1, star.opacity)) + + // 绘制星星 + ctx.beginPath() + ctx.arc(star.x, star.y, star.radius, 0, Math.PI * 2) + ctx.fillStyle = `rgba(255, 255, 255, ${star.opacity})` + ctx.fill() + }) + } + + // 开始动画,每30ms更新一次(约33fps) + this.data.animationFrame = setInterval(animate, 30) + }, + + // 页面卸载时清除定时器,避免内存泄漏 + onUnload() { + if (this.data.animationFrame) { + clearInterval(this.data.animationFrame) + } + } +}) diff --git a/pages/index/index.json b/pages/index/index.json new file mode 100644 index 0000000..aa3f1b0 --- /dev/null +++ b/pages/index/index.json @@ -0,0 +1,5 @@ +{ + "usingComponents": { + "navigation-bar": "/components/navigation-bar/navigation-bar" + } +} \ No newline at end of file diff --git a/pages/index/index.wxml b/pages/index/index.wxml new file mode 100644 index 0000000..3d4f2bb --- /dev/null +++ b/pages/index/index.wxml @@ -0,0 +1,12 @@ + + + + + + 梦之笺 + 记录你的梦 + diff --git a/pages/index/index.wxss b/pages/index/index.wxss new file mode 100644 index 0000000..9c81f66 --- /dev/null +++ b/pages/index/index.wxss @@ -0,0 +1,34 @@ +.starry-canvas { + position: absolute; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: #0a0a1a; /* 深蓝色夜空 */ + z-index: 0; +} + +.content { + position: relative; + z-index: 1; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + color: #ffffff; + padding: 20rpx; +} + +.title { + font-size: 60rpx; + font-weight: bold; + margin-bottom: 20rpx; + text-shadow: 0 0 10rpx rgba(255, 255, 255, 0.5); +} + +.subtitle { + font-size: 32rpx; + opacity: 0.9; +} diff --git a/pages/index2/index2.js b/pages/index2/index2.js new file mode 100644 index 0000000..7e4a50f --- /dev/null +++ b/pages/index2/index2.js @@ -0,0 +1,83 @@ +Page({ + data: { + playbackRate: 5.0, // 默认1倍速 + animationFrame: null // 用于保存定时器ID + }, + + onReady() { + // 获取Canvas上下文 + const query = wx.createSelectorQuery() + + // 获取Canvas宽高 + query.select('.starry-canvas') + .fields({ node: true, size: true }) + .exec((res) => { + const canvas = res[0].node + const ctx = canvas.getContext('2d') + + const dpr = wx.getSystemInfoSync().pixelRatio + canvas.width = res[0].width * dpr + canvas.height = res[0].height * dpr + ctx.scale(dpr, dpr) + + // 绘制星空 + this.drawStars(canvas, ctx) + }) + }, + + // 绘制动态星空 + drawStars(canvas, ctx) { + const width = canvas.width / wx.getSystemInfoSync().pixelRatio + const height = canvas.height / wx.getSystemInfoSync().pixelRatio + + // 创建星星数组 + const stars = [] + const starCount = 200 // 星星数量 + + // 初始化星星 + for (let i = 0; i < starCount; i++) { + stars.push({ + x: Math.random() * width, + y: Math.random() * height, + radius: Math.random() * 1.5 + 0.5, // 星星大小 + opacity: Math.random(), // 透明度 + speed: Math.random() * 0.5 + 0.1 // 移动速度 + }) + } + + // 动画循环 - 使用setInterval替代requestAnimationFrame + const animate = () => { + // 清空画布 + ctx.clearRect(0, 0, width, height) + + // 绘制每颗星星 + stars.forEach(star => { + // 更新星星位置(向上移动) + star.y -= star.speed + if (star.y < 0) { + star.y = height // 星星移出屏幕后重新从底部出现 + } + + // 随机闪烁效果 + star.opacity += (Math.random() - 0.5) * 0.02 + star.opacity = Math.max(0.1, Math.min(1, star.opacity)) + + // 绘制星星 + ctx.beginPath() + ctx.arc(star.x, star.y, star.radius, 0, Math.PI * 2) + ctx.fillStyle = `rgba(255, 255, 255, ${star.opacity})` + ctx.fill() + }) + } + + // 开始动画,每30ms更新一次(约33fps) + this.data.animationFrame = setInterval(animate, 30) + }, + + // 页面卸载时清除定时器,避免内存泄漏 + onUnload() { + if (this.data.animationFrame) { + clearInterval(this.data.animationFrame) + } + } +}) diff --git a/pages/index2/index2.json b/pages/index2/index2.json new file mode 100644 index 0000000..aa3f1b0 --- /dev/null +++ b/pages/index2/index2.json @@ -0,0 +1,5 @@ +{ + "usingComponents": { + "navigation-bar": "/components/navigation-bar/navigation-bar" + } +} \ No newline at end of file diff --git a/pages/index2/index2.wxml b/pages/index2/index2.wxml new file mode 100644 index 0000000..a1d265b --- /dev/null +++ b/pages/index2/index2.wxml @@ -0,0 +1,15 @@ + + + + + 欢迎来到我的梦境 + + diff --git a/pages/index2/index2.wxss b/pages/index2/index2.wxss new file mode 100644 index 0000000..daa02e9 --- /dev/null +++ b/pages/index2/index2.wxss @@ -0,0 +1,31 @@ +.page-container { + position: relative; + width: 100%; + height: 100vh; + overflow: hidden; +} + +#bg-video { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: -1; +} + +.content { + position: relative; + z-index: 1; + display: flex; + justify-content: center; + align-items: center; + height: 100%; + color: white; + text-align: center; +} + +.title { + font-size: 64rpx; + font-weight: bold; +} \ No newline at end of file diff --git a/pages/record/record.js b/pages/record/record.js new file mode 100644 index 0000000..79b4c3a --- /dev/null +++ b/pages/record/record.js @@ -0,0 +1,172 @@ +Page({ + data: { + // 梦境内容 + title: '', + scene: '', + characters: '', + plot: '', + details: '', + + // 标签数据 + dreamTags: [ + '飞行', '追逐', '考试', '重逢', '坠落', + '迷路', '被追逐', '飞翔', '裸奔', '牙齿脱落', + '死亡', '结婚', '学校', '怪物', '亲人', + '朋友', '陌生人', '水', '火', '天空', + '未来', '过去', '重复的梦', '清明梦', '噩梦' + ], + selectedTags: [], + + // 情绪数据 + emotions: [ + { name: '开心', value: 'happy', icon: 'smile' }, + { name: '害怕', value: 'scared', icon: 'warn' }, + { name: '治愈', value: 'healing', icon: 'like' }, + { name: '怪异', value: 'strange', icon: 'question' }, + { name: '悲伤', value: 'sad', icon: 'cry' }, + { name: '愤怒', value: 'angry', icon: 'no' }, + { name: '紧张', value: 'nervous', icon: 'waiting' }, + { name: '平静', value: 'calm', icon: 'sleep' } + ], + selectedEmotion: '' + }, + + // 标题输入 + onTitleChange(e) { + this.setData({ + title: e.detail.value + }); + }, + + // 场景输入 + onSceneChange(e) { + this.setData({ + scene: e.detail.value + }); + }, + + // 人物输入 + onCharactersChange(e) { + this.setData({ + characters: e.detail.value + }); + }, + + // 情节输入 + onPlotChange(e) { + this.setData({ + plot: e.detail.value + }); + }, + + // 细节输入 + onDetailsChange(e) { + this.setData({ + details: e.detail.value + }); + }, + + // 切换标签选择状态 + toggleTag(e) { + const tag = e.currentTarget.dataset.tag; + const { selectedTags } = this.data; + + let newSelectedTags; + if (selectedTags.includes(tag)) { + // 移除标签 + newSelectedTags = selectedTags.filter(t => t !== tag); + } else { + // 添加标签 + newSelectedTags = [...selectedTags, tag]; + } + + this.setData({ + selectedTags: newSelectedTags + }); + }, + + // 选择情绪 + selectEmotion(e) { + const emotion = e.currentTarget.dataset.emotion; + this.setData({ + selectedEmotion: emotion + }); + }, + + // 保存梦境记录 + saveDreamRecord() { + // 简单验证 + if (!this.data.title && !this.data.scene && !this.data.plot) { + wx.showToast({ + title: '请至少填写一些内容', + icon: 'none', + duration: 2000 + }); + return; + } + + // 创建记录对象 + const dreamRecord = { + id: Date.now().toString(), // 使用时间戳作为唯一ID + title: this.data.title || '无标题梦境', + scene: this.data.scene, + characters: this.data.characters, + plot: this.data.plot, + details: this.data.details, + tags: this.data.selectedTags, + emotion: this.data.selectedEmotion, + date: new Date().toLocaleDateString(), + timestamp: Date.now() + }; + + // 从本地存储获取已有记录 + wx.getStorage({ + key: 'dreamRecords', + success: (res) => { + const records = res.data || []; + records.unshift(dreamRecord); // 添加到数组开头 + + // 保存回本地存储 + wx.setStorage({ + key: 'dreamRecords', + data: records, + success: () => { + wx.showToast({ + title: '记录保存成功', + icon: 'success', + duration: 2000 + }); + + // 返回首页 + setTimeout(() => { + wx.navigateBack({ + delta: 1 + }); + }, 1500); + } + }); + }, + fail: () => { + // 如果没有已有记录,创建新数组 + wx.setStorage({ + key: 'dreamRecords', + data: [dreamRecord], + success: () => { + wx.showToast({ + title: '记录保存成功', + icon: 'success', + duration: 2000 + }); + + // 返回首页 + setTimeout(() => { + wx.navigateBack({ + delta: 1 + }); + }, 1500); + } + }); + } + }); + } +}); diff --git a/pages/record/record.json b/pages/record/record.json new file mode 100644 index 0000000..8835af0 --- /dev/null +++ b/pages/record/record.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/record/record.wxml b/pages/record/record.wxml new file mode 100644 index 0000000..be87aa2 --- /dev/null +++ b/pages/record/record.wxml @@ -0,0 +1,114 @@ + + + + 梦境标题 + + + + + + 梦境内容 + 可以分场景、人物、情绪等方面记录 + + + + + + 场景 + + + + + + + + + 人物 + + + + + + + + + 情节 + + + + + + + + + 其他细节 + + + + + + + + 梦境标签 + 选择与你的梦境相关的标签 + + + + {{item}} + + + + + + + 情绪标记 + 这个梦境带给你什么感受? + + + + + {{item.name}} + + + + + + + diff --git a/pages/record/record.wxss b/pages/record/record.wxss new file mode 100644 index 0000000..d93fa42 --- /dev/null +++ b/pages/record/record.wxss @@ -0,0 +1,148 @@ +.container { + padding: 16px; + background-color: #f5f7fa; + min-height: 100vh; +} + +.section { + margin-bottom: 24px; + background-color: white; + border-radius: 12px; + padding: 16px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); +} + +.input-section { + margin-bottom: 24px; +} + +.section-title { + font-size: 18px; + font-weight: 600; + color: #333; + margin-bottom: 8px; + display: block; +} + +.section-desc { + font-size: 14px; + color: #666; + margin-bottom: 16px; + display: block; +} + +.dream-title { + width: 100%; + padding: 12px 16px; + border: 1px solid #e5e7eb; + border-radius: 8px; + font-size: 16px; + background-color: white; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); +} + +.segment { + margin-bottom: 16px; +} + +.segment:last-child { + margin-bottom: 0; +} + +.segment-header { + display: flex; + align-items: center; + margin-bottom: 8px; +} + +.segment-title { + font-size: 16px; + color: #4a6fa5; + margin-left: 8px; + font-weight: 500; +} + +.segment-content { + width: 100%; + min-height: 80px; + padding: 12px 16px; + border: 1px solid #e5e7eb; + border-radius: 8px; + font-size: 15px; + line-height: 1.6; +} + +.tags-container { + display: flex; + flex-wrap: wrap; + gap: 10px; +} + +.tag { + padding: 6px 14px; + background-color: #f1f5f9; + border-radius: 20px; + font-size: 14px; + color: #475569; + cursor: pointer; + transition: all 0.2s ease; +} + +.tag-selected { + background-color: #4a6fa5; + color: white; +} + +.emotions-container { + display: flex; + justify-content: space-between; + flex-wrap: wrap; + gap: 15px; +} + +.emotion { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 80px; + height: 80px; + background-color: #f1f5f9; + border-radius: 12px; + cursor: pointer; + transition: all 0.2s ease; +} + +.emotion text { + margin-top: 8px; + font-size: 14px; + color: #475569; +} + +.emotion-selected { + background-color: #4a6fa5; +} + +.emotion-selected text { + color: white; +} + +.emotion-selected icon { + color: white; +} + +.save-btn { + width: 100%; + padding: 14px 0; + background-color: #4a6fa5; + color: white; + font-size: 16px; + font-weight: 500; + border-radius: 8px; + margin-top: 16px; + margin-bottom: 30px; +} + +.save-btn::after { + border: none; +} diff --git a/project.config.json b/project.config.json new file mode 100644 index 0000000..4ce05e6 --- /dev/null +++ b/project.config.json @@ -0,0 +1,29 @@ +{ + "appid": "wxb902b6272b3d647c", + "compileType": "miniprogram", + "libVersion": "3.10.1", + "packOptions": { + "ignore": [], + "include": [] + }, + "setting": { + "coverView": true, + "es6": true, + "postcss": true, + "minified": true, + "enhance": true, + "showShadowRootInWxmlPanel": true, + "packNpmRelationList": [], + "babelSetting": { + "ignore": [], + "disablePlugins": [], + "outputPath": "" + }, + "condition": false + }, + "condition": {}, + "editorSetting": { + "tabIndent": "insertSpaces", + "tabSize": 2 + } +} \ No newline at end of file diff --git a/project.private.config.json b/project.private.config.json new file mode 100644 index 0000000..6b50b84 --- /dev/null +++ b/project.private.config.json @@ -0,0 +1,7 @@ +{ + "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html", + "projectname": "meng", + "setting": { + "compileHotReLoad": true + } +} \ No newline at end of file diff --git a/sitemap.json b/sitemap.json new file mode 100644 index 0000000..cd24f35 --- /dev/null +++ b/sitemap.json @@ -0,0 +1,7 @@ +{ + "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", + "rules": [{ + "action": "allow", + "page": "*" + }] +} \ No newline at end of file