first commit

This commit is contained in:
ytc1012
2026-02-04 16:11:55 +08:00
commit 0f3ee050dc
165 changed files with 25795 additions and 0 deletions

View File

@@ -0,0 +1,179 @@
const app = getApp()
const db = wx.cloud.database()
Page({
data: {
name: '',
keywords: ['咖啡馆', '餐厅', '公园', '商场', '电影院', 'KTV', '酒吧', '火锅', '烧烤', '其他'],
keyword: '咖啡馆',
meetTime: '',
meetDate: '',
meetTimeOnly: '',
requirements: '',
userInfo: {
avatarUrl: '',
nickName: ''
}
},
onLoad() {
// 生成默认聚会名称
const randomNum = Math.floor(Math.random() * 9000) + 1000
this.setData({
name: `聚会-${randomNum}`
})
},
onNameInput(e) {
this.setData({
name: e.detail.value
})
},
onSelectKeyword(e) {
this.setData({
keyword: e.currentTarget.dataset.keyword
})
},
onTimeInput(e) {
this.setData({
meetTime: e.detail.value
})
},
onDateChange(e) {
const date = e.detail.value
this.setData({
meetDate: date
})
this.updateMeetTime()
},
onTimeChange(e) {
const time = e.detail.value
this.setData({
meetTimeOnly: time
})
this.updateMeetTime()
},
updateMeetTime() {
const { meetDate, meetTimeOnly } = this.data
if (meetDate && meetTimeOnly) {
this.setData({
meetTime: `${meetDate} ${meetTimeOnly}`
})
} else if (meetDate) {
this.setData({
meetTime: meetDate
})
}
},
onRequirementsInput(e) {
this.setData({
requirements: e.detail.value
})
},
onChooseAvatar(e) {
const { avatarUrl } = e.detail
this.setData({
'userInfo.avatarUrl': avatarUrl
})
},
onNicknameChange(e) {
const nickName = e.detail.value
this.setData({
'userInfo.nickName': nickName
})
},
onSubmit() {
const { name, keyword, meetTime, requirements, userInfo } = this.data
if (!name.trim()) {
wx.showToast({
title: '请输入聚会名称',
icon: 'none'
})
return
}
// 检查是否填写了昵称
if (!userInfo.nickName || !userInfo.nickName.trim()) {
wx.showToast({
title: '请输入你的昵称',
icon: 'none'
})
return
}
this.createRoom(name, keyword, meetTime, requirements)
},
onCancel() {
wx.navigateBack()
},
createRoom(name, keywords, meetTime, requirements) {
wx.showLoading({ title: '创建中...', mask: true })
wx.cloud.callFunction({
name: 'createRoom',
data: {
name,
meetTime,
keywords,
requirements: requirements || '',
userInfo: this.data.userInfo
},
success: res => {
wx.hideLoading()
if (res.result.success) {
const roomId = res.result.roomId
// 保存到本地存储
let myRooms = wx.getStorageSync('myRooms') || []
myRooms = myRooms.filter(item => item.roomId !== roomId)
myRooms.unshift({
roomId,
name,
meetTime,
keywords
})
if (myRooms.length > 2) {
myRooms = myRooms.slice(0, 2)
}
wx.setStorageSync('myRooms', myRooms)
// 更新全局roomList
let roomList = wx.getStorageSync('roomList') || []
roomList = roomList.filter(item => item.roomId !== roomId)
roomList.unshift({
roomId,
name,
meetTime,
keywords
})
if (roomList.length > 5) {
roomList = roomList.slice(0, 5)
}
wx.setStorageSync('roomList', roomList)
wx.redirectTo({
url: `/pages/room/room?roomId=${roomId}&isCreator=true`
})
} else {
wx.showToast({ title: res.result.msg || '创建失败', icon: 'none' })
}
},
fail: err => {
wx.hideLoading()
console.error('云函数调用失败', err)
wx.showToast({ title: '网络错误', icon: 'none' })
}
})
}
})

View File

@@ -0,0 +1,3 @@
{
"navigationBarTitleText": "创建聚会"
}

View File

