Files
urbanLifeline/urbanLifelineWeb/packages/workcase_wechat/pages/meeting/meetingCreate/MeetingCreate.uvue

334 lines
9.0 KiB
Plaintext
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>
<!-- #ifdef APP -->
<scroll-view style="flex:1">
<!-- #endif -->
<view class="page">
<!-- 导航栏 -->
<view class="nav" :style="{ paddingTop: headerPaddingTop + 'px', height: headerTotalHeight + 'px' }">
<view class="nav-back" @tap="handleCancel">
<view class="nav-back-icon"></view>
</view>
<text class="nav-title">创建视频会议</text>
<view class="nav-capsule"></view>
</view>
<!-- 内容区域 -->
<scroll-view class="content" scroll-y="true" :style="{ marginTop: headerTotalHeight + 'px' }">
<!-- 表单区域 -->
<view class="section">
<view class="form-container">
<!-- 会议名称 -->
<view class="form-item">
<text class="form-label">会议名称</text>
<input
v-model="formData.meetingName"
class="form-input"
placeholder="请输入会议名称"
maxlength="50"
/>
</view>
<!-- 开始时间 -->
<view class="form-item">
<text class="form-label">开始时间<text class="required">*</text></text>
<picker
mode="multiSelector"
:value="startTimePickerValue"
:range="timePickerRange"
@change="handleStartTimeChange"
>
<view class="picker-content">
<text class="picker-text" :class="{ placeholder: !formData.startTime }">
{{ formData.startTime || '请选择开始时间' }}
</text>
<text class="picker-arrow">></text>
</view>
</picker>
</view>
<!-- 结束时间 -->
<view class="form-item">
<text class="form-label">结束时间<text class="required">*</text></text>
<picker
mode="multiSelector"
:value="endTimePickerValue"
:range="timePickerRange"
@change="handleEndTimeChange"
>
<view class="picker-content">
<text class="picker-text" :class="{ placeholder: !formData.endTime }">
{{ formData.endTime || '请选择结束时间' }}
</text>
<text class="picker-arrow">></text>
</view>
</picker>
</view>
<!-- 提前入会 -->
<view class="form-item">
<text class="form-label">提前入会(分钟)</text>
<input
v-model.number="formData.advance"
class="form-input"
type="number"
placeholder="提前入会时间"
/>
<text class="form-tip">用户可在会议开始前N分钟加入</text>
</view>
<!-- 会议密码 -->
<view class="form-item">
<text class="form-label">会议密码</text>
<input
v-model="formData.meetingPassword"
class="form-input"
type="text"
password
placeholder="可选,留空则无密码"
maxlength="20"
/>
</view>
<!-- 最大人数 -->
<view class="form-item">
<text class="form-label">最大人数</text>
<input
v-model.number="formData.maxParticipants"
class="form-input"
type="number"
placeholder="最大参与人数"
/>
</view>
</view>
</view>
<!-- 底部占位 -->
<view class="footer-placeholder"></view>
</scroll-view>
<!-- 底部操作栏 -->
<view class="footer-actions">
<view class="action-button" @tap="handleCancel">
<text class="button-text">取消</text>
</view>
<view class="action-button primary" @tap="handleSubmit">
<text class="button-text">创建会议</text>
</view>
</view>
</view>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { workcaseChatAPI } from '../../../api/workcase/workcaseChat'
import type { CreateMeetingParam } from '../../../types/workcase/chatRoom'
// 响应式数据
const headerPaddingTop = ref<number>(44)
const headerTotalHeight = ref<number>(88)
// 路由参数
const roomId = ref('')
const workcaseId = ref('')
// 表单数据
const formData = reactive<CreateMeetingParam>({
roomId: '',
workcaseId: '',
meetingName: '',
startTime: '',
endTime: '',
advance: 5,
meetingPassword: '',
maxParticipants: 10
})
const submitting = ref(false)
// 时间选择器数据
const startTimePickerValue = ref([0, 0, 0])
const endTimePickerValue = ref([0, 0, 0])
// 生成时间选择器范围
const timePickerRange = computed(() => {
const now = new Date()
const currentYear = now.getFullYear()
const currentMonth = now.getMonth()
const currentDay = now.getDate()
// 日期范围今天到未来30天
const dates: string[] = []
for (let i = 0; i < 30; i++) {
const date = new Date(currentYear, currentMonth, currentDay + i)
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
dates.push(`${month}-${day}`)
}
// 小时00-23
const hours: string[] = []
for (let i = 0; i < 24; i++) {
hours.push(String(i).padStart(2, '0'))
}
// 分钟00、15、30、45
const minutes = ['00', '15', '30', '45']
return [dates, hours, minutes]
})
// 页面加载时获取参数
onLoad((options: any) => {
if (options.roomId) {
roomId.value = options.roomId
formData.roomId = options.roomId
}
if (options.workcaseId) {
workcaseId.value = options.workcaseId
formData.workcaseId = options.workcaseId
}
})
onMounted(() => {
const windowInfo = uni.getWindowInfo()
const statusBarHeight = windowInfo.statusBarHeight || 44
// #ifdef MP-WEIXIN
try {
const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
headerPaddingTop.value = menuButtonInfo.top
headerTotalHeight.value = menuButtonInfo.bottom + 8
} catch (e) {
headerPaddingTop.value = statusBarHeight
headerTotalHeight.value = statusBarHeight + 44
}
// #endif
// #ifndef MP-WEIXIN
headerPaddingTop.value = statusBarHeight
headerTotalHeight.value = statusBarHeight + 44
// #endif
})
// 处理开始时间选择
function handleStartTimeChange(e: any) {
const val = e.detail.value
startTimePickerValue.value = val
const now = new Date()
const selectedDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() + val[0])
const year = selectedDate.getFullYear()
const month = String(selectedDate.getMonth() + 1).padStart(2, '0')
const day = String(selectedDate.getDate()).padStart(2, '0')
const hour = timePickerRange.value[1][val[1]]
const minute = timePickerRange.value[2][val[2]]
formData.startTime = `${year}-${month}-${day} ${hour}:${minute}:00`
}
// 处理结束时间选择
function handleEndTimeChange(e: any) {
const val = e.detail.value
endTimePickerValue.value = val
const now = new Date()
const selectedDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() + val[0])
const year = selectedDate.getFullYear()
const month = String(selectedDate.getMonth() + 1).padStart(2, '0')
const day = String(selectedDate.getDate()).padStart(2, '0')
const hour = timePickerRange.value[1][val[1]]
const minute = timePickerRange.value[2][val[2]]
formData.endTime = `${year}-${month}-${day} ${hour}:${minute}:00`
}
// 验证表单
function validateForm(): boolean {
if (!formData.startTime) {
uni.showToast({ title: '请选择开始时间', icon: 'none' })
return false
}
if (!formData.endTime) {
uni.showToast({ title: '请选择结束时间', icon: 'none' })
return false
}
const start = new Date(formData.startTime.replace(' ', 'T')).getTime()
const end = new Date(formData.endTime.replace(' ', 'T')).getTime()
if (start < Date.now()) {
uni.showToast({ title: '开始时间不能早于当前时间', icon: 'none' })
return false
}
if (end <= start) {
uni.showToast({ title: '结束时间必须晚于开始时间', icon: 'none' })
return false
}
if (end - start < 5 * 60 * 1000) {
uni.showToast({ title: '会议时长不能少于5分钟', icon: 'none' })
return false
}
if (end - start > 24 * 60 * 60 * 1000) {
uni.showToast({ title: '会议时长不能超过24小时', icon: 'none' })
return false
}
if (formData.advance !== undefined && (formData.advance < 0 || formData.advance > 60)) {
uni.showToast({ title: '提前入会时间范围为0-60分钟', icon: 'none' })
return false
}
if (formData.maxParticipants !== undefined && (formData.maxParticipants < 2 || formData.maxParticipants > 100)) {
uni.showToast({ title: '参与人数范围为2-100人', icon: 'none' })
return false
}
return true
}
// 提交表单
async function handleSubmit() {
if (!validateForm()) {
return
}
if (submitting.value) return
submitting.value = true
try {
const result = await workcaseChatAPI.createVideoMeeting(formData)
if (result.success && result.data) {
uni.showToast({ title: '会议创建成功', icon: 'success' })
// 延迟返回,让用户看到成功提示
setTimeout(() => {
uni.navigateBack()
}, 1500)
} else {
uni.showToast({ title: result.message || '创建会议失败', icon: 'none' })
}
} catch (error) {
console.error('创建会议失败:', error)
uni.showToast({ title: '创建会议失败,请重试', icon: 'none' })
} finally {
submitting.value = false
}
}
// 取消
function handleCancel() {
uni.navigateBack()
}
</script>
<style lang="scss" scoped>
@import "./MeetingCreate.scss";
</style>