This commit is contained in:
Eudemon 2025-03-17 20:54:23 +08:00
parent 0b72cc1c17
commit 797660f0bc
5 changed files with 253 additions and 27 deletions

View File

@ -18,8 +18,42 @@ const api = {
bindWithdrawAccountUrl: ipConfig.api_app + "/user/bindwithdrawaccount", bindWithdrawAccountUrl: ipConfig.api_app + "/user/bindwithdrawaccount",
saveUinfo: ipConfig.api_app + "/fbclick/saveInfo", saveUinfo: ipConfig.api_app + "/fbclick/saveInfo",
getFbInfo: ipConfig.api_app + "/fbclick/getFbInfo", getFbInfo: ipConfig.api_app + "/fbclick/getFbInfo",
getQuestions: ipConfig.api_app + "/customer/get",
questionFail: ipConfig.api_app + "/customer/fail",
questionSuccess: ipConfig.api_app + "/customer/success",
questionIndex: ipConfig.api_app + "/customer/index",
} }
export const getQuestionsApi = (id = 0) => {
return httpRequest.post({
url: api.getQuestions,
data: {
languageType: 'EN',
questionId: id
}
})
}
export const questionFailApi = (params) => {
return httpRequest.post({
url: api.questionFail,
data: params
})
}
export const questionSuccessApi = (params) => {
return httpRequest.post({
url: api.questionSuccess,
data: params
})
}
export const questionIndexApi = (id = '') => {
return httpRequest.post({
url: api.questionIndex,
data: {
questionId: id,
languageType: 'EN'
}
})
}
export const getFbInfoApi = () => { export const getFbInfoApi = () => {
return httpRequest.get({ return httpRequest.get({
url: api.getFbInfo, url: api.getFbInfo,

View File

@ -27,7 +27,7 @@
</el-container> </el-container>
</el-container> --> </el-container> -->
<slot></slot> <slot></slot>
<view <view v-if="showCustomer"
class="service-icon" class="service-icon"
style="width: 50px; height: 50px;" style="width: 50px; height: 50px;"
:style="{ 'bottom': serviceIconXY.bottom + 'px', 'left': serviceIconXY.x + 'px' }" :style="{ 'bottom': serviceIconXY.bottom + 'px', 'left': serviceIconXY.x + 'px' }"
@ -66,6 +66,10 @@
bgColor: { bgColor: {
type: String, type: String,
default: 'transparent' default: 'transparent'
},
showCustomer: {
type: Boolean,
default: true
} }
}) })
const appStore = useAppStore() const appStore = useAppStore()

View File

@ -16,11 +16,15 @@ defineProps({
paddingTop: { paddingTop: {
type: Number, type: Number,
default: 0 default: 0
},
showCustomer: {
type: Boolean,
default: true
} }
}) })
</script> </script>
<template> <template>
<common-layout :bgColor="bgColor"> <common-layout :bgColor="bgColor" :show-customer="showCustomer">
<mobile-sub-header :title="title" :headBgColor="headBgColor"> <mobile-sub-header :title="title" :headBgColor="headBgColor">
<template #right> <template #right>
<slot name="head-right"></slot> <slot name="head-right"></slot>

View File

@ -182,7 +182,8 @@ export default {
toast: { toast: {
phone: "The phone number cannot be empty" phone: "The phone number cannot be empty"
} }
} },
contact: 'Contact Customer Service'
}, },
} }

View File

