動(dòng)態(tài)網(wǎng)站開發(fā)的主要技術(shù)百度推廣計(jì)劃
個(gè)人團(tuán)隊(duì)的比賽項(xiàng)目,僅供學(xué)習(xí)交流使用
一、項(xiàng)目基本介紹
1. 項(xiàng)目簡(jiǎn)介
一款基于微信小程序的輕量化筆記工具,旨在幫助用戶通過(guò)記錄每日心情和事件,更好地管理情緒和生活。用戶可以根據(jù)日期和心情分類(如開心、平靜、難過(guò)等)記錄筆記,并隨時(shí)查看歷史記錄。同時(shí),項(xiàng)目還包含一個(gè)后臺(tái)運(yùn)營(yíng)端小程序,用于數(shù)據(jù)統(tǒng)計(jì)、用戶行為分析、用戶反饋收集與回復(fù),為運(yùn)營(yíng)決策提供支持。代碼已上傳至GitHub
2. 技術(shù)棧
微信小程序原生開發(fā)(JS、WXML、WXSS)、SpringBoot、MySQL、RESTful API、Postman接口測(cè)試、Axure
3. 項(xiàng)目功能
(1)用戶端
微信授權(quán)登錄
主界面:該功能模塊主要包括顯示日歷、顯示筆記、刪除單條筆記。
-
顯示日歷:日歷供用戶選擇查看日期,當(dāng)日總體心情為日期小角標(biāo),用戶點(diǎn)擊日期即可在頁(yè)面下方顯示該日筆記。
-
顯示筆記:底部筆記欄呈現(xiàn)所選日按修改時(shí)間進(jìn)行排序的筆記(默認(rèn)為當(dāng)日),若無(wú)筆記出現(xiàn)"今日還未寫筆記噢!"提示。
-
刪除單條筆記:右滑筆記出現(xiàn)刪除按鈕,并彈出提示框。
個(gè)人中心:該功能模塊主要包括反饋、分享、我的信箱與退出登錄。
-
反饋:用戶在反饋渠道提出意見(jiàn)。
-
分享:將小程序轉(zhuǎn)發(fā)給微信好友。
-
我的信箱:管理員向用戶下發(fā)通知,用戶在我的信箱查看
-
退出登錄:退出登錄后再次登錄需要再次授權(quán)。
筆記記錄:該功能模塊主要功能包括心情選擇和寫筆記。
-
心情選擇:用戶可在心情圖案列表中選擇本條筆記記錄時(shí)的心情;若本條筆記為當(dāng)日第二條及以上,自動(dòng)彈出當(dāng)日總體心情選擇界面;在日歷上方可以改變總體心情,若沒(méi)有選擇總體心情則會(huì)出現(xiàn)"今日還未選擇總體心情哦"提示。
-
寫/修改筆記:用戶可自由進(jìn)行筆記記錄或修改筆記內(nèi)容及此條筆記心情。
-
(2)開發(fā)者端
微信授權(quán)與密鑰登陸
官方通知:發(fā)布官方通知下發(fā)到每一個(gè)用戶
反饋回執(zhí):針對(duì)不同用戶的返回發(fā)送回執(zhí)
二、項(xiàng)目代碼分析
1. 項(xiàng)目代碼架構(gòu)
前端小程序項(xiàng)目結(jié)構(gòu)(以用戶端為例)
后端Java項(xiàng)目結(jié)構(gòu)
2.前端代碼分析(以用戶端主頁(yè)面為例)
main.js
const util = require('../../utils/util.js')
var app = getApp()
Page({data: {avatarUrl: "/images/頭像.png",nickName: '未登錄',date: null,daymood: '今日還未選心情',moodList: new Array(),noteList: new Array(),noteisHave: false,year: 0,month: 0,head: ['日', '一', '二', '三', '四', '五', '六'],dateArr: [],isToday: 0,pickToday: 0,isTodayWeek: false,todayIndex: 0,nottoday: false,havenote:'今日還未寫筆記哦!'},onShow() {let date = new Date();let now = new Date();let year = now.getFullYear();let month = now.getMonth() + 1;console.log(0)this.dateInit();this.setData({year: year,month: month,isToday: '' + year + '-' + month + '-' + now.getDate(),avatarUrl: app.globalData.avatarUrl,nickName: app.globalData.nickName,date: util.formatDate(date)})console.log(3)this.daymoodinit(util.formatYearDate(now)[0]);console.log(5)this.noteinit(util.formatYearDate(now)[0]);},noteinit(date) {var that = this//請(qǐng)求獲取筆記列表wx.request({url: app.globalData.url + '/getNoteList',data: {uid: wx.getStorageSync('uid'),date: date},header: {'content-type': 'application/json'},success(res) {console.log(6)//獲取后端傳入的筆記列表var notelist = res.data.noteList//如果筆記列表不為空if (notelist) {//創(chuàng)建微信小程序存儲(chǔ)數(shù)組值的變量var noteList = new Array();//創(chuàng)建構(gòu)造函數(shù)notefunction Note(nid, context, time, mood) {this.nid = nid;this.context = context;this.time = time;this.mood = mood;}//遍歷后端傳來(lái)的值,將其加到我的數(shù)據(jù)中for (var i = 0; i < notelist.length; i++) {//對(duì)心情處理notelist[i].mood = '/images/' + notelist[i].mood + '.png';//賦值var note = new Note(notelist[i].nid, notelist[i].context+'...', notelist[i].time, notelist[i].mood)noteList[i] = note}//設(shè)置值that.setData({//筆記列表noteList: noteList,noteisHave: true})}}})},daymoodinit(date) {var that = thiswx.request({//獲取某日的總體心情url: app.globalData.url + '/gDateMood',data: {uid: wx.getStorageSync('uid'),date: date},header: {'content-type': 'application/json'},success(res) {console.log(4)if (res.data.daymood) {if (date == util.formatYearDate(new Date())) {that.setData({daymood: '今日心情:' + res.data.daymood})} else {that.setData({daymood: '該日心情:' + res.data.daymood})}} else {if (date == util.formatYearDate(new Date())) {that.setData({daymood: '今日還未選心情'})} else {that.setData({daymood: '該日未記錄心情'})}}}//為測(cè)試所用,正式直接刪掉// fail() {// that.setData({// daymood: '今日心情:開心'// })// }})},backnow() {var date = {date: util.formatYearDate(new Date()).toString()}this.date(date)//自動(dòng)展示為當(dāng)前月份的日歷頁(yè)面this.dateInit()this.setData({nottoday: false})},date(e) {//判斷是從組件傳的值(即點(diǎn)擊日期)還是從函數(shù)傳的值(即點(diǎn)擊回到今日)if (e.date) {var date = e.date} else {var date = e.currentTarget.dataset.date}//轉(zhuǎn)換日期var dates = date.split("-")var month = dates[1]var day = dates[2]var thisdate = month + '月' + day + '日'if(date == util.formatYearDate(new Date())){this.setData({noteisHave: false,pickToday: date,date: thisdate,nottoday: false,havenote:'今日還未寫筆記哦!'})}else{this.setData({noteisHave: false,pickToday: date,date: thisdate,nottoday: true,havenote:'該日還未寫筆記哦!'})}//修改頁(yè)面總體心情this.daymoodinit(date)//向后端請(qǐng)求日期下的筆記列表this.noteinit(date)},add() {wx.navigateTo({url: '/pages/notemood/notemood'})},daymood() {wx.showModal({title: '只能修改今日總體心情',content: '確認(rèn)要修改嗎?',success(res) {if (res.confirm) {wx.navigateTo({url: '/pages/daymood/daymood'})}}})},mine() {wx.navigateTo({url: '/pages/mine/mine',})},changenote(e) {//需向后端傳入標(biāo)識(shí),表示是第一次進(jìn)入修改筆記頁(yè)面,目的為保證渲染層的正確var note = e.currentTarget.dataset.notevar nid = note.nidvar time = note.timevar mood = note.moodwx.redirectTo({url: '/pages/note/note?mood=' + mood + '&nid=' + nid + '&time=' + time + '&flag=1',})},dateInit: function (setYear, setMonth) {//全部時(shí)間的月份都是按0~11基準(zhǔn),顯示月份才+1let dateArr = []; //需要遍歷的日歷數(shù)組數(shù)據(jù)let arrLen = 0; //dateArr的數(shù)組長(zhǎng)度let now = setYear ? new Date(setYear, setMonth) : new Date();let year = setYear || now.getFullYear();let nextYear = 0;let month = setMonth || now.getMonth(); //沒(méi)有+1方便后面計(jì)算當(dāng)月總天數(shù)let nextMonth = (month + 1) > 11 ? 1 : (month + 1);let startWeek = new Date(year + ',' + (month + 1) + ',' + 1).getDay(); //目標(biāo)月1號(hào)對(duì)應(yīng)的星期let dayNums = new Date(year, nextMonth, 0).getDate(); //獲取目標(biāo)月有多少天let obj = {};let num = 0;if (month + 1 > 11) {nextYear = year + 1;dayNums = new Date(nextYear, nextMonth, 0).getDate();}var that = thisconsole.log(1)//得到當(dāng)月心情表從后端wx.request({url: app.globalData.url + '/selectAllMood',data: {uid: wx.getStorageSync('uid'),year: year,month: month + 1},header: {'content-type': 'application/json'},success(res) {console.log(2)if (!res.data) {wx.showToast({title: '日期超出可用范圍咯!',icon: 'none',duration: 2000 //持續(xù)的時(shí)間})} else {that.setData({moodList: res.data.moodList,year: year,month: month + 1})arrLen = startWeek + dayNums;for (let i = 0; i < arrLen; i++) {if (i >= startWeek) {num = i - startWeek + 1;obj = {isToday: '' + year + '-' + (month + 1) + '-' + num,dateNum: num,weight: 5,mood: '/images/' + that.data.moodList[num - 1] + '色.png'}} else {obj = {};}dateArr[i] = obj;}that.setData({dateArr: dateArr})let nowDate = new Date();let nowYear = nowDate.getFullYear();let nowMonth = nowDate.getMonth() + 1;let nowWeek = nowDate.getDay();let getYear = setYear || nowYear;let getMonth = setMonth >= 0 ? (setMonth + 1) : nowMonth;if (nowYear == getYear && nowMonth == getMonth) {that.setData({isTodayWeek: true,todayIndex: nowWeek})} else {that.setData({isTodayWeek: false,todayIndex: -1})}}}//為測(cè)試所用,正式直接刪掉// fail() {// arrLen = startWeek + dayNums;// for (let i = 0; i < arrLen; i++) {// if (i >= startWeek) {// num = i - startWeek + 1;// obj = {// isToday: '' + year + '-' + (month + 1) + '-' + num,// dateNum: num,// weight: 5,// mood: '/images/' + that.data.moodList[num - 1] + '色.png'// }// } else {// obj = {};// }// dateArr[i] = obj;// }// that.setData({// dateArr: dateArr// })// let nowDate = new Date();// let nowYear = nowDate.getFullYear();// let nowMonth = nowDate.getMonth() + 1;// let nowWeek = nowDate.getDay();// let getYear = setYear || nowYear;// let getMonth = setMonth >= 0 ? (setMonth + 1) : nowMonth;// if (nowYear == getYear && nowMonth == getMonth) {// that.setData({// isTodayWeek: true,// todayIndex: nowWeek// })// } else {// that.setData({// isTodayWeek: false,// todayIndex: -1// })// }// }})},lastMonth: function () {//全部時(shí)間的月份都是按0~11基準(zhǔn),顯示月份才+1let year = this.data.month - 2 < 0 ? this.data.year - 1 : this.data.year;let month = this.data.month - 2 < 0 ? 11 : this.data.month - 2;this.dateInit(year, month);},nextMonth: function () {//全部時(shí)間的月份都是按0~11基準(zhǔn),顯示月份才+1let year = this.data.month > 11 ? this.data.year + 1 : this.data.year;let month = this.data.month > 11 ? 0 : this.data.month;this.dateInit(year, month);},/*** 設(shè)置movable-view位移*/setXmove: function (productIndex, xmove) {let noteList = this.data.noteListnoteList[productIndex].xmove = xmovethis.setData({noteList: noteList})},/*** 處理movable-view移動(dòng)事件*/handleMovableChange: function (e) {if (e.detail.source === 'friction') {if (e.detail.x < -30) {this.showDeleteButton(e)} else {this.hideDeleteButton(e)}} else if (e.detail.source === 'out-of-bounds' && e.detail.x === 0) {this.hideDeleteButton(e)}},/*** 顯示刪除按鈕*/showDeleteButton: function (e) {let productIndex = e.currentTarget.dataset.productindexthis.setXmove(productIndex, -65)},/*** 隱藏刪除按鈕*/hideDeleteButton: function (e) {let productIndex = e.currentTarget.dataset.productindexthis.setXmove(productIndex, 0)},/*** 處理touchstart事件*/handleTouchStart(e) {this.startX = e.touches[0].pageX},/*** 處理touchend事件*/handleTouchEnd(e) {if (e.changedTouches[0].pageX < this.startX && e.changedTouches[0].pageX - this.startX <= -30) {this.showDeleteButton(e)} else if (e.changedTouches[0].pageX > this.startX && e.changedTouches[0].pageX - this.startX < 30) {this.showDeleteButton(e)} else {this.hideDeleteButton(e)}},/*** 刪除產(chǎn)品*/handleDeleteProduct: function ({currentTarget: {dataset: {nid}}}) {var that = thiswx.showModal({title: '刪除該條筆記',content: '確認(rèn)要?jiǎng)h除嗎?',success(res) {if (res.confirm) {wx.request({//傳入nid請(qǐng)求刪除url: app.globalData.url + '/deleteNote',data: {nid: nid},header: {'content-type': 'application/json'},success() {let noteList = that.data.noteListlet productIndex = noteList.findIndex(item => item.nid === nid)noteList.splice(productIndex, 1)that.setData({noteList})if (noteList[productIndex]) {that.setXmove(productIndex, 0)}if(!that.data.noteList[0]){that.setData({noteisHave: false,})}},fail() {wx.showToast({title: '刪除失敗!',icon: 'none',duration: 2000 //持續(xù)的時(shí)間})}})}}})},
})
data是初始化
onshow是登錄后要展示的,要對(duì)當(dāng)日心情進(jìn)行初始化,要對(duì)當(dāng)日筆記進(jìn)行初始化
noteinit要根據(jù)用戶的uid和date訪問(wèn)后端(app.globalData.url這個(gè)是后端服務(wù)器地址),獲取到筆記信息后渲染到頁(yè)面上,也就是重設(shè)data里面的值
daymoodinit也是一樣
backnow是什么,里面要對(duì)當(dāng)月的日歷進(jìn)行展示,還要在日歷上展示當(dāng)日的總體心情角標(biāo)
里面要dateInit,也是從后端獲取數(shù)據(jù)
后續(xù)的方法也是點(diǎn)擊主頁(yè)上的一個(gè)按鈕,需要進(jìn)行的操作,有點(diǎn)到某一日、修改總體心情、修改筆記等,比如修改筆記,就用wx.redirectTo進(jìn)行了頁(yè)面跳轉(zhuǎn),需要頁(yè)面間傳遞的數(shù)據(jù)也要在跳轉(zhuǎn)的時(shí)候傳遞;比如修改總體心情,使用的則是navigateTo,這是為啥,還有showModal就是在上層創(chuàng)建新窗口嗎;比如date就是點(diǎn)擊某一日,獲得該日的筆記信息和總體心情,于是要noteinit和daymoodinit;后續(xù)還有滑動(dòng)刪除筆記事件
- 數(shù)據(jù)初始化(data)
在data
中,我們定義了頁(yè)面初始化時(shí)需要使用的各種變量。這些變量包括用戶的頭像、昵稱、日期、心情、筆記列表等。這些數(shù)據(jù)將在頁(yè)面加載時(shí)被初始化,并在用戶與頁(yè)面交互時(shí)動(dòng)態(tài)更新。
- avatarUrl:用戶的頭像URL,默認(rèn)值為
/images/頭像.png
。 - nickName:用戶的昵稱,默認(rèn)值為
未登錄
。 - date:當(dāng)前日期,初始值為
null
。 - daymood:當(dāng)日的心情狀態(tài),默認(rèn)值為
今日還未選心情
。 - moodList:心情列表,用于存儲(chǔ)用戶在不同日期的總體心情。
- noteList:筆記列表,用于存儲(chǔ)用戶在不同日期的筆記內(nèi)容。
- noteisHave:標(biāo)識(shí)當(dāng)前日期是否有筆記,初始值為
false
。 - year和month:當(dāng)前年份和月份,用于日歷展示。
- head:日歷表頭的星期幾標(biāo)識(shí)。
- dateArr:日歷數(shù)組,用于展示當(dāng)前月份的日期和心情角標(biāo)。
- isToday:標(biāo)識(shí)當(dāng)前日期是否為今天。
- pickToday:用戶選擇的日期。
- isTodayWeek:標(biāo)識(shí)當(dāng)前日期是否在本周。
- todayIndex:今天在日歷中的索引。
- nottoday:標(biāo)識(shí)用戶選擇的日期是否為今天。
- havenote:提示用戶當(dāng)前日期是否有筆記。
- 頁(yè)面展示邏輯(onShow)
onShow
是微信小程序的生命周期函數(shù),當(dāng)頁(yè)面顯示時(shí)觸發(fā)。在這個(gè)函數(shù)中,我們主要做了以下幾件事:
- 獲取當(dāng)前日期:通過(guò)
new Date()
獲取當(dāng)前日期,并提取年份和月份。 - 初始化日歷:調(diào)用
dateInit
函數(shù),初始化當(dāng)前月份的日歷數(shù)據(jù)。 - 設(shè)置頁(yè)面數(shù)據(jù):將當(dāng)前日期、用戶頭像、昵稱等信息設(shè)置到頁(yè)面的
data
中。 - 初始化當(dāng)日心情和筆記:調(diào)用
daymoodinit
和noteinit
函數(shù),分別獲取并展示當(dāng)日的心情和筆記。
- 筆記初始化(noteinit)
noteinit
函數(shù)用于根據(jù)用戶的uid
和date
從后端獲取筆記列表,并將獲取到的筆記數(shù)據(jù)渲染到頁(yè)面上。
- 請(qǐng)求筆記列表:通過(guò)
wx.request
向后端發(fā)送請(qǐng)求,獲取指定日期的筆記列表。 - 處理筆記數(shù)據(jù):如果筆記列表不為空,遍歷列表并將每條筆記的數(shù)據(jù)存儲(chǔ)到
noteList
中。 - 更新頁(yè)面數(shù)據(jù):將處理后的筆記列表設(shè)置到頁(yè)面的
data
中,并更新noteisHave
狀態(tài)。
- 當(dāng)日心情初始化(daymoodinit)
daymoodinit
函數(shù)用于獲取并展示用戶當(dāng)日的總體心情。
- 請(qǐng)求當(dāng)日心情:通過(guò)
wx.request
向后端發(fā)送請(qǐng)求,獲取指定日期的總體心情。 - 更新頁(yè)面數(shù)據(jù):根據(jù)獲取到的心情數(shù)據(jù),更新頁(yè)面中的
daymood
狀態(tài)。
- 返回今日(backnow)
backnow
函數(shù)用于將頁(yè)面重置為當(dāng)前日期的狀態(tài)。
- 重置日期:將頁(yè)面日期重置為當(dāng)前日期。
- 初始化日歷:調(diào)用
dateInit
函數(shù),重新初始化當(dāng)前月份的日歷數(shù)據(jù)。 - 更新頁(yè)面數(shù)據(jù):將
nottoday
狀態(tài)設(shè)置為false
,表示當(dāng)前日期為今天。
- 選擇日期(date)
date
函數(shù)用于處理用戶選擇日期的操作。
- 獲取選擇的日期:根據(jù)用戶點(diǎn)擊的日期或從函數(shù)傳入的日期,獲取用戶選擇的日期。
- 更新頁(yè)面數(shù)據(jù):將選擇的日期設(shè)置到頁(yè)面的
data
中,并更新noteisHave
和nottoday
狀態(tài)。 - 初始化心情和筆記:調(diào)用
daymoodinit
和noteinit
函數(shù),獲取并展示選擇日期的心情和筆記。
- 添加筆記(add)
add
函數(shù)用于跳轉(zhuǎn)到添加筆記頁(yè)面。
- 頁(yè)面跳轉(zhuǎn):使用
wx.navigateTo
跳轉(zhuǎn)到/pages/notemood/notemood
頁(yè)面。
- 修改總體心情(daymood)
daymood
函數(shù)用于處理用戶修改總體心情的操作。
- 彈出確認(rèn)框:使用
wx.showModal
彈出確認(rèn)框,詢問(wèn)用戶是否確認(rèn)修改總體心情。 - 頁(yè)面跳轉(zhuǎn):如果用戶確認(rèn),使用
wx.navigateTo
跳轉(zhuǎn)到/pages/daymood/daymood
頁(yè)面。
- 個(gè)人中心(mine)
mine
函數(shù)用于跳轉(zhuǎn)到個(gè)人中心頁(yè)面。
- 頁(yè)面跳轉(zhuǎn):使用
wx.navigateTo
跳轉(zhuǎn)到/pages/mine/mine
頁(yè)面。
- 修改筆記(changenote)
changenote
函數(shù)用于處理用戶修改筆記的操作。
- 獲取筆記信息:從用戶點(diǎn)擊的筆記中獲取筆記的
nid
、time
和mood
信息。 - 頁(yè)面跳轉(zhuǎn):使用
wx.redirectTo
跳轉(zhuǎn)到/pages/note/note
頁(yè)面,并傳遞筆記的相關(guān)信息。
- 日歷初始化(dateInit)
dateInit
函數(shù)用于初始化當(dāng)前月份的日歷數(shù)據(jù)。
- 獲取當(dāng)前月份的天數(shù)和起始星期:通過(guò)
new Date()
獲取當(dāng)前月份的天數(shù)和1號(hào)對(duì)應(yīng)的星期。 - 請(qǐng)求當(dāng)月心情數(shù)據(jù):通過(guò)
wx.request
向后端發(fā)送請(qǐng)求,獲取當(dāng)前月份的心情數(shù)據(jù)。 - 更新頁(yè)面數(shù)據(jù):將獲取到的心情數(shù)據(jù)設(shè)置到頁(yè)面的
data
中,并生成日歷數(shù)組dateArr
。
- 滑動(dòng)刪除筆記
滑動(dòng)刪除筆記功能通過(guò)handleMovableChange
、handleTouchStart
、handleTouchEnd
等函數(shù)實(shí)現(xiàn)。
- 顯示刪除按鈕:當(dāng)用戶向左滑動(dòng)筆記時(shí),顯示刪除按鈕。
- 隱藏刪除按鈕:當(dāng)用戶向右滑動(dòng)或滑動(dòng)距離不足時(shí),隱藏刪除按鈕。
- 刪除筆記:當(dāng)用戶點(diǎn)擊刪除按鈕時(shí),彈出確認(rèn)框,確認(rèn)后通過(guò)
wx.request
向后端發(fā)送刪除請(qǐng)求,并更新頁(yè)面數(shù)據(jù)。
main.wxml
<view class="data"><view class="circle" bindtap="mine"><image src="{{avatarUrl}}" class="head"></image></view><view class="date-mood"><text class="date">{{date}}</text><text class="mood" bindtap="daymood">{{daymood}}</text></view><view class="backnow"><image src="/images/今日.png" class="backnowimg" bindtap="backnow" wx:if="{{nottoday}}"></image>
</view><image src="/images/添加.png" class="add" bindtap="add"></image>
</view>
<view class="calendar"><view class='wrap'><view><view class='date-show'><view class='lt-arrow' bindtap='lastMonth'><image src='/images/左箭頭.png' mode='aspectFit'></image></view>{{year}}年{{month}}月<view class='rt-arrow' bindtap='nextMonth'><image src='/images/右箭頭.png' mode='aspectFit'></image></view></view></view><view class='header'><view wx:for='{{head}}' class='{{(index == todayIndex) && isTodayWeek ? "weekMark" : ""}}'>{{item}}<view></view></view></view><view class='date-box'><view wx:for='{{dateArr}}'class='{{isToday == item.isToday ? "nowDay" : (pickToday == item.isToday ? "pickDay" : "")}}'data-date='{{item.isToday}}' bindtap="date"><view class="sort"><view class="minimoodview"><image src="{{item.mood}}" class="minimood"></image></view><view class='date-head'><view>{{item.dateNum}}</view></view></view></view></view></view>
</view>
<view class="nonote" wx:if="{{!noteisHave}}"><image src="/images/鈴鐺.png" class="bell"></image><view class="empty">{{havenote}}</view>
</view>
<view wx:else><view class="product-list"><view class="product-item" wx:for="{{noteList}}" wx:for-index="index" wx:key="{{item.nid}}"><movable-area data-note="{{item}}" bindtap="changenote"><movable-view out-of-bounds="true" direction="horizontal" x="{{item.xmove}}" inertia="true"data-productIndex="{{index}}" bindtouchstart="handleTouchStart" bindtouchend="handleTouchEnd"bindchange="handleMovableChange"><view class="product-item-wrap"><view class="expression"><image src="{{item.mood}}" class="expressionimg"></image></view><view class="product-movable-item"><view class="product-movable-item-name">{{item.time}}</view><view class="product-movable-item-code">{{item.context}}</view></view></view><view class="blank"></view></movable-view></movable-area><view class="delete-btn" data-nid="{{item.nid}}" bindtap="handleDeleteProduct"><image src="/images/刪除.png" class="delete"></image></view></view></view>
</view>
- 頂部用戶信息與操作區(qū)域
- 用戶頭像:通過(guò)
<image>
組件展示用戶頭像,點(diǎn)擊頭像觸發(fā)mine
函數(shù),跳轉(zhuǎn)到個(gè)人中心頁(yè)面。 - 日期與心情:顯示當(dāng)前日期和當(dāng)日心情,點(diǎn)擊心情文本觸發(fā)
daymood
函數(shù),允許用戶修改當(dāng)日心情。 - 返回今日按鈕:如果用戶選擇的日期不是今天,顯示“返回今日”圖標(biāo),點(diǎn)擊觸發(fā)
backnow
函數(shù),重置為當(dāng)前日期。 - 添加筆記按鈕:點(diǎn)擊“添加”圖標(biāo)觸發(fā)
add
函數(shù),跳轉(zhuǎn)到添加筆記頁(yè)面。
- 日歷區(qū)域
- 日歷頭部:顯示當(dāng)前年份和月份,左右箭頭分別觸發(fā)
lastMonth
和nextMonth
函數(shù),用于切換月份。 - 星期表頭:顯示星期幾,當(dāng)前星期會(huì)高亮顯示。
- 日期展示:展示當(dāng)前月份的日期,每個(gè)日期塊顯示日期數(shù)字和對(duì)應(yīng)的心情圖標(biāo)。點(diǎn)擊日期塊觸發(fā)
date
函數(shù),加載該日期的筆記和心情。
- 筆記展示區(qū)域
- 無(wú)筆記提示:如果當(dāng)前日期沒(méi)有筆記,顯示提示信息(如“今日還未寫筆記哦!”)和一個(gè)鈴鐺圖標(biāo)。
- 筆記列表:如果有筆記,展示筆記列表。每條筆記包含心情圖標(biāo)、時(shí)間和內(nèi)容。筆記支持左右滑動(dòng),滑動(dòng)后顯示刪除按鈕。
- 滑動(dòng)刪除:通過(guò)
movable-view
實(shí)現(xiàn)滑動(dòng)功能,滑動(dòng)到一定距離后顯示刪除按鈕,點(diǎn)擊刪除按鈕觸發(fā)handleDeleteProduct
函數(shù),刪除對(duì)應(yīng)筆記。 - 點(diǎn)擊筆記:點(diǎn)擊筆記內(nèi)容觸發(fā)
changenote
函數(shù),跳轉(zhuǎn)到修改筆記頁(yè)面。
- 滑動(dòng)刪除:通過(guò)
3. 后端代碼分析
以主頁(yè)邏輯業(yè)務(wù)為例
UserDateController.java
package st.nuc.edu.cn.mood_note.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import st.nuc.edu.cn.mood_note.entity.UserDate;
import st.nuc.edu.cn.mood_note.service.UserDateService;@RestController
public class UserDateController {@AutowiredUserDateService userDateService;@RequestMapping("/gDateMood")public Object gDateMood(String uid, String date) {return userDateService.gDateMood(uid, date);}@RequestMapping("/mixOperate")public void mixOperate(UserDate userDate) {userDateService.mixOperate(userDate);}@RequestMapping("/selectAllMood")public Object selectAllMood(String uid, String year, String month) {return userDateService.selectAllMood(uid, year, month);}}
UserDateController
是處理主頁(yè)相關(guān)請(qǐng)求的控制器,主要包含以下接口:
- gDateMood:根據(jù)用戶ID和日期,獲取某日的總體心情。
- mixOperate:處理用戶心情的插入或更新操作。
- selectAllMood:根據(jù)用戶ID、年份和月份,獲取該月的所有心情數(shù)據(jù)。
這些接口通過(guò)調(diào)用UserDateService
中的方法,完成具體的業(yè)務(wù)邏輯。
UserDateServiceImpl.java
package st.nuc.edu.cn.mood_note.service.impl;import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import st.nuc.edu.cn.mood_note.entity.UserDate;
import st.nuc.edu.cn.mood_note.mapper.UserDateMapper;
import st.nuc.edu.cn.mood_note.service.UserDateService;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;@Component
public class UserDateServiceImpl implements UserDateService {@AutowiredUserDateMapper userDateMapper;@Overridepublic Object gDateMood(String uid, String date) {UserDate userDate = userDateMapper.gDateMood(uid, date);if (userDate != null) {JSONObject object = new JSONObject();object.put("daymood",userDate.getDateMood());return object;} else {return null;}}@Overridepublic boolean mixOperate(UserDate userDate) {UserDate userDate1 = userDateMapper.gDateMood(userDate.getUid(), userDate.getDate());if (userDate1 == null) {return userDateMapper.insert(userDate);} else {return userDateMapper.update(userDate);}}@Overridepublic Object selectAllMood(String uid, String year, String month) {int month1 = Integer.parseInt(month);String s = null;if ((month1>0)&&(month1<10)) {s = "0" + month1;} else {s = month;}List<UserDate> userDateList = userDateMapper.gAllDateMood(uid, year, s);if(!userDateList.isEmpty()) {List<String> moodList = new ArrayList();JSONObject object = new JSONObject();for (UserDate userDate : userDateList) {if (userDate.getDateMood() == null) {moodList.add(null);} else {moodList.add(userDate.getDateMood());}}object.put("moodList", moodList);return object;}return null;}
}
UserDateServiceImpl
是UserDateService
接口的實(shí)現(xiàn)類,主要功能如下:
- gDateMood:通過(guò)
UserDateMapper
查詢某日的心情數(shù)據(jù),如果存在則返回心情信息,否則返回null
。 - mixOperate:根據(jù)用戶ID和日期,判斷是插入新心情數(shù)據(jù)還是更新已有數(shù)據(jù)。
- selectAllMood:查詢某月的所有心情數(shù)據(jù),并將其封裝為
JSON
格式返回。如果某日沒(méi)有心情數(shù)據(jù),則對(duì)應(yīng)位置為null
。
UserDateMapper.java
package st.nuc.edu.cn.mood_note.mapper;import org.apache.ibatis.annotations.*;
import st.nuc.edu.cn.mood_note.entity.UserDate;import java.util.List;@Mapper
public interface UserDateMapper {@Select("select * from user_date where uid = #{uid} and date = #{date}")UserDate gDateMood(@Param("uid")String uid, @Param("date")String date);List<UserDate> gAllDateMood(@Param("uid")String uid, @Param("year")String year, @Param("month")String month);@Insert("insert into user_date (uid,date,date_mood) values (#{uid},#{date},#{dateMood})")boolean insert(UserDate userDate);@Update("update user_date set date_mood=#{dateMood} where uid = #{uid} and date = #{date}")boolean update(UserDate userDate);}
UserDateMapper
是MyBatis的Mapper接口,定義了與數(shù)據(jù)庫(kù)交互的方法:
- gDateMood:根據(jù)用戶ID和日期,查詢某日的心情數(shù)據(jù)。
- gAllDateMood:根據(jù)用戶ID、年份和月份,查詢?cè)撛碌乃行那閿?shù)據(jù)。
- insert:插入新的心情數(shù)據(jù)。
- update:更新已有的心情數(shù)據(jù)。
UserDateMapper.xml
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="st.nuc.edu.cn.mood_note.mapper.UserDateMapper"><select id="gAllDateMood" resultType="userDate">SELECT a.uid,date.date,a.date_mood FROM date LEFT JOIN (SELECT * FROM user_date WHERE uid = #{uid}) a ON date.date=a.date where date.date LIKE '${year}_${month}%';</select></mapper>
UserDateMapper.xml
是MyBatis的映射文件,定義了gAllDateMood
方法的SQL查詢邏輯。通過(guò)左連接查詢date
表和user_date
表,獲取某月的所有心情數(shù)據(jù)。
application.yaml
mybatis:type-aliases-package: st.nuc.edu.cn.mood_note.entitymapper-locations: classpath:mapper/*.xmlconfiguration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImplspring:datasource:url: jdbc:mysql://localhost:3306/mood_note?useUnicode=true&characterEncoding=utf8&useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driverserver:port:8080
application.yaml
是Spring Boot的配置文件,主要配置了:
- MyBatis:指定實(shí)體類包路徑、Mapper文件路徑、日志實(shí)現(xiàn)等。
- 數(shù)據(jù)源:配置MySQL數(shù)據(jù)庫(kù)的連接信息,包括URL、用戶名、密碼等。
- 服務(wù)器端口:設(shè)置服務(wù)端口為
8080
。
三、數(shù)據(jù)庫(kù)設(shè)計(jì)
1. 表結(jié)構(gòu)
1.用戶表(用戶)
- uid:用戶ID,主鍵,類型為
varchar(50)
。 - opend:用戶開放ID,類型為
varchar(255)
。
2.用戶日期表(用戶日期)
- uid:用戶ID,外鍵,關(guān)聯(lián)用戶表,類型為
varchar(50)
。 - date:日期,外鍵,關(guān)聯(lián)日期表,類型為
date
。 - date_mod:用戶在該日期的總體心情,類型為
varchar(10)
。
3.登記表(登記)
- uid:用戶ID,主鍵,類型為
int
。 - uid:用戶ID,外鍵,關(guān)聯(lián)用戶表,類型為
varchar(50)
。 - date:日期,外鍵,關(guān)聯(lián)日期表,類型為
date
。 - ncontext:筆記內(nèi)容,類型為
varchar(8000)
。 - ntine:筆記時(shí)間,類型為
time
。 - mod:筆記心情,類型為
varchar(5)
。
4.反饋表(反饋)
- fid:反饋ID,主鍵,類型為
int
。 - uid:用戶ID,外鍵,關(guān)聯(lián)用戶表,類型為
varchar(50)
。 - context:反饋內(nèi)容,類型為
varchar(500)
。 - lz_read:是否已讀,類型為
varchar(10)
。 - rcontext:回復(fù)內(nèi)容,類型為
varchar(500)
。 - rdate:回復(fù)日期,類型為
date
。 - date:反饋日期,外鍵,關(guān)聯(lián)日期表,類型為
date
。
5.日期表(日期)
- date:日期,主鍵,類型為
date
。
6.管理員表(管理員)
- aid:管理員ID,主鍵,類型為
int
。 - opend:管理員開放ID,類型為
varchar(255)
。 - password:管理員密碼,類型為
varchar(255)
。
7.官方通知表(官方通知)
- aid:管理員ID,主鍵,類型為
int
。 - date:通知日期,類型為
date
。 - context:通知內(nèi)容,類型為
varchar(500)
。 - lz_read:是否已讀,類型為
varchar(10)
。