<template>
|
<view class="file-list-page">
|
<PageHeader title="售后附件" @back="goBack" />
|
|
<view class="file-list-container">
|
<view v-if="fileList.length > 0" class="file-list">
|
<view v-for="(file, index) in fileList" :key="file.id || index" class="file-item">
|
<view class="file-info">
|
<text class="file-name">{{ file.name }}</text>
|
</view>
|
<view class="file-actions">
|
<u-button size="small" type="info" plain @click="downloadFile(file)">下载并预览</u-button>
|
<u-button size="small" type="error" plain @click="confirmDelete(file)">删除</u-button>
|
</view>
|
</view>
|
</view>
|
|
<view v-else class="empty-state">
|
<up-icon name="document" size="64" color="#c0c4cc" />
|
<text class="empty-text">暂无附件</text>
|
</view>
|
</view>
|
|
<view class="upload-button" @click="chooseFile">
|
<up-icon name="plus" size="24" color="#ffffff" />
|
<text class="upload-text">上传附件</text>
|
</view>
|
</view>
|
</template>
|
|
<script setup>
|
import { ref, onMounted } from "vue";
|
import PageHeader from "@/components/PageHeader.vue";
|
import config from "@/config";
|
import { getToken } from "@/utils/auth";
|
import { afterSalesServiceFileListPage, afterSalesServiceFileDel } from "@/api/customerService/index";
|
|
const fileList = ref([]);
|
const afterSalesServiceId = ref("");
|
|
const goBack = () => {
|
uni.navigateBack();
|
};
|
|
const showToast = (message) => {
|
uni.showToast({
|
title: message,
|
icon: "none",
|
});
|
};
|
|
const normalizeFileRow = (row) => {
|
return {
|
id: row?.id,
|
name: row?.name || row?.fileName || "-",
|
url: row?.url || row?.fileUrl || "",
|
};
|
};
|
|
const getFileList = () => {
|
if (!afterSalesServiceId.value) {
|
fileList.value = [];
|
return;
|
}
|
uni.showLoading({ title: "加载中...", mask: true });
|
afterSalesServiceFileListPage({
|
afterSalesServiceId: afterSalesServiceId.value,
|
current: 1,
|
size: 100,
|
})
|
.then((res) => {
|
const records = res?.data?.records ?? res?.records ?? [];
|
const list = Array.isArray(records) ? records : [];
|
fileList.value = list.map(normalizeFileRow);
|
})
|
.catch(() => {
|
showToast("获取附件列表失败");
|
fileList.value = [];
|
})
|
.finally(() => {
|
uni.hideLoading();
|
});
|
};
|
|
const chooseFile = () => {
|
if (!afterSalesServiceId.value) {
|
showToast("缺少售后单ID");
|
return;
|
}
|
uni.chooseImage({
|
count: 9,
|
sizeType: ["original", "compressed"],
|
sourceType: ["album", "camera"],
|
success: (res) => {
|
uploadFiles(res.tempFiles || []);
|
},
|
fail: () => {
|
showToast("选择文件失败");
|
},
|
});
|
};
|
|
const uploadFiles = (tempFiles) => {
|
if (!Array.isArray(tempFiles) || tempFiles.length === 0) return;
|
tempFiles.forEach((tempFile) => {
|
uni.showLoading({ title: "上传中...", mask: true });
|
uni.uploadFile({
|
url: config.baseUrl + "/afterSalesService/file/upload",
|
filePath: tempFile.path,
|
name: "file",
|
formData: {
|
id: String(afterSalesServiceId.value),
|
},
|
header: {
|
Authorization: "Bearer " + getToken(),
|
},
|
success: (uploadRes) => {
|
uni.hideLoading();
|
try {
|
const data = JSON.parse(uploadRes.data || "{}");
|
if (data.code === 200 || data.code === undefined) {
|
showToast("上传成功");
|
getFileList();
|
return;
|
}
|
showToast(data.msg || "上传失败");
|
} catch (e) {
|
showToast("上传失败");
|
}
|
},
|
fail: () => {
|
uni.hideLoading();
|
showToast("上传失败");
|
},
|
});
|
});
|
};
|
|
const downloadFile = (file) => {
|
if (!file?.url) {
|
showToast("文件地址为空");
|
return;
|
}
|
const url =
|
config.baseUrl +
|
"/common/download?fileName=" +
|
encodeURIComponent(file.url) +
|
"&delete=true";
|
|
uni
|
.downloadFile({
|
url,
|
responseType: "blob",
|
header: { Authorization: "Bearer " + getToken() },
|
})
|
.then((res) => {
|
const osType = uni.getStorageSync("deviceInfo")?.osName;
|
const filePath = res.tempFilePath;
|
if (osType === "ios") {
|
uni.openDocument({
|
filePath,
|
showMenu: true,
|
});
|
} else {
|
uni.saveFile({
|
tempFilePath: filePath,
|
success: (fileRes) => {
|
setTimeout(() => {
|
uni.openDocument({
|
filePath: fileRes.savedFilePath,
|
});
|
}, 300);
|
},
|
fail: () => {
|
showToast("保存失败");
|
},
|
});
|
}
|
})
|
.catch(() => {
|
showToast("下载失败");
|
});
|
};
|
|
const confirmDelete = (file) => {
|
uni.showModal({
|
title: "删除确认",
|
content: `确定要删除附件 \"${file.name}\" 吗?`,
|
success: (res) => {
|
if (res.confirm) {
|
deleteFile(file);
|
}
|
},
|
});
|
};
|
|
const deleteFile = (file) => {
|
if (!file?.id) return;
|
uni.showLoading({ title: "删除中...", mask: true });
|
afterSalesServiceFileDel(file.id)
|
.then((res) => {
|
if (res?.code === 200 || res?.code === undefined) {
|
showToast("删除成功");
|
getFileList();
|
return;
|
}
|
showToast(res?.msg || "删除失败");
|
})
|
.catch(() => {
|
showToast("删除失败");
|
})
|
.finally(() => {
|
uni.hideLoading();
|
});
|
};
|
|
onMounted(() => {
|
afterSalesServiceId.value = String(uni.getStorageSync("afterSalesServiceFileId") || "");
|
getFileList();
|
});
|
</script>
|
|
<style scoped lang="scss">
|
@import "@/styles/sales-common.scss";
|
|
.file-list-page {
|
min-height: 100vh;
|
background: #f8f9fa;
|
padding-bottom: 100rpx;
|
}
|
|
.file-list-container {
|
padding: 20rpx;
|
}
|
|
.file-list {
|
background: #ffffff;
|
border-radius: 8rpx;
|
overflow: hidden;
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
|
}
|
|
.file-item {
|
display: flex;
|
align-items: center;
|
padding: 20rpx;
|
border-bottom: 1rpx solid #f0f0f0;
|
}
|
|
.file-info {
|
flex: 1;
|
margin-right: 20rpx;
|
}
|
|
.file-name {
|
font-size: 28rpx;
|
color: #333;
|
font-weight: 500;
|
display: block;
|
}
|
|
.file-actions {
|
display: flex;
|
gap: 16rpx;
|
}
|
|
.empty-state {
|
padding: 80rpx 0;
|
text-align: center;
|
}
|
|
.empty-text {
|
display: block;
|
margin-top: 20rpx;
|
color: #999;
|
font-size: 28rpx;
|
}
|
|
.upload-button {
|
position: fixed;
|
bottom: calc(30rpx + env(safe-area-inset-bottom));
|
right: 30rpx;
|
height: 88rpx;
|
padding: 0 28rpx;
|
background: #2979ff;
|
border-radius: 44rpx;
|
display: flex;
|
align-items: center;
|
gap: 14rpx;
|
box-shadow: 0 4rpx 16rpx rgba(41, 121, 255, 0.3);
|
z-index: 1000;
|
}
|
|
.upload-text {
|
color: #ffffff;
|
font-size: 28rpx;
|
font-weight: 500;
|
}
|
</style>
|