431 lines
18 KiB
Vue
431 lines
18 KiB
Vue
<template>
|
||
<view>
|
||
<u-navbar title="处理详情" :border-bottom="false" :background="bgc" back-icon-color="#fff" title-color='#fff'
|
||
title-size='36' height='50'></u-navbar>
|
||
<view class="page">
|
||
<!-- 头部 商家名称 + 状态 + 投诉详情(收起/展开) -->
|
||
<view class="card header" style="border-radius: 0;">
|
||
<view class="row between center">
|
||
<text class="label">{{xqobj.areaName == null ? '--' : xqobj.areaName}}</text>
|
||
<view class="row center right-actions">
|
||
<view class="row center status">
|
||
<view class="dot"></view>
|
||
<text class="status-text" v-if="xqobj.status == 1">商户处理中</text>
|
||
<text class="status-text" v-if="xqobj.status == 2">用户处理中</text>
|
||
<text class="status-text" v-if="xqobj.status == 3">平台处理中</text>
|
||
<text class="status-text" v-if="xqobj.status == 4">已完结</text>
|
||
</view>
|
||
<view class="toggle" @tap="toggleExpand">
|
||
<text class="toggle-text">投诉详情</text>
|
||
<text class="arrow" :class="{up: expanded}"></text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 详情(默认收起,保持结构,便于后续接入真实数据) -->
|
||
<view class="card info collapsible" :class="{collapsed: !expanded}">
|
||
<view class="item"><text class="item-label">申请退款金额</text><text class="item-value emphasis">¥ {{xqobj.needRefundAmount == null ? '0' : xqobj.needRefundAmount}}</text></view>
|
||
<view class="item"><text class="item-label">已退款金额</text><text class="item-value emphasis">¥ {{xqobj.refundAmount == null ? '0' : xqobj.refundAmount}}</text></view>
|
||
<view class="item"><text class="item-label">投诉类型</text><text class="item-value">{{xqobj.title == null ? '--' : xqobj.title}}</text></view>
|
||
<view class="item"><text class="item-label">投诉编号</text><text class="item-value">{{xqobj.no == null ? '' : xqobj.no}}</text></view>
|
||
<view class="item"><text class="item-label">投诉编号</text><text class="item-value">{{xqobj.orderNo == null ? '' : xqobj.orderNo}}</text></view>
|
||
<view class="item"><text class="item-label">投诉时间</text><text class="item-value">{{xqobj.createTime == null ? '--' : xqobj.createTime}}</text></view>
|
||
<view class="item"><text class="item-label" style="width: 480rpx;">投诉原因</text><text class="item-value">{{xqobj.content == null ? '暂无投诉原因' : xqobj.content}}</text></view>
|
||
<view class="item proof">
|
||
<text class="item-label">图片凭证</text>
|
||
<view class="proof-box" v-for="(item,index) in zsimg" :key="index">
|
||
<image :src="item" @click="ClickImage(zsimg,item)" mode="aspectFill" style="border-radius: 10rpx;"></image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 投诉申请已提交卡片 -->
|
||
<view class="card submit-card" style="border-radius: 16rpx;width: 680rpx;margin: auto;margin-top: 20rpx;">
|
||
<view class="row center">
|
||
<view class="check-icon"><text class="check">✓</text></view>
|
||
<text class="submit-title" v-if="xqobj.status == 1">投诉申请已提交</text>
|
||
<text class="submit-title" v-if="xqobj.status == 2">商家已反馈</text>
|
||
<text class="submit-title" v-if="xqobj.status == 3">投诉申请已提交</text>
|
||
<text class="submit-title" v-if="xqobj.status == 4">投诉申请已完结</text>
|
||
</view>
|
||
<text class="submit-sub" v-if="xqobj.status == 1">商家将在一天内处理,请耐心等待</text>
|
||
<text class="submit-sub" v-if="xqobj.status == 2">请在一天内处理</text>
|
||
<text class="submit-sub" v-if="xqobj.status == 3">平台将在一天内处理,请耐心等待</text>
|
||
<text class="submit-sub" v-if="xqobj.status == 4">已完结</text>
|
||
</view>
|
||
|
||
<!-- 对话区(基于 msgList 渲染) -->
|
||
<view class="chat" v-if="Array.isArray(msgList) && msgList.length">
|
||
<block v-for="(msg, idx) in msgList" :key="msg.id || idx">
|
||
<!-- 系统消息:居中展示,无头像 -->
|
||
<view v-if="msg.type == 3" class="sys">
|
||
<view class="pill">
|
||
<text>{{ msg.content || '系统通知' }}</text>
|
||
</view>
|
||
</view>
|
||
<!-- 退款消息:显示退款卡片 -->
|
||
<view v-else-if="msg.type == 4" class="refund card" style="width: 680rpx;margin: auto;margin-top: 20rpx;">
|
||
<view class="refund-row">
|
||
<view class="check-icon solid"><text class="check inverse">✓</text></view>
|
||
<text class="refund-text">退款已到账</text>
|
||
</view>
|
||
<view class="refund-amount">
|
||
<text class="emphasis">¥ {{ msg.content }}</text>
|
||
<text class="light-text" v-if="xqobj.partRefund">(已部分退款)</text>
|
||
</view>
|
||
</view>
|
||
<!-- 用户/商户消息:左右气泡,头像在上名称在下(颜色区分角色) -->
|
||
<block v-else>
|
||
<view class="row chat-row" :class="{ 'right-row': isRight(msg) }">
|
||
<!-- 左侧商户:头像+名称列 在左,气泡在右 -->
|
||
<view v-if="!isRight(msg)" class="person left">
|
||
<view class="avatar merchant"></view>
|
||
<text class="name merchant">{{ msg.sendName }}</text>
|
||
</view>
|
||
<view class="bubble" :class="[ isRight(msg) ? 'right user' : 'left merchant' ]">
|
||
<text v-if="msg.content">{{ msg.content }}</text>
|
||
<!-- 图片列表 -->
|
||
<view v-if="msg.picture" style="margin-top: 12rpx; display:flex; flex-wrap:wrap; gap:12rpx;">
|
||
<image v-for="(pic, pidx) in splitPics(msg.picture)" :key="pidx" :src="pic" mode="aspectFill" style="width: 180rpx; height: 180rpx; border-radius: 8rpx;" @click="ClickImage(splitPics(msg.picture), pic)"></image>
|
||
</view>
|
||
</view>
|
||
<!-- 右侧用户:气泡在左,头像+名称列 在右 -->
|
||
<view v-if="isRight(msg)" class="person right">
|
||
<view class="avatar user"></view>
|
||
<text class="name user">{{ msg.sendName }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="time" :class="{ right: isRight(msg) }" v-if="msg.createTime">{{ msg.createTime }}</view>
|
||
</block>
|
||
</block>
|
||
</view>
|
||
|
||
<!-- 退款结果条由 msgList 的 type==4 消息驱动,不再单独静态展示 -->
|
||
|
||
<!-- 底部按钮 -->
|
||
<view class="footer">
|
||
<button class="primary" @tap="onContinue">继续投诉</button>
|
||
<view class="sqpt" v-if="xqobj.platform == true">
|
||
平台已介入
|
||
</view>
|
||
<view v-else class="sqpt" @click="btnptjr">
|
||
申请平台介入
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 继续投诉弹窗(自定义) -->
|
||
<view v-if="showContinue" class="modal-mask" @touchmove.stop.prevent>
|
||
<view class="modal-panel">
|
||
<view class="popup-header">
|
||
<text class="popup-title">继续投诉</text>
|
||
<text class="popup-close" @tap="showContinue=false">×</text>
|
||
</view>
|
||
<view class="popup-body">
|
||
<view class="textarea-box">
|
||
<textarea v-model="continueText" maxlength="100" :auto-height="true" placeholder="请输入继续投诉内容" placeholder-class="ph"/>
|
||
<text class="count">{{ continueText.length }}/100</text>
|
||
</view>
|
||
<view class="uploader">
|
||
<view class="upload-item add" v-if="images.length < 4" @tap="pickImages">
|
||
<image src="https://api.ccttiot.com/smartmeter/img/static/udgL6KzisrZlMrk9AZb2" mode=""></image>
|
||
</view>
|
||
<view class="upload-item" v-for="(img,idx) in images" :key="idx">
|
||
<image :src="img" mode="aspectFill"></image>
|
||
<view class="del" @tap="removeImage(idx)">×</view>
|
||
</view>
|
||
</view>
|
||
<text class="tip">最多上传4张</text>
|
||
</view>
|
||
<view class="popup-footer">
|
||
<button class="primary" @tap="submitContinue">确认投诉</button>
|
||
<view class="sqpt" v-if="xqobj.platform == true">
|
||
平台已介入
|
||
</view>
|
||
<view v-else class="sqpt" @click="btnptjr">
|
||
申请平台介入
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
bgc: {
|
||
backgroundColor: "#4C97E7",
|
||
},
|
||
expanded: false,
|
||
showContinue: false,
|
||
continueText: '',
|
||
images: [],
|
||
token:'',
|
||
id:'',
|
||
xqobj:{},
|
||
zsimg:[],
|
||
msgList:[]
|
||
}
|
||
},
|
||
onLoad(option) {
|
||
this.id = option.id
|
||
this.getxq()
|
||
this.getqiniuyun()
|
||
},
|
||
methods: {
|
||
// 工具:是否右侧(用户)
|
||
isRight(msg){
|
||
return String(msg.type) == '1'
|
||
},
|
||
// 工具:展示名称
|
||
getSenderName(msg){
|
||
const name = msg && msg.sendName
|
||
if (name) return name
|
||
if(String(msg.type) == '2') return this.xqobj.mchName || '商户'
|
||
if(String(msg.type) == '1') return '用户'
|
||
return '系统'
|
||
},
|
||
// 工具:角色标签
|
||
getRoleLabel(msg){
|
||
if(String(msg.type) == '1') return '用户'
|
||
if(String(msg.type) == '2') return '商户'
|
||
return '系统'
|
||
},
|
||
// 工具:图片字符串切分
|
||
splitPics(picStr){
|
||
if(!picStr){ return [] }
|
||
return picStr.split(',').filter(Boolean)
|
||
},
|
||
// 工具:退款金额
|
||
getRefundAmount(msg){
|
||
// 优先从消息体取,其次从详情对象兜底
|
||
return (msg.amount || msg.refundAmount || this.xqobj.refundAmount || this.xqobj.needRefundAmount || 0)
|
||
},
|
||
// 点击申请平台介入
|
||
btnptjr(){
|
||
let that = this
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '您确定要申请平台介入吗?',
|
||
success: function(res) {
|
||
if (res.confirm) {
|
||
that.$u.put(`/app/complaint/platform?id=${that.id}`).then((res) => {
|
||
if (res.code == 200) {
|
||
uni.showToast({ title:'申请成功', icon:'success',duration:3000})
|
||
that.getxq()
|
||
}else{
|
||
uni.showToast({ title:res.msg, icon:'none',duration:3000});
|
||
}
|
||
})
|
||
}
|
||
}
|
||
})
|
||
},
|
||
// 获取七牛云上传token
|
||
getqiniuyun(){
|
||
this.$u.get("/common/qiniuToken").then((res) => {
|
||
if (res.code == 200) {
|
||
this.token = res.token
|
||
}
|
||
})
|
||
},
|
||
// 点击放大查看图片
|
||
ClickImage(PhotoAddress, index) {
|
||
uni.previewImage({
|
||
urls: PhotoAddress, //需要预览的图片http链接列表
|
||
current: index, // 当前显示图片的http链接,默认是第一个
|
||
success: function(res) {},
|
||
fail: function(res) {},
|
||
complete: function(res) {},
|
||
})
|
||
},
|
||
// 获取订单详情
|
||
getxq(){
|
||
this.$u.get(`/app/complaint/detail?id=${this.id}&showMsg=true&showOrder=true`).then((res) => {
|
||
if (res.code == 200) {
|
||
this.xqobj = res.data || {}
|
||
this.zsimg = res.data.picture ? res.data.picture.split(',').filter(Boolean) : []
|
||
let list = res.data.msgList
|
||
if (!Array.isArray(list) || list.length === 0) {
|
||
const init = []
|
||
// 系统提交提示
|
||
if (this.xqobj && (this.xqobj.status == 1 || this.xqobj.status == '1')) {
|
||
init.push({ id: 'sys-submit', type: 3, content: '投诉申请已提交', createTime: this.xqobj.createTime })
|
||
}
|
||
// 首条用户投诉内容
|
||
// if (this.xqobj && this.xqobj.content) {
|
||
// init.push({ id: 'init-user', type: 1, content: this.xqobj.content, picture: this.xqobj.picture, createTime: this.xqobj.createTime, sendName: this.xqobj.userName })
|
||
// }
|
||
list = init
|
||
}
|
||
this.msgList = list
|
||
}
|
||
})
|
||
},
|
||
|
||
toggleExpand(){
|
||
this.expanded = !this.expanded
|
||
},
|
||
// 继续申诉
|
||
onContinue(){
|
||
this.showContinue = true
|
||
},
|
||
// 选择图片
|
||
pickImages() {
|
||
let _this = this
|
||
let math = 'static/' + _this.$u.guid(20)
|
||
uni.chooseImage({
|
||
count: 4 - this.images.length,
|
||
sizeType: ['compressed'],
|
||
sourceType: ['album', 'camera'],
|
||
success(res) {
|
||
const tempFilePaths = res.tempFilePaths[0]
|
||
wx.uploadFile({
|
||
url: 'https://up-z2.qiniup.com',
|
||
name: 'file',
|
||
filePath: tempFilePaths,
|
||
formData: {
|
||
token: _this.token, //后端返回的token
|
||
key: 'smartmeter/img/' + math
|
||
},
|
||
success: function(res) {
|
||
console.log(res, 'resres');
|
||
let str = JSON.parse(res.data)
|
||
let tempFilePaths = 'https://api.ccttiot.com/' + str.key
|
||
_this.images.push(tempFilePaths)
|
||
console.log(_this.images);
|
||
}
|
||
})
|
||
}
|
||
})
|
||
},
|
||
removeImage(index){
|
||
this.images.splice(index,1)
|
||
},
|
||
submitContinue(){
|
||
let img = this.images.join(',')
|
||
let data = {
|
||
complaintId:this.id,
|
||
content:this.continueText,
|
||
picture:img
|
||
}
|
||
this.$u.put(`/app/complaint/continue`,data).then((res) => {
|
||
if (res.code == 200) {
|
||
uni.showToast({ title:'已提交', icon:'success',duration:3000})
|
||
this.getxq()
|
||
this.showContinue = false
|
||
this.continueText = ''
|
||
this.images = []
|
||
}else{
|
||
uni.showToast({ title:res.msg, icon:'none',duration:3000})
|
||
}
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.page{ max-height: 99999rpx;
|
||
padding-bottom: 20vh;}
|
||
.card{ background:#fff; border-radius:0 0 16rpx 16rpx; padding: 20rpx 24rpx;box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.04); }
|
||
.row{ display:flex; }
|
||
.between{ justify-content: space-between; }
|
||
.center{ align-items: center; }
|
||
|
||
/* header */
|
||
.label{ font-size: 28rpx; color:#111; font-weight: 600; }
|
||
.right-actions{ gap: 16rpx; }
|
||
.status .dot{ width: 18rpx; height: 18rpx; border-radius: 50%; background:#4C97E7; margin-right: 8rpx; }
|
||
.status-text{ color:#4C97E7; font-size: 24rpx; }
|
||
.toggle{ margin-left: 20rpx; display:flex; align-items:center; }
|
||
.toggle-text{ color:#9EA3AA; font-size: 24rpx; }
|
||
.arrow{ width: 0; height: 0; border-left: 10rpx solid transparent; border-right: 10rpx solid transparent; border-top: 12rpx solid #9EA3AA; margin-left: 8rpx; transform: rotate(0deg); transition: transform .2s ease; }
|
||
.arrow.up{ transform: rotate(180deg); }
|
||
|
||
/* 详情(可折叠) */
|
||
.collapsible{ overflow: hidden; transition: all .24s ease; }
|
||
.collapsed{ height: 0; padding-top: 0; padding-bottom: 0; margin-top: 0; box-shadow: none; }
|
||
.info .item{ display:flex; justify-content: space-between; padding: 18rpx 0; border-bottom: 1rpx solid #F2F3F5; }
|
||
.info .item:last-child{ border-bottom: none; }
|
||
.item-label{ color:#666; font-size: 26rpx; }
|
||
.item-value{ color:#111; font-size: 26rpx; }
|
||
.emphasis{ color:#111; font-weight: 700; }
|
||
.proof{ align-items: center; }
|
||
.proof-box{ width: 140rpx; height: 140rpx; background:#EDEFF2; border-radius: 8rpx; }
|
||
|
||
/* 提交卡片 */
|
||
.submit-card{ padding: 20rpx 24rpx; }
|
||
.check-icon{ width: 36rpx; height: 36rpx; border-radius: 50%; background:#E6F6EC; display:flex; align-items:center; justify-content:center; }
|
||
.check-icon.solid{ background:#4C97E7; }
|
||
.check{ color:#4C97E7; font-size: 24rpx; }
|
||
.check.inverse{ color:#fff; }
|
||
.submit-title{ margin-left: 12rpx; color:#111; font-weight: 600; font-size: 28rpx; }
|
||
.submit-sub{ display:block; margin-top: 8rpx; color:#9EA3AA; font-size: 24rpx; }
|
||
|
||
/* 对话区 */
|
||
.chat{ padding: 0 20rpx; padding-top: 20rpx;}
|
||
.from{ color:#9EA3AA; font-size: 22rpx; margin: 16rpx 0 2rpx 0; }
|
||
.from.right{ text-align: right; }
|
||
.name{ color:#9EA3AA; font-size: 22rpx; margin: 16rpx 0 2rpx 0; }
|
||
.name.right{ text-align: right; }
|
||
.name.user{ color:#4C97E7; }
|
||
.name.merchant{ color:#333; }
|
||
.chat-row{ align-items:flex-end; margin-top: 8rpx; }
|
||
.right-row{ justify-content:flex-end; }
|
||
.person{ display:flex; flex-direction: column; align-items:center; gap: 6rpx; }
|
||
.person.left{ margin-right: 12rpx; }
|
||
.person.right{ margin-left: 12rpx; }
|
||
.avatar{ width: 60rpx; height: 60rpx; border-radius: 50%; margin: 0 12rpx; }
|
||
.avatar.user{ background:#D7EEE2; }
|
||
.avatar.merchant{ background:#E6E8EB; }
|
||
.bubble{ max-width: 84%; padding: 16rpx 20rpx; border-radius: 16rpx; margin: 8rpx 0; font-size: 28rpx; line-height: 1.7; }
|
||
.bubble.left.merchant{ background:#fff; border: 1rpx solid #ECEDEF; }
|
||
.bubble.right.user{ background:#E6F6EC; color:#4C97E7; }
|
||
.time{ color:#9EA3AA; font-size:22rpx; margin-top: 10rpx; }
|
||
.time.right{ text-align: right; }
|
||
/* 角色小标签 */
|
||
.role-tag{ color:#666; }
|
||
.role-tag.user{ color:#4C97E7; }
|
||
.role-tag.merchant{ color:#333; }
|
||
/* 系统消息居中 pill */
|
||
.sys{ display:flex; flex-direction: column; align-items:center; margin: 18rpx 0; }
|
||
.sys .pill{ background:#F3F4F6; color:#666; font-size: 24rpx; padding: 10rpx 16rpx; border-radius: 40rpx; max-width: 84%; text-align:center; }
|
||
.sys-time{ color:#B0B5BB; font-size: 22rpx; margin-top: 8rpx; text-align:center; }
|
||
|
||
/* 退款条 */
|
||
.refund-row{ display:flex; align-items:center; padding: 24rpx 0; border-bottom:1rpx solid #F2F3F5; }
|
||
.refund-text{ color:#111; font-weight:600; font-size:28rpx; margin-left: 12rpx; }
|
||
.refund-link{ margin-left:auto; color:#4C97E7; font-size:24rpx; margin-right: 6rpx; }
|
||
.chev{ color:#C0C4CC; font-size: 36rpx; line-height: 1; }
|
||
.refund-amount{ display:flex; align-items:center; padding-top: 18rpx; font-size:26rpx; color:#666; }
|
||
.refund-amount .emphasis{ color:#111; margin: 0 8rpx; font-weight: 700; }
|
||
.light-text{ color:#9EA3AA; }
|
||
|
||
/* 底部按钮 */
|
||
.footer{ position: fixed; left: 0; right: 0; bottom: 0; background:#fff; box-shadow: 0 -6rpx 16rpx rgba(0,0,0,0.06);padding-top: 30rpx;height: 240rpx;}
|
||
.primary{ background:#4C97E7; color:#fff; border-radius: 12rpx; height: 88rpx; line-height: 88rpx; font-size: 30rpx; width: 88%; }
|
||
|
||
/* 弹窗 */
|
||
.modal-mask{ position: fixed; left:0; right:0; top:0; bottom:0; background: rgba(0,0,0,.45); display:flex; align-items:flex-end; z-index: 9999; }
|
||
.modal-panel{ width: 100%; background:#fff; border-radius: 16rpx 16rpx 0 0; }
|
||
.popup-wrap{ background:#fff; border-radius: 16rpx 16rpx 0 0; padding-bottom: env(safe-area-inset-bottom); }
|
||
.popup-header{ position: relative; padding: 24rpx; border-bottom: 1rpx solid #F0F1F3; text-align: center; }
|
||
.popup-title{ font-size: 30rpx; color:#111; font-weight: 600; }
|
||
.popup-close{ position: absolute; right: 24rpx; top: 20rpx; font-size: 40rpx; color:#9EA3AA; }
|
||
.popup-body{ padding: 20rpx 24rpx; }
|
||
.textarea-box{ position: relative; background:#fff; border-bottom: 1rpx solid #F0F1F3; min-height: 180rpx; }
|
||
.textarea-box textarea{ width: 100%; min-height: 160rpx; font-size: 28rpx; padding: 12rpx 0; }
|
||
.ph{ color:#B6BCC3; }
|
||
.count{ position: absolute; right: 0; bottom: 8rpx; color:#B6BCC3; font-size: 22rpx; }
|
||
.uploader{ display: flex; flex-wrap: wrap; gap: 16rpx; margin-top: 20rpx; }
|
||
.upload-item{ width: 140rpx; height: 140rpx; border-radius: 8rpx; position: relative; overflow: hidden; background:#fff; }
|
||
.upload-item image{ width: 140rpx; height: 140rpx; }
|
||
.upload-item.add{ display:flex; align-items:center; justify-content:center; color:#B6BCC3; font-size: 48rpx; }
|
||
.upload-item .del{ position:absolute; right: 6rpx; top: 6rpx; width: 36rpx; height: 36rpx; line-height: 36rpx; text-align:center; border-radius: 50%; background: rgba(0,0,0,.45); color:#fff; font-size: 26rpx; }
|
||
.tip{ display:block; color:#9EA3AA; font-size: 22rpx; margin-top: 8rpx; }
|
||
.popup-footer{ padding: 16rpx 24rpx 46rpx; }
|
||
.sqpt{width: 100%;text-align: center;color: #4C97E7;margin-top: 30rpx;}
|
||
</style> |