@@ -30,8 +30,8 @@ yarn config set ignore-engines true | |||
### node-sass版本6.0.1 | |||
### 测试环境baseURL = 'https://smapitest.malls.iformall.com/C' | |||
### 测试环境baseURL = 'https://mtest.metavatar.cc' | |||
### 正式环境baseURL = 'http://m.metavatar.cc/C' | |||
### 正式环境baseURL = 'https://m.metavatar.cc' | |||
项目根目录下配置有模板vue文件“model.vue”,已配置进入动画、回到顶部等功能,可以此为基础添加页面。 |
@@ -1,42 +1,42 @@ | |||
{ | |||
"name": "Metavatar", | |||
"version": "0.1.0", | |||
"private": true, | |||
"scripts": { | |||
"dev": "vue-cli-service serve --mode development", | |||
"build": "vue-cli-service build --mode test", | |||
"build-test": "vue-cli-service build --mode test", | |||
"build-prd": "vue-cli-service build --mode production" | |||
}, | |||
"dependencies": { | |||
"axios": "0.18.1", | |||
"element-ui": "^2.15.12", | |||
"file-saver": "^2.0.5", | |||
"franc": "^6.1.0", | |||
"image-webpack-loader": "^8.1.0", | |||
"install": "^0.13.0", | |||
"lib-flexible": "^0.3.2", | |||
"mic-recorder-to-mp3": "^2.2.2", | |||
"postcss-px2rem": "^0.3.0", | |||
"register-service-worker": "^1.7.1", | |||
"swiper": "^4.5.1", | |||
"vant": "^2.12.48", | |||
"vue": "^2.6.11", | |||
"vue-cropper": "^0.5.11", | |||
"vue-router": "^3.2.0", | |||
"vue-waterfall2": "^1.10.6", | |||
"vuex": "^3.4.0" | |||
}, | |||
"devDependencies": { | |||
"@vue/cli-plugin-pwa": "~4.5.13", | |||
"@vue/cli-plugin-router": "~4.5.13", | |||
"@vue/cli-plugin-vuex": "~4.5.13", | |||
"@vue/cli-service": "~4.5.13", | |||
"compression-webpack-plugin": "5.0.1", | |||
"node-sass": "^6.0.1", | |||
"sass": "^1.60.0", | |||
"sass-loader": "^7.0.3", | |||
"uglifyjs-webpack-plugin": "^2.2.0", | |||
"vue-template-compiler": "^2.6.11" | |||
} | |||
} | |||
{ | |||
"name": "Metavatar", | |||
"version": "0.1.0", | |||
"private": true, | |||
"scripts": { | |||
"dev": "vue-cli-service serve --mode development", | |||
"build": "vue-cli-service build --mode test", | |||
"build-test": "vue-cli-service build --mode test", | |||
"build-prd": "vue-cli-service build --mode production" | |||
}, | |||
"dependencies": { | |||
"axios": "0.18.1", | |||
"element-ui": "^2.15.12", | |||
"file-saver": "^2.0.5", | |||
"franc": "^6.1.0", | |||
"image-webpack-loader": "^8.1.0", | |||
"install": "^0.13.0", | |||
"lib-flexible": "^0.3.2", | |||
"mic-recorder-to-mp3": "^2.2.2", | |||
"postcss-px2rem": "^0.3.0", | |||
"register-service-worker": "^1.7.1", | |||
"swiper": "^4.5.1", | |||
"vant": "^2.12.48", | |||
"vue": "^2.6.11", | |||
"vue-cropper": "^0.5.11", | |||
"vue-router": "^3.2.0", | |||
"vue-waterfall2": "^1.10.6", | |||
"vuex": "^3.4.0" | |||
}, | |||
"devDependencies": { | |||
"@vue/cli-plugin-pwa": "~4.5.13", | |||
"@vue/cli-plugin-router": "~4.5.13", | |||
"@vue/cli-plugin-vuex": "~4.5.13", | |||
"@vue/cli-service": "~4.5.13", | |||
"compression-webpack-plugin": "5.0.1", | |||
"node-sass": "^6.0.1", | |||
"sass": "^1.60.0", | |||
"sass-loader": "^7.0.3", | |||
"uglifyjs-webpack-plugin": "^2.2.0", | |||
"vue-template-compiler": "^2.6.11" | |||
} | |||
} |
@@ -13,6 +13,76 @@ | |||
</div> | |||
</div> | |||
<!-- isVX && videoPlayBtn --> | |||
<div class="module_0"> | |||
<!-- <video id="video" ref="vidoe" src="../../assets/video/1.mp4" width="100%" height="100%" autoplay muted="muted" loop="loop" /> --> | |||
<!-- <video ref="vidoe" src="https://video.metavatar.cc/sv/d51a6f6-187fa2dff79/d51a6f6-187fa2dff79.mp4" width="100%" height="100%" autoplay muted="muted" loop="loop" /> --> | |||
<div class="vantLoadingBox" style="height: 550px" v-show="!loading"> | |||
<van-loading type="spinner" color="#52d4e5" class="vantLoading" /> | |||
</div> | |||
<div | |||
v-if="isVX && videoPlayBtn && !isAndroid" | |||
@click="playVideo" | |||
style=" | |||
position: absolute; | |||
top: 50%; | |||
left: 50%; | |||
transform: translate(-50%, -50%); | |||
z-index: 999; | |||
width: 100px; | |||
height: 100px; | |||
" | |||
> | |||
<img | |||
src="../../assets/icon/icon-play.png" | |||
alt="" | |||
style="width: 100px; height: 100px" | |||
/> | |||
</div> | |||
<video | |||
@play="videoPlayBtn = false" | |||
id="video" | |||
v-if="loading" | |||
:src="videoUrl" | |||
ref="vidoe" | |||
width="100%" | |||
height="100%" | |||
autoplay | |||
muted="muted" | |||
loop="loop" | |||
playsinline | |||
> | |||
<!-- <source type="audio/ogg" /> --> | |||
</video> | |||
<div class="titleBox"> | |||
<div v-if="characters == 1"> | |||
<div class="text1">卓越之人</div> | |||
<div class="text2">由ChatGPT强势驱动</div> | |||
</div> | |||
<div v-if="characters != 1"> | |||
<div class="text1">Powered By ChatGPT.</div> | |||
<div class="text2">Make it human.</div> | |||
</div> | |||
</div> | |||
<div | |||
:class="isBtnActice ? 'title_btn active' : 'title_btn'" | |||
@touchstart="chatTouchStart" | |||
@click="goToChat" | |||
@touchend="chatTouchEnd" | |||
> | |||
{{ characters == 1 ? "开始聊天" : "Let's Talk" }} | |||
</div> | |||
<div class="bottom"> | |||
<div v-if="characters == 1"> | |||
Explore our website, or click above to let Metavatar show you around | |||
</div> | |||
<div v-if="characters != 1"> | |||
Explore our website, or click above to let Metavatar show you around | |||
</div> | |||
</div> | |||
</div> | |||
<div class="module_1"> | |||
<!-- <video id="video" ref="vidoe" src="../../assets/video/1.mp4" width="100%" height="100%" autoplay muted="muted" loop="loop" /> --> | |||
<!-- <video ref="vidoe" src="https://video.metavatar.cc/sv/d51a6f6-187fa2dff79/d51a6f6-187fa2dff79.mp4" width="100%" height="100%" autoplay muted="muted" loop="loop" /> --> | |||
@@ -527,6 +597,7 @@ export default { | |||
return { | |||
isAndroid: false, //判断是不是ios | |||
inPage: false, | |||
isBtnActice: false, | |||
loading: false, // 加载状态 | |||
videoUrl: "", // 视频路径 | |||
videoUrl2: "", // 视频路径 | |||
@@ -865,6 +936,22 @@ export default { | |||
Toast.fail(err.message); | |||
}); | |||
}, | |||
chatTouchStart() { | |||
console.log("chatTouchStart"); | |||
this.isBtnActice = true; | |||
}, | |||
chatTouchEnd() { | |||
console.log("chatTouchEnd"); | |||
this.isBtnActice = false; | |||
}, | |||
goToChat() { | |||
console.log("goToChat"); | |||
this.isBtnActice = false; | |||
this.$router.push("/realTimeChat"); | |||
}, | |||
}, | |||
computed: { | |||
...mapState({ | |||
@@ -898,7 +985,6 @@ export default { | |||
}, | |||
mounted() { | |||
this.goView("top"); | |||
this.$nextTick(() => { | |||
this.module_6_data = oneList; | |||
this.carouselLsit = twoList; | |||
@@ -1136,6 +1222,76 @@ export default { | |||
height: 70px; | |||
width: 100%; | |||
} | |||
.module_0 { | |||
width: 100%; | |||
background-color: #202020; | |||
// height: 100vh; | |||
// height: 640px; | |||
// background-color: aquamarine; | |||
// background-image: url("../../assets/img/bg.png"); | |||
background-repeat: no-repeat; | |||
background-size: 100% 100%; | |||
overflow: hidden; | |||
position: relative; | |||
border-bottom: 3px solid #c0c0c0; | |||
.titleBox { | |||
position: absolute; | |||
color: #fff; | |||
left: 50%; | |||
bottom: 70%; | |||
transform: translate(-50%, -50%); | |||
font-size: 20px; | |||
text-align: center; | |||
.text1 { | |||
margin-bottom: 10px; | |||
} | |||
.text2 { | |||
text-align: center; | |||
} | |||
} | |||
.title_btn { | |||
position: absolute; | |||
left: 50%; | |||
bottom: 10%; | |||
transform: translate(-50%, -50%); | |||
height: 40px; | |||
line-height: 35px; | |||
width: 120px; | |||
text-align: center; | |||
color: #16e9d6; | |||
border-radius: 16px; | |||
border: #16e9d6 solid 2px; | |||
font-size: 18px; | |||
cursor: pointer; | |||
transition: all 0.1s; | |||
&.active { | |||
color: #ffffff; | |||
background-color: #16e9d6; | |||
transform: translate(-50%, -50%) scale(0.9); | |||
} | |||
} | |||
.bottom { | |||
position: absolute; | |||
color: #fff; | |||
width: 300px; | |||
text-align: center; | |||
left: 50%; | |||
bottom: 5%; | |||
transform: translate(-50%, 0); | |||
font-size: 20px; | |||
font-size: 12px; | |||
.text1 { | |||
margin-bottom: 10px; | |||
} | |||
.text2 { | |||
text-align: center; | |||
} | |||
} | |||
} | |||
.module_1 { | |||
width: 100%; | |||
background-color: #202020; | |||
@@ -121,6 +121,12 @@ const routes = [ | |||
name: 'downloadVideo', | |||
component: () => import("../views/model/downloadVideo"), | |||
}, | |||
// 实时对话 | |||
{ | |||
path: '/realTimeChat', | |||
name: 'realTimeChat', | |||
component: () => import("../views/realTimeChat/realTimeChat"), | |||
}, | |||
] | |||
const router = new VueRouter({ | |||
@@ -0,0 +1,298 @@ | |||
<template> | |||
<div :class="inPage ? 'page active' : 'page'"> | |||
<div id="top"></div> | |||
<top /> | |||
<video | |||
@play="videoPlayBtn = false" | |||
class="videoBox" | |||
id="video" | |||
v-if="loading" | |||
:src="videoUrl" | |||
ref="video" | |||
autoplay | |||
muted="muted" | |||
loop="loop" | |||
playsinline | |||
:style="'width:100%;height:' + screenHeight + 'px;'" | |||
></video> | |||
<div class="controlBox" :style="'width:' + screenWidth + 'px;'"> | |||
<div :class="isExpend ? 'chatBox' : 'chatBox expand'"> | |||
<div class="item top">聊天记录</div> | |||
<div | |||
v-for="item in chatList" | |||
:class="item.type == 0 ? 'item left' : 'item right'" | |||
> | |||
{{ item.type == 0 ? `我:${item.msg}` : `${item.msg}:你` }} | |||
</div> | |||
<div v-if="chatList.length > 0" class="item center">已经到底啦</div> | |||
<div v-if="chatList.length == 0" class="item noMsg">暂无聊天记录哦</div> | |||
</div> | |||
<div class="itemBox left" @click="sendMessage"> | |||
<img src="../../assets/icon/enter.png" alt="" /> | |||
</div> | |||
<input | |||
v-model="inputText" | |||
class="inputInside" | |||
type="text" | |||
placeholder="输入文字聊天" | |||
/> | |||
<img | |||
:class="isExpend ? 'arrow' : 'arrow active'" | |||
src="../../assets/icon/arrow-down-bold.png" | |||
@click="expendChatBox" | |||
/> | |||
<div class="itemBox right" @click="setVoice"> | |||
<img v-if="!isVoiceClose" src="../../assets/icon/voice.png" alt="" /> | |||
<img | |||
v-if="isVoiceClose" | |||
src="../../assets/icon/voice_close.png" | |||
alt="" | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
// 组件 | |||
import Vue from "vue"; | |||
import { Toast } from "vant"; | |||
import { mapState, mapActions } from "vuex"; | |||
import top from "../../components/common/top"; | |||
// 工具 | |||
import { scrollToID } from "../../utils"; | |||
// import io from "socket.io"; | |||
Vue.use(Toast); | |||
export default { | |||
components: { | |||
top, | |||
}, | |||
data() { | |||
return { | |||
inPage: false, | |||
videoUrl: "", | |||
videoPlayBtn: true, | |||
loading: false, // 加载状态 | |||
isVoiceClose: false, | |||
isExpend: false, // 对话框展开状态 | |||
inputText: "", | |||
screenWidth: document.documentElement.clientWidth, | |||
screenHeight: document.documentElement.clientHeight, | |||
socket: null, | |||
chatList: [ | |||
{ | |||
type: 0, | |||
msg: "你好!", | |||
}, | |||
{ | |||
type: 1, | |||
msg: "你好!", | |||
}, | |||
{ | |||
type: 0, | |||
msg: "你好!", | |||
}, | |||
{ | |||
type: 1, | |||
msg: "你好!", | |||
}, | |||
], | |||
}; | |||
}, | |||
computed: { | |||
...mapState({ | |||
characters: (state) => state.publicObj.characters, | |||
}), | |||
}, | |||
methods: { | |||
...mapActions(["setCharacters"]), | |||
go(url) { | |||
this.$router.push(url); | |||
}, | |||
setVoice() { | |||
this.isVoiceClose = !this.isVoiceClose; | |||
Toast.success(this.isVoiceClose ? "麦克风已关闭" : "麦克风已开启"); | |||
}, | |||
sendMessage() {}, | |||
expendChatBox() { | |||
this.isExpend = !this.isExpend; | |||
}, | |||
socketOnLink() { | |||
// const url = "wss://mtest.metavatar.cc/webrtc"; | |||
const url = document.location.host; | |||
this.socket = new WebSocket("wss://" + url + "/webrtc"); | |||
this.socket.onopen = (success) => { | |||
console.log(success, "连接成功!"); | |||
}; | |||
this.socket.onclose = (evt) => { | |||
console.log(evt, "连接已断开!"); | |||
}; | |||
this.socket.onerror = (evt) => { | |||
console.log(evt, "连接失败"); | |||
}; | |||
this.socket.onmessage = (e) => { | |||
console.log(e, "e"); | |||
}; | |||
}, | |||
socketLogin() { | |||
let req = new Object(); | |||
req.cmd = "CMD_USER_LOGIN"; | |||
req.username = "Passager"; | |||
req.password = "123456"; | |||
req.agent = "browser"; | |||
let str = JSON.stringify(req); | |||
this.socket.send(str); | |||
}, | |||
}, | |||
created() {}, | |||
mounted() { | |||
this.inPage = true; | |||
scrollToID("top"); | |||
this.videoUrl = | |||
"https://video.metavatar.cc/sv/d51a6f6-187fa2dff79/d51a6f6-187fa2dff79.mp4"; | |||
this.loading = true; | |||
this.socketOnLink(); | |||
}, | |||
}; | |||
</script> | |||
<style lang="scss" scoped> | |||
.page { | |||
position: relative; | |||
transform: translateX(30%); | |||
opacity: 0; | |||
transition: all 0.5s; // global-transition | |||
&.active { | |||
opacity: 1; | |||
transform: translateX(0); | |||
} | |||
.videoBox { | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
z-index: -1; | |||
object-fit: fill; | |||
} | |||
.controlBox { | |||
position: absolute; | |||
bottom: -670px; | |||
height: 300px; | |||
.chatBox { | |||
position: relative; | |||
width: 100%; | |||
height: 160px; | |||
color: #ffffff; | |||
padding: 15px 30px 15px 30px; | |||
overflow: scroll; | |||
background-color: #00000054; | |||
opacity: 1; | |||
transition: all 0.3s; | |||
.item { | |||
margin-bottom: 8px; | |||
&.top { | |||
position: sticky; | |||
top: 0px; | |||
text-align: center; | |||
} | |||
&.left { | |||
text-align: left; | |||
} | |||
&.right { | |||
text-align: right; | |||
} | |||
&.center { | |||
text-align: center; | |||
margin-top: 40px; | |||
} | |||
&.noMsg { | |||
position: absolute; | |||
left: 50%; | |||
bottom: 0; | |||
transform: translateX(-50%); | |||
text-align: center; | |||
} | |||
} | |||
&.expand { | |||
transform: translateY(100px); | |||
opacity: 0; | |||
z-index: -1; | |||
} | |||
} | |||
.itemBox { | |||
position: absolute; | |||
bottom: 50px; | |||
width: 50px; | |||
height: 50px; | |||
border: 3.5px solid #ffffff; | |||
border-radius: 50%; | |||
text-align: center; | |||
padding: 10px; | |||
transition: all 0.3s; | |||
cursor: pointer; | |||
&.left { | |||
left: 295px; | |||
} | |||
&.right { | |||
right: 295px; | |||
} | |||
img { | |||
width: 100%; | |||
height: 100%; | |||
} | |||
&.active { | |||
opacity: 0.8; | |||
} | |||
} | |||
.arrow { | |||
position: absolute; | |||
bottom: 100px; | |||
left: 50%; | |||
transform: translateX(-50%); | |||
width: 30px; | |||
height: 30px; | |||
transition: all 0.2s; | |||
&.active { | |||
transform: translateX(-50%) rotate(180deg); | |||
} | |||
} | |||
.inputInside { | |||
position: absolute; | |||
bottom: 57px; | |||
left: 50%; | |||
transform: translateX(-50%); | |||
width: 170px; | |||
height: 35px; | |||
border: 3.5px solid #ffffff; | |||
border-radius: 7px; | |||
padding-left: 10px; | |||
color: #ffffff; | |||
caret-color: #ffffff; | |||
&::-webkit-input-placeholder { | |||
color: #ffffffbb; | |||
} | |||
} | |||
} | |||
} | |||
</style> |
@@ -45,11 +45,11 @@ module.exports = { | |||
filename: `js/js[name].${timeStamp}.js`, | |||
chunkFilename: `js/chunk.[id].${timeStamp}.js`, | |||
}, | |||
resolve: { | |||
alias: { | |||
'@': path.resolve(__dirname, 'src') | |||
} | |||
}, | |||
resolve: { | |||
alias: { | |||
'@': path.resolve(__dirname, 'src') | |||
} | |||
}, | |||
externals, | |||
}, | |||
css: { | |||
@@ -57,70 +57,70 @@ module.exports = { | |||
filename: `css/[name].${timeStamp}.css`, | |||
chunkFilename: `css/chunk.[id].${timeStamp}.css`, | |||
}, | |||
loaderOptions: { | |||
css: { | |||
}, | |||
// postcss: { | |||
// // options here will be passed to postcss-loader | |||
// plugins: [require('postcss-px2rem')({ | |||
// remUnit: 75 | |||
// })] | |||
// } | |||
} | |||
}, | |||
loaderOptions: { | |||
css: { | |||
}, | |||
// postcss: { | |||
// // options here will be passed to postcss-loader | |||
// plugins: [require('postcss-px2rem')({ | |||
// remUnit: 75 | |||
// })] | |||
// } | |||
} | |||
}, | |||
pwa: { | |||
iconPaths: { | |||
favicon32: 'favicon.ico', | |||
favicon16: 'favicon.ico', | |||
appleTouchIcon: 'favicon.ico', | |||
maskIcon: 'favicon.ico', | |||
msTileImage: 'favicon.ico' | |||
} | |||
pwa: { | |||
iconPaths: { | |||
favicon32: 'favicon.ico', | |||
favicon16: 'favicon.ico', | |||
appleTouchIcon: 'favicon.ico', | |||
maskIcon: 'favicon.ico', | |||
msTileImage: 'favicon.ico' | |||
} | |||
}, | |||
//http://www.metavatar.cc/ | |||
devServer: { | |||
overlay: { | |||
warnings: false, | |||
errors: false | |||
}, | |||
//http://www.metavatar.cc/ | |||
devServer: { | |||
overlay: { | |||
warnings: false, | |||
errors: false | |||
proxy: { | |||
'/api': { | |||
// target: 'https://smapitestmalls,iformall.com/C/api', | |||
target: process.env.VUE_APP_API_ROOT + '/api', | |||
changeOrigin: true, | |||
pathRewrite: { | |||
'^/api': '' | |||
}, | |||
proxy: { | |||
'/api': { | |||
// target: 'https://smapitestmalls,iformall.com/C/api', | |||
target: process.env.VUE_APP_API_ROOT+'/api', | |||
changeOrigin: true, | |||
pathRewrite: { | |||
'^/api': '' | |||
}, | |||
}, | |||
}, | |||
} | |||
}, | |||
lintOnSave: false, | |||
publicPath: './', // 打包后引用的资源路径 | |||
} | |||
}, | |||
lintOnSave: false, | |||
publicPath: './', // 打包后引用的资源路径 | |||
chainWebpack: config => { | |||
// favicon图标 | |||
config.plugin('html').tap(args => { | |||
args[0].favicon = './public/favicon.ico'; | |||
return args; | |||
}); | |||
// 注入cdn变量 (打包时会执行) | |||
config.plugin('html').tap(args => { | |||
args[0].cdn = cdn // 配置cdn给插件 | |||
return args | |||
}) | |||
// 图片路径 | |||
config.module.rule('images') | |||
// favicon图标 | |||
config.plugin('html').tap(args => { | |||
args[0].favicon = './public/favicon.ico'; | |||
return args; | |||
}); | |||
// 注入cdn变量 (打包时会执行) | |||
config.plugin('html').tap(args => { | |||
args[0].cdn = cdn // 配置cdn给插件 | |||
return args | |||
}) | |||
// 图片路径 | |||
config.module.rule('images') | |||
.use('url-loader') | |||
.tap(options => ({ | |||
name: './assets/images/[name].[ext]', | |||
quality: 85, | |||
limit: 0, | |||
esModule: false, | |||
name: './assets/images/[name].[ext]', | |||
quality: 85, | |||
limit: 0, | |||
esModule: false, | |||
})) | |||
//图片压缩 | |||
config.module | |||
//图片压缩 | |||
config.module | |||
.rule('images') | |||
.use('image-webpack-loader') | |||
.loader('image-webpack-loader') | |||
@@ -144,9 +144,9 @@ module.exports = { | |||
} | |||
}) | |||
.end(); | |||
// 压缩js,只能线上,本地会js访问错误,会将js压缩成.gz文件 | |||
if (process.env.VUE_APP_ENV != 'development') { | |||
if (process.env.VUE_APP_ENV != 'development') { | |||
config.plugin('compression-webpack-plugin').use(new CompressionWebpackPlugin({ | |||
test: /\.(js|css|scss|woff|woff2|ttf)$/, // 匹配文件名 | |||
threshold: 20480, // 对超过20k的数据压缩 | |||
@@ -164,19 +164,19 @@ module.exports = { | |||
} | |||
} | |||
// configureWebpack: { | |||
// plugins: [ | |||
// //打包环境去掉console.log | |||
// new UglifyJsPlugin({ | |||
// uglifyOptions: { | |||
// compress: { | |||
// drop_console: true, //注释console | |||
// drop_debugger: true, //注释debugger | |||
// pure_funcs: ['console.log'], //移除console.log | |||
// }, | |||
// }, | |||
// }), | |||
// ], | |||
// } | |||
} | |||
// configureWebpack: { | |||
// plugins: [ | |||
// //打包环境去掉console.log | |||
// new UglifyJsPlugin({ | |||
// uglifyOptions: { | |||
// compress: { | |||
// drop_console: true, //注释console | |||
// drop_debugger: true, //注释debugger | |||
// pure_funcs: ['console.log'], //移除console.log | |||
// }, | |||
// }, | |||
// }), | |||
// ], | |||
// } | |||
} |