HomeLease/pages/image-upload/image-upload.vue
2025-08-21 13:37:29 +08:00

340 lines
8.0 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="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">支持 JPG、PNG 格式</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>