Add 卓米会 mini program and admin server.
Initial commit of the WeChat mini program, Express backend, and admin console. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
const api = require('../../utils/api')
|
||||
const media = require('../../utils/media')
|
||||
const activityUtil = require('../../utils/activity')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
nickName: '',
|
||||
avatarUrl: '',
|
||||
letter: '微',
|
||||
signups: [],
|
||||
checkins: [],
|
||||
checking: false
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.loadAll()
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.loadAll().then(() => wx.stopPullDownRefresh())
|
||||
},
|
||||
|
||||
loadAll() {
|
||||
return Promise.all([api.profile(), api.mySignups()])
|
||||
.then((results) => {
|
||||
const profile = results[0] || {}
|
||||
const mine = results[1] || {}
|
||||
const nickName = profile.nickName || ''
|
||||
this.setData({
|
||||
nickName: nickName,
|
||||
avatarUrl: media.absUrl(profile.avatarUrl),
|
||||
letter: (nickName || '微').slice(0, 1),
|
||||
signups: mine.signups || [],
|
||||
checkins: mine.checkins || []
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
},
|
||||
|
||||
goProfile() {
|
||||
wx.navigateTo({ url: '/pages/profile/profile' })
|
||||
},
|
||||
|
||||
checkin() {
|
||||
if (this.data.checking) return
|
||||
this.setData({ checking: true })
|
||||
api
|
||||
.checkin({ simulate: true })
|
||||
.then(() => {
|
||||
wx.showToast({ title: '签到成功', icon: 'success' })
|
||||
return this.loadAll()
|
||||
})
|
||||
.catch(activityUtil.toast)
|
||||
.then(() => this.setData({ checking: false }))
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"navigationBarTitleText": "我的"
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<view class="page">
|
||||
<view class="card profile" hover-class="pressed" bindtap="goProfile">
|
||||
<image wx:if="{{avatarUrl}}" class="avatar" src="{{avatarUrl}}" mode="aspectFill" />
|
||||
<view wx:else class="avatar letter">{{letter}}</view>
|
||||
<view class="who">
|
||||
<text class="name">{{nickName || '微信用户'}}</text>
|
||||
<text class="edit">点击编辑资料</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card block">
|
||||
<text class="heading">我的报名</text>
|
||||
<view wx:if="{{!signups.length}}" class="empty">暂无报名记录,去首页报名吧</view>
|
||||
<view wx:for="{{signups}}" wx:key="id" class="item">
|
||||
<view class="item-main">
|
||||
<text class="item-title">{{item.activityTitle}}</text>
|
||||
<text class="item-sub">{{nickName || item.name}} · {{item.phone}}</text>
|
||||
</view>
|
||||
<text class="tag {{item.checkedIn ? 'on' : ''}}">{{item.checkedIn ? '已签到' : '未签到'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card block">
|
||||
<text class="heading">签到记录</text>
|
||||
<view wx:if="{{!checkins.length}}" class="empty">暂无签到记录</view>
|
||||
<view wx:for="{{checkins}}" wx:key="id" class="item">
|
||||
<view class="item-main">
|
||||
<text class="item-title">{{item.activityTitle}}</text>
|
||||
<text class="item-sub">已签到</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="scan" hover-class="scan-pressed" bindtap="checkin">模拟现场扫码签到</view>
|
||||
</view>
|
||||
@@ -0,0 +1,131 @@
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
padding: 28rpx 32rpx 48rpx;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #ffffff;
|
||||
border-radius: 28rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.profile {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 28rpx;
|
||||
padding: 36rpx 32rpx;
|
||||
}
|
||||
|
||||
.pressed {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
flex-shrink: 0;
|
||||
width: 112rpx;
|
||||
height: 112rpx;
|
||||
border-radius: 56rpx;
|
||||
}
|
||||
|
||||
.letter {
|
||||
background: #128a80;
|
||||
color: #ffffff;
|
||||
font-size: 42rpx;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.who {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.name {
|
||||
display: block;
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.edit {
|
||||
display: block;
|
||||
margin-top: 10rpx;
|
||||
color: #9ca3af;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.block {
|
||||
padding: 32rpx;
|
||||
}
|
||||
|
||||
.heading {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.empty {
|
||||
padding: 56rpx 0 28rpx;
|
||||
text-align: center;
|
||||
color: #c5cdd6;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 20rpx;
|
||||
padding-top: 28rpx;
|
||||
}
|
||||
|
||||
.item-main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
display: block;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.item-sub {
|
||||
display: block;
|
||||
margin-top: 6rpx;
|
||||
color: #9ca3af;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.tag {
|
||||
flex-shrink: 0;
|
||||
color: #9ca3af;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.tag.on {
|
||||
color: #128a80;
|
||||
}
|
||||
|
||||
.scan {
|
||||
height: 96rpx;
|
||||
margin-top: 8rpx;
|
||||
border-radius: 20rpx;
|
||||
border: 2rpx solid #128a80;
|
||||
color: #128a80;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.scan-pressed {
|
||||
background: #f0faf9;
|
||||
}
|
||||
Reference in New Issue
Block a user