Merge remote-tracking branch 'origin/master'

This commit is contained in:
lzh
2022-03-01 11:32:18 +08:00
25 changed files with 13288 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
+5
View File
@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
+12265
View File
File diff suppressed because it is too large Load Diff
+50
View File
@@ -0,0 +1,50 @@
{
"name": "demo01",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.24.0",
"core-js": "^3.6.5",
"echarts": "^5.3.0",
"echarts-wordcloud": "^2.0.0",
"element-ui": "^2.15.6",
"less": "^4.1.1",
"less-loader": "^10.0.1",
"vue": "^2.6.11",
"vue-router": "^3.2.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "^4.5.13",
"@vue/cli-service": "~4.5.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"vue-template-compiler": "^2.6.11"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

+17
View File
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon2.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
+24
View File
@@ -0,0 +1,24 @@
# demo01
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
+27
View File
@@ -0,0 +1,27 @@
<template>
<div id="app">
<router-view />
</div>
</template>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body,
html {
margin: 0;
padding: 0;
height: 100%;
}
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* text-align: center; */
color: #2c3e50;
height: 100%;
}
</style>
+23
View File
@@ -0,0 +1,23 @@
import axios from 'axios';
export function regist(params){
return axios({
url:'/regist',
method:'post',
data:params
})
}
export function login(params){
return axios({
url:'/login',
method:'post',
data:params
})
}
export function display(params){
return axios({
url:'/display',
method:'post',
data:params
})
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 485 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

+58
View File
@@ -0,0 +1,58 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
+21
View File
@@ -0,0 +1,21 @@
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
// import '@/styles/index.less'
import 'element-ui/lib/theme-chalk/index.css';
import axios from 'axios';
// 引入echarts
import * as echarts from 'echarts'
import 'echarts-wordcloud';
Vue.prototype.$echarts = echarts;
Vue.prototype.$axios = axios; //全局注册,使用方法为:this.$axios
Vue.use(ElementUI);
Vue.config.productionTip = false;
new Vue({
router,
render: h => h(App)
}).$mount('#app')
+28
View File
@@ -0,0 +1,28 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../views/login/Login.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'login',
component: Login
},
{
path: '/home',
name: 'Home',
component: () => import('../views/home/Home.vue'),
},
]
const router = new VueRouter({
mode: 'hash',
base: process.env.BASE_URL,
routes
})
export default router
View File
+318
View File
@@ -0,0 +1,318 @@
<template>
<div class="homePage">
<div class="header">
<div class="header-title">
<img class="header-icon" src="../../assets/images/pull.png" />
<span class="title">爬虫数据可视化系统</span>
</div>
<div class="user-info">
<img class="header-icon" src="../../assets/images/userIcon.png" />
<span>{{ username }}</span>
</div>
</div>
<div class="content">
<div class="search">
<el-form :inline="true" :model="formData" class="demo-form-inline">
<el-form-item>
<el-input
v-model="formData.url"
placeholder="请输入URL..."
style="width: 500px"
></el-input>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="onSubmit"
icon="el-icon-search"
></el-button>
<el-button
@click="resetSearch"
icon="el-icon-refresh-right"
></el-button>
</el-form-item>
</el-form>
</div>
<div class="charts">
<el-card class="box-card">
<span>Top10积极词汇评分</span>
<div id="positiveChart" style="width: 700px; height: 400px"></div>
</el-card>
<el-card class="box-card">
<div id="pieChart" style="width: 700px; height: 400px"></div>
</el-card>
<el-card class="box-card">
<span>Top10消极词汇评分</span>
<div id="negativeChart" style="width: 700px; height: 400px"></div>
</el-card>
<el-card class="box-card">
<div id="frequencyChart" style="width: 700px; height: 400px"></div>
</el-card>
</div>
</div>
</div>
</template>
<script>
import * as info from "../../api/info";
export default {
data() {
return {
activeIndex: 1,
formData: {
url: "",
},
username: "",
chartsData: [],
positiveChart: null,
negativeChart: null,
pieChart: null,
frequencyChart: null,
positiveChartData: {xData:[],yData:[]},
negativeChartData: {xData:[],yData:[]},
pieChartData: [],
frequencyChartData: [],
};
},
mounted() {
let _this = this;
this.positiveChart = this.$echarts.init(
document.getElementById("positiveChart")
);
this.negativeChart = this.$echarts.init(
document.getElementById("negativeChart")
);
this.pieChart = this.$echarts.init(document.getElementById("pieChart"));
this.frequencyChart = this.$echarts.init(
document.getElementById("frequencyChart")
);
//窗口大小变化时,实现自适应
window.addEventListener("resize", () => {
_this.positiveChart.resize();
_this.negativeChart.resize();
_this.pieChart.resize();
_this.frequencyChart.resize();
});
this.username = localStorage.getItem("username");
},
methods: {
onSubmit() {
let params = {
username: this.username,
url: this.formData.url,
};
info
.display(params)
.then((res) => {
if (res.data.code == 200) {
console.log(res);
this.chartsData = res.data.data;
let positiveChartData = res.data.data.positive;
let negativeChartData = res.data.data.negative;
let pieChartData = res.data.data.tags;
let frequencyChartData = res.data.data.frequency;
this.positiveChartData['xData'] = Object.keys(positiveChartData);
this.positiveChartData.xData.forEach((el) => {
this.positiveChartData['yData'].push(Number(positiveChartData[el].toFixed(2)));
});
this.negativeChartData.xData = Object.keys(negativeChartData);
this.negativeChartData.xData.forEach((el) => {
this.negativeChartData.yData.push(Number(negativeChartData[el].toFixed(2)));
});
let frequencyKeys = Object.keys(frequencyChartData);
frequencyKeys.forEach((el) => {
this.frequencyChartData.push({name:el,value:frequencyChartData[el]})
});
let keys = Object.keys(pieChartData);
keys.splice(0, 1);
keys.forEach((el) => {
this.pieChartData.push({name:el,value:pieChartData[el]})
});
console.log(keys,this.pieChartData)
this.drawChart();
} else {
this.$message.error("拉取错误!");
}
})
// .catch((err) => {
// // this.$Message.error(err + "!");
// });
},
resetSearch() {
this.formData.url = "";
},
drawChart() {
let positiveOption = {
xAxis: {
type: "category",
data: this.positiveChartData.xData,
},
yAxis: {
type: "value",
},
series: [
{
data: this.positiveChartData.yData,
type: "bar",
showBackground: true,
backgroundStyle: {
color: "rgba(180, 180, 180, 0.2)",
},
},
],
};
let negativeOption = {
xAxis: {
type: "category",
data: this.negativeChartData.xData,
},
yAxis: {
type: "value",
},
series: [
{
data: this.negativeChartData.yData,
type: "bar",
showBackground: true,
backgroundStyle: {
color: "rgba(180, 180, 180, 0.2)",
},
},
],
};
let pieOption = {
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
right: '0%'
},
series: [
{
name: 'Access From',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
emphasis: {
label: {
show: true,
fontSize: '20',
fontWeight: 'bold'
}
},
labelLine: {
show: true
},
data: this.pieChartData
}
]
};
let frequencyOption = {
series: [{
type: 'wordCloud',
sizeRange: [15, 80],
rotationRange: [0, 0],
rotationStep: 45,
gridSize: 8,
shape: 'pentagon',
width: '100%',
height: '100%',
textStyle: {
normal: {
color: function () {
return 'rgb(' + [
Math.round(Math.random() * 160),
Math.round(Math.random() * 160),
Math.round(Math.random() * 160)
].join(',') + ')';
}
}
},
data: this.frequencyChartData
}]
};
this.positiveChart.setOption(positiveOption);
this.negativeChart.setOption(negativeOption);
this.pieChart.setOption(pieOption);
this.frequencyChart.setOption(frequencyOption);
},
},
};
</script>
<style scoped>
::v-deep .el-form-item {
margin-bottom: 0px;
}
::v-deep .el-menu.el-menu--horizontal {
border: none;
}
.homePage {
margin: 0;
padding: 0;
height: 100%;
}
.header {
width: 100%;
height: 60px;
line-height: 60px;
background: #0f1423;
position: fixed;
z-index: 999;
}
.content {
padding-top: 60px;
background: #eeeff4;
width: 100%;
display: table;
}
.content::after {
content: '';
display: block;
clear: both;
}
.search {
width: 100%;
background-color: #202741;
height: 80px;
display: flex;
justify-content: center;
align-items: center;
}
.header-title{
margin-left:50px;
float: left;
}
.title{
color: #fff;
margin-left: 40px;
font-size: 20px;
}
.user-info {
float: right;
margin-right: 50px;
color: #fff;
}
.user-info >span:last-child{
margin-left: 40px;
}
.header-icon{
position: absolute;
top: 12px;
}
.charts {
padding: 20px;
height: 100%;
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
}
.box-card {
width: 48%;
height: 420px;
float: left;
margin: 10px;
}
</style>
+407
View File
@@ -0,0 +1,407 @@
<template>
<div class="login">
<div class="login-container">
<div class="contenter">
<!-- 登录 -->
<transition name="slide-fade">
<el-form
v-if="isLogin"
:model="formData"
status-icon
:rules="rules"
ref="formData"
label-width="100px"
class="ruleForm"
label-position="top"
:hide-required-asterisk="true"
>
<div class="title">爬虫数据可视化系统</div>
<el-form-item prop="user" label="用户名">
<el-input
type="text"
v-model="formData.user"
id="username"
autocomplete="off"
placeholder="请输入登录用户名"
></el-input>
</el-form-item>
<el-form-item prop="pass" label="密码">
<el-input
class="password"
type="password"
v-model="formData.pass"
autocomplete="off"
placeholder="请输入登录密码"
></el-input>
</el-form-item>
<el-form-item style="margin-top: 35px">
<el-button
class="sign-in"
style="width: 100%"
type="primary"
@click="submitForm('formData')"
> </el-button
>
<span class="sign-up-tag"
>还没有账户<el-button type="text" @click="toRegist()"
>立即创建</el-button
></span
>
</el-form-item>
</el-form>
</transition>
<!-- 注册 -->
<transition name="slide-fade">
<el-form
style="position:absolute"
v-if="!isLogin && isRegist"
label-position="top"
:model="ruleForm"
status-icon
:rules="rules"
ref="ruleForm"
label-width="100px"
class="ruleForm"
:hide-required-asterisk="true"
>
<el-form-item >
<div class="title-little">注册</div>
</el-form-item>
<el-form-item label="用户名" prop="userNew">
<el-input v-model="ruleForm.userNew"></el-input>
</el-form-item>
<el-form-item label="密码" prop="passNew">
<el-input
type="password"
v-model="ruleForm.passNew"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="checkPass">
<el-input
type="password"
v-model="ruleForm.checkPass"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item style="margin-top:30px">
<el-button type="primary" @click="saveForm('ruleForm')"
>提交</el-button
>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
</transition>
<!-- 注册成功 -->
<transition name="slide-fade">
<div class="regist-success ruleForm" style="position:absolute" v-if="registSuccess && !isLogin">
<div class="title-little">注册</div>
<img class="success-icon" src="../../assets/images/success (2).png" />
<div>账号注册成功</div>
<el-button
class="sign-in"
style="width: 100%"
type="primary"
@click="returnLogin()"
>返回登录页面</el-button
>
</div>
</transition>
</div>
<!-- </div> -->
</div>
</div>
</template>
<script>
// @ is an alias to /src
import * as info from "../../api/info";
export default {
name: "Login",
components: {},
data() {
var validatePass = (rule, value, callback) => {
if (value === "") {
callback(new Error("请输入密码"));
} else {
if (this.ruleForm.checkPass !== "") {
this.$refs.ruleForm.validateField("checkPass");
}
callback();
}
};
var validatePass2 = (rule, value, callback) => {
if (value === "") {
callback(new Error("请再次输入密码"));
} else if (value !== this.ruleForm.passNew) {
callback(new Error("两次输入密码不一致!"));
} else {
callback();
}
};
return {
index: 11111111,
formData: {
user: "",
pass: "",
},
rules: {
user: [
{ required: true, message: "请输入登录用户名", trigger: "blur" },
{
pattern: /^.{1,20}$/,
message: "输入的用户名不得超过20位",
trigger: "blur",
},
],
pass: [{ required: true, message: "请输入登录密码", trigger: "blur" },{
pattern: /^.{1,8}$/,
message: "输入密码不得超过8位",
trigger: "blur",
}],
passNew: [{ validator: validatePass, trigger: "blur" },{
pattern: /^.{1,8}$/,
message: "输入密码不得超过8位",
trigger: "blur",
}],
checkPass: [{ validator: validatePass2, trigger: "blur" }],
userNew: [{ required: true, message: "请输入用户名", trigger: "blur" },
{
pattern: /^.{1,20}$/,
message: "输入的用户名不得超过20位",
trigger: "blur",
},
],
},
ruleForm: {
passNew: "",
checkPass: "",
userNew: "",
},
rules2: {},
isLogin: true,
isRegist:false,
registSuccess: false
};
},
mounted() {
},
methods: {
submitForm(formName) {
// this.$router.push({ path: "/home" });
// console.log(formName);
this.$refs[formName].validate((valid) => {
let params = {
username: this.formData.user,
password: this.formData.pass,
};
if (valid) {
info
.login(params)
.then((res) => {
if (res.data.code == 200) {
console.log(res);
this.data = res.data.data;
localStorage.setItem('username',this.formData.user)
this.$router.push({ path: "/home" });
} else {
this.$message.error("用户名或密码错误!");
}
})
.catch((err) => {
this.$Message.error(err + "!");
});
} else {
console.log("error submit!!");
return false;
}
});
},
toRegist(){
this.isLogin = false;
setTimeout(()=>{
this.isRegist = true
},500)
},
saveForm(formName) {
this.$refs[formName].validate((valid) => {
let params = {
username: this.ruleForm.userNew,
password: this.ruleForm.passNew,
};
if (valid) {
info
.regist(params)
.then((res) => {
if (res.data.code == 200 && res.data.msg == 'success') {
console.log(res);
this.data = res.data.data;
this.isRegist = false;
setTimeout(()=>{
this.registSuccess = true;
},500);
} else {
this.$message.error(res.data.msg + "");
}
})
.catch((err) => {
this.$Message.error(err + "!");
});
} else {
console.log("error submit!!");
return false;
}
});
},
returnLogin(){
this.registSuccess = false;
setTimeout(()=>{
this.isLogin = true;
})
},
resetForm(formName) {
this.$refs[formName].resetFields();
},
},
};
</script>
<style scoped>
/* 可以设置不同的进入和离开动画 */
/* 设置持续时间和动画函数 */
.slide-fade-enter-active {
transition: all .3s ease;
}
.slide-fade-leave-active {
transition: all .5s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active for below version 2.1.8 */ {
transform: translateX(10px);
opacity: 0;
}
::v-deep .el-form--label-top .el-form-item__label {
padding: 0;
}
::v-deep .el-form-item {
margin-bottom: 10px;
}
::v-deep .el-form-item__content {
line-height: 0px;
}
/* ::v-deep .el-button--warning.is-plain:focus,
::v-deep .el-button--warning.is-plain:hover {
border-color: #fdb851;
background: #f9deb5;
} */
.login {
height: 100%;
background: url("../../assets/images/bg1.jpg") no-repeat left 20%;
background-size: cover;
}
.login-title {
height: 100px;
}
.login-container {
padding-top: calc(50% - 200px);
}
.login-bottom {
height: 60px;
position: absolute;
left: 0;
bottom: 0;
}
.content {
width: 360px;
position: relative;
left: calc(50% - 180px);
z-index: 9;
background-color: rgba(251, 252, 241, 0.8);
/* opacity: 0.9; */
border-radius: 10px;
padding: 10px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.contenter {
width: 400px;
height: 420px;
position: absolute;
top: calc(50% - 200px);
right: 250px;
z-index: 999;
background-color: rgba(255, 255, 255);
border-radius: 10px;
padding: 20px 30px 20px;
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24);
}
.title {
font-size: 26px;
font-weight: 600;
margin-top: 10px;
margin-bottom: 40px;
text-align: center;
letter-spacing: 16px;
}
.ruleForm {
position: absolute;
width: calc(100% - 60px);
}
.con-title {
text-align: left;
}
.img-logo {
position: relative;
z-index: 9999;
/* top: 100px; */
left: calc(50% - 90px);
}
/* #nav {
padding: 30px;
}
#nav a {
font-weight: bold;
color: #2c3e50;
}
#nav a.router-link-exact-active {
color: #42b983;
} */
.sign-in {
width: 100%;
}
.sign-up {
width: 100%;
margin-top: 15px;
margin-left: 0px !important;
}
.sign-up-tag {
text-align: center;
display: block;
width: 100%;
margin-top: 15px;
margin-left: 0px !important;
}
.title-little {
font-size: 22px;
font-weight: 600;
margin-top: 10px;
margin-bottom: 10px;
}
.success-icon{
margin: 70px auto 10px;
display: block;
width: 100px;
height: 100px;
}
.regist-success{
padding-bottom: 30px;
}
.regist-success>div:nth-child(3){
text-align: center;
margin-bottom: 80px;
}
</style>
+22
View File
@@ -0,0 +1,22 @@
// vue.config.js
module.exports = {
chainWebpack: config => {
config
.plugin('html')
.tap(args => {
args[0].title= '爬虫数据可视化系统'
return args
})
},
devServer: {
proxy: {
'/': {
target: 'http://101.35.53.113:5000',
changeOrigin: true,
// pathRewrite: {
// '^/server-eggs': ''
// }
}
}
}
}