2025-07-16 15:07:16 +08:00

390 lines
9.4 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="conent">
<view class="form-item">
<view class="label">
<u-icon name="order" color="#3B8CFF" size="38"></u-icon>
工单内容
</view>
<textarea v-model="workOrderContent" placeholder="请输入..." style="width: 100%;" />
<view class="voice-icon">
<u-icon name="mic" color="#409EFF" size="36"></u-icon>
</view>
</view>
<!-- 上传照片/视频 -->
<view class="form-item">
<view class="label">
<u-icon name="photo" color="#3B8CFF" size="38"></u-icon>
上传照片/视频
</view>
<view class="upload-area">
<u-upload :fileList="fileList" @afterRead="handleAfterRead" @delete="handleDelete" :maxCount="8"
width="200" height="200" accept="image/*,video/*" :previewFullImage="true">
</u-upload>
</view>
<text class="note">照片可识别工单内容支持分批上传但最大数量为8</text>
</view>
<!-- 工单分类 -->
<view class="form-item" style="height: 60rpx;line-height: 50rpx;">
<view class="label" @click="showSelect = true">
工单类型
<view @click="showPicker = true" class="select-box">
{{ workOrderCategory || '请选择' }}
<u-icon name="arrow-down" color="#999" size="30"></u-icon>
</view>
</view>
<u-picker :show="showSelect" :columns="categoryList" keyName="label" @confirm="handleConfirm"
@cancel="handleCancel">
</u-picker>
</view>
<!-- 工单地点 -->
<view class="form-item" style="margin-bottom: 30rpx;height: 200rpx;">
<view class="label">
<u-icon name="map" color="#3B8CFF" size="38"></u-icon>
工作地点
</view>
<textarea v-model="workOrderLocation" placeholder="请输入..." style="width: 100%;" />
</view>
<!-- 提交按钮 -->
<view class="submit-button">
<u-button type="primary" @click="handleSubmit">提交</u-button>
</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 {
workOrderContent: '',
fileList: [],
workOrderCategory: '',
workOrderCategoryID: '',
showSelect: false,
categoryList: [],
workOrderLocation: '',
expectedTime: '',
uploadedImages: [], // 专门存储图片URL
uploadedVideos: [], // 专门存储视频URL
videoFormats: ['mp4', 'mov', 'avi', 'wmv', 'mpeg', '3gp', 'flv', 'mkv']
};
},
mounted() {
this.getOrderList();
},
methods: {
handleBack() {
uni.navigateBack({
delta: 1
});
},
// 文件上传相关方法
handleAfterRead(event) {
const {
file
} = event;
let files = [].concat(file);
// 检查文件数量和类型
if (this.fileList.length + files.length > 8) {
uni.showToast({
title: '最多只能上传8个文件',
icon: 'none'
});
return;
}
files.forEach(item => {
// 检查文件类型
const extension = this.getFileExtension(item.url);
const isVideo = this.videoFormats.includes(extension.toLowerCase());
// 添加到文件列表
this.fileList.push({
...item,
status: 'uploading',
message: '上传中...',
isVideo: isVideo
});
// 开始上传
this.uploadFile(item, isVideo);
});
},
// 获取文件扩展名
getFileExtension(filename) {
return filename.split('.').pop().split('?')[0];
},
handleDelete(event) {
const {
index
} = event;
const file = this.fileList[index];
// 从对应数组中删除
if (file.isVideo) {
const videoIndex = this.uploadedVideos.indexOf(file.url);
if (videoIndex !== -1) this.uploadedVideos.splice(videoIndex, 1);
} else {
const imageIndex = this.uploadedImages.indexOf(file.url);
if (imageIndex !== -1) this.uploadedImages.splice(imageIndex, 1);
}
this.fileList.splice(index, 1);
},
async uploadFile(file, isVideo) {
try {
const fullUrl = await this.uploadAvatar(file.url);
const relativePath = fullUrl.replace(BASE_URL, '');
// 更新文件状态
const fileIndex = this.fileList.findIndex(item => item.url === file.url);
if (fileIndex !== -1) {
this.fileList[fileIndex] = {
...this.fileList[fileIndex],
status: 'success',
message: '上传成功',
url: fullUrl, // 预览用完整URL
relativeUrl: relativePath, // 存储相对路径
isVideo: isVideo
};
// 存储相对路径到对应数组
if (isVideo) {
this.uploadedVideos.push(relativePath);
} else {
this.uploadedImages.push(relativePath);
}
}
} catch (error) {
const fileIndex = this.fileList.findIndex(item => item.url === file.url);
if (fileIndex !== -1) {
this.fileList[fileIndex] = {
...this.fileList[fileIndex],
status: 'failed',
message: '上传失败'
};
}
uni.showToast({
title: `${isVideo ? '视频' : '图片'}上传失败: ${error.message}`,
icon: 'none'
});
}
},
uploadAvatar(filePath) {
return new Promise((resolve, reject) => {
uni.uploadFile({
url: `${BASE_URL}/api/v1/upload`,
filePath: filePath,
name: 'file',
header: {
'Authorization': `Bearer ${uni.getStorageSync('token')}`
},
success: (uploadRes) => {
try {
const res = JSON.parse(uploadRes.data);
if (res && res.success) {
resolve(`${IMAGE_BASE_URL}${res.data}`);
} else {
reject(new Error(res.message || '上传失败'));
}
} catch (e) {
reject(new Error('解析响应失败'));
}
},
fail: (err) => {
reject(new Error('上传失败: ' + JSON.stringify(err)));
}
});
});
},
async handleSubmit() {
if (!this.workOrderContent) {
uni.showToast({
title: '请填写工单内容',
icon: 'none'
});
return;
}
if (!this.workOrderCategory) {
uni.showToast({
title: '请选择工单类型',
icon: 'none'
});
return;
}
if (!this.workOrderLocation) {
uni.showToast({
title: '请填写工作地点',
icon: 'none'
});
return;
}
const submitData = {
title: this.workOrderContent,
orderTypeId: this.workOrderCategoryID,
address: this.workOrderLocation,
images: this.uploadedImages, // 只包含图片
videos: this.uploadedVideos, // 只包含视频·
};
console.log('提交数据:', submitData);
// 调用API保存信息
const res = await post('/api/v1/app_auth/work-order', submitData);
uni.hideLoading();
if (res && res.success) {
uni.showToast({
title: '提交成功',
icon: 'success',
duration: 2000
});
this.workOrderContent = null;
this.workOrderCategoryID = null;
this.workOrderCategory = null;
this.workOrderLocation = null;
this.fileList = [];
this.uploadedImages = [];
this.uploadedVideos = [];
setTimeout(()=>{
uni.navigateTo({
url: `/pages/myTickets/index`,
});
},1000)
} else {
uni.showToast({
title: res?.message || '提交失败',
icon: 'none'
});
}
},
// 用户点击"确定"时触发
handleConfirm(e) {
this.workOrderCategory = e.value[0].label;
this.workOrderCategoryID = e.value[0].id;
this.showSelect = false;
},
// 用户点击"取消"时触发
handleCancel() {
this.showSelect = false;
},
//获取工单类型
async getOrderList() {
try {
const res = await get('/api/v1/apps/work-order-type');
if (res?.success) {
this.categoryList = [
[...res.data]
]
}
} catch (err) {
console.error('获取工单类型失败:', err);
uni.showToast({
title: '获取工单类型失败',
icon: 'none'
});
}
},
}
};
</script>
<style lang="scss" scoped>
.container {
width: 100%;
height: 130vh;
opacity: 1;
background: rgba(210, 227, 255, 1);
position: relative;
.conent {
width: 100%;
position: absolute;
margin-top: 20rpx;
.form-item {
margin-bottom: 20px;
height: 400rpx;
width: 95%;
margin: 0 auto;
margin-bottom: 20rpx;
background: #fff;
padding: 20rpx;
display: flex;
flex-direction: column;
position: relative;
.label {
font-size: 32rpx;
color: #333;
margin-bottom: 30px;
display: flex;
white-space: nowrap;
}
.select-box {
display: flex;
align-items: center;
margin-left: 30rpx;
color: #999;
}
.voice-icon {
position: absolute;
right: 30rpx;
bottom: 20rpx;
}
.upload-area {
display: flex;
justify-content: center;
align-items: center;
height: 100px;
}
.note {
font-size: 20rpx;
color: #999;
margin-top: 60rpx;
}
.submit-button {
text-align: center;
margin-top: 20px;
}
}
}
}
</style>