consumer-app/pages/activities/postMessage.vue

618 lines
16 KiB
Vue
Raw Normal View History

2025-12-19 12:27:55 +00:00
<template>
<view class="post-message-page">
<!-- 头部区域 -->
<NavHeader title="发布消息" />
<!-- 表单内容区 -->
<scroll-view class="form-content" scroll-y="true">
<!-- 基本信息 -->
<view class="form-section">
<view class="section-title">基本信息</view>
<!-- 标题 -->
<view class="form-item">
<view class="input-wrapper">
<text class="input-label">标题</text>
<input
class="input-field"
type="text"
v-model="formData.title"
placeholder="请输入消息标题"
maxlength="100"
/>
</view>
</view>
<!-- 摘要 -->
<view class="form-item">
<view class="textarea-wrapper">
<text class="textarea-label">摘要 <text class="optional">选填</text></text>
<textarea
class="textarea-field"
v-model="formData.summary"
placeholder="请输入消息摘要..."
maxlength="200"
:auto-height="true"
></textarea>
<view class="char-count">
<text>{{ formData.summary.length }}/200</text>
</view>
</view>
</view>
<!-- 内容 -->
<view class="form-item">
<view class="textarea-wrapper">
<text class="textarea-label">内容 <text class="optional">选填</text></text>
<textarea
class="textarea-field"
v-model="formData.content"
placeholder="请输入消息详细内容..."
maxlength="2000"
:auto-height="true"
></textarea>
<view class="char-count">
<text>{{ formData.content.length }}/2000</text>
</view>
</view>
</view>
</view>
<!-- 封面图片 -->
<view class="form-section">
<view class="section-title">封面图片</view>
<view class="form-item">
<view class="upload-wrapper">
<text class="upload-label">封面图片 <text class="optional">选填</text></text>
<view class="upload-box" @click="chooseCoverImage">
<image
v-if="formData.coverUrl"
class="uploaded-image"
:src="formData.coverUrl"
mode="aspectFill"
></image>
<view v-else class="upload-placeholder">
<text class="upload-icon">+</text>
<text class="upload-text">点击上传封面</text>
</view>
</view>
</view>
</view>
</view>
<!-- 其他设置 -->
<view class="form-section">
<view class="section-title">其他设置</view>
<!-- 跳转链接 -->
<view class="form-item">
<view class="input-wrapper">
<text class="input-label">跳转链接 <text class="optional">选填</text></text>
<input
class="input-field"
type="text"
v-model="formData.jumpUrl"
placeholder="请输入跳转链接https://www.example.com"
/>
</view>
</view>
<!-- 消息类型 -->
<view class="form-item">
<view class="input-wrapper">
<text class="input-label">消息类型 <text class="optional">选填</text></text>
<picker
mode="selector"
:range="messageTypeOptions"
range-key="label"
:value="messageTypeIndex"
@change="handleMessageTypeChange"
>
<view class="picker-view">
<text :class="['picker-text', messageTypeIndex === -1 ? 'placeholder' : '']">
{{ messageTypeIndex !== -1 ? messageTypeOptions[messageTypeIndex].label : '请选择消息类型' }}
</text>
<text class="picker-arrow"></text>
</view>
</picker>
</view>
</view>
<!-- 等级 -->
<view class="form-item">
<view class="input-wrapper">
<text class="input-label">等级 <text class="optional">选填</text></text>
<picker
mode="selector"
:range="gradeOptions"
range-key="label"
:value="gradeIndex"
@change="handleGradeChange"
>
<view class="picker-view">
<text :class="['picker-text', gradeIndex === -1 ? 'placeholder' : '']">
{{ gradeIndex !== -1 ? gradeOptions[gradeIndex].label : '请选择等级' }}
</text>
<text class="picker-arrow"></text>
</view>
</picker>
</view>
</view>
<!-- 开始时间 -->
<view class="form-item">
<view class="input-wrapper">
<text class="input-label">开始时间 <text class="optional">选填</text></text>
<picker
mode="date"
:value="startTimeDisplay"
@change="handleStartTimeChange"
>
<view class="picker-view">
<text :class="['picker-text', !startTimeDisplay ? 'placeholder' : '']">
{{ startTimeDisplay || '请选择开始时间' }}
</text>
<text class="picker-arrow"></text>
</view>
</picker>
</view>
</view>
<!-- 结束时间 -->
<view class="form-item">
<view class="input-wrapper">
<text class="input-label">结束时间 <text class="optional">选填</text></text>
<picker
mode="date"
:value="endTimeDisplay"
@change="handleEndTimeChange"
>
<view class="picker-view">
<text :class="['picker-text', !endTimeDisplay ? 'placeholder' : '']">
{{ endTimeDisplay || '请选择结束时间' }}
</text>
<text class="picker-arrow"></text>
</view>
</picker>
</view>
</view>
</view>
<!-- 提交按钮 -->
<view class="submit-section">
<button
class="submit-btn"
:class="{ disabled: loading }"
:disabled="loading"
@click="handleSubmit"
>
{{ loading ? '发布中...' : '发布' }}
</button>
</view>
</scroll-view>
</view>
</template>
<script>
import { createLaborUnionMessage } from '@/api/profile.js'
import NavHeader from "@/components/NavHeader/NavHeader.vue";
export default {
components: {
NavHeader
},
data() {
return {
loading: false,
messageTypeIndex: -1,
messageTypeOptions: [
{ label: '类型1', value: 1 },
{ label: '类型2', value: 2 },
{ label: '类型3', value: 3 }
],
gradeIndex: -1,
gradeOptions: [
{ label: '普通', value: 0 },
{ label: '重要', value: 1 }
],
formData: {
title: '',
summary: '',
content: '',
coverUrl: '',
jumpUrl: '',
messageType: null,
grade: null,
startTime: '',
endTime: ''
}
}
},
computed: {
// 开始时间显示(从 ISO 格式提取日期部分)
startTimeDisplay() {
if (!this.formData.startTime) return ''
return this.formData.startTime.split('T')[0]
},
// 结束时间显示(从 ISO 格式提取日期部分)
endTimeDisplay() {
if (!this.formData.endTime) return ''
return this.formData.endTime.split('T')[0]
}
},
onLoad() {
},
methods: {
// 选择封面图片
chooseCoverImage() {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
const tempFilePath = res.tempFilePaths[0]
// 先显示本地预览
this.formData.coverUrl = tempFilePath
// 上传图片到服务器
this.uploadImage(tempFilePath)
},
fail: (err) => {
console.error('选择图片失败:', err)
uni.showToast({
title: '选择图片失败',
icon: 'none'
})
}
})
},
// 上传图片
uploadImage(filePath) {
uni.showLoading({
title: '上传中...',
mask: true
})
// 获取token
const token = uni.getStorageSync('token')
const BASE_URL = 'https://siji.chenjuncn.top'
uni.uploadFile({
url: `${BASE_URL}/app-api/infra/file/upload`,
filePath: filePath,
name: 'file',
header: {
'Authorization': `Bearer ${token}`,
'tenant-id': '1'
},
success: (res) => {
uni.hideLoading()
try {
const data = JSON.parse(res.data)
if (data.code === 200 || data.code === 0) {
// 上传成功保存图片URL
const imageUrl = data.data?.url || data.data || data.url
if (imageUrl) {
this.formData.coverUrl = imageUrl
uni.showToast({
title: '上传成功',
icon: 'success',
duration: 1500
})
} else {
throw new Error('上传成功但未返回图片地址')
}
} else {
throw new Error(data.message || data.msg || '上传失败')
}
} catch (error) {
console.error('解析上传结果失败:', error)
uni.showToast({
title: '上传失败,请重试',
icon: 'none'
})
// 上传失败,清除预览
this.formData.coverUrl = ''
}
},
fail: (err) => {
uni.hideLoading()
console.error('上传图片失败:', err)
uni.showToast({
title: '上传失败,请检查网络',
icon: 'none'
})
// 上传失败,清除预览
this.formData.coverUrl = ''
}
})
},
// 消息类型选择
handleMessageTypeChange(e) {
this.messageTypeIndex = e.detail.value
this.formData.messageType = this.messageTypeOptions[e.detail.value].value
},
// 等级选择
handleGradeChange(e) {
this.gradeIndex = e.detail.value
this.formData.grade = this.gradeOptions[e.detail.value].value
},
// 开始时间选择
handleStartTimeChange(e) {
// 将日期转换为 ISO 格式 (date-time)
const date = e.detail.value
this.formData.startTime = date ? `${date}T00:00:00` : ''
},
// 结束时间选择
handleEndTimeChange(e) {
// 将日期转换为 ISO 格式 (date-time)
const date = e.detail.value
this.formData.endTime = date ? `${date}T23:59:59` : ''
},
// 提交表单
async handleSubmit() {
try {
this.loading = true
// 构建提交数据
const submitData = {
title: this.formData.title ? this.formData.title.trim() : '',
summary: this.formData.summary ? this.formData.summary.trim() : '',
content: this.formData.content ? this.formData.content.trim() : '',
coverUrl: this.formData.coverUrl || '',
jumpUrl: this.formData.jumpUrl ? this.formData.jumpUrl.trim() : '',
messageType: this.formData.messageType,
sourceType: 1, // 会员发布
grade: this.formData.grade,
startTime: this.formData.startTime || null,
endTime: this.formData.endTime || null
}
// 移除空值
Object.keys(submitData).forEach(key => {
if (submitData[key] === '' || submitData[key] === null || submitData[key] === undefined) {
delete submitData[key]
}
})
// 调用接口
const res = await createLaborUnionMessage(submitData)
uni.showToast({
title: '发布成功',
icon: 'success'
})
// 延迟返回上一页
setTimeout(() => {
uni.navigateBack()
}, 1500)
} catch (error) {
console.error('发布消息失败:', error)
uni.showToast({
title: error.message || '发布失败,请重试',
icon: 'none'
})
} finally {
this.loading = false
}
}
}
}
</script>
<style lang="scss" scoped>
.post-message-page {
min-height: 100vh;
background: #e2e8f1;
display: flex;
flex-direction: column;
}
.form-content {
flex: 1;
height: 0;
padding: 0 30rpx 40rpx;
box-sizing: border-box;
}
.form-section {
margin-top: 30rpx;
margin-bottom: 40rpx;
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
margin-bottom: 24rpx;
padding-left: 10rpx;
}
}
.form-item {
margin-bottom: 30rpx;
.input-wrapper {
position: relative;
background-color: #ffffff;
border-radius: 16rpx;
padding: 30rpx 24rpx;
display: flex;
align-items: center;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
.input-label {
width: 160rpx;
font-size: 28rpx;
color: #333333;
font-weight: 500;
flex-shrink: 0;
.optional {
color: #999999;
font-weight: 400;
font-size: 24rpx;
}
}
.input-field {
flex: 1;
font-size: 28rpx;
color: #1a1819;
}
.picker-view {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
.picker-text {
font-size: 28rpx;
color: #1a1819;
&.placeholder {
color: #999999;
}
}
.picker-arrow {
font-size: 40rpx;
color: #cccccc;
line-height: 1;
}
}
}
.textarea-wrapper {
background-color: #ffffff;
border-radius: 16rpx;
padding: 30rpx 24rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
.textarea-label {
display: block;
font-size: 28rpx;
color: #333333;
font-weight: 500;
margin-bottom: 20rpx;
.optional {
color: #999999;
font-weight: 400;
font-size: 24rpx;
}
}
.textarea-field {
width: 100%;
min-height: 200rpx;
font-size: 28rpx;
color: #1a1819;
line-height: 1.6;
box-sizing: border-box;
}
.char-count {
display: flex;
justify-content: flex-end;
margin-top: 16rpx;
font-size: 24rpx;
color: #999999;
}
}
.upload-wrapper {
background-color: #ffffff;
border-radius: 16rpx;
padding: 30rpx 24rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
.upload-label {
display: block;
font-size: 28rpx;
color: #333333;
font-weight: 500;
margin-bottom: 20rpx;
.optional {
color: #999999;
font-weight: 400;
font-size: 24rpx;
}
}
.upload-box {
width: 100%;
height: 400rpx;
border: 2rpx dashed #d0d0d0;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: #fafafa;
position: relative;
overflow: hidden;
.uploaded-image {
width: 100%;
height: 100%;
}
.upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 16rpx;
.upload-icon {
font-size: 60rpx;
color: #999999;
line-height: 1;
}
.upload-text {
font-size: 24rpx;
color: #999999;
}
}
}
}
}
.submit-section {
margin-top: 40rpx;
padding-bottom: 40rpx;
.submit-btn {
width: 100%;
height: 88rpx;
background: linear-gradient(135deg, #004294 0%, #0066cc 100%);
border-radius: 44rpx;
color: #ffffff;
font-size: 32rpx;
font-weight: 500;
border: none;
display: flex;
align-items: center;
justify-content: center;
&::after {
border: none;
}
&.disabled {
background: #cccccc;
color: #999999;
}
}
}
</style>