Files
2025-10-22 08:19:00 +08:00

440 lines
11 KiB
Vue
Raw Permalink 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-container">
<!-- 顶部导航栏 -->
<view class="top-navbar">
<text class="cancel" @click="navigateBack">取消</text>
<text class="title">图片上传</text>
<text class="save" @click="submitUpload" :class="{ disabled: !canSubmit }">提交</text>
</view>
<!-- 内容区域 -->
<scroll-view class="content" scroll-y>
<!-- 部门信息 -->
<view class="dept-info">
<text class="label">所属部门</text>
<text class="value">{{ currentUser.department }}</text>
</view>
<!-- 图片选择区域 -->
<view class="section">
<text class="section-title">选择图片</text>
<view class="image-grid">
<view v-for="(image, index) in selectedImages" :key="index" class="image-item">
<image :src="image" mode="aspectFill"></image>
<view class="delete-btn" @click="removeImage(index)">
<u-icon name="close" size="28" color="#fff"></u-icon>
</view>
</view>
<view v-if="selectedImages.length < maxImages" class="add-image" @click="chooseImage">
<u-icon name="plus" size="60" color="#c0c4cc"></u-icon>
<text>添加图片</text>
</view>
</view>
<text class="hint">{{ selectedImages.length }}/{{ maxImages }} </text>
</view>
<!-- 表单信息 -->
<view class="section">
<text class="section-title">图片信息</text>
<!-- 标题 -->
<view class="form-item">
<text class="form-label">标题</text>
<u-input
v-model="formData.title"
placeholder="请输入图片标题"
border="bottom"
maxlength="50"
></u-input>
</view>
<!-- 标签 -->
<view class="form-item">
<text class="form-label">标签</text>
<view class="tags-container">
<view
v-for="tag in availableTags"
:key="tag.value"
class="tag"
:class="{ active: formData.tags.includes(tag.value) }"
@click="toggleTag(tag.value)"
>
{{ tag.label }}
</view>
</view>
</view>
<!-- 描述 -->
<view class="form-item">
<text class="form-label">描述</text>
<u-input
v-model="formData.description"
placeholder="请输入图片描述(选填)"
border="bottom"
type="textarea"
:rows="3"
maxlength="200"
></u-input>
</view>
<!-- 关联任务 -->
<view class="form-item">
<text class="form-label">关联任务</text>
<u-picker
v-model="showTaskPicker"
:columns="taskOptions"
@confirm="onTaskConfirm"
@cancel="showTaskPicker = false"
title="选择任务"
mode="selector"
@change="onTaskChange"
></u-picker>
<view class="task-select" @click="showTaskPicker = true">
<text v-if="formData.taskId" class="selected-task">{{ selectedTaskName }}</text>
<text v-else class="placeholder">请选择关联任务选填</text>
<u-icon name="arrow-right" size="20" color="#c0c4cc"></u-icon>
</view>
</view>
</view>
</scroll-view>
<!-- 上传进度弹窗 -->
<u-modal v-model="showUploadModal" show-cancel-button="false" :close-on-click-modal="false">
<view class="upload-modal">
<u-loading-icon size="60" color="#1989fa"></u-loading-icon>
<text class="upload-status">{{ uploadStatus }}</text>
<u-progress :percent="uploadProgress" :show-percent="true" height="10"></u-progress>
</view>
</u-modal>
</view>
</template>
<script>
export default {
data() {
return {
// 用户信息
currentUser: {
name: '张三',
department: '研发部'
},
// 表单数据
formData: {
title: '',
tags: [],
description: '',
taskId: ''
},
// 图片相关
selectedImages: [],
maxImages: 9,
// 任务选择器
showTaskPicker: false,
taskOptions: ['项目进度拍摄', '设备巡检', '活动照片收集', '其他任务'],
taskMap: {
'项目进度拍摄': '1',
'设备巡检': '2',
'活动照片收集': '3',
'其他任务': '4'
},
// 标签选项
availableTags: [
{ label: '工作进度', value: 'progress' },
{ label: '设备状态', value: 'equipment' },
{ label: '会议记录', value: 'meeting' },
{ label: '活动现场', value: 'activity' },
{ label: '产品展示', value: 'product' },
{ label: '其他', value: 'other' }
],
// 上传相关
showUploadModal: false,
uploadProgress: 0,
uploadStatus: '准备上传...'
}
},
computed: {
canSubmit() {
return this.selectedImages.length > 0 && this.formData.title.trim() !== ''
},
selectedTaskName() {
for (const [name, id] of Object.entries(this.taskMap)) {
if (id === this.formData.taskId) {
return name
}
}
return ''
}
},
methods: {
navigateBack() {
uni.navigateBack()
},
chooseImage() {
const remainingCount = this.maxImages - this.selectedImages.length
uni.chooseImage({
count: remainingCount,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
const tempFilePaths = res.tempFilePaths
this.selectedImages = [...this.selectedImages, ...tempFilePaths]
}
})
},
removeImage(index) {
this.selectedImages.splice(index, 1)
},
toggleTag(tagValue) {
const index = this.formData.tags.indexOf(tagValue)
if (index > -1) {
this.formData.tags.splice(index, 1)
} else {
this.formData.tags.push(tagValue)
}
},
onTaskConfirm(e) {
const name = this.taskOptions[e.index]
this.formData.taskId = this.taskMap[name]
},
onTaskChange(e) {
// 实时更新选中的任务名称
},
submitUpload() {
if (!this.canSubmit) return
// 显示上传进度弹窗
this.showUploadModal = true
this.uploadProgress = 0
this.uploadStatus = '正在上传...'
// 模拟上传过程
let progress = 0
const timer = setInterval(() => {
progress += 10
this.uploadProgress = progress
if (progress >= 100) {
clearInterval(timer)
this.uploadStatus = '上传成功!'
// 延迟关闭弹窗并返回
setTimeout(() => {
this.showUploadModal = false
this.$u.toast('上传成功')
// 返回上一页
setTimeout(() => {
uni.navigateBack()
}, 1000)
}, 1500)
}
}, 300)
}
}
}
</script>
<style lang="scss" scoped>
.image-upload-container {
padding-top: 44px; // 适配顶部安全区域
height: 100vh;
box-sizing: border-box;
background-color: #f5f7fa;
.top-navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 44px;
background-color: #ffffff;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 30rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
z-index: 999;
.cancel,
.save {
font-size: 32rpx;
color: #1989fa;
}
.save.disabled {
color: #c0c4cc;
}
.title {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
}
.content {
height: calc(100% - 44px);
padding: 20rpx;
}
.dept-info {
background-color: #ffffff;
padding: 20rpx 30rpx;
border-radius: 16rpx;
margin-bottom: 20rpx;
font-size: 28rpx;
.label {
color: #606266;
}
.value {
color: #333;
font-weight: bold;
}
}
.section {
background-color: #ffffff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
display: block;
}
// 图片网格样式
.image-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20rpx;
margin-bottom: 15rpx;
.image-item {
position: relative;
image {
width: 100%;
aspect-ratio: 1;
border-radius: 8rpx;
}
.delete-btn {
position: absolute;
top: -15rpx;
right: -15rpx;
width: 40rpx;
height: 40rpx;
background-color: rgba(0, 0, 0, 0.6);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
}
.add-image {
width: 100%;
aspect-ratio: 1;
border: 2rpx dashed #c0c4cc;
border-radius: 8rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text {
font-size: 24rpx;
color: #c0c4cc;
margin-top: 10rpx;
}
}
}
.hint {
font-size: 24rpx;
color: #909399;
text-align: right;
}
// 表单样式
.form-item {
margin-bottom: 30rpx;
&:last-child {
margin-bottom: 0;
}
.form-label {
font-size: 28rpx;
color: #606266;
margin-bottom: 10rpx;
display: block;
}
// 标签样式
.tags-container {
display: flex;
flex-wrap: wrap;
gap: 15rpx;
.tag {
padding: 10rpx 20rpx;
border: 2rpx solid #dcdfe6;
border-radius: 20rpx;
font-size: 24rpx;
color: #606266;
&.active {
border-color: #1989fa;
background-color: #ecf5ff;
color: #1989fa;
}
}
}
// 任务选择样式
.task-select {
height: 88rpx;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 2rpx solid #ebeef5;
.selected-task {
font-size: 28rpx;
color: #333;
}
.placeholder {
font-size: 28rpx;
color: #c0c4cc;
}
}
}
}
// 上传弹窗样式
.upload-modal {
padding: 40rpx 20rpx;
.upload-status {
display: block;
text-align: center;
font-size: 28rpx;
color: #606266;
margin: 20rpx 0;
}
:deep(.u-progress) {
margin-top: 20rpx;
}
}
}
</style>