@ -1,45 +1,136 @@
<script setup> <script setup>
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useThemeStore } from "@/store/useThemeStore"; import { useThemeStore } from "@/store/useThemeStore";
import { useAppStore } from '@/store/useAppStore' import { useAppStore } from '@/store/useAppStore'
import { getQuestionsApi, questionIndexApi } from '@/api/account'
import { openUrl } from '@/module/utils/openUrl'
const themeStore = useThemeStore() const themeStore = useThemeStore()
const appStore = useAppStore() const appStore = useAppStore()
const scrollHeight = computed(() => { const scrollHeight = computed(() => {
return appStore.windowInfo.screenHeight - appStore.windowInfo.statusBarHeight - 50 return appStore.windowInfo.screenHeight - appStore.windowInfo.statusBarHeight - 50
}) })
const questions = ref([ const lastId = ref('')
{ const questions = ref([])
id: 1,
question: 'What is the capital of France?',
},
{
id: 2,
question: 'Which planet is known as the Red Planet?',
},
{
id: 3,
question: 'What is the largest mammal in the world?',
}
])
const inputVal = ref('') const inputVal = ref('')
const faqs = ref([])
function genId() {
return '' + Date.now() + Math.ceil(Math.random() * 100000);
}
function newMsg(msg, type, mtype) {
const id = genId()
faqs.value.push({
id,
msg,
type,
mtype
})
lastId.value = ''
setTimeout(() => {
lastId.value = id
}, 200);
}
const defaultAnswer = () => {
newMsg('I\'m unable to answer your question. Please click the online customer service at the top right corner.', 2, 'msg')
}
const questionClick = (item) => {
if (item.type === 2) {
newMsg(item.display, 1, 'msg')
questionIndexApi(item.id).then(({ data }) => {
console.log('getQuestionsApi', data);
if (!data || !data?.data) {
defaultAnswer()
} else {
const _data = JSON.parse(data?.data)
if (Array.isArray(_data)) {
newMsg(_data, 2, 'list')
} else {
newMsg(_data, 2, 'msg')
}
}
})
return
}
if (item.type === 6) {
return
}
if (item.type === 7) {
openUrl(appStore.FAQ)
return
}
}
const getQustionList = async () => {
const { data } = await questionIndexApi()
console.log("getQuestionsApi:", data);
const _data = JSON.parse(data?.data)
questions.value = _data
}
onLoad(() => {
getQustionList()
})
</script> </script>
<template> <template>
<mobile-custom-layout title="Self-service Customer" bgColor="#2F0101" <mobile-custom-layout title="Self-service Customer" bgColor="#2F0101" :headBgColor="themeStore.theme.bgColor"
:headBgColor="themeStore.theme.bgColor" :paddingTop="appStore.headerStyle.height"> :paddingTop="appStore.headerStyle.height" :show-customer="false">
<template #head-right> <template #head-right>
<view> <view>
<theme-image src="@/static/account/customer_head.png" class="icon-kf-head"></theme-image> <theme-image src="@/static/account/customer_head.png" class="icon-kf-head"></theme-image>
</view> </view>
</template> </template>
<scroll-view scroll-y class="w-full p-2 scroll" :style="{ height: scrollHeight + 'px' }"> <scroll-view scroll-y class="w-full p-2 scroll" :style="{ height: scrollHeight + 'px' }"
12 :scroll-into-view="'t_' + lastId">
<view class="w-full question-list">
<view class="w-full question-content">
<view v-for="item in questions" :key="item.id" @click="questionClick(item)"
class="flex items-center question-item">
<view class="dot"></view>
<view class="question-text" v-if="item.type === 1">
<rich-text :nodes="item.text"></rich-text>
</view>
<view class="question-text" v-else>
{{ item.display }}
</view>
</view>
<view class="flex items-center justify-center online-service">
<theme-image src="@/static/account/customer.png" class="icon-kf"></theme-image>
<view class="btn-txt">{{ $t('account.contact') }}</view>
</view>
</view>
</view>
<view v-for="item in faqs" :key="item.id" :id="'t_' + item.id" class="w-full flex msg-item"
:class="[item.type === 1 ? 'req-right' : 'req-left']">
<theme-image v-if="item.type === 1" src="@/static/icon-avatar.png" class="icon-avatar"
style="margin-left: 10rpx;"></theme-image>
<theme-image v-else src="@/static/account/customer.png" class="icon-avatar"
style="margin-right: 10rpx;"></theme-image>
<view class="msg-text" :class="[item.type === 1 ? 'mr-10' : 'ml-10']">
<template v-if="item.mtype === 'msg'">
{{ item.msg }}
</template>
<template v-else>
<view v-for="child in item.msg" :key="child.id" @click="questionClick(child)"
class="flex items-center question-item" :style="{paddingLeft: child.type === 2 ? '24rpx' : '0px'}">
<view class="dot" v-if="child.type === 2"></view>
<view class="question-text" v-if="child.type === 1">
<rich-text :nodes="child.text"></rich-text>
</view>
<view class="question-text" v-else>
{{ child.display }}
</view>
</view>
</template>
</view>
</view>
<empty-hold height="120rpx"></empty-hold>
</scroll-view> </scroll-view>
<view class="w-full input-line safe-area"> <view class="w-full input-line safe-area">
<view class="w-full flex items-center input-content"> <view class="w-full flex items-center input-content">
<view class="flex-1 p-1 input-box"> <view class="flex-1 p-1 input-box">
<input type="text" v-model="inputVal" class="w-full ft12" placeholder="Please enter your question" /> <input type="text" v-model="inputVal" class="w-full ft12"
placeholder="Please enter your question" />
</view> </view>
<view class="submit-btn ml-2 ft13 flex-center">Send</view> <view class="submit-btn ml-2 ft13 flex-center">Send</view>
</view> </view>
@ -47,13 +138,104 @@ const inputVal = ref('')
</mobile-custom-layout> </mobile-custom-layout>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
::-webkit-scrollbar {
display: none;
width: 0;
}
.scroll { .scroll {
box-sizing: border-box; box-sizing: border-box;
.question-list {
padding: 20rpx 100rpx;
.question-content {
padding: 18rpx 24rpx;
border-radius: 16rpx;
background-color: #58070D;
.online-service {
margin-top: 20rpx;
width: 100%;
height: 80rpx;
border-radius: 14rpx;
background: linear-gradient(180deg, #6F0000 0%, #580000 100%);
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.5);
.icon-kf {
width: 54rpx;
height: 54rpx;
} }
.btn-txt {
margin-left: 12rpx;
font-size: 30rpx;
color: #E2A1A9;
}
}
}
}
.question-item {
padding: 14rpx 0;
.dot {
width: 10rpx;
height: 10rpx;
border-radius: 50%;
background-color: #E2A1A9;
flex-shrink: 0;
}
.question-text {
margin-left: 12rpx;
color: #E2A1A9;
font-size: 24rpx;
}
}
.msg-item {
align-items: start;
margin-top: 60rpx;
justify-content: flex-start;
.icon-avatar {
width: 54rpx;
height: 54rpx;
}
}
.req-right {
flex-direction: row-reverse;
}
.req-left {
flex-direction: row;
}
.msg-text {
max-width: 520rpx;
padding: 12rpx;
border-radius: 12rpx;
background-color: #59070D;
font-size: 26rpx;
color: #E2A1A9;
}
.mr-10 {
margin-left: 10rpx;
}
.ml-10 {
margin-right: 10rpx;
}
}
.icon-kf-head { .icon-kf-head {
width: 46rpx; width: 46rpx;
height: 46rpx; height: 46rpx;
} }
.input-line { .input-line {
position: fixed; position: fixed;
bottom: 0; bottom: 0;
@ -70,6 +252,7 @@ const inputVal = ref('')
background-color: #5A0107; background-color: #5A0107;
border-radius: 4px; border-radius: 4px;
} }
.submit-btn { .submit-btn {
height: 56rpx; height: 56rpx;
width: 100rpx; width: 100rpx;