相关修改
This commit is contained in:
parent
6dea318ca8
commit
4022a1ebcd
@ -96,7 +96,7 @@
|
||||
<text class="card-desc">维修方便便捷</text>
|
||||
<view class="card-bg"></view>
|
||||
</view>
|
||||
<image class="card-icon" src="/static/imgs/index/weixiu.png"></image>
|
||||
<image class="card-icon" src="/static/imgs/index/weixiu.png" style="width: 80rpx;height: 80rpx;bottom: 32rpx;"></image>
|
||||
</view>
|
||||
|
||||
<!-- <view class="service-card large card-3" @click="goDetail('neighborList')" hover-class="card-hover">
|
||||
@ -522,13 +522,13 @@
|
||||
|
||||
&.card-2 {
|
||||
.card-bg {
|
||||
background: #ff7e7e;
|
||||
top: -30rpx;
|
||||
background: #5b9cf8;
|
||||
top: -50rpx;
|
||||
right: -30rpx;
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
filter: drop-shadow(0 4rpx 8rpx rgba(255, 126, 126, 0.3));
|
||||
filter: drop-shadow(0 4rpx 8rpx rgba(91, 156, 248, 0.3));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
<view class="date">{{ formatTime(order.createdAt,"YYYY-MM-DD") }}</view>
|
||||
</view>
|
||||
<view class="order-description">{{ order.title }}</view>
|
||||
<button @click="handleAction(order)" class="order-action" v-if="order.status == 1 || order.status == 2 || order.status == 99">撤回</button>
|
||||
<button @click.stop="handleAction(order, $event)" class="order-action" v-if="order.status == 1 || order.status == 2 || order.status == 99">撤回</button>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 空状态提示 -->
|
||||
@ -73,7 +73,7 @@
|
||||
<script>
|
||||
// import Header from '@/components/header_common.vue';
|
||||
import Footer from '@/components/footer_common.vue';
|
||||
import { get, post } from '@/utils/request';
|
||||
import { get, post,put } from '@/utils/request';
|
||||
import { IMAGE_BASE_URL,BASE_URL } from '@/utils/config';
|
||||
import { formatTime, formatRelativeTime } from '@/utils/timeFormat';
|
||||
export default {
|
||||
@ -116,7 +116,7 @@
|
||||
2: '进行中',
|
||||
3: '已完成',
|
||||
99:'驳回',
|
||||
98:'已删除'
|
||||
98:'已撤回'
|
||||
};
|
||||
return statusMap[status] || '未知状态';
|
||||
},
|
||||
@ -153,20 +153,39 @@
|
||||
uni.navigateTo({ url: '/pages/serviceTickets/index' });
|
||||
},
|
||||
// 工单操作处理
|
||||
handleAction(order) {
|
||||
if (order.actionText === '撤回') {
|
||||
handleAction(order, e) {
|
||||
// 阻止事件冒泡
|
||||
e.stopPropagation();
|
||||
|
||||
if (order.status == 1 || order.status == 2 || order.status == 99) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定要撤回这个工单吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 执行撤回逻辑
|
||||
this.withdrawOrder(order.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
async withdrawOrder(orderId) {
|
||||
try {
|
||||
const res = await put(`/api/v1/app_auth/work-order/${orderId}`, {status:98});
|
||||
if (res?.success) {
|
||||
uni.showToast({
|
||||
title: '工单已撤回',
|
||||
icon: 'success'
|
||||
});
|
||||
// 刷新列表
|
||||
this.getWorkOrderList();
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('撤回工单失败:', err);
|
||||
uni.showToast({
|
||||
title: '撤回失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@ -4,15 +4,34 @@
|
||||
<!-- 图片区域 - 编辑状态下可修改 -->
|
||||
<view class="image-area card">
|
||||
<view class="img-container">
|
||||
<!-- 非编辑状态显示服务器图片 -->
|
||||
<image
|
||||
class="work-order-img"
|
||||
:src="!isEditing ? `${IMAGE_BASE_URL}${detailObj.images[0] || ''}` : workOrderImg"
|
||||
:src="`${IMAGE_BASE_URL}${detailObj.images[0]}`"
|
||||
mode="widthFix"
|
||||
:lazy-load="true"
|
||||
lazy-load="true"
|
||||
v-if="!isEditing && detailObj.images && detailObj.images.length > 0"
|
||||
></image>
|
||||
|
||||
<!-- 编辑状态显示本地选择的图片 -->
|
||||
<image
|
||||
class="work-order-img"
|
||||
:src="workOrderImg"
|
||||
mode="widthFix"
|
||||
lazy-load="true"
|
||||
v-if="isEditing && workOrderImg"
|
||||
></image>
|
||||
|
||||
<!-- 没有图片时的占位 -->
|
||||
<view class="empty-placeholder" v-if="(!detailObj.images || detailObj.images.length === 0) && !isEditing">
|
||||
<u-icon name="photo" size="48" color="#c0c4cc"></u-icon>
|
||||
<text class="empty-text">暂无图片</text>
|
||||
</view>
|
||||
|
||||
<!-- 编辑状态的上传按钮 -->
|
||||
<view class="upload-btn" @click="uploadImage" v-if="isEditing">
|
||||
<u-icon name="camera" size="28" color="#fff"></u-icon>
|
||||
<text class="upload-text">更换图片</text>
|
||||
<text class="upload-text">{{ workOrderImg ? '更换图片' : '上传图片' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -298,7 +317,22 @@
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.empty-placeholder {
|
||||
width: 100%;
|
||||
height: 300rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: #f5f7fa;
|
||||
border-radius: 8rpx;
|
||||
|
||||
.empty-text {
|
||||
margin-top: 16rpx;
|
||||
font-size: 28rpx;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
/* 页面容器 */
|
||||
.work-order-detail {
|
||||
background-color: $bg-color;
|
||||
|
||||
@ -11,11 +11,7 @@
|
||||
<u-icon name="arrow-down" color="#999" size="30"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
<u-picker
|
||||
:show="showTypeSelect"
|
||||
:columns="areaList"
|
||||
keyName="title"
|
||||
@confirm="handleTypeConfirm"
|
||||
<u-picker :show="showTypeSelect" :columns="areaList" keyName="title" @confirm="handleTypeConfirm"
|
||||
@cancel="showTypeSelect = false">
|
||||
</u-picker>
|
||||
</view>
|
||||
@ -35,7 +31,6 @@
|
||||
</u-picker>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="form-item">
|
||||
<view class="label">
|
||||
<u-icon name="order" color="#3B8CFF" size="38"></u-icon>
|
||||
@ -65,21 +60,29 @@
|
||||
</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="160" height="160" accept="image/*,video/*" :previewFullImage="true">
|
||||
</u-upload>
|
||||
<view class="upload-list">
|
||||
<view class="upload-item" v-for="(item, index) in fileList" :key="index">
|
||||
<image v-if="!item.isVideo" :src="item.url" mode="aspectFill" @click="previewImage(index)"></image>
|
||||
<video v-else :src="item.url" controls></video>
|
||||
<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 < 8">
|
||||
<u-icon name="plus" size="40" color="#c0c4cc"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<text class="note">注:照片可识别工单内容,支持分批上传,但最大数量为8</text>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 工单地点 -->
|
||||
<view class="form-item">
|
||||
<view class="label">
|
||||
@ -95,28 +98,31 @@
|
||||
</view>
|
||||
</view>
|
||||
<Footer></Footer>
|
||||
|
||||
<!-- 上传操作菜单 -->
|
||||
<u-action-sheet
|
||||
:list="actionList"
|
||||
v-model="showActionSheet"
|
||||
@click="handleActionClick"
|
||||
></u-action-sheet>
|
||||
</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';
|
||||
import { get, post } from '@/utils/request';
|
||||
import { IMAGE_BASE_URL, BASE_URL } from '@/utils/config';
|
||||
import uActionSheet from 'uview-ui/components/u-action-sheet/u-action-sheet';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Footer
|
||||
Footer,uActionSheet
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
workOrderContent: '',
|
||||
concatName: '', // 新增联系人姓名字段
|
||||
customerPhone: '', // 新增联系人电话字段
|
||||
concatName: '',
|
||||
customerPhone: '',
|
||||
fileList: [],
|
||||
workOrderCategory: '',
|
||||
workOrderCategoryID: '',
|
||||
@ -131,6 +137,13 @@
|
||||
uploadedVideos: [],
|
||||
videoFormats: ['mp4', 'mov', 'avi', 'wmv', 'mpeg', '3gp', 'flv', 'mkv'],
|
||||
areaList: [],
|
||||
|
||||
// 上传相关
|
||||
showActionSheet: false,
|
||||
actionList: [
|
||||
{ text: '拍照', value: 'camera' },
|
||||
{ text: '从相册选择', value: 'album' }
|
||||
]
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
@ -138,129 +151,206 @@
|
||||
this.getOrderTypeList();
|
||||
},
|
||||
methods: {
|
||||
handleBack() {
|
||||
uni.navigateBack({
|
||||
delta: 1
|
||||
// 显示上传选项
|
||||
showUploadAction() {
|
||||
uni.showActionSheet({
|
||||
itemList: ['拍照', '从相册选择'],
|
||||
success: (res) => {
|
||||
if (res.tapIndex === 0) {
|
||||
this.chooseMedia('camera');
|
||||
} else {
|
||||
this.chooseMedia('album');
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 文件上传相关方法
|
||||
handleAfterRead(event) {
|
||||
const {
|
||||
file
|
||||
} = event;
|
||||
let files = [].concat(file);
|
||||
// 处理上传选项选择
|
||||
handleActionClick(index) {
|
||||
const action = this.actionList[index].value;
|
||||
if (action === 'camera') {
|
||||
this.chooseMedia('camera');
|
||||
} else {
|
||||
this.chooseMedia('album');
|
||||
}
|
||||
},
|
||||
|
||||
if (this.fileList.length + files.length > 8) {
|
||||
uni.showToast({
|
||||
title: '最多只能上传8个文件',
|
||||
icon: 'none'
|
||||
// 选择媒体文件
|
||||
async chooseMedia(sourceType) {
|
||||
try {
|
||||
// 1. 选择图片
|
||||
const res = await new Promise((resolve, reject) => {
|
||||
uni.chooseImage({
|
||||
count: 8 - this.fileList.length,
|
||||
sourceType: [sourceType === 'camera' ? 'camera' : 'album'],
|
||||
success: resolve,
|
||||
fail: reject
|
||||
});
|
||||
return;
|
||||
});
|
||||
|
||||
// 2. 添加到预览列表
|
||||
const newFiles = res.tempFilePaths.map(url => ({
|
||||
url,
|
||||
isVideo: false,
|
||||
status: 'uploading'
|
||||
}));
|
||||
this.fileList = [...this.fileList, ...newFiles];
|
||||
|
||||
// 3. 逐个上传文件
|
||||
for (const file of newFiles) {
|
||||
await this.uploadFile(file);
|
||||
}
|
||||
|
||||
files.forEach(item => {
|
||||
const extension = this.getFileExtension(item.url);
|
||||
const isVideo = this.videoFormats.includes(extension.toLowerCase());
|
||||
} catch (err) {
|
||||
console.error('选择图片失败:', err);
|
||||
uni.showToast({ title: '选择图片失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
_chooseMedia(sourceType) {
|
||||
uni.chooseMedia({
|
||||
count: 8 - this.fileList.length,
|
||||
mediaType: ['image', 'video'],
|
||||
sourceType: [sourceType],
|
||||
success: async (res) => {
|
||||
// 添加到预览列表
|
||||
const newFiles = res.tempFiles.map(file => ({
|
||||
url: file.tempFilePath,
|
||||
isVideo: file.fileType === 'video',
|
||||
status: 'uploading' // 新增上传状态
|
||||
}));
|
||||
this.fileList = [...this.fileList, ...newFiles];
|
||||
|
||||
this.fileList.push({
|
||||
...item,
|
||||
status: 'uploading',
|
||||
message: '上传中...',
|
||||
isVideo: isVideo
|
||||
});
|
||||
|
||||
this.uploadFile(item, isVideo);
|
||||
// 逐个上传文件
|
||||
for (const file of newFiles) {
|
||||
await this.uploadFile(file); // 等待上传完成
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getFileExtension(filename) {
|
||||
return filename.split('.').pop().split('?')[0];
|
||||
},
|
||||
|
||||
handleDelete(event) {
|
||||
const {
|
||||
index
|
||||
} = event;
|
||||
const file = this.fileList[index];
|
||||
// 上传文件
|
||||
uploadFiles(files) {
|
||||
files.forEach(file => {
|
||||
this.uploadFile(file).then(res => {
|
||||
const index = this.fileList.findIndex(item => item.url === file.url);
|
||||
if (index !== -1) {
|
||||
this.$set(this.fileList, index, {
|
||||
...file,
|
||||
status: 'success',
|
||||
serverUrl: res
|
||||
});
|
||||
|
||||
if (file.isVideo) {
|
||||
const videoIndex = this.uploadedVideos.indexOf(file.url);
|
||||
this.uploadedVideos.push(res.replace(BASE_URL, ''));
|
||||
} else {
|
||||
this.uploadedImages.push(res.replace(BASE_URL, ''));
|
||||
}
|
||||
}
|
||||
}).catch(err => {
|
||||
const index = this.fileList.findIndex(item => item.url === file.url);
|
||||
if (index !== -1) {
|
||||
this.$set(this.fileList, index, {
|
||||
...file,
|
||||
status: 'failed'
|
||||
});
|
||||
}
|
||||
console.error('上传失败:', err);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// 单个文件上传
|
||||
async uploadFile(file) {
|
||||
try {
|
||||
const res = await new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: `${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
|
||||
});
|
||||
|
||||
// 添加到提交数组
|
||||
if (file.isVideo) {
|
||||
this.uploadedVideos.push(res);
|
||||
} else {
|
||||
this.uploadedImages.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
|
||||
.filter(item => !item.isVideo)
|
||||
.map(item => item.url);
|
||||
|
||||
uni.previewImage({
|
||||
current: index,
|
||||
urls: images
|
||||
});
|
||||
},
|
||||
|
||||
// 删除文件
|
||||
handleDelete(index) {
|
||||
const file = this.fileList[index];
|
||||
|
||||
if (file.serverUrl) {
|
||||
if (file.isVideo) {
|
||||
const videoIndex = this.uploadedVideos.indexOf(file.serverUrl.replace(BASE_URL, ''));
|
||||
if (videoIndex !== -1) this.uploadedVideos.splice(videoIndex, 1);
|
||||
} else {
|
||||
const imageIndex = this.uploadedImages.indexOf(file.url);
|
||||
const imageIndex = this.uploadedImages.indexOf(file.serverUrl.replace(BASE_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,
|
||||
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({
|
||||
@ -304,8 +394,8 @@
|
||||
|
||||
const submitData = {
|
||||
title: this.workOrderContent,
|
||||
concatName: this.concatName, // 新增联系人姓名
|
||||
customerPhone: this.customerPhone, // 新增联系人电话
|
||||
concatName: this.concatName,
|
||||
customerPhone: this.customerPhone,
|
||||
orderTypeId: this.workOrderCategoryID,
|
||||
orderAreaId: this.workOrderAreaID,
|
||||
address: this.workOrderLocation,
|
||||
@ -315,7 +405,6 @@
|
||||
|
||||
console.log('提交数据:', submitData);
|
||||
|
||||
// 调用API保存信息
|
||||
const res = await post('/api/v1/app_auth/work-order', submitData);
|
||||
|
||||
uni.hideLoading();
|
||||
@ -387,7 +476,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
// 获取工作区域
|
||||
async getOrderTypeList() {
|
||||
try {
|
||||
const res = await get('/api/v1/apps/work-order-area');
|
||||
@ -467,6 +555,47 @@
|
||||
|
||||
.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, video {
|
||||
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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user