@@ -0,0 +1,69 @@
<view class="container">
<form bindsubmit="onSubmit">
<view class="form-section">
<view class="form-item">
<view class="label">聚会名称</view>
<input class="input" placeholder="请输入聚会名称" value="{{name}}" bindinput="onNameInput" />
</view>
<view class="form-item">
<view class="label">聚会地点类型</view>
<view class="keywords-grid">
<view
class="keyword-item {{keyword === item ? 'active' : ''}}"
wx:for="{{keywords}}"
wx:key="index"
bindtap="onSelectKeyword"
data-keyword="{{item}}"
>
{{item}}
</view>
</view>
</view>
<view class="form-item">
<view class="label">聚会时间(可选)</view>
<view class="time-picker-row">
<picker mode="date" value="{{meetDate}}" bindchange="onDateChange" class="picker">
<view class="picker-value">
{{meetDate || '选择日期'}}
</view>
</picker>
<picker mode="time" value="{{meetTimeOnly}}" bindchange="onTimeChange" class="picker">
<view class="picker-value">
{{meetTimeOnly || '选择时间'}}
</view>
</picker>
</view>
</view>
<view class="form-item">
<view class="label">特殊需求(可选)</view>
<textarea
class="textarea"
placeholder="如需要停车位、环境安静、有Wi-Fi等"
value="{{requirements}}"
bindinput="onRequirementsInput"
maxlength="200"
show-confirm-bar="{{false}}"
/>
<view class="char-count">{{requirements.length}}/200</view>
</view>
<view class="form-item">
<view class="label">你的信息</view>
<view class="user-info-section">
<button class="avatar-wrapper" open-type="chooseAvatar" bindchooseavatar="onChooseAvatar">
<image class="avatar" src="{{userInfo.avatarUrl || '/images/default-avatar.png'}}" mode="aspectFill"></image>
</button>
<input type="nickname" class="nickname-input" placeholder="请输入昵称" value="{{userInfo.nickName}}" bindchange="onNicknameChange" />
</view>
</view>
</view>
<view class="btn-area">
<button class="submit-btn" form-type="submit">创建聚会</button>
<button class="cancel-btn" bindtap="onCancel">取消</button>
</view>
</form>
</view>

View File

@@ -0,0 +1,156 @@
.container {
min-height: 100vh;
background-color: #f6f7f9;
padding: 0;
align-items: stretch;
width: 100%;
}
.form-section {
margin-top: 40rpx;
padding: 0 80rpx;
}
.form-item {
background-color: transparent;
padding: 20rpx 0;
border-radius: 0;
margin-bottom: 30rpx;
box-sizing: border-box;
width: 100%;
}
.label {
font-size: 28rpx;
color: #333;
margin-bottom: 20rpx;
font-weight: 500;
}
.input {
width: 100%;
font-size: 32rpx;
color: #333;
border: none;
outline: none;
}
.time-picker-row {
display: flex;
gap: 20rpx;
}
.picker {
flex: 1;
background-color: #fff;
border-radius: 8rpx;
padding: 20rpx;
border: 1rpx solid #e5e5e5;
}
.picker-value {
font-size: 32rpx;
color: #333;
text-align: center;
}
.textarea {
width: 100%;
min-height: 120rpx;
font-size: 32rpx;
color: #333;
background-color: #fff;
border-radius: 8rpx;
padding: 20rpx;
border: 1rpx solid #e5e5e5;
box-sizing: border-box;
}
.char-count {
font-size: 24rpx;
color: #999;
text-align: right;
margin-top: 10rpx;
}
.keywords-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16rpx;
}
.keyword-item {
background-color: #f5f5f5;
color: #666;
padding: 20rpx;
border-radius: 12rpx;
font-size: 28rpx;
text-align: center;
transition: all 0.3s;
}
.keyword-item.active {
background-color: #07c160;
color: white;
}
.btn-area {
margin-top: 60rpx;
padding: 0 80rpx;
}
.submit-btn {
background-color: #07c160;
color: white;
font-size: 36rpx;
padding: 24rpx 0;
border-radius: 50rpx;
width: 100%;
margin-bottom: 20rpx;
}
.cancel-btn {
background-color: #f5f5f5;
color: #666;
font-size: 36rpx;
padding: 24rpx 0;
border-radius: 50rpx;
width: 100%;
}
.user-info-section {
display: flex;
align-items: center;
gap: 20rpx;
background-color: #fff;
padding: 20rpx;
border-radius: 12rpx;
border: 1rpx solid #e5e5e5;
}
.avatar-wrapper {
padding: 0;
margin: 0;
border: none;
background: none;
line-height: 1;
}
.avatar-wrapper::after {
border: none;
}
.avatar {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
background-color: #f0f0f0;
}
.nickname-input {
flex: 1;
font-size: 32rpx;
color: #333;
border: none;
outline: none;
}