From aff4457858976ec93818caed12ddf26c54ef1223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E4=BD=B3=E6=85=A7?= <2488672761@qq.com> Date: Fri, 11 Oct 2024 01:43:38 +0800 Subject: [PATCH] Initial commit on main branch --- .eslintrc.js | 31 ++++ app.js | 80 ++++++++++ app.json | 52 +++++++ app.wxss | 10 ++ assets/icon-created-active.png | Bin 0 -> 9279 bytes assets/icon-created.png | Bin 0 -> 8445 bytes assets/icon-participated-active.png | Bin 0 -> 6807 bytes assets/icon-participated.png | Bin 0 -> 5143 bytes assets/icon-store-active.png | Bin 0 -> 5123 bytes assets/icon-store.png | Bin 0 -> 3899 bytes instruction.md | 12 ++ pages/activityDetail/activityDetail.js | 39 +++++ pages/activityDetail/activityDetail.wxml | 17 ++ pages/activityDetail/activityDetail.wxss | 63 ++++++++ pages/createActivity/createActivity.js | 51 ++++++ pages/createActivity/createActivity.wxml | 27 ++++ pages/createActivity/createActivity.wxss | 70 +++++++++ pages/created/created.js | 27 ++++ pages/created/created.json | 3 + pages/created/created.wxml | 18 +++ pages/created/created.wxss | 64 ++++++++ pages/index/index.js | 49 ++++++ pages/index/index.json | 4 + pages/index/index.wxml | 27 ++++ pages/index/index.wxss | 62 ++++++++ pages/login/login.js | 41 +++++ pages/login/login.wxml | 7 + pages/login/login.wxss | 30 ++++ pages/logs/logs.js | 18 +++ pages/logs/logs.json | 4 + pages/logs/logs.wxml | 6 + pages/logs/logs.wxss | 16 ++ pages/myCreated/myCreated.js | 32 ++++ pages/myCreated/myCreated.wxml | 12 ++ pages/myCreated/myCreated.wxss | 40 +++++ pages/myParticipated/myParticipated.js | 22 +++ pages/myParticipated/myParticipated.wxml | 8 + pages/myParticipated/myParticipated.wxss | 21 +++ pages/participated/participated.js | 52 +++++++ pages/participated/participated.json | 3 + pages/participated/participated.wxml | 9 ++ pages/participated/participated.wxss | 92 +++++++++++ .../participatedDetail/participatedDetail.js | 147 ++++++++++++++++++ .../participatedDetail.json | 3 + .../participatedDetail.wxml | 27 ++++ .../participatedDetail.wxss | 95 +++++++++++ pages/store/store.js | 60 +++++++ pages/store/store.wxml | 24 +++ pages/store/store.wxss | 71 +++++++++ pages/test/test.js | 6 + pages/test/test.json | 3 + pages/test/test.wxml | 1 + pages/test/test.wxss | 3 + project.config.json | 29 ++++ project.private.config.json | 7 + sitemap.json | 7 + utils/util.js | 19 +++ 57 files changed, 1621 insertions(+) create mode 100644 .eslintrc.js create mode 100644 app.js create mode 100644 app.json create mode 100644 app.wxss create mode 100644 assets/icon-created-active.png create mode 100644 assets/icon-created.png create mode 100644 assets/icon-participated-active.png create mode 100644 assets/icon-participated.png create mode 100644 assets/icon-store-active.png create mode 100644 assets/icon-store.png create mode 100644 instruction.md create mode 100644 pages/activityDetail/activityDetail.js create mode 100644 pages/activityDetail/activityDetail.wxml create mode 100644 pages/activityDetail/activityDetail.wxss create mode 100644 pages/createActivity/createActivity.js create mode 100644 pages/createActivity/createActivity.wxml create mode 100644 pages/createActivity/createActivity.wxss create mode 100644 pages/created/created.js create mode 100644 pages/created/created.json create mode 100644 pages/created/created.wxml create mode 100644 pages/created/created.wxss create mode 100644 pages/index/index.js create mode 100644 pages/index/index.json create mode 100644 pages/index/index.wxml create mode 100644 pages/index/index.wxss create mode 100644 pages/login/login.js create mode 100644 pages/login/login.wxml create mode 100644 pages/login/login.wxss create mode 100644 pages/logs/logs.js create mode 100644 pages/logs/logs.json create mode 100644 pages/logs/logs.wxml create mode 100644 pages/logs/logs.wxss create mode 100644 pages/myCreated/myCreated.js create mode 100644 pages/myCreated/myCreated.wxml create mode 100644 pages/myCreated/myCreated.wxss create mode 100644 pages/myParticipated/myParticipated.js create mode 100644 pages/myParticipated/myParticipated.wxml create mode 100644 pages/myParticipated/myParticipated.wxss create mode 100644 pages/participated/participated.js create mode 100644 pages/participated/participated.json create mode 100644 pages/participated/participated.wxml create mode 100644 pages/participated/participated.wxss create mode 100644 pages/participatedDetail/participatedDetail.js create mode 100644 pages/participatedDetail/participatedDetail.json create mode 100644 pages/participatedDetail/participatedDetail.wxml create mode 100644 pages/participatedDetail/participatedDetail.wxss create mode 100644 pages/store/store.js create mode 100644 pages/store/store.wxml create mode 100644 pages/store/store.wxss create mode 100644 pages/test/test.js create mode 100644 pages/test/test.json create mode 100644 pages/test/test.wxml create mode 100644 pages/test/test.wxss create mode 100644 project.config.json create mode 100644 project.private.config.json create mode 100644 sitemap.json create mode 100644 utils/util.js 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/app.js b/app.js new file mode 100644 index 0000000..639f081 --- /dev/null +++ b/app.js @@ -0,0 +1,80 @@ +// app.js +App({ + onLaunch() { + // 监听页面不存在的情况 + wx.onPageNotFound(function(res) { + console.error('Page not found:', res); + wx.redirectTo({ + url: 'pages/participated/participated' + }) + }) + + // 获取本地存储的用户信息 + const userInfo = wx.getStorageSync('userInfo') + if (userInfo) { + this.globalData.userInfo = userInfo + this.globalData.isLoggedIn = true + } + + // 获取本地存储的积分 + const score = wx.getStorageSync('score') + if (score) { + this.globalData.score = score + } + }, + + onShow(options) { + // 小程序从后台进入前台时触发 + console.log('小程序显示', options) + }, + + onHide() { + // 小程序从前台进入后台时触发 + console.log('小程序隐藏') + }, + + globalData: { + userInfo: null, + isLoggedIn: false, + token: '', + score: 0, + activities: [], + participatedActivities: [] + }, + + // 全局方法 + setUserInfo(userInfo) { + this.globalData.userInfo = userInfo + this.globalData.isLoggedIn = true + wx.setStorageSync('userInfo', userInfo) + }, + + clearUserInfo() { + this.globalData.userInfo = null + this.globalData.isLoggedIn = false + this.globalData.token = '' + wx.removeStorageSync('userInfo') + }, + + updateScore(delta) { + this.globalData.score += delta + wx.setStorageSync('score', this.globalData.score) + }, + + addActivity(activity) { + this.globalData.activities.push(activity) + }, + + addParticipatedActivity(activity) { + this.globalData.participatedActivities.push(activity) + }, + + // 模拟随机点名 + randomNameCall(activityId) { + // 这里应该根据 activityId 获取对应活动的参与者列表 + // 为了演示,我们使用一个固定的名单 + const participants = ['张三', '李四', '王五', '赵六', '钱七'] + const randomIndex = Math.floor(Math.random() * participants.length) + return participants[randomIndex] + } +}) diff --git a/app.json b/app.json new file mode 100644 index 0000000..09573a8 --- /dev/null +++ b/app.json @@ -0,0 +1,52 @@ +{ + "pages": [ + "pages/login/login", + "pages/created/created", + "pages/participated/participated", + "pages/store/store", + "pages/createActivity/createActivity", + "pages/participatedDetail/participatedDetail", + "pages/test/test" + ], + "window": { + "backgroundTextStyle": "light", + "navigationBarBackgroundColor": "#fff", + "navigationBarTitleText": "点名小程序", + "navigationBarTextStyle": "black" + }, + "tabBar": { + "color": "#999999", + "selectedColor": "#0d94ff", + "backgroundColor": "#ffffff", + "list": [ + { + "pagePath": "pages/created/created", + "text": "我创建的", + "iconPath": "assets/icon-created.png", + "selectedIconPath": "assets/icon-created-active.png" + }, + { + "pagePath": "pages/participated/participated", + "text": "我参与的", + "iconPath": "assets/icon-participated.png", + "selectedIconPath": "assets/icon-participated-active.png" + }, + { + "pagePath": "pages/store/store", + "text": "商店", + "iconPath": "assets/icon-store.png", + "selectedIconPath": "assets/icon-store-active.png" + } + ] + }, + "style": "v2", + "sitemapLocation": "sitemap.json", + "networkTimeout": { + "request": 10000 + }, + "permission": { + "scope.userLocation": { + "desc": "你的位置信息将用于小程序位置接口的效果展示" + } + } +} \ No newline at end of file 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/assets/icon-created-active.png b/assets/icon-created-active.png new file mode 100644 index 0000000000000000000000000000000000000000..066944858472ef3244087de1d19054f19bc7a28f GIT binary patch literal 9279 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 literal 0 HcmV?d00001 diff --git a/assets/icon-participated-active.png b/assets/icon-participated-active.png new file mode 100644 index 0000000000000000000000000000000000000000..d0e2f089a50a734f8111f9648e3266728e7d5579 GIT binary patch literal 6807 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 FV1gxK;6eZZ literal 0 HcmV?d00001 diff --git a/assets/icon-participated.png b/assets/icon-participated.png new file mode 100644 index 0000000000000000000000000000000000000000..ea54a893f6f67bf702f7842e241362897a81fdbf GIT binary patch literal 5143 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 literal 0 HcmV?d00001 diff --git a/assets/icon-store.png b/assets/icon-store.png new file mode 100644 index 0000000000000000000000000000000000000000..a65435bb391b2594351ceadd26e1939ebcad42c8 GIT binary patch literal 3899 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 literal 0 HcmV?d00001 diff --git a/instruction.md b/instruction.md new file mode 100644 index 0000000..dda8268 --- /dev/null +++ b/instruction.md @@ -0,0 +1,12 @@ +一个微信小程序 +1.你是一个经验丰富的ui设计师,风格简洁 +2.你现在已经在一个微信小程序的项目中,因此不需要生成目录结构 +3.做一个点名小程序 +4.首先需要一个登录页面,用户输入账号和密码,登陆成功后进入“我创建的”页面 +5.导航栏位于页面的底部,分别是我创建的,我参与的,商店 +6.“我创建的”页面上方有一个搜索框,下方有一个创建自定义按钮,点击“创建自定义”按钮可以进入创建活动页面,创建活动页面有活动名称,活动描述和上传xlsx文件,创建成功后返回“我创建的”页面,“我创建的”页面会出现一个活动组件,活动组件有活动名称和参与人数,点击活动组件可以进入活动详情页 +7.活动详情页有随机点名和回答问题两个按钮,点击随机点名按钮后,会随机抽取1个用户并显示在页面中,点击回答问题按钮会随机抽取1个用户并显示在页面中,按钮下方有加1分和减1分按钮,点击加一分按钮后,用户积分加一,点击减一分按钮后,用户积分减一 +8.点击“我参与的”可以找到我参与的活动,假设已经存在一个活动,活动名称是2024软件工程K班,活动人数为104人,点击此活动可以进入活动参与详情页,活动参与详情页有签到和“使用卡牌”两个按钮,点击“签到”按钮即可签到,“使用卡牌”按钮上方有一个显示框,会显示需要回答问题的用户 +9.点击商店按钮可以进入商店页面,商店页面有4个卡牌和需要积分的数量,点击购买按钮后积分减少,商店页面下方有一个猜题赢积分按钮,点击后会弹出一个弹窗,弹窗中有一个问题,用户输入答案后点击提交按钮,如果答案正确则积分加一 +10.背景颜色为#f4f3f3,按钮颜色为#0d94ff,按钮全部为圆角矩形 +11.主标题字号20px,副标题字号为16px,正文字号为14px,按钮标题为14px \ No newline at end of file diff --git a/pages/activityDetail/activityDetail.js b/pages/activityDetail/activityDetail.js new file mode 100644 index 0000000..78cc939 --- /dev/null +++ b/pages/activityDetail/activityDetail.js @@ -0,0 +1,39 @@ +Page({ + data: { + activity: null, + selectedUser: null + }, + + onLoad(options) { + const activityId = options.id; + this.fetchActivityDetails(activityId); + }, + + fetchActivityDetails(id) { + // 这里应该从后端 API 获取活动详情 + const mockActivity = { id: 1, name: '软件工程课程', participants: 50 }; + this.setData({ activity: mockActivity }); + }, + + randomNameCall() { + // 这里应该从后端 API 获取随机用户 + const randomUser = '张三'; + this.setData({ selectedUser: randomUser }); + }, + + randomQuestion() { + // 这里应该从后端 API 获取随机用户 + const randomUser = '李四'; + this.setData({ selectedUser: randomUser }); + }, + + addScore() { + // 这里应该调用后端 API 增加用户积分 + wx.showToast({ title: '积分已增加', icon: 'success' }); + }, + + minusScore() { + // 这里应该调用后端 API 减少用户积分 + wx.showToast({ title: '积分已减少', icon: 'success' }); + } +}); \ No newline at end of file diff --git a/pages/activityDetail/activityDetail.wxml b/pages/activityDetail/activityDetail.wxml new file mode 100644 index 0000000..9dc0b6d --- /dev/null +++ b/pages/activityDetail/activityDetail.wxml @@ -0,0 +1,17 @@ + + + 活动名称 + 参与人数: 50 + + + + + + + {{selectedUser}} + + + + + + \ No newline at end of file diff --git a/pages/activityDetail/activityDetail.wxss b/pages/activityDetail/activityDetail.wxss new file mode 100644 index 0000000..ca4fd56 --- /dev/null +++ b/pages/activityDetail/activityDetail.wxss @@ -0,0 +1,63 @@ +.container { + padding: 20px; + background-color: #f4f3f3; +} + +.activity-info { + background-color: white; + padding: 15px; + border-radius: 10px; + margin-bottom: 20px; +} + +.activity-name { + font-size: 20px; + font-weight: bold; +} + +.activity-participants { + font-size: 14px; + color: #666; +} + +.action-buttons { + display: flex; + justify-content: space-between; + margin-bottom: 20px; +} + +.btn-action { + width: 48%; + height: 40px; + background-color: #0d94ff; + color: white; + border-radius: 20px; + font-size: 14px; +} + +.selected-user { + background-color: white; + padding: 15px; + border-radius: 10px; + text-align: center; +} + +.selected-user-name { + font-size: 18px; + margin-bottom: 10px; +} + +.score-buttons { + display: flex; + justify-content: center; +} + +.btn-score { + width: 80px; + height: 30px; + background-color: #0d94ff; + color: white; + border-radius: 15px; + font-size: 14px; + margin: 0 10px; +} \ No newline at end of file diff --git a/pages/createActivity/createActivity.js b/pages/createActivity/createActivity.js new file mode 100644 index 0000000..748eb20 --- /dev/null +++ b/pages/createActivity/createActivity.js @@ -0,0 +1,51 @@ +Page({ + data: { + fileName: '' + }, + + onUpload() { + wx.chooseMessageFile({ + count: 1, + type: 'file', + extension: ['xlsx'], + success: (res) => { + const file = res.tempFiles[0]; + this.setData({ + fileName: file.name + }); + // 这里可以处理文件上传逻辑 + console.log('选择的文件:', file); + } + }); + }, + + onSubmit(e) { + const { activityName, activityDescription } = e.detail.value; + if (activityName && activityDescription) { + if (!this.data.fileName) { + wx.showToast({ + title: '请上传 XLSX 文件', + icon: 'none', + duration: 2000 + }); + return; + } + // 这里应该添加创建活动的逻辑,比如调用后端 API + console.log('创建活动:', activityName, activityDescription, this.data.fileName); + wx.showToast({ + title: '创建成功', + icon: 'success', + duration: 2000 + }); + setTimeout(() => { + wx.navigateBack(); + }, 2000); + } else { + wx.showToast({ + title: '请填写完整信息', + icon: 'none', + duration: 2000 + }); + } + } +}); \ No newline at end of file diff --git a/pages/createActivity/createActivity.wxml b/pages/createActivity/createActivity.wxml new file mode 100644 index 0000000..a4b48d4 --- /dev/null +++ b/pages/createActivity/createActivity.wxml @@ -0,0 +1,27 @@ + +
+ + 活动名称 + + + + + + + 活动描述 + + + + + + + 上传文件 + + {{fileName}} + + + + + +
+
\ No newline at end of file diff --git a/pages/createActivity/createActivity.wxss b/pages/createActivity/createActivity.wxss new file mode 100644 index 0000000..bc9c2d8 --- /dev/null +++ b/pages/createActivity/createActivity.wxss @@ -0,0 +1,70 @@ +.container { + padding: 20px; + background-color: #f4f3f3; + min-height: 100vh; + box-sizing: border-box; + display: flex; + flex-direction: column; +} + +.form-group { + margin-bottom: 20px; +} + +.label { + display: block; + font-size: 14px; + color: #333; + margin-bottom: 5px; +} + +.input-container { + background-color: #fff; + border-radius: 5px; + padding: 5px; +} + +input, textarea { + width: 100%; + padding: 10px; + border: none; + font-size: 14px; + background-color: transparent; +} + +textarea { + height: 100px; +} + +.upload-btn { + background-color: #f0f0f0; + color: #333; + font-size: 12px; + padding: 8px 15px; + border-radius: 5px; + margin-bottom: 10px; + width: auto; + display: inline-block; +} + +.file-name { + font-size: 12px; + color: #666; + margin-left: 10px; +} + +.submit-container { + flex-grow: 1; + display: flex; + align-items: flex-end; + margin-top: 20px; +} + +.submit-btn { + background-color: #0d94ff; + color: white; + font-size: 16px; + padding: 10px 20px; + border-radius: 5px; + width: 100%; +} \ No newline at end of file diff --git a/pages/created/created.js b/pages/created/created.js new file mode 100644 index 0000000..668c6ea --- /dev/null +++ b/pages/created/created.js @@ -0,0 +1,27 @@ +Page({ + data: { + activities: [ + { id: 1, name: "活动1", participants: 10 }, + { id: 2, name: "活动2", participants: 20 }, + { id: 3, name: "活动3", participants: 15 } + ] + }, + + onSearchInput(e) { + // 实现搜索功能 + console.log("搜索:", e.detail.value); + }, + + onActivityTap(e) { + const activityId = e.currentTarget.dataset.id; + wx.navigateTo({ + url: `/pages/activityDetail/activityDetail?id=${activityId}` + }); + }, + + onCreateActivity() { + wx.navigateTo({ + url: '/pages/createActivity/createActivity' + }); + } +}); \ No newline at end of file diff --git a/pages/created/created.json b/pages/created/created.json new file mode 100644 index 0000000..8835af0 --- /dev/null +++ b/pages/created/created.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/created/created.wxml b/pages/created/created.wxml new file mode 100644 index 0000000..f19a4da --- /dev/null +++ b/pages/created/created.wxml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/pages/created/created.wxss b/pages/created/created.wxss new file mode 100644 index 0000000..f18ba31 --- /dev/null +++ b/pages/created/created.wxss @@ -0,0 +1,64 @@ +.container { + padding: 20px; + background-color: #f4f3f3; + min-height: 100vh; + box-sizing: border-box; +} + +.search-bar { + position: sticky; + top: 0; + z-index: 1000; + background-color: #f4f3f3; + padding: 10px 0; +} + +.search-bar input { + width: 100%; + height: 40px; + padding: 0 15px; + border: 1px solid #ccc; + border-radius: 20px; + background-color: #fff; +} + +.activity-list { + margin-top: 20px; + margin-bottom: 20px; +} + +.activity-item { + width: 100%; + background-color: #fff; + padding: 15px; + margin-bottom: 10px; + border-radius: 5px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + text-align: left; +} + +.activity-info { + display: flex; + flex-direction: column; +} + +.activity-name { + font-size: 16px; + font-weight: bold; + color: #333; +} + +.activity-participants { + font-size: 14px; + color: #666; + margin-top: 5px; +} + +.create-btn { + background-color: #0d94ff; + color: white; + border-radius: 5px; + padding: 10px 20px; + font-size: 16px; + width: 100%; +} \ No newline at end of file diff --git a/pages/index/index.js b/pages/index/index.js new file mode 100644 index 0000000..a8d6aa5 --- /dev/null +++ b/pages/index/index.js @@ -0,0 +1,49 @@ +// index.js +const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0' + +Page({ + data: { + motto: 'Hello World', + userInfo: { + avatarUrl: defaultAvatarUrl, + nickName: '', + }, + hasUserInfo: false, + canIUseGetUserProfile: wx.canIUse('getUserProfile'), + canIUseNicknameComp: wx.canIUse('input.type.nickname'), + }, + bindViewTap() { + wx.navigateTo({ + url: '../logs/logs' + }) + }, + onChooseAvatar(e) { + const { avatarUrl } = e.detail + const { nickName } = this.data.userInfo + this.setData({ + "userInfo.avatarUrl": avatarUrl, + hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl, + }) + }, + onInputChange(e) { + const nickName = e.detail.value + const { avatarUrl } = this.data.userInfo + this.setData({ + "userInfo.nickName": nickName, + hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl, + }) + }, + getUserProfile(e) { + // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认,开发者妥善保管用户快速填写的头像昵称,避免重复弹窗 + wx.getUserProfile({ + desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写 + success: (res) => { + console.log(res) + this.setData({ + userInfo: res.userInfo, + hasUserInfo: true + }) + } + }) + }, +}) diff --git a/pages/index/index.json b/pages/index/index.json new file mode 100644 index 0000000..b55b5a2 --- /dev/null +++ b/pages/index/index.json @@ -0,0 +1,4 @@ +{ + "usingComponents": { + } +} \ No newline at end of file diff --git a/pages/index/index.wxml b/pages/index/index.wxml new file mode 100644 index 0000000..0721ba0 --- /dev/null +++ b/pages/index/index.wxml @@ -0,0 +1,27 @@ + + + + + + + + 昵称 + + + + + + 请使用2.10.4及以上版本基础库 + + + + {{userInfo.nickName}} + + + + {{motto}} + + + diff --git a/pages/index/index.wxss b/pages/index/index.wxss new file mode 100644 index 0000000..1ebed4b --- /dev/null +++ b/pages/index/index.wxss @@ -0,0 +1,62 @@ +/**index.wxss**/ +page { + height: 100vh; + display: flex; + flex-direction: column; +} +.scrollarea { + flex: 1; + overflow-y: hidden; +} + +.userinfo { + display: flex; + flex-direction: column; + align-items: center; + color: #aaa; + width: 80%; +} + +.userinfo-avatar { + overflow: hidden; + width: 128rpx; + height: 128rpx; + margin: 20rpx; + border-radius: 50%; +} + +.usermotto { + margin-top: 200px; +} + +.avatar-wrapper { + padding: 0; + width: 56px !important; + border-radius: 8px; + margin-top: 40px; + margin-bottom: 40px; +} + +.avatar { + display: block; + width: 56px; + height: 56px; +} + +.nickname-wrapper { + display: flex; + width: 100%; + padding: 16px; + box-sizing: border-box; + border-top: .5px solid rgba(0, 0, 0, 0.1); + border-bottom: .5px solid rgba(0, 0, 0, 0.1); + color: black; +} + +.nickname-label { + width: 105px; +} + +.nickname-input { + flex: 1; +} diff --git a/pages/login/login.js b/pages/login/login.js new file mode 100644 index 0000000..85407d2 --- /dev/null +++ b/pages/login/login.js @@ -0,0 +1,41 @@ +Page({ + data: { + account: '', + password: '' + }, + + onAccountInput(e) { + this.setData({ + account: e.detail.value + }) + }, + + onPasswordInput(e) { + this.setData({ + password: e.detail.value + }) + }, + + onLogin() { + const { account, password } = this.data + if (account && password) { + // 这里应该添加实际的登录逻辑,比如调用后端 API + // 现在我们只是模拟登录成功 + wx.showToast({ + title: '登录成功', + icon: 'success', + duration: 2000 + }) + // 登录成功后跳转到"我创建的"页面 + wx.switchTab({ + url: '/pages/created/created' + }) + } else { + wx.showToast({ + title: '请输入账号和密码', + icon: 'none', + duration: 2000 + }) + } + } +}) \ No newline at end of file diff --git a/pages/login/login.wxml b/pages/login/login.wxml new file mode 100644 index 0000000..7eae0f0 --- /dev/null +++ b/pages/login/login.wxml @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/pages/login/login.wxss b/pages/login/login.wxss new file mode 100644 index 0000000..a42a0f8 --- /dev/null +++ b/pages/login/login.wxss @@ -0,0 +1,30 @@ +.container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; + background-color: #f4f3f3; +} + +.login-form { + width: 80%; + max-width: 300px; +} + +input { + width: 100%; + height: 40px; + margin-bottom: 20px; + padding: 0 10px; + border: 1px solid #ccc; + border-radius: 5px; +} + +button { + width: 100%; + height: 40px; + line-height: 40px; + text-align: center; + font-size: 16px; +} \ No newline at end of file diff --git a/pages/logs/logs.js b/pages/logs/logs.js new file mode 100644 index 0000000..85f6aac --- /dev/null +++ b/pages/logs/logs.js @@ -0,0 +1,18 @@ +// logs.js +const util = require('../../utils/util.js') + +Page({ + data: { + logs: [] + }, + onLoad() { + this.setData({ + logs: (wx.getStorageSync('logs') || []).map(log => { + return { + date: util.formatTime(new Date(log)), + timeStamp: log + } + }) + }) + } +}) diff --git a/pages/logs/logs.json b/pages/logs/logs.json new file mode 100644 index 0000000..b55b5a2 --- /dev/null +++ b/pages/logs/logs.json @@ -0,0 +1,4 @@ +{ + "usingComponents": { + } +} \ No newline at end of file diff --git a/pages/logs/logs.wxml b/pages/logs/logs.wxml new file mode 100644 index 0000000..85cf1bf --- /dev/null +++ b/pages/logs/logs.wxml @@ -0,0 +1,6 @@ + + + + {{index + 1}}. {{log.date}} + + diff --git a/pages/logs/logs.wxss b/pages/logs/logs.wxss new file mode 100644 index 0000000..33f9d9e --- /dev/null +++ b/pages/logs/logs.wxss @@ -0,0 +1,16 @@ +page { + height: 100vh; + display: flex; + flex-direction: column; +} +.scrollarea { + flex: 1; + overflow-y: hidden; +} +.log-item { + margin-top: 20rpx; + text-align: center; +} +.log-item:last-child { + padding-bottom: env(safe-area-inset-bottom); +} diff --git a/pages/myCreated/myCreated.js b/pages/myCreated/myCreated.js new file mode 100644 index 0000000..38bce58 --- /dev/null +++ b/pages/myCreated/myCreated.js @@ -0,0 +1,32 @@ +Page({ + data: { + activities: [] + }, + + onLoad() { + this.fetchActivities(); + }, + + fetchActivities() { + // 这里应该从后端 API 获取活动列表 + const mockActivities = [ + { id: 1, name: '软件工程课程', participants: 50 }, + { id: 2, name: '数据结构讨论', participants: 30 } + ]; + this.setData({ activities: mockActivities }); + }, + + onSearch(e) { + const keyword = e.detail.value; + // 实现搜索逻辑 + }, + + goToCreateActivity() { + wx.navigateTo({ url: '/pages/createActivity/createActivity' }); + }, + + goToActivityDetail(e) { + const activityId = e.currentTarget.dataset.id; + wx.navigateTo({ url: `/pages/activityDetail/activityDetail?id=${activityId}` }); + } +}); \ No newline at end of file diff --git a/pages/myCreated/myCreated.wxml b/pages/myCreated/myCreated.wxml new file mode 100644 index 0000000..667c3c6 --- /dev/null +++ b/pages/myCreated/myCreated.wxml @@ -0,0 +1,12 @@ + + + + + + + + 活动名称 + 参与人数: 50 + + + \ No newline at end of file diff --git a/pages/myCreated/myCreated.wxss b/pages/myCreated/myCreated.wxss new file mode 100644 index 0000000..272d0b0 --- /dev/null +++ b/pages/myCreated/myCreated.wxss @@ -0,0 +1,40 @@ +.container { + padding: 20px; + background-color: #f4f3f3; +} + +.search-bar { + width: 100%; + height: 40px; + background-color: white; + border-radius: 20px; + padding: 0 10px; + margin-bottom: 20px; +} + +.btn-create { + width: 100%; + height: 40px; + background-color: #0d94ff; + color: white; + border-radius: 20px; + font-size: 14px; + margin-bottom: 20px; +} + +.activity-item { + background-color: white; + padding: 15px; + border-radius: 10px; + margin-bottom: 10px; +} + +.activity-name { + font-size: 16px; + font-weight: bold; +} + +.activity-participants { + font-size: 14px; + color: #666; +} \ No newline at end of file diff --git a/pages/myParticipated/myParticipated.js b/pages/myParticipated/myParticipated.js new file mode 100644 index 0000000..260b038 --- /dev/null +++ b/pages/myParticipated/myParticipated.js @@ -0,0 +1,22 @@ +Page({ + data: { + activities: [] + }, + + onLoad() { + this.fetchParticipatedActivities(); + }, + + fetchParticipatedActivities() { + // 这里应该从后端 API 获取参与的活动列表 + const mockActivities = [ + { id: 1, name: '2024软件工程K班', participants: 104 } + ]; + this.setData({ activities: mockActivities }); + }, + + goToParticipatedDetail(e) { + const activityId = e.currentTarget.dataset.id; + wx.navigateTo({ url: `/pages/participatedDetail/participatedDetail?id=${activityId}` }); + } +}); \ No newline at end of file diff --git a/pages/myParticipated/myParticipated.wxml b/pages/myParticipated/myParticipated.wxml new file mode 100644 index 0000000..c5a0deb --- /dev/null +++ b/pages/myParticipated/myParticipated.wxml @@ -0,0 +1,8 @@ + + + + 2024软件工程K班 + 参与人数: 104 + + + \ No newline at end of file diff --git a/pages/myParticipated/myParticipated.wxss b/pages/myParticipated/myParticipated.wxss new file mode 100644 index 0000000..397a584 --- /dev/null +++ b/pages/myParticipated/myParticipated.wxss @@ -0,0 +1,21 @@ +.container { + padding: 20px; + background-color: #f4f3f3; +} + +.activity-item { + background-color: white; + padding: 15px; + border-radius: 10px; + margin-bottom: 10px; +} + +.activity-name { + font-size: 16px; + font-weight: bold; +} + +.activity-participants { + font-size: 14px; + color: #666; +} \ No newline at end of file diff --git a/pages/participated/participated.js b/pages/participated/participated.js new file mode 100644 index 0000000..37052d7 --- /dev/null +++ b/pages/participated/participated.js @@ -0,0 +1,52 @@ +Page({ + data: { + activities: [ + { id: 1, name: "2024软件工程K班", participants: 104 } + // 可以添加更多活动 + ], + filteredActivities: [] + }, + + onLoad: function() { + this.setData({ + filteredActivities: this.data.activities.slice(1) // 除了第一个活动外的所有活动 + }); + }, + + onSearchInput(e) { + const searchText = e.detail.value.toLowerCase(); + const filtered = this.data.activities.filter(activity => + activity.name.toLowerCase().includes(searchText) + ); + this.setData({ + filteredActivities: filtered + }); + }, + + onActivitySummaryTap() { + wx.navigateTo({ + url: '/pages/participatedDetail/participatedDetail?id=1', + fail: (err) => { + console.error('Navigation failed:', err); + wx.showToast({ + title: '页面跳转失败', + icon: 'none' + }); + } + }); + }, + + onActivityTap(e) { + const activityId = e.currentTarget.dataset.id; + wx.navigateTo({ + url: `/pages/participatedDetail/participatedDetail?id=${activityId}`, + fail: (err) => { + console.error('Navigation failed:', err); + wx.showToast({ + title: '页面跳转失败', + icon: 'none' + }); + } + }); + } +}); \ No newline at end of file diff --git a/pages/participated/participated.json b/pages/participated/participated.json new file mode 100644 index 0000000..8835af0 --- /dev/null +++ b/pages/participated/participated.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/participated/participated.wxml b/pages/participated/participated.wxml new file mode 100644 index 0000000..d4b285d --- /dev/null +++ b/pages/participated/participated.wxml @@ -0,0 +1,9 @@ + + + + 2024软件工程K班 + 参与人数:104人 + + + + \ No newline at end of file diff --git a/pages/participated/participated.wxss b/pages/participated/participated.wxss new file mode 100644 index 0000000..6c313d1 --- /dev/null +++ b/pages/participated/participated.wxss @@ -0,0 +1,92 @@ +.container { + background-color: #f4f3f3; + min-height: 100vh; + box-sizing: border-box; + display: flex; + flex-direction: column; +} + +.top-section { + padding: 20px; +} + +.search-container { + margin-bottom: 15px; +} + +.search-bar { + display: flex; + align-items: center; + background-color: #fff; + border-radius: 20px; + padding: 5px 15px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + +.search-bar icon { + margin-right: 5px; +} + +.search-bar input { + flex: 1; + border: none; + background: transparent; + height: 30px; + font-size: 14px; +} + +.activity-summary { + background-color: #0d94ff; + color: white; + padding: 15px; + border-radius: 5px; + display: flex; + flex-direction: column; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + +.summary-title { + font-size: 18px; + font-weight: bold; + margin-bottom: 5px; +} + +.summary-participants { + font-size: 14px; +} + +.activity-list { + padding: 20px; +} + +.activity-item { + background-color: #fff; + padding: 15px; + margin-bottom: 10px; + border-radius: 5px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + +.activity-info { + display: flex; + flex-direction: column; +} + +.activity-name { + font-size: 16px; + font-weight: bold; + color: #333; +} + +.activity-participants { + font-size: 14px; + color: #666; + margin-top: 5px; +} + +.no-activities { + text-align: center; + color: #999; + margin-top: 50px; + padding: 0 20px; +} \ No newline at end of file diff --git a/pages/participatedDetail/participatedDetail.js b/pages/participatedDetail/participatedDetail.js new file mode 100644 index 0000000..d5d592f --- /dev/null +++ b/pages/participatedDetail/participatedDetail.js @@ -0,0 +1,147 @@ +const app = getApp() + +Page({ + data: { + activity: null, + luckyStudent: null, + isLoading: false, + studentId: null, + showAnswerModal: false + }, + + onLoad: function(options) { + const activityId = options.id; + // 这里应该根据 activityId 从服务器或本地存储加载活动详情 + // 现在我们只是模拟一下 + this.setData({ + activity: { id: activityId, name: "2024软件工程K班", participants: 104 } + }); + // 这里应该从全局状态或本地存储获取当前用户的 student_id + this.setData({ + studentId: app.globalData.studentId || '12345' // 假设的学生ID + }); + }, + + onSignIn: function() { + wx.request({ + url: 'http://10.133.7.205:3000/update_attendance_score', + method: 'POST', + data: { + student_id: this.data.studentId + }, + success: (res) => { + if (res.statusCode === 200) { + wx.showToast({ + title: '签到成功', + icon: 'success' + }); + } else { + wx.showToast({ + title: '签到失败', + icon: 'none' + }); + } + }, + fail: (err) => { + console.error('API request failed:', err); + wx.showToast({ + title: '网络错误', + icon: 'none' + }); + } + }); + }, + + onDrawLuckyStudent: function() { + if (this.data.isLoading) return; // 防止重复点击 + + this.setData({ isLoading: true }); + + this.drawLuckyStudentWithRetry(3); // 最多重试3次 + }, + + drawLuckyStudentWithRetry: function(retryCount) { + wx.request({ + url: 'http://10.133.7.205:3000/get_random_student', + method: 'GET', + timeout: 15000, // 增加超时时间到15秒 + success: (res) => { + if (res.statusCode === 200) { + this.setData({ + luckyStudent: res.data.name, + studentId: res.data.id, + isLoading: false, + showAnswerModal: true + }); + wx.showToast({ + title: '已抽取幸运儿', + icon: 'success' + }); + } else { + this.handleDrawError('服务器返回错误', retryCount); + } + }, + fail: (err) => { + console.error('API request failed:', err); + this.handleDrawError('网络请求失败', retryCount); + } + }); + }, + + handleDrawError: function(errorMsg, retryCount) { + if (retryCount > 0) { + setTimeout(() => { + this.drawLuckyStudentWithRetry(retryCount - 1); + }, 1000); // 1秒后重试 + } else { + this.setData({ isLoading: false }); + wx.showModal({ + title: '抽取失败', + content: `${errorMsg},请稍后再试。`, + showCancel: false + }); + } + }, + + onAnswerCorrect: function() { + this.updateAnswerScore(true, 1); + }, + + onAnswerIncorrect: function() { + this.updateAnswerScore(false, 0); + }, + + updateAnswerScore: function(repeatedCorrectly, answerScore) { + wx.request({ + url: 'http://10.133.7.205:3000/update_answer_score', + method: 'POST', + data: { + student_id: this.data.studentId, + repeated_correctly: repeatedCorrectly, + answer_score: answerScore + }, + success: (res) => { + if (res.statusCode === 200) { + wx.showToast({ + title: '回答已记录', + icon: 'success' + }); + } else { + wx.showToast({ + title: '记录失败', + icon: 'none' + }); + } + this.setData({ showAnswerModal: false }); + }, + fail: (err) => { + console.error('API request failed:', err); + wx.showToast({ + title: '网络错误', + icon: 'none' + }); + this.setData({ showAnswerModal: false }); + } + }); + } +}); \ No newline at end of file diff --git a/pages/participatedDetail/participatedDetail.json b/pages/participatedDetail/participatedDetail.json new file mode 100644 index 0000000..8835af0 --- /dev/null +++ b/pages/participatedDetail/participatedDetail.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/participatedDetail/participatedDetail.wxml b/pages/participatedDetail/participatedDetail.wxml new file mode 100644 index 0000000..be82fc4 --- /dev/null +++ b/pages/participatedDetail/participatedDetail.wxml @@ -0,0 +1,27 @@ + + + {{activity.name}} + 参与人数:{{activity.participants}}人 + + + + 幸运儿:{{luckyStudent}} + + + + + + + + + + {{luckyStudent}} 回答问题: + + + + + + + \ No newline at end of file diff --git a/pages/participatedDetail/participatedDetail.wxss b/pages/participatedDetail/participatedDetail.wxss new file mode 100644 index 0000000..1ede768 --- /dev/null +++ b/pages/participatedDetail/participatedDetail.wxss @@ -0,0 +1,95 @@ +.container { + padding: 20rpx; + background-color: #f4f3f3; + min-height: 100vh; +} + +.activity-info { + background-color: #ffffff; + border-radius: 10rpx; + padding: 20rpx; + margin-bottom: 20rpx; + box-shadow: 0 2rpx 4rpx rgba(0,0,0,0.1); +} + +.activity-name { + font-size: 20px; + font-weight: bold; + display: block; + margin-bottom: 10rpx; +} + +.activity-participants { + font-size: 16px; + color: #666; +} + +.lucky-student { + background-color: #ffffff; + border-radius: 10rpx; + padding: 20rpx; + margin-bottom: 20rpx; + box-shadow: 0 2rpx 4rpx rgba(0,0,0,0.1); + text-align: center; + font-size: 18px; + font-weight: bold; + color: #0d94ff; +} + +.action-buttons { + display: flex; + justify-content: space-between; + margin-bottom: 20rpx; +} + +.action-btn { + background-color: #0d94ff; + color: #ffffff; + border-radius: 20rpx; + font-size: 14px; + padding: 10rpx 20rpx; + width: 45%; +} + +.answer-modal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; +} + +.modal-content { + background-color: #ffffff; + border-radius: 10rpx; + padding: 20rpx; + width: 80%; + text-align: center; +} + +.answer-buttons { + display: flex; + justify-content: space-around; + margin-top: 20rpx; +} + +.answer-btn { + border-radius: 20rpx; + font-size: 14px; + padding: 10rpx 20rpx; + width: 45%; +} + +.correct { + background-color: #4CAF50; + color: white; +} + +.incorrect { + background-color: #F44336; + color: white; +} \ No newline at end of file diff --git a/pages/store/store.js b/pages/store/store.js new file mode 100644 index 0000000..9f90816 --- /dev/null +++ b/pages/store/store.js @@ -0,0 +1,60 @@ +Page({ + data: { + cards: [ + { id: 1, name: "卡牌1", price: 100, image: "/assets/card1.png" }, + { id: 2, name: "卡牌2", price: 200, image: "/assets/card2.png" }, + { id: 3, name: "卡牌3", price: 300, image: "/assets/card3.png" }, + { id: 4, name: "卡牌4", price: 400, image: "/assets/card4.png" } + ], + userPoints: 1000 // 假设用户初始有1000积分 + }, + + onBuy: function(e) { + const cardId = e.currentTarget.dataset.id; + const card = this.data.cards.find(c => c.id === cardId); + if (this.data.userPoints >= card.price) { + this.setData({ + userPoints: this.data.userPoints - card.price + }); + wx.showToast({ + title: '购买成功', + icon: 'success' + }); + } else { + wx.showToast({ + title: '积分不足', + icon: 'none' + }); + } + }, + + onGuess: function() { + wx.showModal({ + title: '猜题', + content: '1 + 1 = ?', + editable: true, + placeholderText: '请输入答案', + confirmText: '提交', + cancelText: '取消', + success: (res) => { + if (res.confirm) { + const answer = res.content; + if (answer === '2') { + this.setData({ + userPoints: this.data.userPoints + 1 + }); + wx.showToast({ + title: '答对了,获得1积分', + icon: 'success' + }); + } else { + wx.showToast({ + title: '答错了,再接再厉', + icon: 'none' + }); + } + } + } + }); + } +}); \ No newline at end of file diff --git a/pages/store/store.wxml b/pages/store/store.wxml new file mode 100644 index 0000000..63ad446 --- /dev/null +++ b/pages/store/store.wxml @@ -0,0 +1,24 @@ + + + 当前积分:{{userPoints}} + + + + + {{item.name}} + + + {{item.price}} 积分 + + + + + + + + + \ No newline at end of file diff --git a/pages/store/store.wxss b/pages/store/store.wxss new file mode 100644 index 0000000..fdcb173 --- /dev/null +++ b/pages/store/store.wxss @@ -0,0 +1,71 @@ +.container { + padding: 20rpx; + background-color: #f4f3f3; + min-height: 100vh; + box-sizing: border-box; +} + +.user-points { + font-size: 16px; + margin-bottom: 20rpx; +} + +.card-list { + display: flex; + flex-direction: column; +} + +.card-item { + background-color: #ffffff; + border-radius: 10rpx; + padding: 20rpx; + margin-bottom: 20rpx; + box-shadow: 0 2rpx 4rpx rgba(0,0,0,0.1); + display: flex; + flex-direction: column; + align-items: center; +} + +.card-name { + font-size: 20px; + font-weight: bold; + margin-bottom: 10rpx; +} + +.card-image { + width: 300rpx; + height: 300rpx; + object-fit: cover; + margin: 20rpx 0; +} + +.card-info { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; +} + +.card-price { + font-size: 16px; + color: #666; + margin-bottom: 20rpx; +} + +.buy-btn, .guess-btn { + background-color: #0d94ff; + color: #ffffff; + border-radius: 20rpx; + font-size: 14px; + padding: 10rpx 20rpx; + width: 80%; +} + +.bottom-section { + margin-top: 20rpx; + width: 100%; +} + +.guess-btn { + width: 100%; +} \ No newline at end of file diff --git a/pages/test/test.js b/pages/test/test.js new file mode 100644 index 0000000..210d34b --- /dev/null +++ b/pages/test/test.js @@ -0,0 +1,6 @@ +Page({ + data: {} , + onLoad: function() { + console.log('Test page loaded'); + } +}) \ No newline at end of file diff --git a/pages/test/test.json b/pages/test/test.json new file mode 100644 index 0000000..8835af0 --- /dev/null +++ b/pages/test/test.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} \ No newline at end of file diff --git a/pages/test/test.wxml b/pages/test/test.wxml new file mode 100644 index 0000000..c9bb97a --- /dev/null +++ b/pages/test/test.wxml @@ -0,0 +1 @@ +This is a test page \ No newline at end of file diff --git a/pages/test/test.wxss b/pages/test/test.wxss new file mode 100644 index 0000000..584a528 --- /dev/null +++ b/pages/test/test.wxss @@ -0,0 +1,3 @@ +view { + padding: 20px; +} \ No newline at end of file diff --git a/project.config.json b/project.config.json new file mode 100644 index 0000000..0884f77 --- /dev/null +++ b/project.config.json @@ -0,0 +1,29 @@ +{ + "compileType": "miniprogram", + "libVersion": "trial", + "packOptions": { + "ignore": [], + "include": [] + }, + "setting": { + "coverView": true, + "es6": true, + "postcss": true, + "minified": true, + "enhance": true, + "showShadowRootInWxmlPanel": true, + "packNpmRelationList": [], + "babelSetting": { + "ignore": [], + "disablePlugins": [], + "outputPath": "" + }, + "urlCheck": false + }, + "condition": {}, + "editorSetting": { + "tabIndent": "auto", + "tabSize": 2 + }, + "appid": "wxcbc61201213ab639" +} \ No newline at end of file diff --git a/project.private.config.json b/project.private.config.json new file mode 100644 index 0000000..236961d --- /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": "K%E7%82%B9%E5%90%8D", + "setting": { + "compileHotReLoad": true + } +} \ No newline at end of file diff --git a/sitemap.json b/sitemap.json new file mode 100644 index 0000000..ca02add --- /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 diff --git a/utils/util.js b/utils/util.js new file mode 100644 index 0000000..764bc2c --- /dev/null +++ b/utils/util.js @@ -0,0 +1,19 @@ +const formatTime = date => { + const year = date.getFullYear() + const month = date.getMonth() + 1 + const day = date.getDate() + const hour = date.getHours() + const minute = date.getMinutes() + const second = date.getSeconds() + + return `${[year, month, day].map(formatNumber).join('/')} ${[hour, minute, second].map(formatNumber).join(':')}` +} + +const formatNumber = n => { + n = n.toString() + return n[1] ? n : `0${n}` +} + +module.exports = { + formatTime +}