You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

686 lines
14 KiB

<template>
<view class="main">
<view class="top" :style="{height:iSMT+'px'}"></view>
<!-- 头部导航 -->
<view class="header">
<view class="back-icon">
<image @click="onBack" src="/static/customer-service-platform/cs-platform-back.png"
class="header-icon-image"></image>
</view>
<view class="title">{{headerTitle}}</view>
<view class="notification-icon">
<image src="/static/customer-service-platform/message.png" class="header-icon-image"></image>
</view>
</view>
<!-- 内容区域 - 使用滚动视图 -->
<scroll-view scroll-y class="content-container">
<view class="content-header">
<view class="content-header-area">
<view class="logo">
<image mode="aspectFit" src="/static/customer-service-platform/ellipse-dc-img.png"></image>
</view>
<view class="greeting">
<text class="greet-title">我能为你做点什么</text>
<text class="greet-sub">DeepChart随时为您提供服务</text>
</view>
</view>
</view>
<!--猜你想问卡片部分-->
<view class="card">
<view class="suggest-header">
<text class="suggest-title">猜你想问</text>
<view class="swap" @click="getQuestionList()">
<image class="swap-icon" src="/static/customer-service-platform/refresh-icon.png"></image>
<text class="swap-title">换一换</text>
</view>
</view>
<view class="card-line"></view>
<view class="suggest-list">
<view class="suggest-item" v-for="(q, idx) in showQuestions" :key="idx" @click="onQuestionClick(q)">
<view class="left">
<view :class="['num', 'num-' + ((idx % 5) + 1)]">{{ idx + 1 }}</view>
<text class="q-text">{{ q }}</text>
</view>
<view class="right">
<text class="arrow">›</text>
</view>
</view>
</view>
</view>
<!--反馈卡片部分-->
<text class="feedback-card-title">反馈中心</text>
<view class="card">
<view class="suggest-header">
<text class="feedback-title">填写反馈内容</text>
</view>
<view class="card-line"></view>
<textarea class="feedback-input" placeholder="请描述您想反馈的内容 最多可输入200字" maxlength="200"
v-model="feedbackText" />
<view class="meta-row">
<text class="char-count">{{ feedbackText.length }}/200</text>
</view>
<view class="suggest-header">
<text class="upload-img-tip">上传图片</text>
</view>
<view class="upload-row">
<view class="img-slot" v-for="(img, index) in images" :key="index">
<image :src="img" mode="scaleToFill" class="slot-img" />
<button v-if="img" class="remove" @click="removeImage(index)">×</button>
</view>
<view class="img-slot" v-if="images.length < 3">
<view class="slot-empty" @click="chooseImage()">
<image src="/static/customer-service-platform/camera.png" class="camera-icon" />
</view>
</view>
<text class="tip-text" v-if="images.length === 0">最多添加3张图片</text>
</view>
<button class="feedback-btn" @click="onSumbitFeedback()">提交</button>
<feedback-modal ref="feedback" @confirm="onConfirm" />
</view>
<!--历史反馈卡片部分-->
<view class="card">
<text class="feedback-title">历史反馈内容</text>
<view class="card-line"></view>
<button class="feedback-btn" @click="viewHistory">查看</button>
</view>
</scroll-view>
</view>
</template>
<script>
import {
getQuestionApi,
addFeedbackRecordApi,
uploadImageApi
} from "../../api/customerServicePlatform/customerServicePlatform";
import FeedbackModal from '@/components/FeedbackModal.vue'
export default {
components: {
FeedbackModal
},
data() {
return {
headerTitle: '智能客服中台',
iSMT: 0,
questions: [
"DeepChart 有免费功能和付费功能的区分吗?具体有哪些?",
"如何参与平台的用户反馈活动?反馈的问题会被采纳吗?",
"我的自选股最多能添加多少只?能否按市场分类管理?",
"注册时必须提供手机号 / 邮箱吗?能否匿名使用?",
"忘记登录密码了,如何找回?",
'如何注册账号?',
'为什么无法注册账户?'
],
showQuestions: [],
feedbackText: '',
images: [],
}
},
mounted() {
// 状态栏高度
this.iSMT = uni.getSystemInfoSync().statusBarHeight;
this.getQuestionList()
},
created() {
},
methods: {
onSuccess() {
this.$refs.feedback.show({
status: 'success',
title: '提交成功',
subtitle: '— 感谢您的反馈 —',
buttonText: '确定',
width: '80%',
});
},
onFail() {
this.$refs.feedback.show({
status: 'fail',
title: '提交失败',
subtitle: '— 请重新提交 —',
buttonText: '确定',
width: '80%',
});
},
onBack() {
if (typeof uni !== 'undefined') uni.navigateBack();
},
async getQuestionList() {
const res = await getQuestionApi()
console.log(res)
if (res.code == 200) {
this.showQuestions = res.data
}
},
onQuestionClick(q) {
if (typeof uni !== 'undefined') uni.navigateTo({
url: `/pages/customerServicePlatform/questionDetail?question=${encodeURIComponent(q)}`
});
},
chooseImage() {
const that = this;
if (typeof uni === 'undefined' || !uni.chooseImage) return;
const remain = 3 - (that.images ? that.images.length : 0);
if (remain <= 0) {
if (typeof uni !== 'undefined') uni.showToast({
title: '最多只能上传3张',
icon: 'none'
});
return;
}
uni.chooseImage({
count: remain,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const paths = res.tempFilePaths || (res.tempFiles && res.tempFiles.map(f => f.path)) || [];
for (let p of paths) {
if (that.images.length < 3) {
that.images.push(p);
}
}
},
fail(err) {
uni.showToast({
title: `选择图片失败`,
icon: 'none'
});
}
});
},
removeImage(index) {
// 删除并保持响应
this.images.splice(index, 1);
},
async onSumbitFeedback() {
if (!this.feedbackText.trim()) {
if (typeof uni !== 'undefined') uni.showToast({
title: '请填写反馈内容',
icon: 'none'
});
return;
}
if (typeof uni !== 'undefined') uni.showLoading({
title: '提交中...'
});
try {
let uploadedImages = [];
let imgFlag = true
for (let i = 0; i < this.images.length; i++) {
const f = this.images[i];
await new Promise((resolve, reject) => {
uni.getImageInfo({
src: f,
success: () => resolve(),
fail: reject
});
});
const uploadRes = await new Promise((resolve, reject) => {
uni.uploadFile({
url: 'http://39.101.133.168:8828/hljw/api/aws/upload',
filePath: f,
name: 'file',
formData: {
dir: 'deepchart'
},
success: (res) => {
try {
const data = JSON.parse(res.data);
if (data.code === 200) {
uploadedImages.push(data.data.url);
resolve(data);
} else {
uni.showToast({
title: `${i + 1}张图片上传失败`,
icon: 'none'
});
imgFlag = false;
reject(data);
}
} catch (err) {
imgFlag = false;
reject(err);
}
},
fail: (err) => {
imgFlag = false;
uni.showToast({
title: `${i + 1}张图片上传失败`,
icon: 'none'
});
reject(err);
}
});
});
}
if (!imgFlag) {
return
}
const [image1 = '', image2 = '', image3 = ''] = uploadedImages;
const res = await addFeedbackRecordApi({
token: "a1bef735d336831ccb0cc3f532093b60",
content: this.feedbackText,
image1,
image2,
image3
})
if (res.code == 200) {
this.onSuccess()
} else {
this.onFail()
}
} catch {
this.onFail()
} finally {
uni.hideLoading();
this.feedbackText = '';
this.images = [];
}
},
viewHistory() {
// 跳转到历史页
if (typeof uni !== 'undefined') uni.navigateTo({
url: '/pages/customerServicePlatform/historyRecord'
});
}
}
}
</script>
<style scoped>
.main {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #ffffff;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 30rpx;
background-color: #ffffff;
}
.title {
color: #000000;
text-align: center;
font-size: 32rpx;
font-style: normal;
font-weight: 400;
}
.back-icon,
.notification-icon {
width: 40rpx;
display: flex;
align-items: center;
justify-content: center;
}
.header-icon-image {
width: 40rpx;
height: 40rpx;
object-fit: contain;
}
.content-container {
padding: 20rpx;
width: 100%;
box-sizing: border-box;
overflow-x: hidden;
}
.content-header {
display: flex;
align-items: center;
justify-content: center;
gap: 24rpx;
padding: 0 60rpx;
width: 100%;
box-sizing: border-box;
height: 188rpx;
}
.content-header-area {
display: flex;
gap: 20rpx;
}
.logo {
width: 120rpx;
height: 120rpx;
display: flex;
align-items: center;
justify-content: center;
flex: 0 0 112rpx;
}
.greeting {
display: flex;
flex-direction: column;
justify-content: center;
flex: 1 1 auto;
}
.greet-title {
color: #000;
font-size: 40rpx;
font-style: normal;
font-weight: 500;
line-height: normal;
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.greet-sub {
color: #838383;
font-size: 28rpx;
font-style: normal;
font-weight: 400;
line-height: normal;
margin-top: 12rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card {
width: 90%;
margin: 0 auto;
border-radius: 16rpx;
padding: 20rpx 40rpx;
box-sizing: border-box;
border-radius: 12rpx;
border: 4rpx solid #FCC8D4;
background: linear-gradient(180deg, #FCC8D3 0%, #FEF0F3 30%, #FFF 100%);
margin-bottom: 20rpx;
}
.suggest-header {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.suggest-title {
color: #000000;
font-size: 32rpx;
font-style: normal;
font-weight: 400;
line-height: normal;
}
.swap {
display: flex;
align-items: center;
transition: transform 0.1s ease, background-color 0.1s ease;
}
.swap:active {
transform: scale(0.95);
}
.swap-icon {
width: 30rpx;
height: 30rpx;
}
.swap-title {
padding-left: 8rpx;
color: #000000;
font-size: 24rpx;
font-style: normal;
font-weight: 400;
line-height: normal;
}
.suggest-list {
margin-top: 20rpx;
}
.card-line {
margin-top: 20rpx;
width: 100%;
height: 2rpx;
border-radius: 2rpx;
background: #FFF;
}
.suggest-item {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 10rpx;
border-radius: 12rpx;
margin-bottom: 20rpx;
width: 100%;
box-sizing: border-box;
}
.left {
width: 90%;
display: flex;
align-items: center;
}
.num {
font-size: 40rpx;
font-style: normal;
font-weight: 700;
line-height: normal;
}
.num-1 {
color: #df5662;
}
.num-2 {
color: #ec6d4f;
}
.num-3 {
color: #f3ba40;
}
.num-4 {
color: #9296a0;
}
.num-5 {
color: #9296a0;
}
.q-text {
padding-left: 14rpx;
display: block;
color: #333;
font-size: 28rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.right {
width: 48rpx;
display: flex;
align-items: center;
justify-content: flex-end;
}
.arrow {
color: #cfcfcf;
font-size: 36rpx;
}
.suggest-item:active {
background: rgba(255, 77, 128, 0.06);
}
.feedback-card-title {
display: flex;
justify-content: center;
color: #000000;
font-size: 32rpx;
font-weight: 700;
line-height: 40rpx;
width: 100%;
margin-bottom: 20rpx;
}
.feedback-title {
color: #000000;
font-size: 32rpx;
font-style: normal;
font-weight: 400;
line-height: normal;
}
.feedback-input {
width: 100%;
display: flex;
padding: 20rpx;
flex-direction: column;
box-sizing: border-box;
align-items: flex-start;
gap: 12rpx;
align-self: stretch;
border-radius: 12rpx;
border: 2rpx solid #F0F1F1;
margin-top: 20rpx;
display: flex;
background: #FFF;
color: #8a8a8a;
font-size: 24rpx;
font-weight: 700;
line-height: normal;
}
.meta-row {
display: flex;
justify-content: flex-end;
margin-top: 12rpx;
}
.char-count {
color: #999
}
.upload-img-tip {
color: #000000;
font-size: 24rpx;
font-style: normal;
font-weight: 400;
line-height: normal;
}
.upload-row {
display: flex;
justify-content: flex-start;
align-items: flex-start;
align-content: flex-start;
flex-wrap: wrap;
gap: 20rpx;
margin-top: 20rpx;
width: 100%;
}
.img-slot {
width: calc((100% - 2 * 30rpx) / 3);
aspect-ratio: 1 / 1;
border-radius: 6px;
border: 1px solid #F0F1F1;
background: #FFF;
position: relative;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
transition: transform 0.2s ease;
}
.slot-empty {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.camera-icon {
width: 34rpx;
height: 34rpx;
}
.slot-img {
width: 100%;
height: 100%;
border-radius: 16rpx;
}
.remove {
position: absolute;
right: 6rpx;
top: 6rpx;
border-radius: 50%;
background: #fd5c58;
padding: 0;
color: #fff;
width: 36rpx;
height: 36rpx;
font-size: 28rpx;
line-height: 36rpx;
text-align: center;
border: none;
outline: none;
cursor: pointer;
}
.remove:active {
background: rgba(0, 0, 0, 0.75);
}
.image-upload-tip {
display: flex;
align-items: center;
}
.tip-text {
color: #999999;
font-size: 24rpx;
font-style: normal;
font-weight: 400;
line-height: 40rpx;
padding-top: 64rpx;
}
.feedback-btn {
margin-top: 24rpx;
width: 180rpx;
height: 60rpx;
aspect-ratio: 89/30;
border-radius: 30rpx;
background: #090A08;
color: #ffffff;
display: flex;
justify-content: center;
align-items: center;
font-size: 32rpx;
font-style: normal;
font-weight: 700;
line-height: normal;
}
</style>