feat: 初始化

This commit is contained in:
George
2025-07-07 16:05:18 +08:00
commit c169958240
986 changed files with 132574 additions and 0 deletions

105
pages/contact/index.scss Normal file
View File

@ -0,0 +1,105 @@
#service-btn {
display: none;
justify-content: center;
align-items: center;
width: 56px;
height: 56px;
border-radius: 100%;
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.25);
position: fixed;
right: 16px;
bottom: 32px;
background-color: #fff;
z-index: 10009;
}
/* #ifdef APP */
#service-btn {
display: flex;
}
/* #endif */
.container {
padding: 0 16px 24px;
.swiper {
margin: 14px 0 18px;
}
.pageTitle {
margin: 14px 0 15px;
}
.banner {
width: 100%;
height: 90px;
}
.infoList {
display: flex;
flex-direction: column;
row-gap: 15px;
margin-top: 15px;
.infoCard {
position: relative;
display: flex;
flex-direction: column;
row-gap: 6px;
padding: 18px 96px 14px 18px;
min-height: 113px;
box-sizing: border-box;
box-shadow: -1px 0px 5px 1px rgba(0, 0, 0, 0.15);
.title {
font-size: 20px;
font-weight: 700;
}
.subTitle {
color: #666666;
font-size: 12px;
line-height: 17px;
}
.img {
position: absolute;
right: 12px;
bottom: 12px;
width: 46px;
height: 46px;
}
}
}
.videoListTitle {
margin-top: 28px;
margin-bottom: 15px;
font-size: 20px;
font-weight: 700;
}
.videoList {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
column-gap: 10px;
row-gap: 20px;
.videoItem {
display: flex;
flex-direction: column;
align-items: center;
row-gap: 10px;
.video {
width: 100%;
max-width: 165px;
height: 103px;
::v-deep .uni-video-bar {
padding: 0;
}
::v-deep .uni-video-control-button {
width: 10px;
}
::v-deep .uni-video-progress {
margin-left: 10px;
margin-right: 10px;
}
::v-deep .uni-video-ball {
width: 12px;
height: 12px;
padding: 16px;
}
}
.videoTitle {
font-size: 18px;
}
}
}
}

175
pages/contact/index.vue Normal file
View File

@ -0,0 +1,175 @@
<template>
<NavBar @navLeft="handleNavLeft" @navRight="handleNavRight" />
<cover-view id="service-btn" @click="goLiveChatPage">
<cover-image src="/static/contact/liveChat.png" mode="aspectFit" style="width: 26px; height: 26px"></cover-image>
</cover-view>
<view class="container">
<view class="pageTitle">
<PageTitle :title="$t('contact.pageTitle')" />
</view>
<image src="/static/contact/contactBanner.png" mode="aspectFill" class="banner"></image>
<view class="infoList">
<view class="infoCard" @click="openLiveChat">
<view class="title">{{ $t('contact.customerService') }}</view>
<view class="subTitle">{{ $t('contact.customerServiceDesc') }}</view>
<image src="/static/contact/customerService.png" mode="aspectFit" class="img"></image>
</view>
<view class="infoCard">
<view class="title">{{ $t('contact.email') }}</view>
<view class="subTitle">{{ contactInfo.email ?? '-' }}</view>
<image src="/static/contact/email.png" mode="aspectFit" class="img"></image>
</view>
<view class="infoCard">
<view class="title">{{ $t('contact.contactNumber') }}</view>
<view class="subTitle">{{ contactInfo.phone ?? '-' }}</view>
<image src="/static/contact/phone.png" mode="aspectFit" class="img"></image>
</view>
</view>
<view class="videoListWrapper" v-show="showVideo">
<view class="videoListTitle">{{ $t('contact.educationalVideos') }}</view>
<view class="videoList">
<view class="videoItem" v-for="video in videoList" :key="video.name">
<video class="video" id="myVideo" :src="video.video_url ?? ''" controls></video>
<view class="videoTitle">{{ video.name }}</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { getContactInfo, getVideoList } from '@/services/contact/index.ts';
export default {
data() {
return {
contactInfo: {},
videoList: [],
showVideo: true
};
},
methods: {
async getContactData() {
const res = await getContactInfo();
if (res && res.code === 0) {
this.contactInfo = res.data;
}
},
async getVideoData() {
const res = await getVideoList();
if (res && res.code === 0) {
this.videoList = res.data;
}
},
initLiveChat() {
let si = setInterval(() => {
const e = document.getElementById('chat-widget-minimized');
if (e) {
document.getElementById('service-btn').style.display = 'flex';
e.style.display = 'block';
clearInterval(si);
}
}, 200);
window.__lc = window.__lc || {};
window.__lc.license = 15504243;
(function (n, t, c) {
function i(n) {
return e._h ? e._h.apply(null, n) : e._q.push(n);
}
var e = {
_q: [],
_h: null,
_v: '2.0',
on: function () {
i(['on', c.call(arguments)]);
},
once: function () {
i(['once', c.call(arguments)]);
},
off: function () {
i(['off', c.call(arguments)]);
},
get: function () {
if (!e._h) throw new Error("[LiveChatWidget] You can't use getters before load.");
return i(['get', c.call(arguments)]);
},
call: function () {
i(['call', c.call(arguments)]);
},
init: function () {
var n = t.createElement('script');
(n.async = !0), (n.type = 'text/javascript'), (n.src = 'https://cdn.livechatinc.com/tracking.js'), t.head.appendChild(n);
}
};
!n.__lc.asyncInit && e.init(), (n.LiveChatWidget = n.LiveChatWidget || e);
})(window, document, [].slice);
},
openLiveChat() {
// #ifdef H5
const liveChat = document.getElementById('chat-widget-minimized');
if (liveChat) {
const liveChatBtn = liveChat.contentDocument.getElementsByTagName('button')[0];
if (liveChatBtn) {
liveChatBtn.click();
}
}
// #endif
// #ifdef APP
this.goLiveChatPage()
// #endif
},
hideLiveChat() {
// #ifdef H5
let si = setInterval(() => {
const e = document.getElementById('chat-widget-minimized');
if (e) {
e.style.display = 'none';
clearInterval(si);
}
}, 200);
// #endif
},
goLiveChatPage() {
// #ifdef APP
uni.navigateTo({
url: '/pages/contact/serviceView',
animationType: 'none'
})
// #endif
},
handleNavLeft(data) {
this.showVideo = !data
},
handleNavRight(data) {
this.showVideo = !data
},
},
created() {
this.getContactData();
this.getVideoData();
},
onUnload() {
// #ifdef H5
this.hideLiveChat();
// #endif
},
onShow() {
// #ifdef H5
this.initLiveChat();
// #endif
},
onHide() {
// #ifdef H5
this.hideLiveChat();
// #endif
},
mounted() {
// #ifdef H5
this.initLiveChat();
// #endif
}
};
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

View File

@ -0,0 +1,25 @@
<template>
<view>
<web-view :src="host + '/static/html/livechat.html'" @message="handleMsg"></web-view>
</view>
</template>
<script>
import { app_host } from '@/utils/request'
export default {
data() {
return {
host: app_host.replace('/api', '')
}
},
methods: {
handleMsg(data) {
console.log(data)
}
}
}
</script>
<style>
</style>