Files
hejiu/pages/event-create/event-create.vue
T
cg eaa0d7101f feat(chat): 添加私信功能和WebSocket实时通信
- 集成WebSocket管理器,支持心跳、自动重连、消息队列
- 实现私信相关API接口,包括会话列表、历史消息、已读标记等
- 添加聊天页面和会话列表页面,支持实时消息收发
- 配置地图权限和腾讯地图SDK用于酒局定位功能
- 修改应用名称为"喝酒了么"并更新应用描述
- 在App.vue中初始化WebSocket连接和私信功能
- 添加详细的私信模块接口文档和Mock数据
- 优化单图片动态高度计算和预加载逻辑
2026-07-21 21:27:01 +08:00

469 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view :class="themeClass" class="page-container create-page">
<!-- 顶部导航 -->
<view class="create-nav" :style="{ paddingTop: navPaddingTop }">
<view class="create-nav-inner">
<view class="create-back" @click="goBack">
<text class="create-back-icon"></text>
</view>
<text class="create-nav-title">发起酒局</text>
<view class="create-nav-ph"></view>
</view>
</view>
<scroll-view class="create-scroll" scroll-y>
<view class="create-body">
<!-- 标题 -->
<view class="form-group">
<text class="form-label">酒局名称</text>
<input
class="form-input"
v-model="form.title"
placeholder="例如:周五夜·老地方火锅局"
placeholder-class="form-placeholder"
:maxlength="30"
/>
</view>
<!-- 时间 -->
<view class="form-group">
<text class="form-label">时间</text>
<picker mode="date" :value="form.date" @change="onDateChange">
<view class="form-picker">
<text :class="form.date ? 'form-picker-text' : 'form-picker-ph'">{{ form.date || '选择日期' }}</text>
<text class="form-picker-arrow"></text>
</view>
</picker>
<picker mode="time" :value="form.time" @change="onTimeChange">
<view class="form-picker" style="margin-top: 16rpx;">
<text :class="form.time ? 'form-picker-text' : 'form-picker-ph'">{{ form.time || '选择时间' }}</text>
<text class="form-picker-arrow"></text>
</view>
</picker>
</view>
<!-- 地点 -->
<view class="form-group">
<text class="form-label">地点</text>
<!-- 已选地点显示地图预览 -->
<view v-if="form.latitude" class="location-preview">
<map
class="location-map"
:latitude="form.latitude"
:longitude="form.longitude"
:markers="locationMarkers"
:scale="15"
:show-location="false"
@click="chooseLocation"
></map>
<view class="location-info">
<text class="location-name">{{ form.location }}</text>
<text class="location-address">{{ form.address || '' }}</text>
</view>
<view class="location-change" @click="chooseLocation">
<text class="location-change-text">重新选择</text>
</view>
</view>
<!-- 未选地点点击选择 -->
<view v-else class="location-picker" @click="chooseLocation">
<text class="location-picker-icon">📍</text>
<text class="location-picker-text">点击选择地点</text>
<text class="location-picker-arrow"></text>
</view>
</view>
<!-- 人数 -->
<view class="form-group">
<text class="form-label">人数上限</text>
<view class="form-stepper">
<view class="stepper-btn" @click="changePeople(-1)">
<text class="stepper-btn-text"></text>
</view>
<text class="stepper-value">{{ form.maxPeople }}</text>
<view class="stepper-btn" @click="changePeople(1)">
<text class="stepper-btn-text">+</text>
</view>
</view>
</view>
<!-- 备注 -->
<view class="form-group">
<text class="form-label">备注选填</text>
<textarea
class="form-textarea"
v-model="form.note"
placeholder="例如:自带酒水,AA制餐费"
placeholder-class="form-placeholder"
:maxlength="200"
/>
</view>
<!-- 发布按钮 -->
<button class="create-submit" :class="{ disabled: !canSubmit }" @click="handleSubmit">
发布酒局
</button>
</view>
</scroll-view>
</view>
</template>
<script>
import { CreateEvent } from '../../common/api'
import themeMixin from '../../common/theme-mixin'
export default {
mixins: [themeMixin],
data() {
const menuBtn = uni.getMenuButtonBoundingClientRect()
return {
navPaddingTop: menuBtn.top + 'px',
form: {
title: '',
date: '',
time: '',
location: '',
address: '',
latitude: null,
longitude: null,
maxPeople: 6,
note: ''
},
submitting: false
}
},
computed: {
canSubmit() {
return this.form.title.trim() && this.form.date && this.form.time && this.form.location.trim() && !this.submitting
},
locationMarkers() {
if (!this.form.latitude) return []
return [{
id: 1,
latitude: this.form.latitude,
longitude: this.form.longitude,
title: this.form.location,
width: 28,
height: 38
}]
}
},
methods: {
goBack() {
uni.navigateBack()
},
onDateChange(e) {
this.form.date = e.detail.value
},
onTimeChange(e) {
this.form.time = e.detail.value
},
chooseLocation() {
uni.chooseLocation({
success: (res) => {
this.form.location = res.name || res.address || ''
this.form.address = res.address || ''
this.form.latitude = res.latitude
this.form.longitude = res.longitude
},
fail: () => {
// 用户取消或无权限,不做处理
}
})
},
changePeople(delta) {
const val = this.form.maxPeople + delta
if (val >= 2 && val <= 50) {
this.form.maxPeople = val
}
},
async handleSubmit() {
if (!this.canSubmit) return
this.submitting = true
try {
await CreateEvent({
title: this.form.title,
time: `${this.form.date} ${this.form.time}`,
location: this.form.location,
address: this.form.address,
latitude: this.form.latitude,
longitude: this.form.longitude,
maxPeople: this.form.maxPeople,
note: this.form.note
})
uni.showToast({ title: '酒局已发布 🎉', icon: 'none' })
setTimeout(() => uni.navigateBack(), 800)
} catch (e) {
uni.showToast({ title: '发布失败', icon: 'none' })
}
this.submitting = false
}
}
}
</script>
<style lang="scss" scoped>
.create-page {
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
}
.create-nav {
background: $bg-base;
padding-left: $sp-lg;
padding-right: $sp-lg;
}
.create-nav-inner {
display: flex;
align-items: center;
justify-content: space-between;
height: 88rpx;
}
.create-back {
width: 64rpx;
height: 64rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: $bg-card;
&:active { background: $bg-card-alt; }
}
.create-back-icon {
font-size: $fs-xl;
color: $text-primary;
font-weight: $fw-bold;
}
.create-nav-title {
font-size: $fs-base;
font-weight: $fw-bold;
color: $text-primary;
}
.create-nav-ph {
width: 64rpx;
}
.create-scroll {
flex: 1;
height: 0;
}
.create-body {
padding: $sp-lg;
padding-bottom: calc(env(safe-area-inset-bottom) + #{$sp-2xl});
}
.form-group {
margin-bottom: $sp-xl;
}
.form-label {
display: block;
font-size: $fs-sm;
font-weight: $fw-medium;
color: $text-secondary;
margin-bottom: $sp-md;
}
.form-input {
width: 100%;
height: 88rpx;
padding: 0 $sp-lg;
background: $bg-card;
border-radius: $radius-lg;
border: 1rpx solid var(--border-faint, rgba(255,255,255,0.08));
font-size: $fs-base;
color: $text-primary;
box-sizing: border-box;
}
.form-placeholder {
color: $text-tertiary;
}
.form-picker {
display: flex;
align-items: center;
justify-content: space-between;
height: 88rpx;
padding: 0 $sp-lg;
background: $bg-card;
border-radius: $radius-lg;
border: 1rpx solid var(--border-faint, rgba(255,255,255,0.08));
}
.form-picker-text {
font-size: $fs-base;
color: $text-primary;
}
.form-picker-ph {
font-size: $fs-base;
color: $text-tertiary;
}
.form-picker-arrow {
font-size: $fs-xl;
color: $text-tertiary;
}
.form-textarea {
width: 100%;
min-height: 160rpx;
padding: $sp-lg;
background: $bg-card;
border-radius: $radius-lg;
border: 1rpx solid var(--border-faint, rgba(255,255,255,0.08));
font-size: $fs-base;
color: $text-primary;
line-height: $lh-normal;
box-sizing: border-box;
}
/* 地点选择器 */
.location-picker {
display: flex;
align-items: center;
gap: $sp-md;
height: 96rpx;
padding: 0 $sp-lg;
background: $bg-card;
border-radius: $radius-lg;
border: 2rpx dashed var(--border-dashed, rgba(255,255,255,0.12));
&:active {
background: $bg-card-alt;
}
}
.location-picker-icon {
font-size: $fs-lg;
}
.location-picker-text {
flex: 1;
font-size: $fs-base;
color: $text-tertiary;
}
.location-picker-arrow {
font-size: $fs-xl;
color: $text-tertiary;
}
/* 地图预览 */
.location-preview {
border-radius: $radius-lg;
overflow: hidden;
border: 1rpx solid var(--border-faint, rgba(255,255,255,0.08));
}
.location-map {
width: 100%;
height: 280rpx;
}
.location-info {
display: flex;
flex-direction: column;
gap: 6rpx;
padding: $sp-md $sp-lg;
background: $bg-card;
}
.location-name {
font-size: $fs-base;
font-weight: $fw-bold;
color: $text-primary;
}
.location-address {
font-size: $fs-xs;
color: $text-tertiary;
}
.location-change {
display: flex;
align-items: center;
justify-content: center;
padding: $sp-sm;
background: $bg-card-alt;
&:active {
background: $bg-elevated;
}
}
.location-change-text {
font-size: $fs-sm;
color: $amber;
font-weight: $fw-medium;
}
/* 人数步进器 */
.form-stepper {
display: flex;
align-items: center;
gap: $sp-xl;
}
.stepper-btn {
width: 72rpx;
height: 72rpx;
border-radius: 50%;
background: $bg-card;
border: 1rpx solid var(--border-faint, rgba(255,255,255,0.08));
display: flex;
align-items: center;
justify-content: center;
&:active { background: $bg-card-alt; }
}
.stepper-btn-text {
font-size: $fs-xl;
color: $text-primary;
font-weight: $fw-bold;
}
.stepper-value {
font-size: $fs-xl;
font-weight: $fw-black;
color: $amber;
min-width: 60rpx;
text-align: center;
}
/* 提交 */
.create-submit {
width: 100%;
height: 96rpx;
line-height: 96rpx;
text-align: center;
background: linear-gradient(135deg, $amber, $amber-deep);
color: $text-on-amber;
font-size: $fs-lg;
font-weight: $fw-bold;
border-radius: $radius-full;
border: none;
margin-top: $sp-xl;
&::after { border: none; }
&.disabled {
opacity: 0.4;
}
&:active {
transform: scale(0.98);
}
}
</style>