前端初始化

This commit is contained in:
zer0Black
2022-08-31 13:33:52 +08:00
commit 0a11097b80
108 changed files with 14283 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
> 1%
last 2 versions
not dead
+26
View File
@@ -0,0 +1,26 @@
.DS_Store
node_modules
/dist
*.zip
# 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?
*.lock
*-lock.json
+71
View File
@@ -0,0 +1,71 @@
vpnhttps://60.247.58.110:33543
账号密码:lixuan 1qaz@WSX
项目开发分支地址(用于开发) 前端代码地址 http://60.247.58.117:50018/lichaocharlie/CA-DataAnalysis-UI.git master分支
后端代码地址 http://60.247.58.117:50018/lichaocharlie/CA-DataAnalysis.git master分支
项目版本分支地址(用于部署) 前端代码地址
后端代码地址
http://60.247.58.117:50018/lichaocharlie/CA-DataAnalysis-Mysql.git
项目文档地址
禅道地址 http://60.247.58.121:81/pro/user-login-L3Byby9idWctYnJvd3NlLTM0My0wLXVucmVzb2x2ZWQtMC5odG1s.html
账号分配 李昌盛 lijieyu 123456
卢金秋 lichunxiao 123456
司马世豪 cairuiqi 123456
窦旭旺、张亚兰
演示版 内部开发版 内部测试版
本地开发环境简介 应用服务器
(和产品决策用一个) 操作系统 Linux 应用程序 访问地址 【外网地址】http://123.127.164.53:18866
【内网地址】http://192.168.144.22:8866 http://192.168.144.22:9966 http://192.168.144.22:7766
ip:端口 192.168.144.22:12816 程序用户名(超管) admin1 admin1 admin1
服务器用户名 root 程序密码(超管) Ad12345678 Ad12345678 Ad12345678
服务器密码 UBxabSEQFHKQ6hhM 程序用户名(普通用户) leee
程序包路径 【前端】
【后端】 程序密码(普通用户) Lcx123456
数据库服务器 操作系统 Linux 数据库 数据库类型 MySQL MySQL MySQL
ip:端口 192.168.144.80:12816 ip:端口 192.168.144.124:3306 192.168.144.80:3306 192.168.144.80:3306
服务器用户名 root 数据库名称 cadata2 cadata cadata2
服务器密码 $gc7P@k^0tWcZ$7dVA 数据库用户名 adc_forecast root root
数据库路径 数据库密码 adc_forecast root root
插件信息
长安测试环境简介 应用服务器 操作系统 Linux 应用程序 访问地址
ip:端口 程序用户名(超管)
服务器用户名 程序密码(超管)
服务器密码 程序用户名(普通用户)
程序位置 程序密码(普通用户)
数据库服务器 操作系统 Linux 数据库 数据库类型 MySQL
ip:端口 ip:端口
服务器用户名 实例
服务器密码 数据库用户名
数据库密码
var series = option.series;
series[series.length] = {
name: '',
type: 'bar',
data: [0, 0, 0, 0, 0, 0, 0],
color: '#bbf',
stack: '总量',
barWidth: 30,
label: {
show: true,
position: 'top',
color: 'black'
}
};
series[series.length - 1].label.formatter = function (params) {
var datavalue = 0;
for (var i = 0; i < series.length; i++) {
datavalue += series[i].data[params.dataIndex];
}
return datavalue;
};
myChart.setOption(option);
+50
View File
@@ -0,0 +1,50 @@
# CA-DataAnalysis-UI
## Package
```
npm install xe-utils@3 vxe-table@3
https://xuliangzhan_admin.gitee.io/vxe-table/#/table/start/install
npm i vuex-persistedstate
https://blog.csdn.net/weixin_43526371/article/details/110517581
npm i element-ui -S
https://element.eleme.io/#/zh-CN/component/installation
npm install --save axios vue-axios
http://www.axios-js.com/docs/vue-axios.html
npm install uuid
https://www.npmjs.com/package/uuid
npm install echarts vue-echarts
https://blog.csdn.net/weixin_43526371/article/details/121010069?spm=1001.2014.3001.5502
npm install moment
http://momentjs.cn/
npm install --save js-base64
https://www.npmjs.com/package/js-base64
npm install vuedraggable
https://www.itxst.com/vue-draggable/tutorial.html
https://www.npmjs.com/package/vuedraggable
```
## Project setup
```
yarn install
```
### Compiles and hot-reloads for development
```
yarn serve
```
### Compiles and minifies for production
```
yarn build
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
+5
View File
@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
}
+44
View File
@@ -0,0 +1,44 @@
{
"name": "ca_data_analysis_ui",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"vueui": "vue ui"
},
"dependencies": {
"axios": "^0.24.0",
"core-js": "^3.19.1",
"echarts": "^5.2.2",
"element-ui": "^2.15.6",
"js-base64": "^2.6.2",
"linq": "^4.0.0",
"lodash": "^4.17.21",
"moment": "^2.29.1",
"quill": "^1.3.6",
"quill-image-drop-module": "^1.0.3",
"quill-image-extend-module": "^1.1.2",
"quill-image-resize-module": "^3.0.0",
"uuid": "^3.4.0",
"vue": "^2.6.11",
"vue-axios": "^3.4.0",
"vue-echarts": "^6.0.0",
"vue-quill-editor": "^3.0.6",
"vue-router": "^3.2.0",
"vuedraggable": "^2.24.3",
"vuex": "^3.4.0",
"vuex-persistedstate": "^4.1.0",
"vxe-table": "^3.4.6",
"xe-utils": "^3.4.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"sass": "^1.43.4",
"sass-loader": "^8.0.2",
"vue-template-compiler": "^2.6.11"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 66 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 %>favicon.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>
+540
View File
@@ -0,0 +1,540 @@
<template>
<div id="app">
<i @click="closeLoading" class="custom-close el-icon-close" v-if="$store.state.isLoading"></i>
<router-view/>
</div>
</template>
<script>
import {loading} from "./utils/request";
export default {
name: "ReportManager",
data() {
return {}
},
methods: {
getQueryVariable(r, variable) {
if (r) {
var query = r.split('?');
if (query && query.length == 2) {
var vars = query[1].split("&");
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}
}
}
},
closeLoading() {
loading.close();
this.$store.commit('saveIsLoading', false);
},
},
created() {
let _that = this
// var path = window.location.search
// var ticket = this.getQueryVariable(path, 'ticket')
// var loginType = this.getQueryVariable(path, 'loginType')
// if (loginType == 1) {
// window.open('http://10.12.1.78:9090/cas/login?service=http://192.168.144.22:9966/home', '_self');
// } else {
// // if (ticket) {
// // var params = {
// // service: 'http://localhost:8080/home',
// // ticket: ticket
// // }
// // this.$api.login.loginByTicket(params).then(res => {
// // if (res.respCode !== '0') {
// // // this.verifyCode();
// // return this.$message.error(res.data.message);
// // }
// // this.$message.success('登录成功');
// // _that.$store.commit('saveUserInfo', res.data);
// // _that.$router.push('/home');
// // }).catch(_ => {
// // // this.verifyCode();
// // this.$router.push('/');
// // })
// //
// // } else {
// // this.$router.push('/');
// // }
// }
}
}
</script>
<style lang="scss">
* {
margin: 0;
padding: 0;
text-decoration: none;
list-style: none;
box-sizing: border-box;
outline: none;
font-style: normal;
font-family: 'Helvetica Neue', Arial, sans-serif;
}
html, body {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
#app {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
min-width: 1200px;
}
}
img {
background-color: transparent !important;
}
/* =============================================== 多选select =============================================== */
.el-select {
.el-select__tags-text {
max-width: 40px;
}
}
.el-select-dropdown {
z-index: 7777 !important;
}
.el-cascader__tags .el-tag {
max-width: 40px !important;
}
.el-cascader .el-input .el-input__inner {
height: 24px !important;
}
/* =============================================== 页面加载 =============================================== */
.el-loading-mask.is-fullscreen {
z-index: 8888 !important;
}
.custom-close {
cursor: pointer;
position: absolute;
right: 20px;
top: 20px;
z-index: 9999;
font-size: 30px;
color: #6c6c6c;
}
/* =============================================== 页面最小高度 =============================================== */
.content-height {
min-height: calc(100vh - 60px - 20px);
box-shadow: 0 6px 11px 0 rgba(163, 163, 163, 0.2);
border-radius: 6px;
background: #FFFFFF;
}
/* =============================================== el-button =============================================== */
.el-button.del-btn {
color: #ED5C57 !important;
}
.el-button.el-button--primary:hover, .el-button.el-button--primary:focus {
border-color: #1890FF !important;
background-color: transparent !important;
}
.el-button.el-button--primary:hover,
.el-button.el-button--primary:focus {
border-color: #1890FF !important;
background-color: #1890FF !important;
color: #FFFFFF !important;
}
.el-button.el-button--primary:active {
color: #1890FF !important;
}
.el-button--text {
color: #1890FF !important;
border: 0 !important;
}
.el-button--text:hover, .el-button--text:focus {
border: 0 transparent !important;
}
.el-button--primary.is-plain,
.el-button--primary.is-plain:hover,
.el-button--primary.is-plain:focus {
background-color: transparent !important;
color: #1890FF !important;
border-color: #1890FF !important;
}
/* =============================================== input内容颜色 =============================================== */
.el-input__inner,
.el-textarea__inner {
font-weight: 400;
color: #434343;
}
/* =============================================== 虚拟滚动条 =============================================== */
.el-scrollbar {
.el-scrollbar__wrap {
overflow-x: hidden;
margin-bottom: 0 !important;
}
}
/* =============================================== vxetable header高度 =============================================== */
.vxe-header--row {
th.vxe-header--column {
height: 40px !important;
}
th.vxe-header--column.col--checkbox {
padding: 0 !important;
}
}
/* =============================================== vxetable滚动条 =============================================== */
/*滚动条整体部分*/
.vxe-table ::-webkit-scrollbar {
width: 10px;
height: 10px;
}
/*滚动条的轨道*/
.vxe-table ::-webkit-scrollbar-track {
background-color: #EAEAEA;
}
/*滚动条里面的小方块,能向上向下移动*/
.vxe-table ::-webkit-scrollbar-thumb {
background-color: #D8D8D8;
border-radius: 5px;
border: 1px solid #D8D8D8;
box-shadow: inset 0 0 6px rgba(0, 0, 0, .1);
}
.vxe-table ::-webkit-scrollbar-thumb:hover {
background-color: #D8D8D8;
}
.vxe-table ::-webkit-scrollbar-thumb:active {
background-color: #D8D8D8;
}
/*边角,即两个滚动条的交汇处*/
.vxe-table ::-webkit-scrollbar-corner {
background-color: #EAEAEA;
}
/* =============================================== 分页基本样式 =============================================== */
.el-pagination {
text-align: right;
.el-pagination__total,
.el-pagination__sizes {
float: left;
color: #606266;
}
.el-input--mini .el-input__inner {
height: 28px;
line-height: 28px;
}
button {
padding: 0 !important;
text-align: center;
background-color: #FAFAFA !important;
color: #606266 !important;
}
.el-pager {
margin: 0 5px;
.number {
background-color: #FAFAFA !important;
margin: 0 5px;
font-weight: 400;
}
.number.active {
background-color: rgba(64, 158, 255, 0.1) !important;
}
}
}
/* =============================================== 弹窗 =============================================== */
.el-dialog {
position: absolute !important;
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
margin: 0 !important;
min-width: 600px !important;
border-radius: 6px !important;
.el-dialog__header {
height: 52px;
line-height: 52px;
padding-bottom: 0;
margin: 0 18px 0 22px;
border-bottom: 1px solid #EBEEF5;
font-weight: 600;
color: #262626;
.el-dialog__headerbtn {
margin: 16px 24px 0 0;
.el-dialog__close {
font-size: 24px;
color: #6C6C6C;
font-weight: 500;
}
}
}
.el-dialog__body {
padding: 0;
}
}
/* =============================================== search-tag =============================================== */
.search-tag {
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0) !important;
&:hover {
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.25) !important;
}
}
.test {
width: auto!important;
padding: 0px !important;
}
.ql-snow .ql-tooltip[data-mode='link']::before {
content: '请输入链接地址:';
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
border-right: 0px;
content: '保存';
padding-right: 0px;
}
.ql-snow .ql-tooltip[data-mode='video']::before {
content: '请输入视频地址:';
}
.ql-snow .ql-picker.ql-size {
width: 70px!important;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='14px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='14px']::before {
content: '14px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='16px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='16px']::before {
content: '16px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='18px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='18px']::before {
content: '18px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='20px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='20px']::before {
content: '20px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='32px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='32px']::before {
content: '32px';
}
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: '文本';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='1']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='1']::before {
content: '标题1';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='2']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='2']::before {
content: '标题2';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='3']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='3']::before {
content: '标题3';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='4']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='4']::before {
content: '标题4';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='5']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='5']::before {
content: '标题5';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='6']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='6']::before {
content: '标题6';
}
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
content: '标准字体';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='serif']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='serif']::before {
content: '衬线字体';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='monospace']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='monospace']::before {
content: '等宽字体';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-label::before {
content: '行高';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='initial']::before {
content: '默认';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='1']::before {
content: '1';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='1.5']::before {
content: '1.5';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='1.75']::before {
content: '1.75';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='2']::before {
content: '2';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='3']::before {
content: '3';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='4']::before {
content: '4';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='5']::before {
content: '5';
}
.ql-snow .ql-picker.ql-lineheight {
width: 70px;
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=SimSun]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=SimSun]::before {
content: "宋体";
font-family: "SimSun";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=SimHei]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=SimHei]::before {
content: "黑体";
font-family: "SimHei";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Microsoft-YaHei]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Microsoft-YaHei]::before {
content: "微软雅黑";
font-family: "Microsoft YaHei";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=KaiTi]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=KaiTi]::before {
content: "楷体";
font-family: "KaiTi";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=FangSong]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=FangSong]::before {
content: "仿宋";
font-family: "FangSong";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Arial]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Arial]::before {
content: "Arial";
font-family: "Arial";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Times-New-Roman]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Times-New-Roman]::before {
content: "Times New Roman";
font-family: "Times New Roman";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=sans-serif]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=sans-serif]::before {
content: "sans-serif";
font-family: "sans-serif";
}
.ql-font-SimSun {
font-family: "SimSun";
}
.ql-font-SimHei {
font-family: "SimHei";
}
.ql-font-Microsoft-YaHei {
font-family: "Microsoft YaHei";
}
.ql-font-KaiTi {
font-family: "KaiTi";
}
.ql-font-FangSong {
font-family: "FangSong";
}
.ql-font-Arial {
font-family: "Arial";
}
.ql-font-Times-New-Roman {
font-family: "Times New Roman";
}
.ql-font-sans-serif {
font-family: "sans-serif";
}
</style>
+35
View File
@@ -0,0 +1,35 @@
import Vue from "vue";
/**
* 多层级的对象合并
* @param target 目标对象(需要合并到的对象)
* @param source 资源(拥有的对象)
* @returns {target} 合并后的对象
*/
function assignObj(target, source) {
if (typeof (target) !== 'object' || typeof (source) !== 'object') {
return source;
}
for (let key in source) {
target[key] = assignObj(target[key], source[key]);
}
return target;
}
/**
* 获取API
* @type {{install(): *|{}}} Vue.use默认执行的方法
*/
export default {
install() {
Vue.prototype.$api = {}
const requireComponents = require.context('./modules', true, /\.js/)
requireComponents.keys().forEach(file => {
const mod = requireComponents(file);
let fileName = file.replace(/\.\/|\.js/g, '');
fileName = fileName.split('/').map(item => item.replace(/\./g, '_')).reverse().reduce((p, c) => ({[c]: p}), mod.default);
Vue.prototype.$api = assignObj(Vue.prototype.$api, fileName)
})
return Vue.prototype.$api
}
};
+31
View File
@@ -0,0 +1,31 @@
import {instance as request} from "@/utils/request";
export default {
// 获取查询项
queryGetQuery(data) {
return request({
url: `/api/query/getQuery`,
method: 'GET',
params: data
})
},
// 获取品牌
queryGetBrand(data) {
return request({
url: `/api/query/getBrand`,
method: 'GET',
params: data
})
},
// 获取车型
marketSegmentsVehicleSeries(data) {
return request({
url: `/api/marketSegmentsCompete/vehicleSeries`,
method: 'POST',
params: data
})
},
}
+36
View File
@@ -0,0 +1,36 @@
import {instance as request} from "@/utils/request";
// 细分市场竞争格局
export default {
// 车型对比
chooseStyle(data) {
return request({
url: `/api/chooseStyle`,
method: 'GET',
params: data,
});
},
//配置查询
configQuery(data) {
return request({
url: `/api/configQuery`,
method: 'GET',
params: data,
});
},
//基础信息配置查询
configGradientTable(data) {
return request({
url: `/api/gradientContrast`,
method: 'GET',
params: data,
});
},
// 添加车型
chooseStyleAdd(data) {
return request({
url: `/api/chooseStyle/add`,
method: 'GET',
params: data,
});
},
}
+28
View File
@@ -0,0 +1,28 @@
import {instance as request} from "@/utils/request";
// 细分市场竞争格局
export default {
// 车型对比
chooseStyle(data) {
return request({
url: `/api/chooseStyle`,
method: 'GET',
params: data,
});
},
//配置查询
configQuery(data) {
return request({
url: `/api/configQuery`,
method: 'GET',
params: data,
});
},
//基础信息配置查询
configBaseQuery(data) {
return request({
url: `/api/configQuery/carBaseInfo`,
method: 'GET',
params: data,
});
},
}
+19
View File
@@ -0,0 +1,19 @@
import {instance as request} from "@/utils/request";
export default {
// 获取查询项
queryTableData(data) {
return request({
url: '/api/eatpContrast',
method: 'GET',
params: data
})
},
queryOtherData(data) {
return request({
url: '/api/eatpContrast/page',
method: 'GET',
params: data
})
},
}
+42
View File
@@ -0,0 +1,42 @@
import {instance as request} from "@/utils/request";
export default {
// 登录
login(data) {
return request({
url: `/api/login`,
method: 'post',
data
})
},
// 长按ticket登录
// loginByTicket(data) {
// return request({
// url: `/api/cas/validateLogin?service=`+data.service+'&ticket='+data.ticket,
// method: 'get'
// })
// },
pageLog(data) {
return request({
url: `/api/log/log/save?accessPage=`+data,
method: 'get'
})
},
// 获取验证码
verifyCode(data) {
return request({
url: `/api/verifyCode`,
method: 'get',
params: data,
responseType: 'arraybuffer'
})
},
// 退出登录
logout(data) {
return request({
url: `/api/logout`,
method: 'get',
param: data,
})
},
}
+51
View File
@@ -0,0 +1,51 @@
import {instance as request} from "@/utils/request";
export default {
// 删除
delSysRole(data){
return request({
url: `/api/sys/role/${data.id}`,
method: 'DELETE',
})
},
// 修改
putSysRole(data){
return request({
url: `/api/sys/role`,
method: 'PUT',
data
})
},
// 配置角色菜单
sysRoleSaveRoleMenu(data){
return request({
url: `/api/sys/role/saveRoleMenu`,
method: 'POST',
data
})
},
// 配置角色首页
sysRoleSaveRoleHome(data){
return request({
url: `/api/sys/role/saveRoleHome`,
method: 'POST',
data
})
},
// 获取角色首页
sysRoleGetRoleHome(data){
return request({
url: `/api/sys/role/getRoleHome`,
method: 'GET',
params: data
})
},
}
+45
View File
@@ -0,0 +1,45 @@
import {instance as request} from "@/utils/request";
export default {
// 查询菜单
sysMenuFindAllMenus(data) {
return request({
url: `/api/sys/menu/findAllMenus`,
method: 'GET',
params: data
})
},
// 新增
postSysMenu(data) {
return request({
url: `/api/sys/menu`,
method: 'POST',
data
})
},
// 删除
sysMenuDeleteId(data) {
return request({
url: `/api/sys/menu/${data.ids}`,
method: 'DELETE',
})
},
// 修改
putSysMenu(data) {
return request({
url: `/api/sys/menu`,
method: 'PUT',
data
})
},
// 角色对应的菜单
getSysMenu(data) {
return request({
url: `/api/sys/menu`,
method: 'GET',
params: data
})
},
}
+48
View File
@@ -0,0 +1,48 @@
import {instance as request} from "@/utils/request";
// 细分市场竞争格局
export default {
// 车型对比
modelContrastVehicleContrast(data) {
return request({
url: `/api/modelContrast/vehicleContrast`,
method: 'POST',
data
})
},
// 获取款型下拉框
modelContrastGetKxmcList(data) {
return request({
url: `/api/modelContrast/getKxmcList`,
method: 'POST',
data
})
},
// 一个对比组款型对比
modelContrastKxContrast(data) {
return request({
url: `/api/modelContrast/kxContrast`,
method: 'POST',
data
})
},
// 一个对比组的款型对比Execel导出
modelContrastKxExcel(data) {
return request({
url: `/api/modelContrast/kxExcel`,
method: 'POST',
data,
responseType: 'blob'
})
},
// 车型对比Execel导出
modelContrastVehicleExcel(data) {
return request({
url: `/api/modelContrast/vehicleExcel`,
method: 'POST',
data,
responseType: 'blob'
})
},
}
+34
View File
@@ -0,0 +1,34 @@
import {instance as request} from "@/utils/request";
// 车型竞争格局
export default {
// Excel导出
vehicleModelCompeteDownload(data) {
return request({
url: `/api/vehicleModelCompete/download`,
method: 'GET',
params: data,
responseType: 'blob'
})
},
// 主销TP
vehicleModelCompeteKingpinTP(data) {
return request({
url: `/api/vehicleModelCompete/kingpinTP`,
method: 'POST',
params: data
})
},
// 时间段加权TP
vehicleModelCompeteWeightedTP(data) {
return request({
url: `/api/vehicleModelCompete/weightedTP`,
method: 'POST',
params: data
})
},
}
+22
View File
@@ -0,0 +1,22 @@
import {instance as request} from "@/utils/request";
// 分价格段市占率
export default {
// 宽表基础数据
baseDataList(data) {
return request({
url: `/api/baseData/list`,
method: 'GET',
params: data
})
},
// Excel导出
baseDataDownload(data) {
return request({
url: `/api/baseData/download`,
method: 'GET',
params: data,
responseType: 'blob'
})
},
}
+21
View File
@@ -0,0 +1,21 @@
import {instance as request} from "@/utils/request";
// 分价格段市占率
export default {
// 车型趋势Execel导出
vehicleTrendVehicleTrendExcel(data) {
return request({
url: `/api/vehicleTrend/vehicleTrendExcel`,
method: 'POST',
data,
responseType: 'blob'
})
},
// 车型趋势
vehicleTrendVehicleTrendMap(data) {
return request({
url: `/api/vehicleTrend/vehicleTrendMap`,
method: 'POST',
data
})
},
}
+47
View File
@@ -0,0 +1,47 @@
import {instance as request} from "@/utils/request";
// 细分市场竞争格局
export default {
// 整体加权TP
marketSegmentsCompeteOverallWeightedTP(data) {
return request({
url: `/api/marketSegmentsCompete/overallWeightedTP`,
method: 'POST',
params: data
})
},
// 主销TP
marketSegmentsCompeteKingpinTP(data) {
return request({
url: `/api/marketSegmentsCompete/kingpinTP`,
method: 'POST',
params: data
})
},
// Excel导出
marketSegmentsCompeteDownload(data) {
return request({
url: `/api/marketSegmentsCompete/download`,
method: 'GET',
params: data,
responseType: 'blob'
})
},
// downloadPPT
pptDownload(data) {
return request({
url: `/api/pptDownload/download`,
method: 'POST',
data,
responseType: 'blob'
})
},
// downloadPPT
pptDownloads(data) {
return request({
url: `/api/pptDownload/downloads`,
method: 'POST',
data,
responseType: 'blob'
})
},
}
+64
View File
@@ -0,0 +1,64 @@
import {instance as request} from "@/utils/request";
// 分价格段市占率
export default {
// 计算分价格段占比-国别大类
priceGetCltPriceStatistic(data) {
return request({
url: `/api/price/getCltPriceStatistic`,
method: 'GET',
params: data
})
},
// 计算分价格段占比-细分大类
priceGetSltPriceStatistic(data) {
return request({
url: `/api/price/getSltPriceStatistic`,
method: 'GET',
params: data
})
},
// 计算分价格段占比-细分大类-图
getSltPriceStatisticChart(data) {
return request({
url: `/api/price/getSltPriceStatisticChart`,
method: 'GET',
params: data
})
},
// 计算分价格段占比-细分大类-表
getSltPriceStatisticTable(data) {
return request({
url: `/api/price/getSltPriceStatisticTable`,
method: 'GET',
params: data
})
},
// 计算分价格段占比-整体
priceGetToalPriceStatistic(data) {
return request({
url: `/api/price/getToalPriceStatistic`,
method: 'GET',
params: data
})
},
// priceType: tp msrp showType: 'MIX' type: 0 1 2 unit: 1元 2 万元
// excel导出
priceDownload(data) {
return request({
url: `/api/price/download/${data.type}`,
method: 'GET',
params: data,
responseType: 'blob'
})
},
// ppt导出 isUseGb
pricePpt(data) {
return request({
url: `/api/price/ppt`,
method: 'GET',
params: data,
responseType: 'blob'
})
},
}
+21
View File
@@ -0,0 +1,21 @@
import {instance as request} from "@/utils/request";
// 分价格段市占率
export default {
// 整体趋势Execel导出
wholeTrendWholeTrendExcel(data) {
return request({
url: `/api/wholeTrend/wholeTrendExcel`,
method: 'POST',
data,
responseType: 'blob'
})
},
// 整体趋势
wholeTrendWholeTrendMap(data) {
return request({
url: `/api/wholeTrend/wholeTrendMap`,
method: 'POST',
data
})
},
}
+132
View File
@@ -0,0 +1,132 @@
import {instance as request} from "@/utils/request";
export function reportUploadPicFile(data){
return request({
url: `/api/report/uploadPicFile`,
method: 'POST',
data,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
}
export default {
// 日志列表
reportLogList(data){
return request({
url: `/api/reportLog/list`,
method: 'GET',
params: data
})
},
// 标签管理
labelAdd(data){
return request({
url: `/api/label/add`,
method: 'POST',
data
})
},
// 标签列表
labelList(data){
return request({
url: `/api/label/list`,
method: 'GET',
params: data
})
},
// 标签删除|单个
labelDeleteId(data){
return request({
url: `/api/label/delete/${data.id}`,
method: 'POST',
})
},
// 新增或编辑报告
reportAdd(data){
return request({
url: `/api/report/add`,
method: 'POST',
data
})
},
// 详情||上传文件
reportUploadFile(data){
return request({
url: `/api/report/uploadFile`,
method: 'POST',
data,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
},
// 获取报告预览
reportGetReportHtmlId(data){
return request({
url: `/api/report/getReportHtml/${data.id}`,
method: 'GET',
})
},
// 删除报告
reportDelete(data){
return request({
url: `/api/report/delete`,
method: 'POST',
params: data,
})
},
// 报告列表
reportList(data){
return request({
url: `/api/report/list`,
method: 'POST',
data,
})
},
// 获取报告日期列表
reportDateList(data){
return request({
url: `/api/report/reportDateList`,
method: 'GET',
params: data,
})
},
// 标签批量保存
labelSave(data){
return request({
url: `/api/label/save`,
method: 'POST',
data,
})
},
// 下载文件
reportDownload(data){
return request({
url: `/api/report/download`,
method: 'GET',
params: data,
responseType: 'blob'
})
},
// 上传图片
reportUploadPicFile(data){
return request({
url: `/api/report/uploadPicFile`,
method: 'POST',
data,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
},
// 标签顺序
labelMove(data){
return request({
url: `/api/label/move`,
method: 'POST',
params: data,
})
},
}
+67
View File
@@ -0,0 +1,67 @@
import {instance as request} from "@/utils/request";
export default {
// 列表
getSysRole(data){
return request({
url: `/api/sys/role`,
method: 'GET',
params: data
})
},
// 删除
delSysRole(data){
return request({
url: `/api/sys/role/${data.id}`,
method: 'DELETE',
})
},
// 新增
postSysRole(data){
return request({
url: `/api/sys/role`,
method: 'POST',
data
})
},
// 修改
putSysRole(data){
return request({
url: `/api/sys/role`,
method: 'PUT',
data
})
},
// 配置角色菜单
sysRoleSaveRoleMenu(data){
return request({
url: `/api/sys/role/saveRoleMenu`,
method: 'POST',
data
})
},
// 配置角色首页
sysRoleSaveRoleHome(data){
return request({
url: `/api/sys/role/saveRoleHome`,
method: 'POST',
data
})
},
// 获取角色首页
sysRoleGetRoleHome(data){
return request({
url: `/api/sys/role/getRoleHome`,
method: 'GET',
params: data
})
},
}
+42
View File
@@ -0,0 +1,42 @@
import {instance as request} from "@/utils/request";
export default {
// 新增|编辑
sysUserAddUser(data){
return request({
url: `/api/sys/user/addUser`,
method: 'POST',
data
})
},
// 用户启用或禁用
sysUserIsUse(data){
return request({
url: `/api/sys/user/isUse/${data.USID}/${data.type}`,
method: 'POST',
})
},
// 获取所有用户
sysUserList(data){
return request({
url: `/api/sys/user/list`,
method: 'GET',
params: data
})
},
// 获取所有用户
sysUserAllList(){
return request({
url: `/api/sys/user/allList`,
method: 'GET',
})
},
// 删除用户
sysUserDelete(data){
return request({
url: `/api/sys/user/delete`,
method: 'POST',
params: data
})
},
}
+32
View File
@@ -0,0 +1,32 @@
/* ElementUI */
$--color-primary: #1890FF;
$--button-primary-border-color: #1890FF;
$--button-mini-font-size: 14px;
$--button-mini-padding-vertical: 4px;
$--button-mini-padding-horizontal: 26px;
$--input-mini-height: 24px;
$--checkbox-checked-font-color: #1890FF;
$--checkbox-checked-icon-color: #1890FF;
$--checkbox-checked-background-color: #FFFFFF;
$--checkbox-font-weight: 400;
$--pagination-button-width: 30px;
$--pagination-button-height: 30px;
$--menu-item-font-size: 16px;
$--menu-item-font-color: #606266;
$--select-input-focus-border-color: #1890FF;
$--dialog-title-font-size: 16px;
$--dialog-padding-primary: 0;
/* VXE-Table */
$vxe-table-border-color: #EBEEF5;
$vxe-table-header-font-weight: 500;
$vxe-table-header-background-color: #F2F6FC;
$vxe-table-header-font-color: #262626;
$vxe-table-row-striped-background-color: #FAFAFA;
/* ElementUI 主题必需 */
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@import "../../../node_modules/element-ui/packages/theme-chalk/src/index";
/* VXE-Table 主题必需*/
@import '../../../node_modules/vxe-table/styles/index.scss';
+11
View File
@@ -0,0 +1,11 @@
u {
text-decoration: underline;
}
em {
font-style: italic;
}
s, strike, del {
text-decoration: line-through
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

+340
View File
@@ -0,0 +1,340 @@
<template>
<el-scrollbar class="demo-content">
<el-divider>表格</el-divider>
<vxe-table class="tree-data" :data="treeData" :empty-render="{name: 'NotData'}" align="center" border height="800px" row-id="id"
:tree-config="{transform: true, rowField: 'id', parentField: 'parentId', expandAll: false }">
<vxe-column show-overflow show-header-overflow field="date" title="时间" align="left" width="200" tree-node>
<template #header>
<div class="first-col">
<div class="first-col-top">名称</div>
<div class="first-col-bottom">类型</div>
</div>
</template>
</vxe-column>
<template v-for="item in tableHeader">
<vxe-column show-overflow show-header-overflow :field="item.field" :title="item.title"></vxe-column>
</template>
</vxe-table>
<el-divider>修改echarts横坐标顺序</el-divider>
<el-row>
<el-col :span="24">
<v-chart style="height: 300px;" :options="option1" autoresize theme="dark"></v-chart>
</el-col>
<el-col :span="24">
<div class="sort-data">
<vuedraggable v-model="sortData">
<transition-group>
<template v-for="item in sortData">
<el-button type="primary" :key="item.id">{{item.name}}</el-button>
</template>
</transition-group>
</vuedraggable>
</div>
</el-col>
</el-row>
<el-divider>周选择器</el-divider>
<el-date-picker v-model="week" type="week" format="yyyy 第 WW 周" placeholder="选择周" :picker-options="{firstDayOfWeek: 1}"
@change="handleWeekChange"/>
{{ startDate }}~{{ endDate }} | {{ year_week }}
<el-divider>自定义ElementUI主题样式</el-divider>
<el-button type="primary" size="mini">按钮</el-button>
<el-button type="primary" size="small">按钮</el-button>
<el-button type="primary" size="medium">按钮</el-button>
<el-button type="primary" size="default">按钮</el-button>
<!--<el-divider>全局指令(获取当前标签的DOM)</el-divider>-->
<!--<div v-dom>获取当前标签的DOM</div>-->
<el-divider>全局过滤器(格式化时间)</el-divider>
<div>{{ new Date() | formatDate }}</div>
<el-divider>全局调用Api(使用请求拦截器)</el-divider>
<el-button @click="exFun">Request</el-button>
<el-divider>vue-echarts</el-divider>
<el-button style="margin-bottom: 10px;" @click="changeOption">修改</el-button>
<v-chart style="height: 300px;" :options="option" autoresize theme="dark"></v-chart>
<el-divider>el-scrollbar</el-divider>
<p>{{ max }} {{ value }}</p>
<el-scrollbar ref="scrollbar" style="height: 200px;border: 1px solid #333;">
<p v-for="item in 20" :key="item"
style="text-align: center;background: #99a9bf;margin: 10px;line-height: 30px;">{{ item }}</p>
</el-scrollbar>
<el-slider v-model="value" :max="max" :format-tooltip="formatTooltip"></el-slider>
<el-divider>VXETable(表格与分页)</el-divider>
<vxe-table :empty-render="{name: 'NotData'}" border show-overflow highlight-hover-row ref="xTable" height="200"
:sort-config="{trigger: 'cell'}">
<vxe-column show-overflow type="seq" width="100"></vxe-column>
<vxe-column show-overflow field="name" title="Name" sortable></vxe-column>
<vxe-column show-overflow field="sex" title="Sex"></vxe-column>
<vxe-column show-overflow field="age" title="Age"></vxe-column>
<vxe-column show-overflow field="address" title="Address" show-overflow></vxe-column>
</vxe-table>
<vxe-pager align="left" :current-page.sync="q.page" :page-size.sync="q.size" :total="q.total"></vxe-pager>
<el-divider>vuex-persistedstate</el-divider>
<el-button @click="saveUserInfo">vuex-persistedstate: {{ $store.state.userInfo }}</el-button>
<el-divider>uuid</el-divider>
<p>uuid: {{ uuid }}</p>
</el-scrollbar>
</template>
<script>
import {v4 as uuidv4} from "uuid";
import vuedraggable from 'vuedraggable'
export default {
name: "Demo",
components: {
vuedraggable
},
data() {
return {
option1: {
xAxis: {
type: "category",
data: [],
},
yAxis: {
type: "value",
},
series: [
{
data: [],
type: "scatter",
symbolSize: function (data) {
return data[1] / 2.5;
},
},
],
},
sortData: [
{id: uuidv4(), name: 'Mon', value: 150},
{id: uuidv4(), name: 'Tue', value: 230},
{id: uuidv4(), name: 'Wed', value: 224},
{id: uuidv4(), name: 'Thu', value: 218},
{id: uuidv4(), name: 'Fri', value: 135},
{id: uuidv4(), name: 'Sat', value: 147},
{id: uuidv4(), name: 'Sun', value: 260},
],
week: "",
year_week: "",
startDate: "",
endDate: "",
option: {
xAxis: {
type: "category",
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
},
yAxis: {
type: "value",
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: "line",
},
],
},
max: 0,
value: 0,
q: {
page: 1,
size: 20,
total: 200,
},
uuid: uuidv4(),
tableHeader: [
{ field: 'a', title: '2020-01'},
{ field: 'b', title: '2020-02'},
{ field: 'c', title: '2020-03'},
{ field: 'd', title: '2020-04'},
],
treeData: [
{ id: 10000, parentId: null, a: 'Test1', b: '1111', c: '222', d: '3333' },
{ id: 10001, parentId: 10000, a: 'Test1', b: '1111', c: '222', d: '3333' },
{ id: 10002, parentId: 10000, a: 'Test1', b: '1111', c: '222', d: '3333' },
{ id: 10003, parentId: 10000, a: 'Test1', b: '1111', c: '222', d: '3333' },
{ id: 20000, parentId: null, a: 'Test2', b: '1111', c: '222', d: '3333' },
{ id: 20001, parentId: 20000, a: 'Test2', b: '1111', c: '222', d: '3333' },
{ id: 20002, parentId: 20000, a: 'Test2', b: '1111', c: '222', d: '3333' },
{ id: 20003, parentId: 20000, a: 'Test2', b: '1111', c: '222', d: '3333' },
{ id: 20004, parentId: 20000, a: 'Test2', b: '1111', c: '222', d: '3333' },
{ id: 30000, parentId: null, a: 'Test3', b: '1111', c: '222', d: '3333' },
{ id: 30001, parentId: 30000, a: 'Test3', b: '1111', c: '222', d: '3333' },
{ id: 40000, parentId: null, a: 'Test4', b: '1111', c: '222', d: '3333' },
],
};
},
methods: {
handleTree(arr){
let cloneData = JSON.parse(JSON.stringify(arr)) // 对源数据深度克隆
return cloneData.filter((father) => {
let branchArr = cloneData.filter(child => father.id == child.parentId); //返回每一项的子级数组
father.children = branchArr.length > 0 ? branchArr : null; //如果存在子级,则给父级添加一个children属性,并赋值
return father.parentId == -1; //返回第一层
})
},
handleWeekChange(val) {
let date = `${new Date(val).getFullYear()}-${new Date(val).getMonth() + 1}-${new Date(val).getDate()}`;
let firstTime = new Date(date).getTime() - 24 * 60 * 60 * 1000;
this.startDate = `${new Date(firstTime).getFullYear()}-${new Date(firstTime).getMonth() + 1}-${new Date(firstTime).getDate()}`;
let lastTime = new Date(date).getTime() + 5 * 24 * 60 * 60 * 1000;
this.endDate = `${new Date(lastTime).getFullYear()}-${new Date(lastTime).getMonth() + 1}-${new Date(lastTime).getDate()}`;
let year = require("moment")(val).utcOffset("+08:00").format("yyyy");
let week = require("moment")(val).utcOffset("+08:00").format("WW");
this.year_week = `${year}${week}`;
},
// Api
exFun() {
console.log(require("moment"));
this.$api.ex
.exFun()
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
},
// vue-echarts
changeOption() {
this.option.series[0].type = "bar";
},
// el-scrollbar
scrollChange() {
this.max =
this.$refs.scrollbar.wrap.scrollHeight -
this.$refs.scrollbar.wrap.clientHeight;
this.$refs.scrollbar.wrap.onscroll = (e) => {
this.value = e.target.scrollTop;
};
},
formatTooltip(value) {
this.$refs.scrollbar.wrap.scrollTop = value;
},
// VXETable
getTableData() {
this.$nextTick(() => {
const $table = this.$refs.xTable;
const list = [];
for (let index = 0; index < 50; index++) {
list.push({
name: `名称${index}`,
sex: "0",
num: 123,
age: 18,
num2: 234,
rate: 3,
address: "shenzhen",
});
}
$table.loadData(list);
});
},
// vuex-persistedstate
saveUserInfo() {
// this.$store.commit("saveUserInfo", {name: "Lee"});
},
},
created() {
console.log("created");
},
mounted() {
this.scrollChange();
this.getTableData();
console.log("mounted");
},
updated(){
// 修改统计顺序
this.option1.xAxis.data = this.sortData.map(item => item.name);
this.option1.series[0].data = this.sortData.map(item => [item.name, item.value]);
},
// 进入组件执行 仅在keep-alive时起作用
activated() {
this.$refs.scrollbar.wrap.scrollTop = this.value;
console.log("activated");
},
// 离开组件执行 仅在keep-alive时起作用
deactivated() {
console.log("deactivated");
},
};
</script>
<style lang="scss" scoped>
.demo-content {
width: 100%;
height: 100%;
padding: 20px;
background-color: #FAFAFA;
.sort-data{
padding: 5px 10px;
background-color: #333333;
>div>span{
display: flex;
justify-content: space-between;
align-items: center;
.el-button{
flex: 1;
}
}
}
.tree-data{
::v-deep .vxe-header--column.col--ellipsis > .vxe-cell:first-child{
padding: 0;
.first-col {
position: relative;
height: 40px;
width: 200px;
display: flex;
justify-content: space-between;
align-items: center;
&:before{
content: "";
position: absolute;
left: -2px;
top: 20px;
width: 204px;
height: 1px;
transform: rotate(11deg);
background-color: #e8eaec;
}
.first-col-top {
flex: 1;
text-align: left;
padding: 10px 0 0 10px;
}
.first-col-bottom{
flex: 1;
text-align: right;
padding: 0 10px 10px 0;
}
}
}
::v-deep .vxe-table--body .vxe-body--row>td:first-child{
background-color: #F2F6FC;
}
::v-deep .vxe-table--body tbody> tr:nth-child(2n) td{
background-color: #FAFAFA;
}
}
}
</style>
+308
View File
@@ -0,0 +1,308 @@
<template>
<div></div>
</template>
<script>
import * as echarts from 'echarts/lib/echarts'
import debounce from 'lodash/debounce'
import {addListener, removeListener} from 'resize-detector'
// enumerating ECharts events for now
const EVENTS = [
'legendselectchanged',
'legendselected',
'legendunselected',
'legendscroll',
'datazoom',
'datarangeselected',
'timelinechanged',
'timelineplaychanged',
'restore',
'dataviewchanged',
'magictypechanged',
'geoselectchanged',
'geoselected',
'geounselected',
'pieselectchanged',
'pieselected',
'pieunselected',
'mapselectchanged',
'mapselected',
'mapunselected',
'axisareaselected',
'focusnodeadjacency',
'unfocusnodeadjacency',
'brush',
'brushselected',
'rendered',
'finished',
'click',
'dblclick',
'mouseover',
'mouseout',
'mousemove',
'mousedown',
'mouseup',
'globalout',
'contextmenu'
]
const ZR_EVENTS = [
'click',
'mousedown',
'mouseup',
'mousewheel',
'dblclick',
'contextmenu'
]
const INIT_TRIGGERS = ['theme', 'initOptions', 'autoresize']
const REWATCH_TRIGGERS = ['manualUpdate', 'watchShallow']
export default {
props: {
options: Object,
theme: [String, Object],
initOptions: Object,
group: String,
autoresize: Boolean,
watchShallow: Boolean,
manualUpdate: Boolean
},
data() {
return {
lastArea: 0
}
},
watch: {
group(group) {
this.chart.group = group
},
},
methods: {
// provide an explicit merge option method
mergeOptions(options, notMerge, lazyUpdate) {
if (this.manualUpdate) {
this.manualOptions = options
}
if (!this.chart) {
this.init(options)
} else {
this.delegateMethod('setOption', options, notMerge, lazyUpdate)
}
},
// just delegates ECharts methods to Vue component
// use explicit params to reduce transpiled size for now
appendData(params) {
this.delegateMethod('appendData', params)
},
resize(options) {
this.delegateMethod('resize', options)
},
dispatchAction(payload) {
this.delegateMethod('dispatchAction', payload)
},
convertToPixel(finder, value) {
return this.delegateMethod('convertToPixel', finder, value)
},
convertFromPixel(finder, value) {
return this.delegateMethod('convertFromPixel', finder, value)
},
containPixel(finder, value) {
return this.delegateMethod('containPixel', finder, value)
},
showLoading(type, options) {
this.delegateMethod('showLoading', type, options)
},
hideLoading() {
this.delegateMethod('hideLoading')
},
getDataURL(options) {
return this.delegateMethod('getDataURL', options)
},
getConnectedDataURL(options) {
return this.delegateMethod('getConnectedDataURL', options)
},
clear() {
this.delegateMethod('clear')
},
dispose() {
this.delegateMethod('dispose')
},
delegateMethod(name, ...args) {
if (!this.chart) {
this.init()
}
return this.chart[name](...args)
},
delegateGet(methodName) {
if (!this.chart) {
this.init()
}
return this.chart[methodName]()
},
getArea() {
return this.$el.offsetWidth * this.$el.offsetHeight
},
init(options) {
if (this.chart) {
return
}
let chart = echarts.init(this.$el, this.theme, this.initOptions)
if (this.group) {
chart.group = this.group
}
chart.setOption(options || this.manualOptions || this.options || {}, true)
// expose ECharts events as custom events
EVENTS.forEach(event => {
chart.on(event, params => {
this.$emit(event, params)
})
})
ZR_EVENTS.forEach(event => {
chart.getZr().on(event, params => {
this.$emit(`zr:${event}`, params)
})
})
if (this.autoresize) {
this.lastArea = this.getArea()
this.__resizeHandler = debounce(() => {
if (this.lastArea === 0) {
// emulate initial render for initially hidden charts
this.mergeOptions({}, true)
this.resize()
this.mergeOptions(this.options || this.manualOptions || {}, true)
} else {
this.resize()
}
this.lastArea = this.getArea()
}, 100, {leading: true})
addListener(this.$el, this.__resizeHandler)
}
Object.defineProperties(this, {
// Only recalculated when accessed from JavaScript.
// Won't update DOM on value change because getters
// don't depend on reactive values
width: {
configurable: true,
get: () => {
return this.delegateGet('getWidth')
}
},
height: {
configurable: true,
get: () => {
return this.delegateGet('getHeight')
}
},
isDisposed: {
configurable: true,
get: () => {
return !!this.delegateGet('isDisposed')
}
},
computedOptions: {
configurable: true,
get: () => {
return this.delegateGet('getOption')
}
}
})
this.chart = chart
},
initOptionsWatcher() {
if (this.__unwatchOptions) {
this.__unwatchOptions()
this.__unwatchOptions = null
}
if (!this.manualUpdate) {
this.__unwatchOptions = this.$watch('options', (val, oldVal) => {
if (!this.chart && val) {
this.init()
} else {
// mutating `options` will lead to merging
// replacing it with new reference will lead to not merging
// eg.
// `this.options = Object.assign({}, this.options, { ... })`
// will trigger `this.chart.setOption(val, true)
// `this.options.title.text = 'Trends'`
// will trigger `this.chart.setOption(val, false)`
this.chart.setOption(val, val !== oldVal)
}
}, {deep: !this.watchShallow})
}
},
destroy() {
if (this.autoresize) {
removeListener(this.$el, this.__resizeHandler)
}
this.dispose()
this.chart = null
},
refresh() {
if (this.chart) {
this.destroy()
this.init()
}
}
},
created() {
this.initOptionsWatcher()
INIT_TRIGGERS.forEach(prop => {
this.$watch(prop, () => {
this.refresh()
}, {deep: true})
})
REWATCH_TRIGGERS.forEach(prop => {
this.$watch(prop, () => {
this.initOptionsWatcher()
this.refresh()
})
})
},
mounted() {
// auto init if `options` is already provided
if (this.options) {
this.init()
}
},
activated() {
if (this.autoresize) {
this.chart && this.chart.resize()
}
},
destroyed() {
if (this.chart) {
this.destroy()
}
},
connect(group) {
if (typeof group !== 'string') {
group = group.map(chart => chart.chart)
}
echarts.connect(group)
},
disconnect(group) {
echarts.disConnect(group)
},
registerMap(mapName, geoJSON, specialAreas) {
echarts.registerMap(mapName, geoJSON, specialAreas)
},
registerTheme(name, theme) {
echarts.registerTheme(name, theme)
},
graphic: echarts.graphic
}
</script>
+222
View File
@@ -0,0 +1,222 @@
<template>
<div class="header">
<div class="logo">
<img src="@/assets/imgs/logo.jpg" alt="">
</div>
<div class="breadcrumb">
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/report/list', query: {showId: $route.query.id } }"><img
src="@/assets/imgs/icon-home.png" alt=""><span>首页</span></el-breadcrumb-item>
<el-breadcrumb-item v-if="this.$route.path == '/system/urlIndex'">{{this.$store.state.menuName}}</el-breadcrumb-item>
<el-breadcrumb-item v-else-if="this.$route.path == '/system/401Page'">{{this.$store.state.menuName}}</el-breadcrumb-item>
<template v-else v-for="item in $route.meta.crumb">
<el-breadcrumb-item>{{ item }}</el-breadcrumb-item>
</template>
</el-breadcrumb>
</div>
<div style="display: flex;margin-left: auto">
<div class="setsys-menu" @click="goSystemPage" v-if="isSystemManager">
<img src="../assets/imgs/icon-setting.png" alt="" width="14" height="14">
<span>系统设置</span>
</div>
<div>
<el-popover v-model="popoverValue" trigger="click" transition="">
<div class="user-operate">
<el-row>
<el-col :span="24">
<el-button type="text" @click="logout">退出系统</el-button>
</el-col>
</el-row>
</div>
<div class="user" slot="reference">
<img src="@/assets/imgs/avatar.png" alt="">
<span>你好{{$store.state.userInfo.usname}}</span>
<i v-if="!popoverValue" class="el-icon-arrow-down"></i>
<i v-else class="el-icon-arrow-up"></i>
</div>
</el-popover>
</div>
</div>
</div>
</template>
<script>
import {mapGetters} from 'vuex';
import {BASE_URL} from "../utils/http";
export default {
name: "Header",
data() {
return {
popoverValue: false
}
},
computed: {
...mapGetters({
menuData: 'menuData',
}),
isSystemManager() {
return this.menuData.some(menu => menu.id === 'AVL9YSB7ZF');
},
isSystemManagerBelong() {
return this.menuData.some(menu => menu.id === 'AVL9YSB7ZF' && menu.belong == 1);
},
},
methods: {
// 退出系统
logout() {
this.$confirm('确定退出系统?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$api.login.logout().then(_ => {
this.$message.success('退出成功');
this.$store.commit('saveUserInfo', null);
// var sevice = "http://"+window.location.host+"/";
// var serviceUrl = encodeURIComponent(sevice);
//正式
// window.open("https://caddmuat.changan.com.cn/cas/logout?service=http://10.64.23.30:7766/home", '_self');
//测试
// window.open(BASE_URL.BASE_CHANGAN + "/logout?service=" + BASE_URL.BASE_LOCAL + "/login?loginType=1", '_self');
this.$router.push('/login');
})
})
},
goSystemPage() {
if(this.isSystemManagerBelong){
if (this.$route.path === '/system/menu') return;
this.$store.commit('savePathUrl', '/system/menu');
this.$router.push({path: '/system/menu', query: {id: 'AVL9YSB7ZF'}});
}else{
if(this.$route.path == '/system/401Page'){
}else{
this.$router.replace({name: '401Page', query: {id: 'AVL9YSB7ZF'}});
}
}
}
}
}
</script>
<style lang="scss" scoped>
.header {
display: flex;
align-items: center;
height: 100%;
position: relative;
background: rgb(4, 71, 155);
.logo {
width: 200px;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
img {
width: auto !important;
height: 40px !important;
// width: 172px;
// height: 26px;
margin-top: 0 !important;
}
}
.breadcrumb {
padding-left: 30px;
height: 100%;
::v-deep .el-breadcrumb {
height: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
.el-breadcrumb__item {
display: flex;
justify-content: flex-start;
align-items: center;
.el-breadcrumb__inner {
display: flex;
justify-content: flex-start;
align-items: center;
}
}
img {
width: 14px;
height: 14px;
margin-right: 3px;
margin-top: -2px;
}
span {
color: #FFFFFF;
font-weight: 500;
}
.el-breadcrumb__separator {
margin: 0 5px;
}
}
}
.setsys-menu {
margin-right: 10px;
display: inline-flex;
justify-content: center;
align-items: center;
/*position: absolute;*/
/*right: 225px;*/
cursor: pointer;
span {
color: #FFFFFF;
margin-left: 5px;
font-size: 14px;
}
}
.user {
/*position: absolute;*/
/*top: 0;*/
/*right: 0;*/
/*bottom: 0;*/
height: 100%;
display: flex;
align-items: center;
img {
width: 38px;
height: 38px;
margin-right: 15px;
}
span {
font-size: 16px;
color: #FFFFFF;
margin-right: 19px;
}
i {
margin-right: 17px;
color: #FFFFFF;
}
}
}
.user-operate {
::v-deep .el-button {
width: 100%;
font-size: 14px;
}
}
</style>
+194
View File
@@ -0,0 +1,194 @@
<template>
<div class="menu-submenu" :class="{'submenu-active': $route.path.indexOf(path) !== -1}">
<!-- 遍历菜单数据 -->
<MenuItem :key="item.id" v-for="(item, index) in menuData" :menuItemData="item">
<!-- 没有children的子菜单 -->
<template v-if="!item.children">
<div class="menu-content" :class="{'active': item.href.indexOf($route.path) !== -1 || (item.href==$store.state.pathUrl)}">
<div class="menu-data" @click="handleRouter(item)"
:style="{'padding-left': item.level >= 2 ? '30px' : '10px'}">
<div class="menu-data-flex">
<img class="menu-icon" v-if="item.icon" :src="item.icon" alt="">
<span> <i class="icon-level2" v-if="item.level===3"></i> {{ item.label }}</span>
</div>
</div>
</div>
</template>
<!-- 有children的子菜单 -->
<template v-else>
<div class="menu-content"
:class="{'active': item.href.indexOf($route.path) !== -1 || (item.href==$store.state.pathUrl), 'is-collage': !item.isCollage}"
@click="collageMenu(item)">
<div class="menu-data"
:class="item.level === 1 ? 'bor-b' : ''"
:style="{'padding-left': item.level >= 2 ? '30px' : '10px'}">
<div class="menu-data-flex">
<img class="menu-icon" v-if="item.icon" :src="item.icon" alt="">
<span>{{ item.label }}</span>
</div>
<template v-if="item.level === 1">
<i v-if="!item.isCollage" class="el-icon-arrow-right" style="margin-right: 12px;"></i>
<i v-else class="el-icon-arrow-down" style="margin-right: 12px;"></i>
</template>
<template v-else>
<i v-if="!item.isCollage" class="el-icon-plus" style="margin-right: 12px;"></i>
<i v-else class="el-icon-minus" style="margin-right: 12px;"></i>
</template>
</div>
</div>
<!-- 递归操作 -->
<Menu :menuData="item.children" :path="item.href"></Menu>
</template>
</MenuItem>
</div>
</template>
<script>
import {createLogger} from 'vuex';
import MenuItem from "./MenuItem";
import login from '../api/modules/login'
import store from '../store'
export default {
name: "Menu",
props: ["menuData", "path"],
components: {
MenuItem
},
methods: {
handleRouter(item) {
if(item.belong == 0){
this.$store.commit('saveMenuName', item.label);
if(this.$route.path == '/system/401Page'){
}else{
this.$router.push({name: '401Page', query: this.$route.query});
}
}else{
this.$store.commit('savePathUrl', item.href);
if (item.isUrl && Number(item.isUrl || 0)) {
var param = this.$route.query
// delete(this.$route.query.itemHref)
// param.itemHref = item.href
if(this.$route.path == '/system/urlIndex'){
this.$store.commit('saveMenuName', item.label);
login.pageLog(this.$store.state.menuName).then(res => {
}).catch(_ => {
})
}else{
this.$store.commit('saveMenuName', item.label);
this.$router.push({name: 'urlIndex', query: param});
}
} else {
if (this.$route.path === item.href) return;
// delete(this.$route.query.itemHref)
this.$router.push({path: item.href, query: this.$route.query});
}
}
},
collageMenu(item) {
item.isCollage = !item.isCollage;
console.log(item.isCollage);
}
}
}
</script>
<style lang="scss" scoped>
.menu-submenu {
background-color: #f3f6fd;
&.submenu-active {
// background-color: #f3f6fd;
}
.menu-content {
overflow: hidden;
height: 48px;
&.active {
.menu-data {
position: relative;
// background-color: rgba(216, 230, 246, 1);
background-color: #c7d0dd;
// border-radius: 100px 0 0 100px;
&::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 4px;
background-color: #168fe3;
}
span {
// color: rgba(24, 144, 255, 1);
color: #333;
}
}
}
&.is-collage + .menu-submenu {
display: none;
}
.menu-data {
cursor: pointer;
display: flex;
/*justify-content: space-between;*/
align-items: center;
padding-left: 21px;
// margin-top: 6px;
height: 100%;
// background-color: #EDEDED;
.menu-data-flex {
display: flex;
align-items: center;
justify-content: flex-start;
}
.menu-icon {
width: 16px;
height: 16px;
margin-right: 5px;
margin-top: 0 !important;
}
}
span {
color: #262626;
font-size: 16px;
font-weight: 500;
/*white-space: nowrap;*/
}
}
.menu-submenu {
.menu-data {
span {
font-size: 14px;
}
}
}
}
.icon-level2 {
display: inline-block;
width: 3px;
height: 3px;
background-color: #333;
// background-color: rgba(183, 191, 195, 1);
border-radius: 50%;
margin-right: 3px;
vertical-align: middle;
}
.bor-b {
border-top: 1px solid #e3e8f3;
border-bottom: 1px solid #e3e8f3;
}
</style>
+18
View File
@@ -0,0 +1,18 @@
<template>
<div class="menu-item" :class="{'active': (menuItemData.href.indexOf($route.path) !== -1) || (menuItemData.href == $store.state.pathUrl)}"><slot/></div>
</template>
<script>
export default {
name: "MenuItem",
props: ['menuItemData']
}
</script>
<style lang="scss" scoped>
.menu-item{
&.active{
// background: #F8F8FA;
}
}
</style>
+256
View File
@@ -0,0 +1,256 @@
<template>
<el-dialog
title="品牌->车型->款型"
style=";font-family: auto"
class="my-dialog"
:visible.sync="dialogVisible">
<div class="AZClass">
<div class="word-list" ref="letterList">
<div class="letterClass" :class="{hoverClass: clicked == item}"
v-for="item in wordList"
:key="item"
@click="goIndex(item)">
{{ item }}
</div>
</div>
<el-cascader-panel style="height:638px" :props="{multiple:false}" ref="groupRef" :options="options"
@change="selectFun">
<template slot-scope="{ node, data }" :class="{hoverClass: data.level != 3}">
<div v-if="data.level != 3">
<span v-if="wordList.indexOf(data.label) != -1">{{ data.label }}</span>
<span v-else>{{ data.label }}</span>
</div>
<div v-else style="display: inline-flex;width: 100%;padding-bottom: 5px">
<span style="display: inline-block;width: 66%;white-space: break-spaces;line-height: 17px">{{data.data.kxmc}}</span>
<span style="display: inline-block;width: 17%;line-height: 17px;position: absolute;left: 66%">{{data.data.msrpw ? (data.data.msrpw + '万') : '-'}}</span>
<span style="display: inline-block;width: 17%;line-height: 17px;position: absolute;left: 83%">{{data.data.mix && data.data.mix!='-' ? data.data.mix : '0.00%'}}</span>
</div>
</template>
</el-cascader-panel>
</div>
</el-dialog>
</template>
<script>
export default {
data() {
return {
clicked: '',
options: [],
wordList: [
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z'
],
dialogVisible: false
}
},
props: ['callback'],
mounted() {
this.getList()
this.clicked = ''
},
methods: {
changeOpen() {
this.dialogVisible = !this.dialogVisible
},
selectFun(item) {
if (this.callback && item.length == 3) {
this.callback(item)
this.dialogVisible = false
}
},
getList() {
this.options = []
this.$api.config.gradient.chooseStyleAdd().then(res => {
this.options = this.formatDataFirst(res.data)
// Object.keys(res.data).forEach(key => {
// // tag
// let d = {
// value:key,
// label:key
// }
// this.options.push(d)
// // info
// let info = res.data[key]
// Object.keys(info).forEach(newkey => {
// debugger
// let ib = {
// value:newkey,
// label:newkey,
// children:info[newkey]
// }
// this.options.push(ib)
// })
// });
//
})
},
formatDataFirst(data) {
let list = []
Object.keys(data).forEach(key => {
// tag
let d = {
level: 1,
value: key,
label: key
}
list.push(d)
// info
let info = data[key]
Object.keys(info).forEach(newkey => {
let ib = {
level: 1,
value: newkey,
label: newkey,
children: []
}
ib.children = this.formatData(info[newkey])
list.push(ib)
})
});
return list
},
formatData(data) {
let list = []
Object.keys(data).forEach(key => {
let id = data[key]
let d = {
level: 2,
value: key,
label: key,
children: []
}
id.forEach(newdata => {
let ib = {
level: 3,
value: newdata,
label: newdata['kxmc'] + (newdata['msrpw'] ? (" " + newdata['msrpw']) : '') + " " + newdata['mix'],
data: newdata
}
d.children.push(ib)
})
// debugger
list.push(d)
})
return list
},
goIndex(params) {
const groupRef = this.$refs.groupRef.$children[0].$children[0].$refs.resize
const titleRef = this.$refs.groupRef.$children[0].$children[0].$refs.resize.childNodes
this.clicked = params
titleRef.forEach((item) => {
if (item.innerText === params) {
// debugger
groupRef.parentElement.scrollTo({
top: item.offsetTop,
behavior: 'smooth' // 平滑移动
})
}
})
// groupRef.scrollTop = offsetTop
}
}
}
</script>
<style lang="scss" scoped>
.AZClass {
// background: #fff;
display: flex;
// position: absolute;
// top: 0;
// left: 0;
// z-index: 999;
}
.word-list {
color: #fff;
background-color: #1f69c3;
font-size: 14px;
line-height: 18px;
padding: 6px;
text-align: center;
width: 30px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.letterClass {
margin-bottom: 4px;
}
.letterClass:hover {
font-size: 16px;
font-weight: bolder;
cursor: pointer;
}
.hoverClass {
font-size: 16px;
font-weight: bolder;
cursor: pointer;
}
.el-scrollbar ::v-deep .el-scrollbar__wrap {
height: 100%;
}
.my-dialog {
height: 1000px
}
.el-dialog__title {
font-family: auto;
}
</style>
<style>
.AZClass .el-cascader-menu .el-cascader-menu__wrap {
height: 630px !important;
}
.my-dialog .el-dialog {
width: 930px;
}
.my-dialog .el-cascader-menu {
width: 240px;
}
.my-dialog .el-cascader-menu:last-child {
width: 420px;
}
.my-dialog .el-cascader-menu:nth-child(3) .el-cascader-node {
height: auto;
line-height: 17px;
}
</style>
+17
View File
@@ -0,0 +1,17 @@
import Vue from "vue";
/**
* 获取API
* @type {{install(): *|{}}} Vue.use默认执行的方法
*/
export default {
install() {
const requireComponents = require.context('./modules', false, /\.js/);
requireComponents.keys().forEach(file => {
const directives = requireComponents(file).default;
for (const directive in directives) {
Vue.directive(directive, directives[directive]);
}
});
}
};
@@ -0,0 +1,11 @@
import Vue from "vue";
export default {
tableMinHeight: {
// 指令的定义
inserted(el, binding, vnode) {
let dom = el.getElementsByClassName('vxe-table--body-wrapper body--wrapper').item(0);
dom.style.setProperty('min-height', binding.value, 'important')
},
}
}
+17
View File
@@ -0,0 +1,17 @@
import Vue from "vue";
/**
* 获取API
* @type {{install(): *|{}}} Vue.use默认执行的方法
*/
export default {
install() {
const requireComponents = require.context('./modules', false, /\.js/);
requireComponents.keys().forEach(file => {
const filters = requireComponents(file).default;
for (const filter in filters) {
Vue.filter(filter, filters[filter]);
}
});
}
};
+9
View File
@@ -0,0 +1,9 @@
export default {
formatDate: function (value) {
let date = new Date(value);
let y = date.getFullYear();
let m = date.getMonth() + 1;
let d = date.getDate();
return `${y}/${m}/${d}`;
}
}
+73
View File
@@ -0,0 +1,73 @@
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import config from "@/utils/config";
// VXETable
import 'xe-utils'
import VXETable from 'vxe-table'
import 'vxe-table/lib/style.css'
// ElementUI
import ElementUI from 'element-ui';
import './assets/css/element-variables.scss'
// ECharts
import 'echarts'
import ECharts from './components/ECharts';
// Api
import Api from './api'
// 自定义指令
import Directive from './directives'
// 自定义过滤器
import Filter from './filters'
// 加密函数
import JSEncrypt from '../src/assets/js/jsencrypt.min.js';
VXETable.setup({
table: {
resizable: true,
}
})
Vue.use(VXETable);
// 富文本引用
import VueQuillEditor from 'vue-quill-editor'
// require styles 引入样式
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
Vue.use(VueQuillEditor)
Vue.use(ElementUI, {size: 'mini', zIndex: 3000});
Vue.component('v-chart', ECharts);
Vue.use(Api);
Vue.use(Directive);
Vue.use(Filter);
Vue.prototype.$JSEncrypt = (data) => {
if(data === ''){
return '';
}
let encryptor = new JSEncrypt();
encryptor.setPublicKey(config.PUBLIC_KEY);
return encryptor.encrypt(data) || '';
}
VXETable.renderer.add('NotData', {
// 空内容模板
renderEmpty (h, renderOpts) {
return [
<span>
<img width="100" src={require('./assets/imgs/icon-nodata.png')}/>
<p style="margin-top: 10px;">暂无数据</p>
</span>
]
}
})
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
+81
View File
@@ -0,0 +1,81 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import store from '../store'
import login from '../api/modules/login'
import {BASE_URL} from "../utils/http"
Vue.use(VueRouter)
let routes = [];
const requireComponents = require.context('./modules', false, /\.js/);
requireComponents.keys().forEach(file => routes = [...routes, ...requireComponents(file).default]);
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
scrollBehavior(to, from, position) {
return position;
},
})
// 路由守卫
router.beforeEach((to, from, next) => {
/**
* 仅报告价格板块
* 报告板块 http://10.10.1.184:8080/#/report/list?id=XBFBR7UADZ
* 价格板块 http://10.10.1.184:8080/#/overall/opricetrend?id=SBME88VTUD
*/
// store.commit('saveUserInfo', {});
// store.commit('saveMenuData', menuTree);
// var url = BASE_URL.BASE_LOCAL + '/login?loginType=1'
// var loginUrl = BASE_URL.BASE_CHANGAN + "/login?service=" + url;
// var logoutUrl = BASE_URL.BASE_CHANGAN + "/logout?service=" + url
if (to.meta.crumb) {
var jumpStr = to.meta.crumb.join('/')
if(jumpStr){
if (jumpStr == 'urlIndex' && to.path != '/system/401Page') {
login.pageLog(store.state.menuName).then(res => {
}).catch(_ => {
})
}else{
login.pageLog(jumpStr).then(res => {
}).catch(_ => {
})
}
}
}
// debugger
// if (to.query.loginType) {
// if (to.query.loginType == 1 && to.query.ticket) {
// var params = {
// service: url,
// ticket: to.query.ticket
// }
// login.loginByTicket(params).then(res => {
// if (res.respCode !== '0') {
// // this.verifyCode();
// // return this.$message.error(res.data.message);
// }
// // this.$message.success('登录成功');
// store.commit('saveUserInfo', res.data);
// next('/home');
// }).catch(_ => {
// window.open(logoutUrl, '_self');
// })
// } else {
// window.open(loginUrl, '_self');
// }
// } else if (to.path.toLowerCase() !== '/login') {
// if (!store.state.userInfo) {
// window.open(logoutUrl, '_self');
// }
// next();
// } else {
next();
// }
})
export default router
+53
View File
@@ -0,0 +1,53 @@
const routes = [
{
path: '/system',
name: '',
component: () => import('../../views/Layout.vue'),
children: [
{
path: 'urlIndex',
name: 'urlIndex',
component: () => import('../../views/System/urlIndex.vue'),
meta: {
crumb: ['urlIndex'],
}
}]},
{
path: '/',
redirect: {
name: 'Login'
// path: '/report/list?id=XBFBR7UADZ'
}
},
// 登录
{
path: '/login',
name: 'Login',
component: () => import('../../views/Login.vue')
},
// // 注册
// {
// path: '/register',
// name: 'Register',
// component: () => import('../../views/Register.vue')
// },
// 首页
// {
// path: '/home',
// name: 'Home',
// component: () => import('../../views/Home.vue')
// },
{
path: '/layout',
name: 'LayoutBox',
component: () => import('../../views/Layout.vue')
},
// // Demo
// {
// path: '/demo',
// name: 'Demo',
// component: () => import('../../components/Demo.vue')
// },
];
export default routes;
+39
View File
@@ -0,0 +1,39 @@
const routes = [
// 报告管理
{
path: '/report',
name: 'Layout',
component: () => import('../../views/Layout.vue'),
children: [
// 报告列表
{
path: 'list',
name: 'ReportList',
component: () => import('../../views/Report/ReportList.vue'),
meta: {
crumb: ['报告列表'],
}
},
// 报告详情
{
path: 'detail',
name: 'ReportDetail',
component: () => import('../../views/Report/ReportDetail.vue'),
meta: {
crumb: ['报告详情'],
}
},
// 报告管理
{
path: '/report/manager',
name: 'ReportManager',
component: () => import('../../views/Report/ReportManager.vue'),
meta: {
crumb: ['报告管理'],
}
},
]
},
];
export default routes;
+65
View File
@@ -0,0 +1,65 @@
const routes = [
// 系统管理
{
path: '/system',
name: '',
component: () => import('../../views/Layout.vue'),
children: [
// 菜单管理
{
path: 'menu',
name: 'MenuManager',
component: () => import('../../views/System/MenuManager.vue'),
meta: {
crumb: ['菜单管理'],
}
},
// 用户管理
{
path: 'user',
name: 'User',
component: () => import('../../views/System/User.vue'),
meta: {
crumb: ['用户管理'],
}
},
// 角色管理
{
path: 'role',
name: 'Role',
component: () => import('../../views/System/Role.vue'),
meta: {
crumb: ['角色管理'],
}
},
// // 角色管理
// {
// path: 'mail',
// name: 'Mail',
// component: () => import('../../views/System/mail.vue'),
// meta: {
// crumb: ['邮件管理'],
// }
// },
// // 角色管理
// {
// path: 'notification',
// name: 'Notification',
// component: () => import('../../views/System/notification.vue'),
// meta: {
// crumb: ['通知管理'],
// }
// },
{
path: '401Page',
name: '401Page',
component: () => import('../../views/System/401Page.vue'),
meta: {
crumb: ['暂无权限'],
}
},
]
},
];
export default routes;
+43
View File
@@ -0,0 +1,43 @@
import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
userInfo: null,
isLoading: false,
rememberData: null,
menuData: [],
pathUrl: '',
menuName: '',
},
getters: {
menuData: (state) => state.menuData,
menuName: (state) => state.menuName,
},
mutations: {
saveUserInfo(state, data) {
state.userInfo = data;
},
saveIsLoading(state, data){
state.isLoading = data;
},
saveRememberData(state, data){
state.rememberData = data;
},
saveMenuData(state, data){
state.menuData = data;
},
savePathUrl(state, data){
state.pathUrl = data;
},
saveMenuName(state, data){
state.menuName = data;
},
},
actions: {},
modules: {},
plugins: [createPersistedState()]
})
+3
View File
@@ -0,0 +1,3 @@
export default {
PUBLIC_KEY: `MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKwvimHNGEiyV5L73llAeTv8O/3c9KLZLjNDpzNVOvzowk1MJySdSh6BiZPFXGLJ49Rrp/0U1L68ZCvC2Zv07YYTrr7Bd8o8lKB9HlUqcJo/seIHrLCLl2ePuLn+NYtIM4xxbbvAOdy5Ep/QbK4aWz8G7vsx8pctijLksYKNBQyQIDAQAB`,
}
+13
View File
@@ -0,0 +1,13 @@
import {fileType} from "./fileType";
export const downloadFile = (res) => {
let file_name = decodeURI(res.headers["content-disposition"]).split('=').pop();
let file_type = file_name.split('.').pop();
let blobData = new Blob([res.data], {type: fileType[file_type]});
let downloadUrl = window.URL.createObjectURL(blobData);
let anchor = document.createElement("a");
anchor.href = downloadUrl;
anchor.download = file_name;
anchor.click();
window.URL.revokeObjectURL(blobData);
}
+13
View File
@@ -0,0 +1,13 @@
export const fileType = {
pdf: 'application/pdf',
xls: 'application/vnd.ms-excel',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
doc: 'application/msword',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
ppt: 'application/vnd.ms-powerpoint',
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
png: 'image/png',
jpg: 'image/jpeg',
rar: 'application/x-rar',
zip: 'application/zip',
}
+15
View File
@@ -0,0 +1,15 @@
export const BASE_URL = {
// LOGIN_URL : "http://192.168.144.29:9090/cas/login?service=http://192.168.144.22:9966/login?loginType=1",
// LOGOUT_URL : "http://192.168.144.29:9090/cas/logout?service=http://192.168.144.22:9966/login?loginType=1",
//内部测试
// BASE_CHANGAN:'http://192.168.144.29:9090/cas',
BASE_LOCAL:'http://127.0.0.1:8080',
BASE_LOCAL_IMG:'http://127.0.0.1:8080',
// //企业测试
// BASE_CHANGAN:'https://caddmuat.changan.com.cn/cas',
// BASE_LOCAL:'https://caddmuat.changan.com.cn/mi',
// BASE_LOCAL_IMG:'https://caddmuat.changan.com.cn',
}
+13
View File
@@ -0,0 +1,13 @@
import Quill from "quill";
let Parchment = Quill.import("parchment");
class lineHeightAttributor extends Parchment.Attributor.Style {
}
const lineHeightStyle = new lineHeightAttributor("lineHeight", "line-height", {
scope: Parchment.Scope.INLINE,
whitelist: ["initial", "1", "1.5", "1.75", "2", "3", "4"]
});
export {lineHeightStyle};
+128
View File
@@ -0,0 +1,128 @@
[
{
"id": "37SSNVGSP9",
"parentId": "AVL9YSB7ZF",
"label": "菜单管理",
"href": "/system/menu",
"icon": "/api/home/pic//20211208163844522.png"
},
{
"id": "6F46UACEMG",
"parentId": "SBME88VTUD",
"label": "整体市场价格分析",
"href": "overall",
"icon": "/api/home/pic//20211209090648732.png"
},
{
"id": "KF8L94BZC4",
"parentId": "8SJZZFCZJS",
"label": "车型量价查询",
"href": "/models/modelsquery",
"icon": ""
},
{
"id": "PNK5Z3REGN",
"parentId": "6F46UACEMG",
"label": "价格趋势",
"href": "/overall/opricetrend",
"icon": ""
},
{
"id": "UZHN9Z835U",
"parentId": "XBFBR7UADZ",
"label": "报告列表",
"href": "/report/list",
"icon": "/api/home/pic//20211209090610575.png"
},
{
"id": "XBFBR7UADZ",
"parentId": "6f6fafb4a7",
"label": "报告板块",
"href": "/report/list",
"icon": "/api/home/pic//20211116142717856.png"
},
{
"id": "8SJZZFCZJS",
"parentId": "SBME88VTUD",
"label": "车型市场价格分析",
"href": "models",
"icon": "/api/home/pic//20211209090657836.png"
},
{
"id": "A5DMDVJFHF",
"parentId": "AVL9YSB7ZF",
"label": "角色管理",
"href": "/system/role",
"icon": "/api/home/pic//20211117143545387.png"
},
{
"id": "ASPYP4MLJZ",
"parentId": "XBFBR7UADZ",
"label": "报告管理",
"href": "/report/manager",
"icon": "/api/home/pic//20211209090620133.png"
},
{
"id": "AVL9YSB7ZF",
"parentId": "6f6fafb4a7",
"label": "系统管理",
"href": "/system/menu",
"icon": "/api/home/pic//20211117143522174.png"
},
{
"id": "JM54MJCN3X",
"parentId": "6F46UACEMG",
"label": "分价格段市占率",
"href": "/overall/occupancy",
"icon": ""
},
{
"id": "KTBEN9KFFW",
"parentId": "8SJZZFCZJS",
"label": "价格趋势",
"href": "/models/mpricetrend",
"icon": ""
},
{
"id": "5AFTKUQ2Q5",
"parentId": "8SJZZFCZJS",
"label": "车型对比分析",
"href": "/models/contrast",
"icon": ""
},
{
"id": "CC5ZS54PPK",
"parentId": "AVL9YSB7ZF",
"label": "用户管理",
"href": "/system/user",
"icon": "/api/home/pic//20211116145901232.png"
},
{
"id": "KFP3AXHFP9",
"parentId": "6F46UACEMG",
"label": "细分市场竞争格局",
"href": "/overall/marketpattern",
"icon": ""
},
{
"id": "SBME88VTUD",
"parentId": "6f6fafb4a7",
"label": "价格板块",
"href": "/overall/opricetrend",
"icon": "/api/home/pic//20211116153747821.png"
},
{
"id": "2EDDH5GWZJ",
"parentId": "8SJZZFCZJS",
"label": "车型竞争格局",
"href": "/models/modelspattern",
"icon": ""
},
{
"id": "6f6fafb4a7",
"parentId": "0",
"label": "顶级菜单",
"href": null,
"icon": null
}
]
+104
View File
@@ -0,0 +1,104 @@
import axios from 'axios';
import {Message, Loading} from 'element-ui';
import store from '../store';
import router from "../router";
import {BASE_URL} from "../utils/http";
// 记录请求个数、加载
let count = 0, loading = null;
// axios实例化
const instance = axios.create({
baseURL: '/library',
// timeout: 60000,
headers: {
'Cache-Control': 'no-cache',
'Pragma': 'no-cache'
}
});
// 添加请求拦截器
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
loading = Loading.service(null);
count++;
store.commit('saveIsLoading', true);
return config;
}, function (error) {
// 对请求错误做些什么
count--;
if (count < 1) {
loading.close();
store.commit('saveIsLoading', false);
}
Message.error(error);
return Promise.reject(error);
});
// 添加响应拦截器
instance.interceptors.response.use(function (response) {
// 对响应数据做点什么
count--;
if (count < 1) {
loading.close();
store.commit('saveIsLoading', false);
}
// 登录超时
if (response.data.respCode === '401') {
store.commit('saveUserInfo', null);
router.push('/login');
Message.error('登录超时过期');
// var url = 'http://192.168.144.22:9966/login?loginType=1'
// // var url = 'http://10.64.23.30:7766/home'
//
// return window.open('http://192.168.144.29:9090/cas/login?service='+url, '_self');
// return window.open('https://caddmuat.changan.com.cn/cas/login?service='+url, '_self');
// window.open(BASE_URL.BASE_CHANGAN + "/logout?service=" + BASE_URL.BASE_LOCAL + "/login?loginType=1", '_self');
}
// 请求成功
if (response.status === 200) {
if (response.data.respCode === "0") {
return response.data;
} else if (response.data.respCode === "-1") {
Message.error(response.data.message);
return Promise.reject(response);
} else {
return response;
}
} else { // 请求失败
Message.error(response.data.message);
return Promise.reject(response);
}
}, function (error) {
// 对响应错误做点什么
count--;
if (count < 1) {
loading.close();
store.commit('saveIsLoading', false);
}
// 登录过期
if (error.response.status === 401) {
store.commit('saveUserInfo', null);
router.push('/login');
Message.error('登录超时过期');
// window.open(BASE_URL.BASE_CHANGAN + "/logout?service=" + BASE_URL.BASE_LOCAL + "/login?loginType=1", '_self');
// var url = 'http://192.168.144.22:9966/login?loginType=1'
// // var url = 'http://10.64.23.30:7766/home'
//
// return window.open('http://192.168.144.29:9090/cas/login?service='+url, '_self');
// // return window.open('https://caddmuat.changan.com.cn/cas/login?service='+url, '_self');
}
// 判断超时
if (error.code === "ECONNABORTED" && error.message.indexOf('timeout') !== -1 && !error.config._retry) {
Message.error(error.message);
} else {
Message.error(error.message);
}
return Promise.reject(error);
});
export {instance, loading};
+6444
View File
File diff suppressed because it is too large Load Diff
+173
View File
@@ -0,0 +1,173 @@
<template>
<el-container>
<el-header>
<Header></Header>
</el-header>
<el-container class="main-content">
<el-aside width="200px">
<el-scrollbar class="menu">
<Menu :menuData="menuData"></Menu>
</el-scrollbar>
</el-aside>
<el-main>
<el-scrollbar class="main main1">
<router-view/>
</el-scrollbar>
</el-main>
</el-container>
</el-container>
</template>
<script>
import Header from '@/components/Header';
import Menu from '@/components/Menu';
export default {
name: "Layout",
components: {
Header,
Menu
},
data() {
return {
menuData: []
}
},
watch: {
'$route.path': {
handler(val) {
this.getMenu();
},
deep: true
}
},
methods: {
handleTree(arr, parentId) {
let cloneData = JSON.parse(JSON.stringify(arr)); // 对源数据深度克隆
return cloneData.filter((father) => {
let branchArr = cloneData.filter(child => father.id === child.parentId); //返回每一项的子级数组
father.children = branchArr.length > 0 ? branchArr : null; //如果存在子级,则给父级添加一个children属性,并赋值
return father.parentId === parentId; //返回第一层
})
},
addLevel(data, level) {
data.forEach(item => {
item.level = level;
if (item.children) {
this.addLevel(item.children, level + 1);
}
});
return data;
},
getMenu() {
if (!this.$route.query.id) {
return this.$router.push({path: '/report/list', query:{"id": "AEHJB8YNJ3"}});
}
let data = JSON.parse(JSON.stringify(this.$store.state.menuData));
let menu = data.filter(item => item.parentId === this.$route.query.id);
let menuData = [];
let menuFun = (menu) => {
menuData = [...menuData, ...menu];
let parentIds = menu.map(item => item.id);
if (parentIds.length) {
menuFun(data.filter(item => parentIds.find(el => el === item.parentId)))
}
};
menuFun(menu);
let treeData = this.handleTree(menuData, this.$route.query.id);
this.menuData = this.addLevel(treeData, 1);
},
getSysMenu() {
this.$api.role.sysRoleGetRoleHome({roleId: this.$store.state.userInfo.roleIdList[0]}).then(({data}) => {
if (data === null) {
data = []
}
data = data.sort((a, b) => a.sort - b.sort);
let menu = data;//.filter(item => item.belong);
let menuData = [];
let menuFun = (menu) => {
menuData = [...menuData, ...menu]
let parentIds = menu.map(item => item.parentId);
if (parentIds.length) {
menuFun(data.filter(item => parentIds.find(el => el === item.id)))
}
}
menuFun(menu);
let treeData = menuData.map(item => ({
id: item.id,
parentId: item.parentId,
label: item.name,
href: item.href,
icon: item.iconHref,
isCollage: true,
belong: item.belong,
isUrl: item.isUrl
}));
// 去重
let obj = {};
treeData.forEach(item => {
obj[item.id] = item;
})
this.$store.commit('saveMenuData', Object.values(obj));
this.getMenu();
});
}
},
created() {
// 判定菜单是否存在,存在则不加载
let menuData = this.$store.state.menuData;
if (menuData.length == 0) {
this.getSysMenu();
} else {
this.getMenu();
}
}
}
</script>
<style lang="scss" scoped>
.el-header {
background: url("../assets/imgs/bg-header.png") no-repeat center center;
background-size: cover;
padding: 0;
}
.main-content {
height: calc(100vh - 60px);
.el-aside {
background-color: #FFFFFF;
.menu {
width: 100%;
height: 100%;
}
}
.el-main {
background-color: #F8F8FA;
padding: 0;
::v-deep .main.el-scrollbar {
height: 100%;
.el-scrollbar__view {
padding: 10px 8px;
}
}
::v-deep .main1.el-scrollbar {
height: 100%;
.el-scrollbar__view {
height: 100% !important;
padding: 10px 8px;
}
}
}
}
</style>
+171
View File
@@ -0,0 +1,171 @@
<template>
<div class="login">
<div class="login-main">
<div class="login-box">
<el-form :model="form" label-position="top" label-width="80px">
<el-form-item>
<h1>长安汽车-科技长安智慧伙伴</h1>
</el-form-item>
<el-form-item label="用户名:">
<el-input v-model="form.username" prefix-icon="el-icon-user" size="small"
placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="密码:">
<el-input v-model="form.password" prefix-icon="el-icon-edit" type="password" size="small"
placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item label="验证码:">
<el-input v-model="form.verifyCode" prefix-icon="el-icon-edit-outline" size="small"
placeholder="请输入验证码">
<div slot="append" style="width: 100px;height: 30px;">
<el-image style="width: 100%; height: 100%" @click="verifyCode" :src="verifyImg"
fit="fill"></el-image>
</div>
</el-input>
</el-form-item>
<el-form-item>
<el-checkbox v-model="isChecked">记住密码</el-checkbox>
</el-form-item>
<el-form-item>
<el-button type="primary" size="small" style="width: 100%;" @click="login">登录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import {Base64} from "js-base64";
export default {
name: "Login",
data() {
return {
form: {
username: '',
password: '',
verifyCode: '',
},
verifyImg: '',
isChecked: false,
}
},
created() {
this.init();
},
methods: {
getQueryVariable(r, variable) {
if (r) {
var query = r.split('?');
if (query && query.length == 2) {
var vars = query[1].split("&");
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}
}
}
},
init() {
this.isChecked = !!this.$store.state.rememberData;
if (this.isChecked) {
this.form.username = this.$store.state.rememberData.username;
this.form.password = this.$store.state.rememberData.password;
}
this.verifyCode();
},
// 登录
login() {
if (!this.form.username) {
return this.$message.warning('请输入用户名')
}
if (!this.form.password) {
return this.$message.warning('请输入密码')
}
if (!this.form.verifyCode) {
return this.$message.warning('请输入验证码')
}
if (this.form.verifyCode.length !== 4) {
return this.$message.warning('请检查验证码')
}
this.$store.commit('saveRememberData', this.isChecked ? {
username: this.form.username,
password: this.form.password
} : null);
let data = JSON.parse(JSON.stringify(this.form));
data.username = this.$JSEncrypt(data.username);
data.password = this.$JSEncrypt(data.password);
let jsonData = JSON.stringify(data);
this.$api.login.login(Base64.encode(jsonData)).then(res => {
if (res.respCode !== '0') {
this.verifyCode();
return this.$message.error(res.data.message);
}
this.$message.success('登录成功');
this.$store.commit('saveUserInfo', res.data);
this.$router.push({path: '/report/list', query:{"id": "AEHJB8YNJ3"}});
}).catch(_ => {
this.verifyCode();
})
},
// 获取验证码
verifyCode() {
this.$api.login.verifyCode({})
.then(res => {
this.verifyImg = `data: image/jpeg;base64,${btoa(new Uint8Array(res.data).reduce((data, byte) => data + String.fromCharCode(byte), ''))}`
})
},
}
}
</script>
<style lang="scss" scoped>
.login {
width: 100%;
height: 100%;
background-color: #1fc8db;
background-image: linear-gradient(45deg, #9fb8ad 0%, #1fc8db 51%, #2cb5e8 75%);
position: relative;
.login-main {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
.login-box {
background-color: #fff;
width: 400px;
min-height: 200px;
margin-top: 20px;
border-radius: 5px;
box-shadow: 0 0 20px 0 rgb(0 0 0 / .2);
padding: 30px 20px;
h1 {
text-align: center;
color: #2b2b2b;
font-size: 18px;
}
::v-deep .el-form-item {
margin-bottom: 10px;
.el-form-item__label {
padding-bottom: 0;
}
.el-input-group__append {
padding: 0;
}
}
}
}
}
</style>
+15
View File
@@ -0,0 +1,15 @@
<template>
<div>
注册
</div>
</template>
<script>
export default {
name: "Register"
}
</script>
<style scoped>
</style>
+154
View File
@@ -0,0 +1,154 @@
<template>
<div class="content-height report-detail">
<div class="title">
<el-tooltip :content="row.name" placement="top-start">
<span>{{ row.name || '-' }}</span>
</el-tooltip>
</div>
<div class="desc">
<el-row>
<el-col :span="24" class="desc-item">
<label>关键词</label>
<div>{{ row.keyContent || '-' }}</div>
</el-col>
<el-col :span="24" class="desc-item">
<label>内容摘要</label>
<p>{{ row.mainContent || '-' }}</p>
</el-col>
<el-col :span="24" class="desc-item">
<label>所属部门</label>
<div>{{ row.department || '-' }}</div>
</el-col>
</el-row>
</div>
<div class="report-download">
<span>报告详情</span>
<el-button type="primary" @click="downloadRow(row)">报告下载</el-button>
</div>
<div class="preview-content" v-html="content"></div>
</div>
</template>
<script>
import {downloadFile} from "../../utils/downloadFile";
export default {
name: "ReportDetail",
data(){
return {
content: '',
row: {},
}
},
methods: {
// 预览
previewRow() {
if(!this.$route.query.row){
this.$router.push({path: '/report/list', query: {id: this.$route.query.id}});
return
}
this.row = JSON.parse(this.$route.query.row);
this.$api.report.reportGetReportHtmlId({id: this.row.id}).then(({data}) => {
this.content = data.content;
})
},
// 下载
downloadRow(row){
// this.$confirm('此操作将下载所选数据文件, 是否继续?', '提示', {
// confirmButtonText: '确定',
// cancelButtonText: '取消',
// type: 'warning'
// }).then(() => {
this.$api.report.reportDownload({fileId: row.fileId}).then(res => {
downloadFile(res);
})
// })
}
},
created() {
this.previewRow();
}
}
</script>
<style lang="scss" scoped>
.report-detail {
.title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
border-bottom: 1px solid #EBEEF5;
height: 42px;
line-height: 42px;
margin: 0 18px 0 22px;
text-align: center;
span {
font-size: 16px;
font-weight: 600;
color: #262626;
}
}
.desc{
padding: 11px 26px 6px 48px;
.desc-item{
display: flex;
justify-content: flex-start;
align-items: flex-start;
margin-bottom: 12px;
label{
display: inline-block;
height: 19px;
line-height: 19px;
font-size: 14px;
font-weight: 400;
color: #595959;
width: 64px;
border-right: 1px solid #BFBFBF;
margin-right: 9px;
}
div,p{
flex: 1;
font-size: 14px;
font-weight: 400;
color: #434343;
}
p{
line-height: 20px;
text-align: justify;
}
}
}
.report-download {
height: 40px;
background: #F2F6FC;
border: 1px solid #EBEEF5;
margin: 0 14px 0 13px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 7px 0 9px;
span {
font-size: 16px;
font-weight: 500;
color: #262626;
}
}
.preview-content {
margin: 0 14px 0 13px;
padding-bottom: 11px;
img {
max-width: 100% !important;
}
table{
margin: 0 auto;
}
}
}
</style>

Some files were not shown because too many files have changed in this diff Show More