ts_aimz_uni/pages/shop/replenishStuffDetail/replenishStuffDetail.vue
2025-06-20 18:06:49 +08:00

740 lines
19 KiB
Vue

<template>
<view class="page-container page-gray-color">
<view class="content-box">
<view class="content-container" style="min-height: 100vh;">
<view class="info-title">平台需要您补充的内容说明</view>
<!-- 第一部分 -->
<view class="section" v-if="replenish != null">
<view class="item">
<text class="label">主题</text>
<view class="select-content-item">
<view class="value v-select">{{replenish.correctionTitle}}</view>
</view>
</view>
<view class="item">
<text class="label">内容</text>
<view class="select-content-no-h">
<view class="select-item-box">
<view class="value v-select">{{replenish.correctionRemark}}</view>
</view>
</view>
</view>
<view class="item" v-if="replenish.correctionFiles !== ''">
<text class="label">附件</text>
<view class="select-content-no-h">
<view class="select-item-box">
<view class="value v-select">
<view class="accessory-box">
<view class="accessory-item" v-for="(item, index) in replenishFiles"
@click="doDownloadFile(item)" :key="index">
<block v-if="isImg(item.fileType)">
<image class="accessory-img" :src="item.netUrl" mode="scaleToFill">
</image>
<view class="file-name">{{item.fileName}}</view>
</block>
<block v-else>
<view class="icon-source"></view>
<view class="file-name">{{item.fileName}}</view>
</block>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="info-title">您补充的内容</view>
<!-- 第一部分 -->
<view class="section" v-if="restore != null">
<view class="item">
<text class="label">内容</text>
<view class="select-content-no-h">
<view class="select-item-box">
<view class="value v-select">{{restore.correctionRemark}}</view>
</view>
</view>
</view>
<view class="item" v-if="restore.correctionFiles !== ''">
<text class="label">附件</text>
<view class="select-content-no-h">
<view class="select-item-box">
<view class="value v-select">
<view class="accessory-box">
<view class="accessory-item" v-for="(item, index) in restoreFiles"
@click="doDownloadFile(item)" :key="index">
<block v-if="isImg(item.fileType)">
<image class="accessory-img" :src="item.netUrl" mode="scaleToFill">
</image>
<view class="file-name">{{item.fileName}}</view>
</block>
<block v-else>
<view class="icon-source"></view>
<view class="file-name">{{item.fileName}}</view>
</block>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<DownProgress :isShow="downloading" :progress="downloadProgress"></DownProgress>
<uni-popup type="message" ref="msg">
<uni-popup-message :type="msgType" :duration="2000" :message="msgHint"></uni-popup-message>
</uni-popup>
</view>
</template>
<script>
import DownProgress from '@/components/download-progress.vue'
import Shop from '@/common/js/net/shop.js'
import {
upShopImgUrl,
sImgPrefix,
upShopFileUrl
} from '@/common/js/net/mainUrl.js'
import {
isImg
} from '@/common/js/conver.js'
import {
get
} from '@/common/js/cache/storage.js'
const docFix = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf']
const imgFix = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'ico', 'tiff', 'tif']
export default {
components: {
DownProgress
},
data() {
return {
msgHint: '',
msgType: 'info',
msgShow: false,
files: [],
maxCount: 4,
replenishId: '',
replenish: null,
replenishFiles: [],
downloading: false,
downloadProgress: 0,
showActionsheet: false,
kind: 'buy',
restore: null,
restoreFiles: []
}
},
onLoad(options) {
uni.setNavigationBarTitle({
title: '资料补充'
})
uni.setNavigationBarColor({
frontColor: '#000000',
backgroundColor: '#FFFFFF',
animation: {
duration: 500,
timingFunc: 'easeIn'
}
})
const {
id,
kind
} = options
if (id) {
this.replenishId = id
this.kind = kind
this.doGetReplenishDetail()
} else {
this.showMessage('数据有误,请稍后重试', 'error')
setTimeout(() => uni.navigateBack(), 1500)
}
},
methods: {
isImg,
// 获取补充详情
async doGetReplenishDetail() {
try {
uni.showLoading({
title: '加载中...'
})
const res = await Shop.doGetReplenishDetail(this.replenishId)
uni.hideLoading()
this.replenish = res
console.log('详情', res)
// 获取附件信息
if (res.correctionFiles) {
await this.doGetFileInfo(1, res.correctionFiles)
}
// 判断是购买还是售卖
await this.doGetReplenishRestoreDetail()
} catch (err) {
console.error(err)
uni.hideLoading()
this.showMessage(err.msg || '网络错误,请稍后重试', 'error')
setTimeout(() => uni.navigateBack(), 1500)
}
},
// 获取回复详情
async doGetReplenishRestoreDetail() {
try {
uni.showLoading({
title: '加载中...'
})
const id = this.kind === 'buy' ? this.replenish.buyId : this.replenish.sellId
const res = await Shop.doGetReplenishDetail(id)
uni.hideLoading()
console.log('回复详情', res)
if (res) {
this.restore = res
if (res.correctionFiles) {
await this.doGetFileInfo(2, res.correctionFiles)
}
}
} catch (err) {
console.error(err)
uni.hideLoading()
this.showMessage(err.msg || '网络错误,请稍后重试', 'error')
}
},
// 获取文件信息
async doGetFileInfo(type, ids) {
try {
uni.showLoading({
title: '加载中...'
})
const res = await Shop.doGetFileInfos({
ids
})
uni.hideLoading()
if (res) {
const list = this.addPrefix(res)
if (type === 1) {
this.replenishFiles = list
} else {
this.restoreFiles = list
}
}
} catch (err) {
uni.hideLoading()
this.showMessage(err.msg || '获取附件失败,请稍后重试', 'error')
}
},
inputRemark(e) {
this.remark = e.detail.value
},
// 添加baseUrl
addPrefix(list) {
return list.map(item => {
item.netUrl = sImgPrefix + item.fileId
return item
})
},
doPreImg(url) {
uni.previewImage({
urls: [url]
})
},
// 下载文件
doDownloadFile(item) {
if (this.isImageFile(item.fileName)) {
this.doPreImg(item.netUrl)
} else if (this.isDocumentFile(item.fileName)) {
this.goDownloadFile(item)
} else {
this.showMessage('该文件无法在小程序中打开,请前往电脑端查看', 'info')
}
},
async goDownloadFile(item) {
try {
this.downloadProgress = 0
this.downloading = true
const token = get('token')
const header = token ? {
'Auth': `Bearer ${token}`
} : {}
const url = item.netUrl + '.' + item.fileType
const res = await this.doStartDownload(url, header)
var path = ''
if (res.tempFilePath.endsWith('.' + item.fileType)) {
path = res.tempFilePath
} else {
path = res.tempFilePath + '.' + item.fileType
}
console.log('文件路径', path, '=========', res.tempFilePath)
uni.openDocument({
filePath: path,
showMenu: true,
fileType: item.fileType,
success(res) {
console.log('打开文件', res)
},
fail(err) {
console.log('打开文件失败', err)
}
})
} catch (err) {
console.error('下载失败', err)
this.showMessage('很抱歉,文件下载出现问题。建议您稍作等待,之后再尝试下载。', 'error')
} finally {
this.downloadProgress = 0
this.downloading = false
}
},
async doStartDownload(url, header) {
const _self = this
return new Promise((resolve, reject) => {
const downloadTask = uni.downloadFile({
url: url,
header: header,
success: resolve,
fail: reject
})
downloadTask.onProgressUpdate(res => {
_self.downloadProgress = res.progress
console.log(res)
})
})
},
backPageRefresh() {
const pages = getCurrentPages()
const beforePage = pages[pages.length - 2]
if (beforePage) {
beforePage.$vm.needRefresh = true
}
uni.navigateBack()
},
showMessage(msg, type = 'info') {
this.msgHint = msg
this.msgType = type
this.$refs.msg.open()
},
bindChooseWay(e) {
this.showActionsheet = false
const value = e.detail.value
if (value === 'img') {
uni.chooseMedia({
count: 4,
mediaType: ['image'],
sourceType: ['album'],
success: ({
tempFiles
}) => {
if (tempFiles.length > 0) {
this.doUploadFile(1, tempFiles)
}
},
fail: (err) => {
this.showMessage(err.errMsg || '选择文件失败,请稍后重试', 'error')
}
})
} else {
uni.chooseMessageFile({
count: 1,
type: 'file',
extension: docFix,
success: ({
tempFiles
}) => {
if (tempFiles.length > 0) {
this.doUploadFile(2, tempFiles)
}
},
fail: (err) => {
this.showMessage(err.errMsg || '选择文件失败,请稍后重试', 'error')
}
})
}
},
bindChooseFile() {
this.showActionsheet = true
},
// 上传文件 type=1 图片 =2文件
async doUploadFile(type, files) {
try {
uni.showLoading({
title: '上传中...'
})
const upUrl = type === 1 ? upShopImgUrl : upShopFileUrl
const upType = type === 1 ? 'image' : 'file'
const token = get('token')
const header = token ? {
'Auth': `Bearer ${token}`
} : {}
const uploadPromises = files.map(file => {
const filePath = type === 1 ? file.tempFilePath : file.path
return new Promise((resolve, reject) => {
uni.uploadFile({
url: upUrl,
header,
filePath,
name: upType,
success: (res) => {
try {
const result = JSON.parse(res.data)
result.data.netUrl = sImgPrefix + result.data
.fileId
resolve(result.data)
} catch (err) {
reject(new Error('解析上传结果失败'))
}
},
fail: reject
})
})
})
const results = await Promise.all(uploadPromises)
this.files = [...this.files, ...results]
uni.hideLoading()
} catch (err) {
console.error('上传失败', err)
uni.hideLoading()
this.showMessage('上传文件失败,请稍后重试', 'error')
}
},
doDelFile(index) {
if (index >= 0 && index < this.files.length) {
this.files.splice(index, 1)
}
},
// 校验参数
checkParams() {
const isRemarkValid = this.remark.trim() !== ''
const isFileValid = this.files.length > 0
if (!isRemarkValid && !isFileValid) {
this.showMessage('请输入补充内容或上传附件(至少完成一项)', 'error')
return false
}
return true
},
// 提交
async doSubmit() {
if (this.checkParams()) {
try {
uni.showLoading({
title: '提交中...'
})
const fileIds = this.files.map(item => item.fileId).join(',')
const data = {
correctionFiles: fileIds,
correctionParentId: this.replenish.correctionId,
correctionRemark: this.remark,
orderId: this.replenish.orderId
}
await Shop.doSaveReplenish(data)
this.showMessage('提交成功', 'success')
setTimeout(() => {
this.backPageRefresh()
}, 1500)
} catch (err) {
this.showMessage(err.msg || '网络错误,请稍后重试', 'error')
} finally {
uni.hideLoading()
}
}
},
// 工具函数:检查文件类型
getFileExtension(filename) {
if (!filename || typeof filename !== 'string') return ''
const lastDot = filename.lastIndexOf('.')
return lastDot === -1 ? '' : filename.substring(lastDot + 1).toLowerCase()
},
isImageFile(filename) {
return imgFix.includes(this.getFileExtension(filename))
},
isDocumentFile(filename) {
return docFix.includes(this.getFileExtension(filename))
}
}
}
</script>
<style lang="scss" scoped>
.page-gray-color {
background-color: $divider-color;
}
.content-box {
border-radius: 20rpx;
margin-top: -10rpx;
}
.upload-img-box {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.content-container {
margin: 0rpx -30rpx 0rpx -30rpx;
background-color: white;
display: flex;
flex-direction: column;
padding: 30rpx;
}
.info-title {
font-size: 36rpx;
font-weight: bold;
display: flex;
flex-direction: row;
align-items: center;
}
.info-title::before {
content: "";
width: 10rpx;
height: 36rpx;
margin-right: 5rpx;
border-left: 15rpx solid $blue-color;
vertical-align: middle;
}
.section {
margin-bottom: 15rpx;
margin-left: 20rpx;
}
.item {
display: flex;
flex-direction: column;
margin-bottom: 10rpx;
padding: 20rpx 10rpx;
font-size: 28rpx;
}
.label {
color: $text-color;
font-weight: bold;
}
.textarea-content {
margin-top: 10rpx;
padding: 10rpx 0rpx;
font-size: 28rpx;
border-bottom: 1rpx solid $divider-color;
}
.select-content {
margin-top: 15rpx;
display: flex;
height: 70rpx;
flex-direction: row;
border-radius: 5rpx;
background-color: $bg-gray-input-color;
padding: 0rpx 10rpx;
}
.select-content-no-h {
margin-top: 15rpx;
display: flex;
flex-direction: row;
align-items: center;
min-height: 70rpx;
flex-direction: row;
border-radius: 5rpx;
padding: 0rpx 15rpx 10rpx 0rpx;
border-bottom: 1rpx solid $divider-color;
}
.select-content-item {
margin-top: 15rpx;
display: flex;
flex-direction: row;
align-items: center;
height: 70rpx;
flex-direction: row;
border-radius: 5rpx;
padding: 0rpx 15rpx 10rpx 0rpx;
border-bottom: 1rpx solid $divider-color;
}
.select-item-box {
flex: 1;
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding: 5rpx;
}
.select-item-item {
display: flex;
flex-direction: row;
align-items: center;
background-color: $divider-color;
padding: 5rpx 15rpx;
border-radius: 5rpx;
font-size: 24rpx;
margin-right: 15rpx;
margin-top: 5rpx;
color: $text-color;
}
.desc {
flex: 1;
color: #999;
text-align: left;
padding-left: 20rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
padding-right: 10px;
align-items: center;
}
.select-time {
color: $text-color;
flex: 1;
font-size: 28rpx;
text-align: left;
}
.clear-icon {
width: 20px;
height: 20px;
margin-right: 20rpx;
}
.value {
flex: 1;
text-align: left;
font-size: 28rpx;
}
.value-hint {
color: $text-gray-hint-color;
}
.v-select {
color: $text-color;
}
.v-normal {
color: $text-gray-hint-color;
}
.custom-dialog {
background-color: $white-color;
}
.custom-tips {
margin-top: 80px;
}
.upload-file-box {
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding: 20rpx 0rpx;
}
.upload-file-item {
width: 20%;
height: 150rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border: 1rpx solid $divider-color;
border-radius: 10rpx;
position: relative;
}
.upload-file-del {
width: 50rpx;
height: 50rpx;
position: absolute;
top: -15rpx;
right: -15rpx;
}
.upload-file-item:nth-of-type(n+2) {
margin-left: 20rpx;
}
.icon-add-line {
background-image: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB0PSIxNzQ5ODEwMTM0NTA0IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjQzMDkiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZD0iTTUxMS45MTQ2NjcgOTYwYTIxLjMzMzMzMyAyMS4zMzMzMzMgMCAwIDEtMjEuMzMzMzM0LTIxLjMzMzMzM2wwLjEyOC04NTMuMzMzMzM0YTIxLjMzMzMzMyAyMS4zMzMzMzMgMCAxIDEgNDIuNjY2NjY3IDBsLTAuMTI4IDg1My4zMzMzMzRhMjEuMzMzMzMzIDIxLjMzMzMzMyAwIDAgMS0yMS4zMzMzMzMgMjEuMzMzMzMzeiIgZmlsbD0iI2NkY2RjZCIgcC1pZD0iNDMxMCI+PC9wYXRoPjxwYXRoIGQ9Ik05MzguNjY2NjY3IDUzMy4zMTJIODUuMzMzMzMzYTIxLjMzMzMzMyAyMS4zMzMzMzMgMCAxIDEgMC00Mi42NjY2NjdoODUzLjMzMzMzNGEyMS4zMzMzMzMgMjEuMzMzMzMzIDAgMSAxIDAgNDIuNjY2NjY3eiIgZmlsbD0iI2NkY2RjZCIgcC1pZD0iNDMxMSI+PC9wYXRoPjwvc3ZnPg==');
background-size: cover;
background-repeat: no-repeat;
}
.accessory-box {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.accessory-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
width: 21%;
padding: 15rpx;
margin: 10rpx;
border: 1rpx solid $divider-color;
box-sizing: border-box;
min-width: auto;
}
.accessory-img {
width: 100%;
height: 100rpx;
}
.file-name {
width: 100%;
font-size: 20rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.icon-source {
background-image: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSI2NCA2NCA4OTYgODk2IiB3aWR0aD0iNTIiIGhlaWdodD0iNTIiIHN0eWxlPSIiIGZpbHRlcj0ibm9uZSI+CiAgICAKICAgIDxnPgogICAgPHBhdGggZD0iTTkyOCAxNjFINjk5LjJjLTQ5LjEgMC05Ny4xIDE0LjEtMTM4LjQgNDAuN0w1MTIgMjMzbC00OC44LTMxLjNBMjU1LjIgMjU1LjIgMCAwIDAgMzI0LjggMTYxSDk2Yy0xNy43IDAtMzIgMTQuMy0zMiAzMnY1NjhjMCAxNy43IDE0LjMgMzIgMzIgMzJoMjI4LjhjNDkuMSAwIDk3LjEgMTQuMSAxMzguNCA0MC43bDQ0LjQgMjguNmMxLjMuOCAyLjggMS4zIDQuMyAxLjNzMy0uNCA0LjMtMS4zbDQ0LjQtMjguNkM2MDIgODA3LjEgNjUwLjEgNzkzIDY5OS4yIDc5M0g5MjhjMTcuNyAwIDMyLTE0LjMgMzItMzJWMTkzYzAtMTcuNy0xNC4zLTMyLTMyLTMyek00MDQgNTUzLjVjMCA0LjEtMy4yIDcuNS03LjEgNy41SDIxMS4xYy0zLjkgMC03LjEtMy40LTcuMS03LjV2LTQ1YzAtNC4xIDMuMi03LjUgNy4xLTcuNWgxODUuN2MzLjkgMCA3LjEgMy40IDcuMSA3LjV2NDV6bTAtMTQwYzAgNC4xLTMuMiA3LjUtNy4xIDcuNUgyMTEuMWMtMy45IDAtNy4xLTMuNC03LjEtNy41di00NWMwLTQuMSAzLjItNy41IDcuMS03LjVoMTg1LjdjMy45IDAgNy4xIDMuNCA3LjEgNy41djQ1em00MTYgMTQwYzAgNC4xLTMuMiA3LjUtNy4xIDcuNUg2MjcuMWMtMy45IDAtNy4xLTMuNC03LjEtNy41di00NWMwLTQuMSAzLjItNy41IDcuMS03LjVoMTg1LjdjMy45IDAgNy4xIDMuNCA3LjEgNy41djQ1em0wLTE0MGMwIDQuMS0zLjIgNy41LTcuMSA3LjVINjI3LjFjLTMuOSAwLTcuMS0zLjQtNy4xLTcuNXYtNDVjMC00LjEgMy4yLTcuNSA3LjEtNy41aDE4NS43YzMuOSAwIDcuMSAzLjQgNy4xIDcuNXY0NXoiIGZpbGw9InJnYmEoMTI5LDE3OSw1NSwxKSI+PC9wYXRoPgogICAgPC9nPgogIDwvc3ZnPg==');
background-size: cover;
background-repeat: no-repeat;
width: 42px;
height: 42px;
}
</style>