shop_app/pages/mine/msg/complaint.vue

483 lines
11 KiB
Vue
Raw Permalink Normal View History

2025-05-08 09:16:37 +08:00
<template>
<view class="whole">
<view class="tips" :style="{color: Color}">此投诉为本小程序自有投诉渠道非微信官方投诉渠道</view>
<view class="oneBox">
<view class="row">
<view class="span">补充描述<text>*</text></view>
<view class="pad20">
<up-textarea v-model="desc" count placeholder="补充描述" style="font-size: 28rpx;" :height="70" :maxlength="500"></up-textarea>
</view>
</view>
<view class="row">
<view class="span">联系电话<text>*</text></view>
<view class="pad20">
<input class="input" type="text" v-model="mobile" placeholder="请输入您的联系方式" />
</view>
</view>
<view class="orderBox row" v-if="type == 1">
<view class="span">相关订单</view>
<view class="cont flex" @click="showOrder = true">
<view v-if="order_sn">
<view class="tit">{{order_sn}}</view>
<text>{{goods_name}}</text>
</view>
<view class="tit" v-else>请选择订单</view>
<up-icon name="arrow-right" />
</view>
</view>
<view class="row">
<view class="span">图片凭证选填</view>
<view class="upImg">
<view class="hasimg" v-for="(item, index) in imgList" :key="index">
<image :src="item" class="img" mode="aspectFill"></image>
<view class="icon flexc" @click="delUpImg(item, index)"><up-icon name="close" color="#fff" size="12" /></view>
</view>
<view class="plus flexc" @click="uploadImg()">
<up-icon name="camera-fill" color="#9D9D9D" size="24" />
<text>上传凭证</text>
</view>
</view>
</view>
<view class="btmbox flexc" @click="commitSubmit()">提交</view>
</view>
<up-popup :show="showOrder" mode="bottom" :round="10" @close="showOrder = false">
<view class="itemBox">
<view class="title">我的订单</view>
<scroll-view scroll-y="true" class="content" @scrolltolower="scorllBottom">
<view class="item" v-for="item in orderList" :key="item.id" @click="selectOrder(item)">
<view class="one flex">
<view class="no">{{item.order_sn}}</view>
<text>{{statusObj[item.status]}}</text>
</view>
<view class="two" v-for="it in item.items" :key="it.id">
<image :src="it.pic_url + '?x-oss-process=image/format,webp'" :webp="true" mode="aspectFill"></image>
<view class="cont">
<view class="tit">{{it.goods_name}}<view class="sku">{{it.sku_name}}</view></view>
<view class="btm flex">
<view class="price">{{it.price}}</view>
<text>×{{it.number}}</text>
</view>
</view>
</view>
</view>
<view class="noMore" v-if="orderList.length && page >= lastPage && !loading"> 没有更多了 </view>
<view v-if="!orderList.length && !loading">
<up-empty mode="order" icon="https://ct-upimg.yx090.com/g.ii090/images/sprite/empty/order.png" text="暂无订单"></up-empty>
</view>
<view v-if="loading" class="loadbox">
<up-loading-icon text="加载中..." textSize="14"></up-loading-icon>
</view>
</scroll-view>
</view>
</up-popup>
</view>
</template>
<script>
import { reactive, toRefs } from 'vue'
import { get, post } from '@/api/request.js'
import { showToast } from '@/components/common.js'
import { Style } from '@/utils/list.js'
import API from '/api/index'
export default {
setup() {
const data = reactive({
reason: '',
mobile: '',
desc: '',
imgList: [],
Color: uni.getStorageSync('theme_color'),
bgColor: Style[uni.getStorageSync('theme_index') * 1].bgColor,
showPrivacy: false,
order_id: 0,
order_sn: 0,
goods_name: '',
showOrder: false,
page: 1,
lastPage: 0,
orderList: [],
loading: false,
statusObj: {
'0': '待付款',
'1': '待发货',
'2': '处理中',
'3': '待收货',
'7': '已完成',
'6': '退款成功',
'8': '关闭订单',
'9': '取消订单'
},
type: 0
})
function changeDesc(e) {
data.desc = e.detail
}
// 上传图片
async function uploadImg() {
if(data.imgList.length === 5) {
showToast('最多只能添加5张图片喔')
return false
}
data.onDialog = true
uni.chooseImage({
success(res) {
const tempFilePaths = res.tempFilePaths
uni.showLoading({
title: '正在上传...',
mask: true
})
uni.uploadFile({
url: API.url + '/api/v1/upload',
filePath: tempFilePaths[0],
name: 'file',
header: {
Authorization: uni.getStorageSync('token') || '',
accept: 'application/json',
appid: API.appId
},
success(req) {
const imgUrl = JSON.parse(req.data).data.link
data.imgList.push(imgUrl)
uni.hideLoading()
data.onDialog = false
},
fail() {
uni.hideLoading()
data.onDialog = false
}
})
},
fail() {
data.onDialog = false
}
})
}
// 删除图片
function delUpImg(item, index) {
data.imgList.splice(index, 1)
}
// 确认提交
const commitSubmit = async () => {
if(!data.mobile) {
return showToast('请填写联系方式')
}
if(!data.desc) {
return showToast('请输入补充描述')
}
if(data.type == 1 && !data.order_id) {
return showToast('商品问题的投诉需选择相应订单')
}
uni.showLoading({
mask: true,
title: '正在提交'
})
let param = {
complain_type: data.type,
order_id: data.order_id,
complain_reason: data.reason,
contact_phone: data.mobile,
added_desc: data.desc,
images: data.imgList
}
if(data.type != 1) {
param.order_id = ''
}
post('/api/v1/feedback', param).then(res => {
uni.hideLoading()
uni.showToast({
title: '提交成功',
icon: 'success',
duration: 1000,
mask: true,
success() {
setTimeout(() => {
uni.navigateBack({delta: 1})
}, 1000)
}
})
}).catch(() => {
uni.hideLoading()
})
}
function getPhone() {
get('/api/v1/address/default').then(res => {
if(!Array.isArray(res.data)) {
data.mobile = res.data.mobile
}
})
}
function getOrderList() {
data.loading = true
get('/api/v1/order', {page: data.page, pageSize: 20, status: ''}).then(res => {
data.orderList = data.orderList.concat(res.data)
data.lastPage = res.meta.last_page
data.loading = false
}).catch(() => {
data.loading = false
})
}
function getOrderInfo() {
get('/api/v1/order/' + data.order_id).then(res => {
data.order_sn = res.data.order_sn
data.goods_name = res.data.items && res.data.items[0].goods_name
})
}
function scorllBottom() {
if (data.page < data.lastPage) {
data.page++
getOrderList()
}
}
function selectOrder(item) {
data.order_id = item.id
data.order_sn = item.order_sn
data.goods_name = item.items[0].goods_name
data.showOrder = false
}
return {
...toRefs(data),
changeDesc,
commitSubmit,
uploadImg,
delUpImg,
getPhone,
scorllBottom,
getOrderList,
selectOrder,
getOrderInfo
}
},
async onLoad(options) {
this.order_id = (options.order_id || 0) * 1
this.type = (options.type || 0) * 1
// await this.$onLaunched
this.getPhone()
if(this.type == 1) {
this.getOrderList()
if(this.order_id * 1) {
this.getOrderInfo()
}
}
}
}
</script>
<style lang="scss" scoped>
.whole {
background-color: #F5F5F5;
position: relative;
padding-bottom: 140rpx;
.pad20{
padding: 20rpx 0;
box-sizing: border-box;
}
.oneBox{
.row{
padding: 0 24rpx;
font-size: 28rpx;
background-color: #fff;
margin-bottom: 20rpx;
.span{
line-height: 80rpx;
font-weight: 600;
font-size: 30rpx;
position: relative;
&::after{
position: absolute;
border-bottom: 1px solid #f4f4f4;
width: calc(100% + 40rpx);
left: -20rpx;
bottom: 0;
content: '';
}
text{
font-size: 24rpx;
color: #f00;
}
}
.input{
width: 100%;
height: 64rpx;
}
.upImg{
display: flex;
flex-wrap: wrap;
width: 100%;
padding: 24rpx 0;
.hasimg{
width: 130rpx;
height: 130rpx;
margin-right: 30rpx;
margin-bottom: 30rpx;
position: relative;
.img{
width: 100%;
height: 100%;
}
.icon{
position: absolute;
top: -18rpx;
right: -18rpx;
width: 36rpx;
height: 36rpx;
background: rgba(0, 0, 0, 0.6);
border-radius: 50%;
z-index: 10;
}
}
.plus{
width: 140rpx;
height: 140rpx;
flex-direction: column;
border: 1px dashed #707070;
box-sizing: border-box;
border-radius: 6rpx;
text{
font-size: 24rpx;
color: #9D9D9D;
text-align: center;
}
}
}
}
}
.tips{
position: sticky;
top: 0;
width: 100%;
margin-bottom: 24rpx;
background: v-bind('bgColor');
font-size: 26rpx;
padding: 14rpx 0;
text-align: center;
z-index: 10;
}
.orderBox{
.cont{
padding: 18rpx 0;
.tit{
padding: 8rpx 0;
}
text{
font-size: 26rpx;
color: #9D9D9D;
}
}
}
.btmbox{
width: 94%;
height: 80rpx;
color: #fff;
background: v-bind('Color');
border-radius: 10rpx;
font-size: 30rpx;
position: fixed;
bottom: 30rpx;
left: 3%;
}
.flexc{
display: flex;
align-items: center;
justify-content: center;
}
.flex{
display: flex;
align-items: center;
justify-content: space-between;
}
}
.itemBox{
.title{
font-size: 30rpx;
font-weight: 600;
text-align: center;
line-height: 80rpx;
}
.content{
height: calc(80vh - 80rpx);
overflow: auto;
padding: 1rpx 20rpx 20rpx;
box-sizing: border-box;
background-color: #f2f2f2;
}
.item{
margin-top: 20rpx;
box-sizing: border-box;
font-size: 28rpx;
background: #fff;
padding: 0 20rpx;
border-radius: 10rpx;
.one{
line-height: 70rpx;
border-bottom: 1px solid #e8e8e8;
text{
color: #9D9D9D;
}
}
.two{
display: flex;
justify-content: space-between;
padding: 20rpx 0;
border-bottom: 1px solid #f7f7f7;
.cont{
width: calc(100% - 180rpx);
display: flex;
flex-direction: column;
justify-content: space-between;
.tit{
.sku{
font-size: 26rpx;
color: #888;
}
}
.btm{
.price{
font-size: 30rpx;
}
text{
font-size: 24rpx;
color: #9D9D9D;
}
}
}
image{
width: 160rpx;
height: 160rpx;
}
}
}
.noMore{
text-align: center;
font-size: 24rpx;
color: #999;
margin: auto;
padding: 30rpx 0;
width: 100%;
}
.loadbox{
padding: 30rpx 0;
text-align: center;
color: #666;
}
}
</style>