文章目录
一、环境准备
首先准备好node
环境并安装好vue
,在存储项目的目录下使用命令vue init webpack movie-web
,然后一路enter
,等待片刻便可以初始化一个名为movie-web
的Vue 2
项目。
进入Vue
项目主目录,依次调用如下命令安装第三方组件:
npm install element-ui -S
npm install echarts@4.9.0
npm install vue-router
npm install axios
二、前端构建
2.1 页面绘制
2.1.1 网站框架App.vue
<template>
<div id="app">
<el-header id="header" height="60px">
<div id="title">
<span id="big-title">uQiYi</span>
<span id="small-title">v1.0.1</span>
</div>
<div id="userinfo">
<span id="user-name">Hello, Chiak1</span>
</div>
</el-header>
<el-container>
<el-aside width="20%">
<el-menu default-active="1">
<el-submenu index="1">
<template slot="title">前台观影</template>
<el-menu-item index="movie" @click="goTo('/movie')">电影首页</el-menu-item>
<el-menu-item index="rating" @click="goTo('/player')">播放电影</el-menu-item>
</el-submenu>
<el-submenu index="2">
<template slot="title">数据查询</template>
<el-menu-item index="movie_query" @click="goTo('/movie_query')">电影筛选</el-menu-item>
<el-menu-item index="rating_query" @click="goTo('/rating_query')">评分细查</el-menu-item>
<el-menu-item index="charts" @click="goTo('/charts')">可视化数据</el-menu-item>
</el-submenu>
<el-submenu index="3">
<template slot="title">用户中心</template>
<el-menu-item index="userinfo">用户信息</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</div>
</template>
<script>
export default {
name: 'App',
methods: {
goTo (url) {
this.$router.replace(url)
}
}
}
</script>
<style scoped>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
#header {
height: 10%;
background-color: #67C23A;
position: absolute;
top: 0px;
left: 0px;
right: 0px;
}
#title {
position: absolute;
top: 10px;
left: 50px;
}
#big-title {
font-size: 30px;
color: white;
}
#small-title {
padding-left: 10px;
font-size: 14px;
color: white;
}
#userinfo {
position: absolute;
top: 18px;
right: 50px;
}
#user-name {
font-size: 20px;
color: white;
}
span {
font-size: 14px;
}
</style>
2.1.2 前台观影/电影首页Movie.vue
/* eslint-disable */
<template>
<div>
<div class="block">
<span style="color: green; font-size: 20px; font-weight: bold">猜你喜欢</span>
<el-carousel :interval="3000" type="card" height="300px" style="padding-top: 10px">
<el-carousel-item v-for="poster in this.posters" :key="poster">
<el-image :src="poster" fit="cover" style="width: 210px; height: 300px"></el-image>
</el-carousel-item>
</el-carousel>
<el-table stripe :data="recommend" height="300px" style="width: 650px; position: absolute; left: 5%">
<el-table-column label="电影ID" prop="movieId"></el-table-column>
<el-table-column label="电影名" prop="title"></el-table-column>
<el-table-column label="平均评分" prop="avgRating"></el-table-column>
</el-table>
</div>
<div id="box2">
<span style="color: green">最近热播 Hot(10s 更新一次)</span>
<el-table stripe :data="hot" v-loading="loading" height="650px">
<el-table-column type="index"></el-table-column>
<el-table-column label="电影ID" prop="movieId"></el-table-column>
<el-table-column label="电影名" prop="title"></el-table-column>
<el-table-column label="播放次数" prop="count"></el-table-column>
</el-table>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'Movie',
data () {
return {
timer: null,
posters: [],
// 示例数据
movies: {
1: {movieId: 1, title: "你的名字", avgRating: 4.82},
2: {movieId: 2, title: "超凡蜘蛛侠", avgRating: 4.3},
3: {movieId: 3, title: "毒液:致命守护者", avgRating: 4.44},
4: {movieId: 4, title: "硬汉", avgRating: 3.98},
5: {movieId: 5, title: "不明身份", avgRating: 3.99},
6: {movieId: 6, title: "天下无贼", avgRating: 4.52},
7: {movieId: 7, title: "蝙蝠侠:黑暗骑士", avgRating: 4.51},
8: {movieId: 8, title: "釜山行", avgRating: 4.03},
9: {movieId: 9, title: "寂静岭", avgRating: 3.87},
10: {movieId: 10, title: "我是传奇", avgRating: 3.92},
11: {movieId: 11, title: "泰坦尼克", avgRating: 4.91},
12: {movieId: 12, title: "翻译疑云", avgRating: 3.69},
13: {movieId: 13, title: "禁闭岛", avgRating: 4.61},
14: {movieId: 14, title: "绣春刀", avgRating: 3.98}
},
recommend: [],
hot: []
}
},
created () {
var posterNames = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
for (var i = 0; i < 5; i++) {
var id = parseInt(Math.random() * posterNames.length)
this.posters.push(require("@/assets/" + posterNames[id] + ".jpeg"))
this.recommend.push(this.movies[posterNames[id]])
posterNames.splice(id, 1)
}
this.init()
},
beforeDestroy () {
clearInterval(this.timer)
this.timer = null
},
methods: {
init () {
this.timer = setInterval(() => {
axios.post('/movie/hot').then((res) => {
if (res.data) {
this.hot = res.data
} else {
this.$message("查询数据失败")
this.hot = []
}
})
}, 10000)
}
}
}
</script>
<style scoped>
.block {
width: 50%;
position: absolute;
top: 10%;
left: 20%
}
#box2 {
width: 25%;
position: absolute;
top: 10%;
left: 72%;
}
</style>
2.1.3 前台观影/播放电影Player.vue
/* eslint-disable */
<template>
<div>
<div id="box1">
<el-input v-model="movieId" placeholder="电影ID" style="width: 150px"></el-input>
<el-button type="success" plain @click="play()">播放电影</el-button>
<el-button type="danger" plain @click="clear()">取消播放</el-button>
</div>
<div id="box2">
<video width="800px" height="500px" controls autoplay>
<source :src="movie" type="video/mp4">
您的浏览器不支持 video 标签。
</video>
</div>
<div id="box3">
<el-rate v-model="rating" :colors="colors"></el-rate>
<el-input v-model="userId" placeholder="用户ID" style="width: 150px"></el-input>
<el-button type="success" plain @click="rate()">确认评分</el-button>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'Player',
data () {
return {
movieId: null,
movie: null,
rating: null,
userId: null,
colors: ['#99A9BF', '#F7BA2A', '#FF9900']
}
},
methods: {
play () {
this.movie = require("@/assets/video/" + this.movieId + ".mp4")
},
clear () {
this.movie = null
this.movieId = null
this.rating = null
this.userId = null
},
rate () {
axios.post('/player/rate', {"userId": this.userId, "movieId": this.movieId, "rating": this.rating})
this.$message("评分成功")
this.clear()
}
}
}
</script>
<style scoped>
#box1 {
width: 40%;
height: 100px;
position: absolute;
top: 12%;
left: 15%;
}
#box2 {
position: absolute;
left: 30%;
bottom: 10%;
}
#box3 {
width: 40%;
height: 100px;
position: absolute;
top: 10%;
right: 5%;
}
</style>
2.1.4 数据查询/电影筛选MovieQuery.vue
/* eslint-disable */
<template>
<div>
<div id="box1">
<el-input v-model="minAvgRating" placeholder="平均分≥" style="width: 150px"></el-input>
<el-input v-model="minCount" placeholder="评分次数≥" style="width: 150px; padding-right: 20px"></el-input>
<el-switch v-model="useCount" active-text="评分次数" inactive-text="平均分"></el-switch>
<el-button type="primary" plain @click="query()" style="margin-left: 30px">查询结果</el-button>
<el-button type="danger" plain @click="clear()">清除查询</el-button>
</div>
<div id="box2">
<el-table stripe :data="movieList" v-loading="loading" height="550px">
<el-table-column type="index"></el-table-column>
<el-table-column label="电影ID" prop="movieId"></el-table-column>
<el-table-column label="电影名" prop="title"></el-table-column>
<el-table-column label="电影题材" prop="genres"></el-table-column>
<el-table-column label="平均评分" prop="avgRating"></el-table-column>
<el-table-column label="评分次数" prop="count"></el-table-column>
</el-table>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'MovieQuery',
data () {
return {
minAvgRating: null,
minCount: null,
useCount: null,
movieList: [],
loading: false
}
},
methods: {
query () {
if (this.loading) {
this.$message('当前有查询正在进行,请稍后')
} else {
this.loading = true
axios.post('/movie_query/query', {minAvgRating: this.minAvgRating, minCount: this.minCount, useCount: this.useCount}).then((res) => {
if (res.data && this.loading) {
this.movieList = res.data
this.$message('查询成功')
} else {
this.$message('查询失败')
}
this.loading = false
})
}
},
clear () {
this.minAvgRating = null
this.minCount = null
this.useCount = null
this.movieList = []
this.loading = false
}
}
}
</script>
<style scoped>
#adv {
height: 20%;
width: 79.62%;
position: absolute;
top: 7.3%;
left: 20.38%;
}
#box1 {
width: 70%;
height: 100px;
position: relative;
top: 10%;
}
</style>
2.1.5 数据查询/评分细查RatingQuery.vue
/* eslint-disable */
<template>
<div>
<div id="box1">
<el-input v-model="movieId" placeholder="电影ID" @change="searchRating()" style="width: 150px" clearable></el-input>
<el-input v-model="avgRating" placeholder="平均评分" style="width: 150px" label="平均分" readonly="true"></el-input>
<el-button type="danger" plain @click="clear()">清除数据</el-button>
</div>
<div id="box2">
<el-table stripe :data="ratingList" v-loading="loading" height="550px">
<el-table-column type="index"></el-table-column>
<el-table-column label="电影ID" prop="movieId"></el-table-column>
<el-table-column label="电影名" prop="title"></el-table-column>
<el-table-column label="用户ID" prop="userId"></el-table-column>
<el-table-column label="用户评分" prop="rating"></el-table-column>
</el-table>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'RatingQuery',
data () {
return {
movieId: null,
avgRating: null,
ratingList: [],
loading: false
}
},
methods: {
searchRating () {
if (this.movieId) {
if (this.loading) {
this.$message('当前有查询正在进行,请稍后')
} else {
this.loading = true
axios.post('/rating_query/query', {movieId: this.movieId}).then((res) => {
if (res.data && this.loading) {
this.ratingList = res.data
var sum = 0
var count = 0
for (var i in this.ratingList) {
sum += this.ratingList[i].rating
count += 1
}
this.avgRating = (sum / count).toFixed(2)
this.$message('查询成功')
} else {
this.$message('查询失败')
}
this.loading = false
})
}
}
},
clear () {
this.movieId = null
this.avgRating = null
this.ratingList = []
this.loading = false
}
}
}
</script>
<style scoped>
#box1 {
width: 40%;
height: 100px;
position: relative;
top: 10%;
}
</style>
2.1.6 数据查询/可视化数据Charts.vue
/* eslint-disable */
<template>
<div>
<el-tabs v-model="active" type="border-card" @tab-click="handleClick" style="height: 700px">
<el-tab-pane label="信息概览" name="A" style="height: 630px; width: 1070px;">
<div id="chart1"></div>
<div id="chart2"></div>
<div id="chart3"></div>
<div id="chart4"></div>
</el-tab-pane>
<el-tab-pane label="电影数据" name="B" style="height: 630px; width: 1070px;">
<div id="chart5"></div>
<div id="chart6"></div>
<div id="chart7"></div>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import axios from 'axios'
import * as echarts from 'echarts'
export default {
name: 'Charts',
data () {
return {
timer: null,
active: "A",
chart1x: [],
chart1y: [],
chart2data: [],
chart3x: [],
chart3y: [],
chart4x: [],
chart4y: [],
chart5x: [],
chart5y: [],
chart6x: [],
chart6y: [],
chart7data: []
}
},
created () {
this.init()
},
beforeDestroy () {
clearInterval(this.timer)
this.timer = null
},
methods: {
init () {
this.timer = setInterval(() => {
axios.post('/charts/query').then((res) => {
if (res.data) {
this.chart1x = res.data.chart1.x
console.log(this.chart1x)
this.chart1y = res.data.chart1.y
this.chart2data = res.data.chart2.data
this.chart3x = res.data.chart3.x
this.chart3y = res.data.chart3.y
this.chart4x = res.data.chart4.x
this.chart4y = res.data.chart4.y
this.chart5x = res.data.chart5.x
this.chart5y = res.data.chart5.y
this.chart6x = res.data.chart6.x
this.chart6y = res.data.chart6.y
this.chart7data = res.data.chart7.data
this.drawLine()
} else {
this.$message("查询数据失败")
}
})
}, 1000)
},
drawLine () {
var chart1 = echarts.init(document.getElementById('chart1'))
chart1.setOption({
title: {text: '评分分布'},
color: ['#67C23A'],
tooltip: {},
xAxis: {
type: 'category',
boundaryGap: false,
data: this.chart1x
},
yAxis: {},
series: [{
name: '电影评分',
type: 'bar',
data: this.chart1y
}]
})
var chart2 = echarts.init(document.getElementById('chart2'))
chart2.setOption({
tooltip: {
trigger: 'item'
},
legend: {
top: '5%',
left: 'center'
},
series: [{
name: '评分分布',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '40',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: this.chart2data
}]
})
var chart3 = echarts.init(document.getElementById('chart3'))
chart3.setOption({
title: {text: '每 10s 平台电影评分次数'},
color: ['#67C23A'],
tooltip: {},
xAxis: {
type: 'category',
boundaryGap: false,
data: this.chart3x
},
yAxis: {
type: 'value'
},
series: [{
name: '评分次数',
type: 'line',
data: this.chart3y,
smooth: true
}]
})
var chart4 = echarts.init(document.getElementById('chart4'))
chart4.setOption({
title: {text: '平台电影评分总次数'},
color: ['#67C23A'],
tooltip: {},
xAxis: {
type: 'category',
boundaryGap: false,
data: this.chart4x
},
yAxis: {
type: 'value'
},
series: [{
name: '评分次数',
type: 'line',
data: this.chart4y,
smooth: true
}]
})
var chart5 = echarts.init(document.getElementById('chart5'))
chart5.setOption({
title: {text: '电影评分 Top5'},
color: ['#67C23A'],
tooltip: {},
xAxis: {
type: 'category',
boundaryGap: false,
data: this.chart5x
},
yAxis: {},
series: [{
name: '电影评分',
type: 'bar',
data: this.chart5y
}]
})
var chart6 = echarts.init(document.getElementById('chart6'))
chart6.setOption({
title: {text: '评分次数 Top5'},
color: ['#67C23A'],
tooltip: {},
xAxis: {
type: 'category',
boundaryGap: false,
data: this.chart6x
},
yAxis: {},
series: [{
name: '电影评分',
type: 'bar',
data: this.chart6y
}]
})
var chart7 = echarts.init(document.getElementById('chart7'))
chart7.setOption({
legend: {
top: 'bottom'
},
tooltip: {},
series: [{
name: '评分次数',
type: 'pie',
radius: [50, 250],
center: ['50%', '50%'],
roseType: 'area',
itemStyle: {
borderRadius: 8
},
data: this.chart7data
}]
})
}
}
}
</script>
<style scoped>
#chart1 {
width: 300px;
height: 300px;
position: absolute;
top: 20px;
left: 40px;
}
#chart2 {
width: 300px;
height: 300px;
position: absolute;
top: 340px;
left: 40px;
}
#chart3 {
width: 600px;
height: 300px;
position: absolute;
top: 20px;
left: 380px;
}
#chart4 {
width: 600px;
height: 300px;
position: absolute;
top: 340px;
left: 380px;
}
#chart5 {
width: 300px;
height: 300px;
position: absolute;
top: 20px;
left: 40px;
}
#chart6 {
width: 300px;
height: 300px;
position: absolute;
top: 340px;
left: 40px;
}
#chart7 {
width: 650px;
height: 600px;
position: absolute;
top: 20px;
left: 400px;
}
</style>
2.2 相关配置
2.2.1 项目配置main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import Vue from 'vue'
import App from './App'
import VueResource from 'vue-resource'
import router from './router'
Vue.use(VueResource)
Vue.use(ElementUI)
Vue.config.productionTip = false
var axios = require('axios')
axios.defaults.baseURL = 'http://localhost:8001'
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
2.2.2 路由配置router/index.js
初始化的Vue
项目中并不包含路由,所以需要手动在src
目录下创建文件夹router
,然后在router
下创建配置文件index.js
如下:
import Vue from 'vue'
import Router from 'vue-router'
import Movie from '@/components/Movie'
import Player from '@/components/Player'
import MovieQuery from '@/components/MovieQuery'
import RatingQuery from '@/components/RatingQuery'
import Charts from '@/components/Charts'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
redirect: '/movie'
},
{
path: '/movie',
name: 'Movie',
component: Movie
},
{
path: '/player',
name: 'Player',
component: Player
},
{
path: '/movie_query',
name: 'MovieQuery',
component: MovieQuery
},
{
path: '/rating_query',
name: 'RatingQuery',
component: RatingQuery
},
{
path: '/charts',
name: 'Charts',
component: Charts
}
]
})