HomeLease/pages/image-upload/image-upload.vue

340 lines
8.0 KiB
Vue
Raw Normal View History

2025-08-21 13:37:29 +08:00
<template>
<view class="image-upload-page">
<view class="content">
<!-- 上传区域 -->
<view class="upload-area" @click="chooseImage">
<view v-if="!imageUrl" class="upload-placeholder">
<u-icon color="#ccc" name="camera" size="60"></u-icon>
<text class="upload-text">点击选择图片</text>
<text class="upload-hint">支持 JPGPNG 格式</text>
</view>
<image v-else :src="imageUrl" class="preview-image" mode="aspectFit"></image>
</view>
<!-- 上传按钮 -->
<button
:disabled="!selectedImagePath || uploading"
:loading="uploading"
class="upload-btn"
@click="uploadImage"
>
{{ uploading ? '上传中...' : '上传图片' }}
</button>
<!-- 结果展示 -->
<view v-if="uploadResult" class="result-section">
<view class="result-item">
<text class="result-label">上传状态:</text>
<text class="result-value success">成功</text>
</view>
<view class="result-item">
<text class="result-label">图片URL:</text>
<text class="result-url" @click="copyUrl">{{ uploadResult }}</text>
</view>
<button class="copy-btn" @click="copyUrl">复制URL</button>
</view>
<!-- 错误信息 -->
<view v-if="errorMessage" class="error-section">
<text class="error-text">{{ errorMessage }}</text>
</view>
</view>
</view>
</template>
<script>
import { getQiniuUploadToken, uploadToQiniu } from '@/api/upload.js'
export default {
data() {
return {
selectedImagePath: '', // 选择的图片路径
imageUrl: '', // 预览图片URL
uploadResult: '', // 上传成功后的完整URL
uploading: false, // 上传状态
errorMessage: '', // 错误信息
qiniuToken: '', // 七牛云上传token
}
},
onLoad() {
this.getQiniuToken()
},
methods: {
// 选择图片
chooseImage() {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: res => {
this.selectedImagePath = res.tempFilePaths[0]
this.imageUrl = res.tempFilePaths[0]
this.uploadResult = ''
this.errorMessage = ''
},
fail: err => {
console.error('选择图片失败:', err)
uni.showToast({
title: '选择图片失败',
icon: 'none',
})
},
})
},
// 上传图片
async uploadImage() {
if (!this.selectedImagePath) {
uni.showToast({
title: '请先选择图片',
icon: 'none',
})
return
}
this.uploading = true
this.errorMessage = ''
try {
// 确保有token
if (!this.qiniuToken) {
await this.getQiniuToken()
}
// 生成唯一文件名
const key = `uploads/${Date.now()}_${Math.random().toString(36).slice(2)}.jpg`
// 上传到七牛云
const result = await uploadToQiniu(this.selectedImagePath, this.qiniuToken, key)
// 构建完整的图片URL
this.uploadResult = `https://api.ccttiot.com/${result.key}`
uni.showToast({
title: '上传成功',
icon: 'success',
})
// 返回上一页并传递图片URL
const pages = getCurrentPages()
const prevPage = pages[pages.length - 2]
if (prevPage) {
// 如果上一页存在,可以通过事件总线或其他方式传递数据
// 这里我们通过URL参数的方式返回
uni.navigateBack({
success: () => {
// 延迟执行,确保页面已经返回
setTimeout(() => {
uni.$emit('image-upload-success', this.uploadResult)
}, 100)
},
})
} else {
// 如果没有上一页直接返回URL参数
uni.navigateBack({
delta: 1,
success: () => {
// 通过URL参数传递结果
const currentPage = getCurrentPages()[getCurrentPages().length - 1]
if (currentPage && currentPage.onLoad) {
currentPage.onLoad({
imageUrl: encodeURIComponent(this.uploadResult),
})
}
},
})
}
} catch (error) {
console.error('上传失败:', error)
this.errorMessage = error.message || '上传失败'
uni.showToast({
title: '上传失败',
icon: 'none',
})
} finally {
this.uploading = false
}
},
// 获取七牛云token
async getQiniuToken() {
try {
const res = await getQiniuUploadToken()
console.log('Token响应:', res)
if (res.code === 200) {
// 尝试不同的可能字段名
const token = res.data?.token || res.data?.uploadToken || res.token || res.data
if (token) {
this.qiniuToken = token
console.log('Token获取成功:', token.substring(0, 20) + '...')
} else {
throw new Error('Token字段不存在')
}
} else {
throw new Error(res.msg || '获取Token失败')
}
} catch (error) {
console.error('获取Token失败:', error)
this.errorMessage = `获取上传凭证失败: ${error.message}`
uni.showToast({
title: '获取上传凭证失败',
icon: 'none',
})
}
},
// 复制URL
copyUrl() {
if (this.uploadResult) {
uni.setClipboardData({
data: this.uploadResult,
success: () => {
uni.showToast({
title: 'URL已复制',
icon: 'success',
})
},
})
}
},
},
}
</script>
<style lang="scss" scoped>
.image-upload-page {
min-height: 100vh;
background: #f5f5f5;
.content {
padding: 30rpx;
}
.upload-area {
width: 100%;
height: 400rpx;
background: #fff;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 30rpx;
border: 2rpx dashed #ddd;
.upload-placeholder {
text-align: center;
.upload-text {
display: block;
font-size: 32rpx;
color: #333;
margin-top: 20rpx;
margin-bottom: 10rpx;
}
.upload-hint {
display: block;
font-size: 24rpx;
color: #999;
}
}
.preview-image {
width: 100%;
height: 100%;
border-radius: 16rpx;
}
}
.upload-btn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
background: #007aff;
color: #fff;
border-radius: 12rpx;
font-size: 32rpx;
border: none;
margin-bottom: 30rpx;
&:active {
background: #0056cc;
}
&:disabled {
background: #ccc;
color: #999;
}
}
.result-section {
background: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 30rpx;
.result-item {
display: flex;
align-items: center;
margin-bottom: 20rpx;
.result-label {
font-size: 28rpx;
color: #333;
font-weight: bold;
margin-right: 20rpx;
min-width: 120rpx;
}
.result-value {
font-size: 28rpx;
&.success {
color: #52c41a;
}
}
.result-url {
flex: 1;
font-size: 24rpx;
color: #007aff;
word-break: break-all;
line-height: 1.4;
}
}
.copy-btn {
width: 100%;
height: 70rpx;
line-height: 70rpx;
background: #f0f0f0;
color: #333;
border-radius: 8rpx;
font-size: 28rpx;
border: none;
&:active {
background: #e0e0e0;
}
}
}
.error-section {
background: #fff2f0;
border: 1rpx solid #ffccc7;
border-radius: 12rpx;
padding: 20rpx;
.error-text {
font-size: 26rpx;
color: #ff4d4f;
line-height: 1.4;
}
}
}
</style>