2025-08-08 19:37:56 +08:00

373 lines
8.7 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="container">
<view class="content">
<view class="content_wapper">
<!-- 添加标题 -->
<view class="input-section">
<u-input placeholder="添加标题" v-model="title" border></u-input>
</view>
<!-- 输入求助内容 -->
<view class="textarea-section">
<u--textarea placeholder="请输入求助内容..." v-model="content" border height="300"></u--textarea>
</view>
<!-- 图片上传 - 修改后的上传组件 -->
<view class="upload-section">
<view class="label">
<u-icon name="photo" color="#3B8CFF" size="38"></u-icon>
上传照片
</view>
<view class="upload-area">
<view class="upload-list">
<view class="upload-item" v-for="(item, index) in fileList" :key="index">
<image :src="item.url" mode="aspectFill" @click="previewImage(index)"></image>
<view class="delete-btn" @click="handleDelete(index)">
<u-icon name="close" color="#fff" size="24"></u-icon>
</view>
</view>
<view class="upload-btn" @click="showUploadAction" v-if="fileList.length < 9">
<u-icon name="plus" size="40" color="#c0c4cc"></u-icon>
</view>
</view>
</view>
<text class="note">照片支持分批上传但最大数量为9</text>
</view>
<!-- 发布按钮 -->
<view class="publish-section">
<u-button type="primary" text="立即发布" @click="publish"></u-button>
</view>
</view>
</view>
<Footer></Footer>
</view>
</template>
<script>
import Footer from '@/components/footer_common.vue';
import {
get,
post
} from '@/utils/request';
import {
IMAGE_BASE_URL,
BASE_URL
} from '@/utils/config';
export default {
components: {
Footer
},
data() {
return {
title: '',
content: '',
fileList: [],
uploadedImageUrls: []
};
},
methods: {
handleBack() {
uni.navigateBack({
delta: 1 // 返回上一级页面
});
},
// 显示上传选项
showUploadAction() {
uni.showActionSheet({
itemList: ['拍照', '从相册选择'],
success: (res) => {
if (res.tapIndex === 0) {
this.chooseMedia('camera');
} else {
this.chooseMedia('album');
}
}
});
},
// 选择媒体文件
async chooseMedia(sourceType) {
try {
// 1. 选择图片
const res = await new Promise((resolve, reject) => {
uni.chooseImage({
count: 9 - this.fileList.length,
sourceType: [sourceType === 'camera' ? 'camera' : 'album'],
success: resolve,
fail: reject
});
});
// 2. 添加到预览列表
const newFiles = res.tempFilePaths.map(url => ({
url,
status: 'uploading'
}));
this.fileList = [...this.fileList, ...newFiles];
// 3. 逐个上传文件
for (const file of newFiles) {
await this.uploadFile(file);
}
} catch (err) {
console.error('选择图片失败:', err);
uni.showToast({ title: '选择图片失败', icon: 'none' });
}
},
// 单个文件上传
async uploadFile(file) {
try {
const res = await new Promise((resolve, reject) => {
uni.uploadFile({
url: `${IMAGE_BASE_URL}/api/v1/upload`,
filePath: file.url,
name: 'file',
header: {
'Authorization': `Bearer ${uni.getStorageSync('token')}`,
'Content-Type': 'multipart/form-data'
},
success: (uploadRes) => {
try {
const data = JSON.parse(uploadRes.data);
if (data.success) {
resolve(data.data); // 使用服务器返回的完整URL
} else {
reject(data.message || '上传失败');
}
} catch (e) {
reject('解析响应失败');
}
},
fail: (err) => reject(err)
});
});
// 更新文件状态
const index = this.fileList.findIndex(f => f.url === file.url);
if (index !== -1) {
this.$set(this.fileList, index, {
...file,
status: 'success',
serverUrl: res // 存储服务器返回的URL
});
// 添加到提交数组
this.uploadedImageUrls.push(res);
}
} catch (err) {
console.error('上传失败:', err);
const index = this.fileList.findIndex(f => f.url === file.url);
if (index !== -1) {
this.$set(this.fileList, index, {
...file,
status: 'failed',
error: err.message || err
});
}
uni.showToast({
title: `上传失败: ${err.message || err}`,
icon: 'none'
});
}
},
// 预览图片
previewImage(index) {
const images = this.fileList.map(item => item.url);
uni.previewImage({
current: index,
urls: images
});
},
// 删除文件
handleDelete(index) {
const file = this.fileList[index];
if (file.serverUrl) {
const imageIndex = this.uploadedImageUrls.indexOf(file.serverUrl);
if (imageIndex !== -1) this.uploadedImageUrls.splice(imageIndex, 1);
}
this.fileList.splice(index, 1);
},
async publish() {
if (!this.title.trim()) {
uni.showToast({
title: '请输入标题',
icon: 'none'
});
return;
}
if (!this.content.trim()) {
uni.showToast({
title: '请输入内容',
icon: 'none'
});
return;
}
uni.showLoading({
title: '发布中...'
});
try {
// 构造请求数据图片URL以数组形式传递
const postData = {
title: this.title,
content: this.content,
images: this.uploadedImageUrls.length > 0 ?
this.uploadedImageUrls :
[] // 如果没有图片则传空数组
};
// 调用API
const res = await post('/api/v1/app_auth/reciprocities', postData);
if (!res || !res.success) {
throw new Error('发布失败');
}
uni.showToast({
title: '发布成功',
icon: 'success'
});
// 发布成功后返回上一页
setTimeout(() => {
uni.redirectTo({
url:'/pages/mySeekHelp/index'
});
}, 1500);
} catch (error) {
console.error('发布失败:', error);
uni.showToast({
title: '发布失败',
icon: 'none'
});
} finally {
uni.hideLoading();
}
}
}
};
</script>
<style lang="scss" scoped>
.container {
width: 100%;
height: 100vh;
/* 占满整个视口高度 */
opacity: 1;
background: linear-gradient(0deg, rgba(240, 240, 240, 1) 0%, rgba(255, 250, 250, 0) 100%),
linear-gradient(0deg, rgba(255, 241, 235, 1) 0%, rgba(192, 219, 250, 1) 100%);
position: relative;
.content {
width: 100%;
position: absolute;
margin-top: 40rpx;
border-top-left-radius: 30rpx;
border-top-right-radius: 30rpx;
background-color: rgba(255, 255, 255, 0.65);
padding-bottom: 60rpx;
.content_wapper {
width: 90%;
margin: 0 auto;
}
}
.input-section {
border-bottom: 2rpx solid #C3DCFA;
height: 90rpx;
line-height: 90rpx;
}
.input-section,
.textarea-section,
.upload-section {
margin-bottom: 30rpx;
}
.upload-section {
.label {
font-size: 32rpx;
color: #333;
font-weight: 500;
margin-bottom: 24rpx;
display: flex;
align-items: center;
.u-icon {
margin-right: 12rpx;
}
}
.upload-area {
margin-top: 16rpx;
.upload-list {
display: flex;
flex-wrap: wrap;
margin: -5rpx;
.upload-item, .upload-btn {
width: 160rpx;
height: 160rpx;
margin: 5rpx;
position: relative;
background: #f8f8f8;
border-radius: 8rpx;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
.delete-btn {
position: absolute;
right: 0;
top: 0;
width: 40rpx;
height: 40rpx;
background: rgba(0, 0, 0, 0.5);
border-radius: 0 0 0 8rpx;
display: flex;
justify-content: center;
align-items: center;
}
}
.upload-btn {
border: 1rpx dashed #c0c4cc;
}
}
}
.note {
font-size: 24rpx;
color: #999;
margin-top: 24rpx;
display: block;
}
}
.publish-section {
text-align: center;
margin-top: 100rpx;
}
}
</style>