Commit 02d17ae6 by 姜雷

整合全部模块路由

parent 5644be2d
VUE_APP_LIB_BASE_MANAGER=http://ex-dev-dcxy-static.168cad.top
VUE_APP_LIB_MANAGER=http://ex-dev-dcxy-static.168cad.top
VUE_APP_BASE_URL=/systemManageShell/
VUE_APP_MENU_CODE=0003
VUE_APP_WHITE_LIST=/login,/404,/401
......
......@@ -18,6 +18,7 @@
"analyz": "cross-env NODE_ENV=production npm_config_report=true npm run build"
},
"dependencies": {
"@antv/g2": "^3.5.1",
"axios": "^0.18.0",
"blueimp-md5": "^2.10.0",
"element-ui": "^2.4.5",
......
......@@ -5,11 +5,21 @@
<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" />
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script> -->
<!-- <script src="<%= VUE_APP_LIB_BASE_MANAGER %>/baseManage/lib/manageShell.umd.js"></script> -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script src="<%= VUE_APP_LIB_MANAGER %>/customerManage/lib/customerManage.umd.js"></script>
<script src="<%= VUE_APP_LIB_MANAGER %>/baseManage/lib/baseManage.umd.js"></script>
<script src="<%= VUE_APP_LIB_MANAGER %>/systemManage/lib/systemManage.umd.js"></script>
<link
rel="stylesheet"
href="<%= VUE_APP_LIB_BASE_MANAGER %>/baseManage/lib/manageShell.css"
href="<%= VUE_APP_LIB_MANAGER %>/customerManage/lib/customerManage.css"
/>
<link
rel="stylesheet"
href="<%= VUE_APP_LIB_MANAGER %>/baseManage/lib/baseManage.css"
/>
<link
rel="stylesheet"
href="<%= VUE_APP_LIB_MANAGER %>/systemManage/lib/systemManage.css"
/>
<title>系统管理</title>
</head>
......
<template>
<div id="app">
<app-layout v-if="isInnerPage">
<template slot="title">
<div
class="AppTopBar"
slot="title"
>
<UserBox />
<IconMenus
:routers="allRoutes"
:dashboardVisiable="dashboardVisiable"
/>
</div>
<template v-if="dashboardVisiable">
<router-view
class="body-container"
slot="container"
/>
</template>
<template v-else>
<template slot="nav">
<sidebar-nav :routers="route" />
<sidebar-nav
v-if="showFastLink"
:routers="route"
/>
<sidebar-nav
v-else
:routers="route"
/>
</template>
<router-view v-if="routerDone" />
<div
......@@ -13,6 +34,7 @@
v-else
v-loading="!routerDone"
></div>
</template>
</app-layout>
<router-view v-else />
</div>
......@@ -20,24 +42,35 @@
<script>
import UserBox from './containers/layout/components/UserBox';
import IconMenus from './containers/layout/components/IconMenu';
const whiteList = process.env.VUE_APP_WHITE_LIST.split(','); // 不重定向白名单
export default {
name: 'App',
components: { UserBox },
components: { UserBox, IconMenus },
props: {
route: {
type: Array,
default: () => [],
},
allRoutes: {
type: Array,
default: () => [],
},
},
data() {
return {
routerDone: false,
isInnerPage: true,
showFastLink: false,
};
},
computed: {
dashboardVisiable() {
return this.$route.name === 'dashboard';
},
},
mounted() {
if (this.$route.meta && this.$route.meta.store) {
this.showComponents(this.$route.meta.store);
......@@ -48,6 +81,8 @@ export default {
watch: {
$route(newVal) {
this.routerDone = false;
console.log(newVal);
if (newVal.meta && newVal.meta.store) {
this.showComponents(newVal.meta.store);
} else {
......@@ -56,6 +91,9 @@ export default {
},
},
methods: {
toggleDashboard() {
this.dashboardVisiable = !this.dashboardVisiable;
},
showComponents(store) {
this.isInnerPage =
whiteList.indexOf(this.$route.path) !== -1 ? false : true;
......@@ -73,8 +111,12 @@ export default {
</script>
<style lang="scss">
.AppTopBar {
flex: 1;
display: flex;
justify-content: space-between;
}
.loading-container {
margin: 50px;
}
</style>
import fetch from '../fetch';
const path = process.env.VUE_APP_CUSTOMER_SERVER_URL;
export const fetchConsumeList = req =>
fetch({
url: path + '/dcxy/reportInfo/queryConsumeList',
timeout: 30000,
...req,
});
export const fetchReportList = req =>
fetch({
url: path + '/dcxy/reportInfo/queryReportList',
...req,
});
export const fetchTitleList = req =>
fetch({
url: path + '/dcxy/reportInfo/queryTitleList',
...req,
});
import fetch from '@/api/fetch';
export const updateUserinfo = req =>
fetch({
url: '/adminChange/updatePwd',
method: 'post',
...req,
});
export const updateUserCellphone = req =>
fetch({
url: '/adminChange/updatePhone',
...req,
});
export const getVcode = req =>
fetch({
url: '/adminChange/getCode',
...req,
});
import {
fetchConsumeList,
fetchReportList,
fetchTitleList,
} from '@/api/dashboard/dashboard';
const GET_CONSUME_DATA = 'GET_CONSUME_DATA';
const GET_REPORT_DATA = 'GET_REPORT_DATA';
const GET_TITLE_DATA = 'GET_TITLE_DATA';
const state = () => ({
consume: {
consumeHardVos: [],
list: [],
percentList: [],
},
report: {
year: new Date().getFullYear(),
month: new Date().getMonth() + 1,
registePerDay: [],
registePerMonth: [],
activeUser: [],
},
title: {
activeCount: 0,
countArea: 0,
countCustomer: 0,
},
});
const getters = {
reportYear: state => state.report.year,
reportMonth: state => state.report.month,
registePerDay: state => state.report.registePerDay,
registePerMonth: state => state.report.registePerMonth,
activeUser: state => state.report.activeUser,
titleData: state => state.title,
consumeHardVos: state => state.consume.consumeHardVos,
campusRankList: state => state.consume.list,
seviceRatioList: state => state.consume.percentList,
};
const actions = {
fetchConsumeList({ commit }, entity) {
return fetchConsumeList({
params: {
...entity,
},
}).then(res => {
let list = res.data;
commit(GET_CONSUME_DATA, list);
});
},
fetchReportList({ commit }, entity) {
return fetchReportList({
params: {
...entity,
},
}).then(res => {
let list = res.data;
commit(GET_REPORT_DATA, list);
});
},
fetchTitleList({ commit }) {
return fetchTitleList().then(res => {
let data = res.data;
commit(GET_TITLE_DATA, data);
});
},
};
const mutations = {
[GET_CONSUME_DATA]: (state, data) => {
state.consume.consumeHardVos = data.consumeHardVos;
state.consume.list = data.list;
state.consume.percentList = data.percentList;
},
[GET_REPORT_DATA]: (state, data) => {
state.report.year = data.year;
state.report.month = data.month;
let dayList = new Array(31).fill({ count: 0 });
dayList = dayList.map((v, idx) => ({ ...v, days: idx + 1 }));
data.dayVos.map(val => {
let idx = Number(val.days.substr(-2)) - 1;
dayList[idx].count = val.count;
});
state.report.registePerDay = dayList;
state.report.registePerMonth = data.list;
state.report.activeUser = data.listCount;
},
[GET_TITLE_DATA](state, data) {
state.title = data;
},
};
export default {
namespaced: true,
state,
getters,
actions,
mutations,
};
<template>
<div class="Dashboard">
<div class="Dashboard-DataCard">
<div class="Dashboard-SearchBar">
<search-item label="年份">
<el-date-picker
v-model.trim="campusFilters.year"
@change="changeReportYearHandle"
type="year"
value-format="yyyy"
placeholder="请选择"
>
</el-date-picker>
</search-item>
<search-item label="校区">
<area-select
v-model.trim="campusFilters.areaId"
@change="changeReportAreaHandle"
type="user"
/>
</search-item>
</div>
<div class="Dashboard-CampusData">
<div class="Dashboard-CampusItem">
<div class="Dashboard-title">{{ reportYear }}年每月注册数据</div>
<RegisterByMonth :data="registePerMonth"></RegisterByMonth>
</div>
<div class="Dashboard-CampusItem">
<div class="Dashboard-title">
{{ reportYear }}{{ reportMonth }}月注册数据
</div>
<RegisterByDay :data="registePerDay" />
</div>
<div class="Dashboard-CampusItem">
<div class="Dashboard-title">{{ reportYear }}年每月活跃数据</div>
<ActiveUserByMonth :data="activeUser" />
</div>
</div>
</div>
<div class="Dashboard-OperatorData">
<div class="Dashboard-DataCard">
<div class="Dashboard-SearchBar">
<search-item label="年份">
<el-date-picker
v-model.trim="operatorFilters.year"
@change="changeConsumeYearHandle"
type="year"
value-format="yyyy"
placeholder="请选择"
></el-date-picker>
</search-item>
<search-item label="月份">
<el-date-picker
v-model.trim="operatorFilters.month"
@change="changeConsumeMouthHandle"
type="month"
value-format="MM"
format="MM"
:picker-options="monthRange"
placeholder="请选择"
></el-date-picker>
</search-item>
<search-item label="运营商">
<operator-select
v-model.trim="operatorFilters.operatorId"
@input="changeConsumeOperatorHandle"
/>
</search-item>
</div>
<CampusRank :data="campusRankList" />
</div>
<div class="Dashboard-DataCard">
<div class="Dashboard-title">
<div class="Dashboard-title-icon service">
<img src="@/assets/images/dashboard/icon_zhanbi@2x.png" />
</div>
<div class="Dashboard-title-text">各服务消费占比</div>
<div class="Dashboard-title-top">TOP1</div>
</div>
<SeviceRatio :data="seviceRatioList" />
</div>
<div class="Dashboard-DataCard">
<div class="Dashboard-title">
<div class="Dashboard-title-icon equipment">
<img src="@/assets/images/dashboard/icon_paiming@2x.png" />
</div>
<div class="Dashboard-title-text">各设备消费排名</div>
<div class="Dashboard-title-top">TOP1-5</div>
</div>
<EquipmentList :data="consumeHardVos" />
</div>
</div>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
import RegisterByMonth from './components/RegisterByMonth';
import RegisterByDay from './components/RegisterByDay';
import SeviceRatio from './components/SeviceRatio';
import CampusRank from './components/CampusRank';
import ActiveUserByMonth from './components/ActiveUserByMonth';
import EquipmentList from './components/EquipmentList';
export default {
name: 'Dashboard',
components: {
RegisterByMonth,
RegisterByDay,
ActiveUserByMonth,
SeviceRatio,
CampusRank,
EquipmentList,
},
data() {
return {
campusFilters: {
year: undefined,
areaId: undefined,
},
operatorFilters: {
year: undefined,
month: undefined,
operateId: undefined,
},
monthRange: {
disabledDate: time => {
return this.operatorFilters.year
? time.getTime() < new Date(this.operatorFilters.year) ||
time.getTime() > new Date(this.operatorFilters.year + '-12-31')
: true;
},
},
};
},
computed: {
...mapGetters('Dashboard', [
'reportYear',
'reportMonth',
'registePerDay',
'registePerMonth',
'activeUser',
'campusRankList',
'seviceRatioList',
'consumeHardVos',
]),
},
created() {
this.initData();
},
methods: {
...mapActions('Dashboard', [
'fetchReportList',
'fetchConsumeList',
'fetchTitleList',
]),
initData() {
this.fetchReportList();
this.fetchConsumeList();
this.fetchTitleList();
},
changeReportYearHandle(val) {
if (val) {
let areaId = this.campusFilters.areaId;
this.fetchReportList({
year: val,
areaId: areaId ? areaId : null,
});
}
},
changeReportAreaHandle(val) {
if (val && this.campusFilters.year) {
this.fetchReportList({
year: this.campusFilters.year,
areaId: val,
});
}
},
changeConsumeYearHandle(val) {
if (val) {
let month = this.operatorFilters.month;
let operateId = this.operatorFilters.operateId;
this.fetchConsumeList({
year: val,
month: month ? month : null,
operateId: operateId ? operateId : null,
});
}
},
changeConsumeMouthHandle(val) {
if (val && this.operatorFilters.year) {
let operateId = this.operatorFilters.operateId;
this.fetchConsumeList({
year: this.operatorFilters.year,
month: val,
operateId: operateId ? operateId : null,
});
}
},
changeConsumeOperatorHandle(val) {
if (val && this.operatorFilters.year) {
let month = this.operatorFilters.month;
this.fetchConsumeList({
year: this.operatorFilters.year,
month: month ? month : null,
operateId: val,
});
}
},
},
};
</script>
<style lang="scss">
.Dashboard {
display: flex;
flex-direction: column;
background-color: #eee;
padding: 0 34px;
.Dashboard-title {
font-size: 20px;
color: #333;
font-weight: 700;
}
.Dashboard-DataCard {
margin-top: 12px;
background-color: #fff;
border-radius: 8px;
}
.Dashboard-SearchBar {
display: flex;
padding: 20px 0 50px;
.el-input,
.el-input__inner,
.filter-item {
height: 34px;
line-height: 34px;
}
.filter-item {
margin: 0 0 0 34px;
}
.el-input,
.filter-item-label {
width: auto;
}
}
.Dashboard-CampusData {
display: flex;
height: 300px;
padding: 0 15px;
.Dashboard-title {
position: relative;
}
.Dashboard-title::before {
content: '';
position: absolute;
bottom: -12px;
left: 0;
width: 32px;
height: 4px;
background-color: #4e82fb;
}
.Dashboard-CampusItem {
flex: 1;
&:nth-child(2) {
flex: 1.4;
}
}
}
.Dashboard-OperatorData {
flex: 1;
display: flex;
padding-bottom: 12px;
// height: 400px;
.Dashboard-SearchBar {
align-items: center;
justify-content: center;
padding: 0;
min-width: 480px;
height: 70px;
border-bottom: 1px solid #f1f1f1;
.filter-item {
margin: 0 10px 0 0;
.filter-item-input---normal {
width: 113px;
}
}
}
.Dashboard-title {
display: flex;
align-items: center;
margin: 22px 10px 0;
padding-bottom: 20px;
border-bottom: 1px solid #f1f1f1;
.Dashboard-title-icon.service {
width: 28px;
height: 28px;
margin-right: 13px;
}
.Dashboard-title-icon.equipment {
width: 36px;
height: 20px;
margin-right: 12px;
margin-left: 15px;
}
.Dashboard-title-text {
flex: 1;
}
.Dashboard-title-top {
font-size: 20px;
color: #4e83fb;
}
}
.Dashboard-DataCard {
flex: 2;
&:nth-child(2) {
flex: 1.5;
margin: 12px 12px 0;
}
}
}
}
</style>
export default {
props: {
data: {
type: Array,
default: () => [],
},
},
data() {
return {
chart: null,
chartGeom: null,
};
},
watch: {
data() {
this.refreshData();
},
},
mounted() {
this.initData();
},
methods: {
initData() {},
updateData() {},
refreshData() {
if (this.chart) {
this.chart.changeData(this.data);
this.chart.render();
this.updateData();
}
},
},
};
<template>
<div id='ActiveUserByMonth'></div>
</template>
<script>
import G2 from '@antv/g2';
import chartMixin from '../chartMixin';
export default {
name: 'ActiveUserByMonth',
mixins: [chartMixin],
data() {
return {
demoData: [{ month: 1, mark: 'monthAppActive', count: 12 }],
serviceList: [
{ value: 'monthAppActive', name: 'APP活跃用户' },
{ value: 'monthHardActive', name: '硬件活跃用户' },
{ value: 'allActive', name: '两者兼具' },
],
};
},
methods: {
initData() {
this.chart = new G2.Chart({
container: 'ActiveUserByMonth',
forceFit: true,
height: 270,
padding: [50, 40],
});
this.chart
.source(this.data, {
month: {
min: 1,
max: 12,
tickCount: 12,
},
mark: {
formatter: value => {
let service = this.serviceList.find(item => item.value === value);
return service ? service.name : '';
},
},
})
.tooltip({
showTitle: false,
});
// 图例
this.chart
.legend({
position: 'top',
title: null,
marker: 'square',
})
.axis('count', false)
.axis('mark', {
formatter: value => {
let service = this.serviceList.find(item => item.value === value);
return service ? `${service.name}` : '';
},
})
.intervalStack()
.position('month*count')
.color('mark', ['#4e82fb', '#ffc934', '#26c9a8']);
this.chart.render();
},
},
};
</script>
<template>
<div class="CampusRank">
<div id="CampusRank"></div>
<div class="CampusRank-title">截至到{{ today }},前十校区消费汇总数据</div>
</div>
</template>
<script>
import chartMixin from '../chartMixin';
export default {
name: 'CampusRank',
mixins: [chartMixin],
data() {
let totle = this.data.reduce((count, item) => count + item.count, 0);
return {
chart: null,
today: this.$formatDate(new Date(), 'yyyy-MM-dd'),
totle: totle,
percentDom: null,
areaNameDom: null,
};
},
mounted() {
this.initChart();
},
methods: {
initChart() {
this.chart = new G2.Chart({
container: 'CampusRank',
forceFit: true,
height: 270,
padding: [0, 130, 0, 0],
});
this.chart.source(this.data);
this.chart.coord('theta', {
radius: 0.9,
innerRadius: 0.75,
});
this.chart.tooltip(false);
// 图例
this.chart.legend({
position: 'right-center',
marker: 'square',
useHtml: true,
itemTpl: (value, color, checked, index) => {
const obj = this.data[index];
return obj.type === '8'
? `
<li
class="g2-legend-list-item item-${index} ${checked}"
data-value="${value}"
data-color=${color}
style="cursor: pointer;font-size:14px;"
>
<i
class="g2-legend-marker"
style="background-color:${color};"
></i>
<span>其他校区<br/>汇总数据</span>
</li>
`
: `<li
class="g2-legend-list-item item-noshow item-${index} ${checked}"
data-value="${value}"
data-color=${color}
>
<i
class="g2-legend-marker"
style="background-color:${color};"
></i>
${value}
</li>`;
},
'g2-legend-list-item': {
display: 'flex',
// color: '#333',
},
'g2-legend-marker': {
width: '10px',
height: '5px',
borderRadius: 'none',
marginTop: '8px',
marginRight: '10px',
},
'item-noshow': {
display: 'none',
},
});
// 坐标系及着色
this.chartGeom = this.chart
.intervalStack()
.position('count')
.color('areaName', [
'#ff3a34',
'#4e82fb',
'#fb774e',
'#ffc934',
'#41bf52',
'#9b50ff',
'#94de70',
'#b5593d',
'#fe8787',
'#254eae',
'#2f4554',
]);
// 辅助元素
this.chart.guide().html({
position: ['50%', '50%'],
html: `<div style="color:#333;font-size: 20px;text-align: center;width: 4em;">
<span class="CampusRank-percent">0.00</span>%<br>
<span class="CampusRank-areaName" style="font-size:16px;"></span>
</div>`,
alignX: 'middle',
alignY: 'middle',
});
this.chart.render();
this.chart.on('plotclick', this.clickHandle);
},
updateData() {
if (this.data.length) {
this.totle = this.data.reduce((count, item) => count + item.count, 0);
this.chartGeom.setSelected(this.data[0]);
this.changeSelected(this.data[0]);
}
},
clickHandle(ev) {
if (ev.data) {
let data = ev.data._origin;
this.changeSelected(data);
}
},
changeSelected(data) {
this.percentDom = document.querySelector('.CampusRank-percent');
this.areaNameDom = document.querySelector('.CampusRank-areaName');
if (this.percentDom) {
this.percentDom.innerHTML = ((data.count / this.totle) * 100).toFixed(
2
);
}
if (this.areaNameDom) {
this.areaNameDom.innerHTML = data.areaName;
}
},
},
};
</script>
<style lang="scss">
.CampusRank {
.CampusRank-title {
font-size: 16px;
text-align: center;
}
}
</style>
<template>
<div class="Dashboard-Equipment">
<div
v-for="(item, index) in data.slice(0, 5)"
:key="index"
class="Dashboard-Equipment-item"
>
<div class="Dashboard-Equipment-icon" v-if="index === 0">
<img src="@/assets/images/dashboard/icon_no.1@2x.png" />
</div>
<div class="Dashboard-Equipment-icon" v-else-if="index === 1">
<img src="@/assets/images/dashboard/icon_no.2@2x.png" />
</div>
<div class="Dashboard-Equipment-icon" v-else-if="index === 2">
<img src="@/assets/images/dashboard/icon_no.3@2x.png" />
</div>
<div class="Dashboard-Equipment-icon" v-else>NO.{{ index + 1 }}</div>
<div class="Dashboard-Equipment-name">{{ item.equipmentNumber }}</div>
<div class="Dashboard-Equipment-location">
{{ item.equipmentPosition }}
</div>
<div class="Dashboard-Equipment-money">{{ item.money.toFixed(2) }}</div>
</div>
</div>
</template>
<script>
export default {
name: 'EquipmentList',
props: {
data: {
type: Array,
default: () => [],
},
},
};
</script>
<style lang="scss">
@import '@/assets/styles/variables.scss';
.Dashboard-Equipment {
.Dashboard-Equipment-item {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 14px;
color: #333;
text-align: center;
height: 35px;
margin: 0 10px;
border-bottom: 1px solid #f1f1f1;
&:last-child {
border-bottom: 0;
}
.Dashboard-Equipment-icon {
width: 20px;
img {
width: 16px;
height: 20px;
margin: 0 auto;
}
}
.Dashboard-Equipment-name {
width: 64px;
}
.Dashboard-Equipment-location {
width: 200px;
}
.Dashboard-Equipment-money {
font-size: 16px;
text-align: right;
width: 116px;
}
}
}
@media screen and (min-width: $bigScreenWidth) {
.Dashboard-Equipment {
.Dashboard-Equipment-item {
font-size: 16px;
height: 70px;
margin: 0 20px;
}
.Dashboard-Equipment-icon {
width: 40px;
img {
width: 32px;
height: 40px;
margin: 0 auto;
}
}
.Dashboard-Equipment-name {
width: 128px;
}
.Dashboard-Equipment-location {
width: 200px;
}
.Dashboard-Equipment-money {
font-size: 20px;
width: 116px;
}
}
}
</style>
<template>
<div id='RegisterByDay'></div>
</template>
<script>
import G2 from '@antv/g2';
import chartMixin from '../chartMixin';
export default {
name: 'RegisterByDay',
mixins: [chartMixin],
data() {
return {
demoData: [{ days: 1, count: 10 }],
};
},
methods: {
initData() {
this.chart = new G2.Chart({
container: 'RegisterByDay',
forceFit: true,
height: 270,
padding: [40, 20, 30, 45],
});
this.chart
.source(this.data, {
days: {
min: 1,
max: 31,
type: 'linear',
tickCount: 31,
},
count: {
alias: '人数',
},
})
.tooltip({
showTitle: false,
})
.line()
.position('days*count');
this.chart.area().position('days*count');
this.chart.render();
},
},
};
</script>
<template>
<div id="RegisterByMonth"></div>
</template>
<script>
import G2 from '@antv/g2';
import chartMixin from '../chartMixin';
export default {
name: 'RegisterByMonth',
mixins: [chartMixin],
data() {
return {
demoData: [{ month: 1, count: 421 }],
};
},
methods: {
initData() {
this.chart = new G2.Chart({
container: 'RegisterByMonth',
forceFit: true,
height: 270,
padding: [0, 20, 30, 20],
});
this.chart
.source(this.data, {
month: {
min: 1,
max: 12,
tickCount: 12,
},
count: {
alias: '人数',
},
})
.axis('count', false)
.axis('month', {
label: {
textStyle: {
fill: '#333',
},
},
})
.tooltip({
showTitle: false,
})
.interval()
.position('month*count')
.color('#4e82fb');
this.chart.render();
},
},
};
</script>
<template>
<div class="SeviceRatio">
<div id="SeviceRatio"></div>
<div class="SeviceRatio-title">成都师范学院</div>
</div>
</template>
<script>
import G2 from '@antv/g2';
import chartMixin from '../chartMixin';
export default {
name: 'SeviceRatio',
mixins: [chartMixin],
data() {
let totle = this.data.reduce((count, item) => count + item.count, 0);
return {
totle: totle,
percentDom: null,
serviceNameDom: null,
};
},
mounted() {
this.initChart();
},
methods: {
initChart() {
this.totle = this.data.reduce((count, item) => count + item.count, 0);
this.chart = new G2.Chart({
container: 'SeviceRatio',
forceFit: true,
height: 270,
padding: [0, 130, 0, 0],
});
this.chart.source(this.data);
this.chart.coord('theta', {
radius: 0.75,
innerRadius: 0.6,
});
this.chart.tooltip(false);
// 图例
this.chart.legend({
position: 'right-center',
marker: 'square',
useHtml: true,
containerTpl: `
<div class="g2-legend">
<ul class="g2-legend-list" style="list-style-type:none;margin:0;padding:0;"></ul>
</div>`,
itemTpl: (value, color, checked, index) => {
const obj = this.data[index];
checked = checked ? 'checked' : 'unChecked';
return `
<li
class="g2-legend-list-item item-${index} ${checked}"
data-value="${value}"
data-color=${color}
style="cursor: pointer;font-size:14px;"
>
<i
class="g2-legend-marker"
style="display:inline-block;margin-right:10px;background-color:${color};"
></i>
<span class="g2-legend-text">${value}: </span>
<span>${obj.count}</span>
</li>
`;
},
'g2-legend': {
width: '130px',
// left: '-20px',
},
'g2-legend-list-item': {
height: '22px',
color: '#333',
},
'g2-legend-marker': {
width: '10px',
height: '5px',
borderRadius: 'none',
},
});
// 坐标系及着色
this.chartGeom = this.chart
.intervalStack()
.position('count')
.color('serviceName', ['#4e82fb', '#fb774e', '#ffc934', '#41bf52']);
// 辅助元素
this.chart.guide().html({
position: ['50%', '50%'],
html: `<div style="color:#333;font-size:20px;text-align: center;">
<span class="SeviceRatio-percent">0.00</span>%<br>
<span class="SeviceRatio-serviceName" style="font-size:16px;"></span>
</div>`,
alignX: 'middle',
alignY: 'middle',
});
this.chart.render();
this.chart.on('plotclick', this.clickHandle);
},
updateData() {
if (this.data.length) {
this.totle = this.data.reduce((count, item) => count + item.count, 0);
this.chartGeom.setSelected(this.data[0]);
this.changeSelected(this.data[0]);
}
},
clickHandle(ev) {
if (ev.data) {
let data = ev.data._origin;
this.changeSelected(data);
}
},
changeSelected(data) {
this.percentDom = document.querySelector('.SeviceRatio-percent');
this.serviceNameDom = document.querySelector('.SeviceRatio-serviceName');
if (this.percentDom) {
this.percentDom.innerHTML = ((data.count / this.totle) * 100).toFixed(
2
);
}
if (this.serviceNameDom) {
this.serviceNameDom.innerHTML = data.serviceName;
}
},
},
};
</script>
<style lang="scss">
.SeviceRatio-title {
font-size: 16px;
text-align: center;
}
</style>
import Dashboard from './Dashboard';
export default {
install(store) {
if (!store.state.Dashboard) {
store.registerModule(['Dashboard'], Dashboard);
}
},
uninstall(store) {
store.unregisterModule(['Dashboard']);
},
};
<template>
<div class="IconMenus">
<div
class="TitleData"
v-if="dashboardVisiable"
>
<div class="dataItem">所运营的校区<span class="dataNumber">{{titleData.countArea}}</span></div>
<div class="dataItem">累计用户数<span class="dataNumber">{{titleData.countCustomer}}</span></div>
<div class="dataItem">活跃用户数<span class="dataNumber">{{titleData.activeCount}}</span></div>
</div>
<div
class="IconMenus-list"
v-else
>
<MenuItem
v-if="customerManage && customerManage.length"
menuName="会员管理"
:menuList="customerManage[0].children"
>
<img
slot="icon"
src="@/assets/images/layout/icon_huiyuanguanli@2x.png"
/>
</MenuItem>
<MenuItem menuName="自助运营">
<img
slot="icon"
src="@/assets/images/layout/icon_zizhuyunying@2x.png"
/>
</MenuItem>
<MenuItem
v-if="baseManage && baseManage.length"
menuName="基础数据"
:menuList="baseManage[0].children"
>
<img
slot="icon"
src="@/assets/images/layout/icon_jichu@2x.png"
/>
</MenuItem>
<MenuItem menuName="统计系统">
<img
slot="icon"
src="@/assets/images/layout/icon_tongji@2x.png"
/>
</MenuItem>
<MenuItem
v-if="systemManage && systemManage.length"
menuName="系统管理"
:menuList="systemManage[0].children"
>
<img
slot="icon"
src="@/assets/images/layout/icon_xitong@2x.png"
/>
</MenuItem>
<MenuItem menuName="全业态">
<img
slot="icon"
src="@/assets/images/layout/icon_quanyetai@2x.png"
/>
</MenuItem>
</div>
<MenuItem
:class="`fastLink ${dashboardVisiable?'marleft':''}`"
menuName="快速访问"
>
<img
slot="icon"
src="@/assets/images/layout/icon_ksfw.png"
/>
</MenuItem>
<div
class="DashboardButton"
@click="clickHandle"
>
<img
v-if="dashboardVisiable"
src="@/assets/images/layout/icon_yewu@2x.png"
/>
<img
v-else
src="@/assets/images/layout/icon_shuju@2x.png"
>
</div>
</div>
</template>
<script>
import MenuItem from './MenuItem';
import { mapGetters } from 'vuex';
import { formatRouteLink } from '@/utils/route';
export default {
name: 'IconMenus',
components: { MenuItem },
props: {
routers: {
type: Array,
default: () => [],
},
dashboardVisiable: {
type: Boolean,
},
},
data() {
return {
menuList: [
{
path: '/OperLog',
name: '19',
meta: { title: '后台操作日志', icon: '' },
},
{
path: '/interface',
name: '27',
meta: { title: '接口管理', icon: '' },
children: [
{
path: '/interface/interfaceApp',
name: '29',
meta: { title: 'APP接口', icon: '' },
},
{
path: '/interface/interfaceManager',
name: '30',
meta: { title: '后台接口', icon: '' },
},
],
},
],
};
},
computed: {
...mapGetters('Dashboard', ['titleData']),
customerManage() {
let item = this.routers.find(
menu => menu.menuCode === process.env.VUE_APP_CUSTOMER_MENU_CODE
);
return item ? formatRouteLink([item]) : null;
},
baseManage() {
let item = this.routers.find(
menu => menu.menuCode === process.env.VUE_APP_BASE_MENU_CODE
);
return item ? formatRouteLink([item]) : null;
},
systemManage() {
let item = this.routers.find(
menu => menu.menuCode === process.env.VUE_APP_SYSTEM_MENU_CODE
);
return item ? formatRouteLink([item]) : null;
},
},
methods: {
clickHandle() {
if (this.dashboardVisiable) {
this.$router.go(-1);
} else {
this.$router.push({
path: '/dashboard',
});
}
},
},
};
</script>
<style lang="scss">
@import '../../../assets/styles/variables.scss';
.IconMenus {
flex: 1;
display: flex;
justify-content: flex-end;
align-items: center;
.TitleData {
border-left: 2px solid #fff;
border-right: 2px solid #fff;
display: flex;
font-size: 14px;
color: #fff;
.dataItem {
width: 180px;
display: flex;
justify-content: center;
align-items: center;
}
.dataNumber {
margin-left: 10px;
font-size: 16px;
}
}
.IconMenus-list {
height: 100%;
display: flex;
}
.fastLink.marleft {
margin-left: 60px;
}
.DashboardButton {
height: 44px;
width: 44px;
}
}
@media screen and (min-width: $bigScreenWidth) {
.IconMenus {
.TitleData {
font-size: 20px;
.dataItem {
width: 280px;
}
.dataNumber {
font-size: 26px;
}
}
.fastLink.marleft {
margin-left: 133px;
}
.DashboardButton {
height: 80px;
width: 80px;
}
}
}
</style>
<template>
<div
ref="MenuItem"
:class="`MenuItem ${showSubMenus?'Selected':''}`"
@mouseenter="toggleSubmenus"
@mouseleave="toggleSubmenus"
>
<div class="IconMenus">
<div class="IconMenus-icon">
<slot name="icon">
<img src="@/assets/images/layout/icon_huiyuanguanli@2x.png" />
</slot>
</div>
<div class="IconMenus-name">{{ menuName }}</div>
</div>
<div
:class="`SubmenuBox ${showSubMenus?'show':''}`"
:style="style"
>
<div class="Submenu">
<div class="Submenu-title">
<span>会员管理</span>
<span class="like-icon"><img src="@/assets/images/layout/icon_nor_weishoucang.png"></span>
</div>
<div class="Submenu-list">
<div class="Submenu-link">
<span class="like-icon"><img src="@/assets/images/layout/icon_nor_weishoucang.png"></span>
<span class="Submenu-link-text">会员信息</span>
</div>
<div class="Submenu-link">
<span class="like-icon"><img src="@/assets/images/layout/icon_nor_weishoucang.png"></span>
<span class="Submenu-link-text">会员反馈</span>
</div>
<div class="Submenu-link">
<span class="like-icon"><img src="@/assets/images/layout/icon_nor_weishoucang.png"></span>
<span class="Submenu-link-text">密码管理</span>
</div>
</div>
</div>
<div class="Submenu">
<div class="Submenu-title">会员账务</div>
<div class="Submenu-list">
<div class="Submenu-link">
<span class="like-icon"><img src="@/assets/images/layout/icon_nor_weishoucang.png"></span>
<span class="Submenu-link-text">会员充值</span>
</div>
<div class="Submenu-link">
<span class="like-icon"><img src="@/assets/images/layout/icon_nor_weishoucang.png"></span>
<span class="Submenu-link-text">会员退款</span>
</div>
<div class="Submenu-link">
<span class="like-icon"><img src="@/assets/images/layout/icon_nor_weishoucang.png"></span>
<span class="Submenu-link-text">豆赠送处理</span>
</div>
</div>
</div>
<div class="Submenu">
<div class="Submenu-title">会员订单</div>
<div class="Submenu-list">
<div class="Submenu-link">
<span class="like-icon"><img src="@/assets/images/layout/icon_nor_weishoucang.png"></span>
<span class="Submenu-link-text">充值订单</span>
</div>
<div class="Submenu-link">
<span class="like-icon"><img src="@/assets/images/layout/icon_nor_weishoucang.png"></span>
<span class="Submenu-link-text">失败订单</span>
</div>
<div class="Submenu-link">
<span class="like-icon"><img src="@/assets/images/layout/icon_nor_weishoucang.png"></span>
<span class="Submenu-link-text">自助消费流水</span>
</div>
<div class="Submenu-link">
<span class="like-icon"><img src="@/assets/images/layout/icon_nor_weishoucang.png"></span>
<span class="Submenu-link-text">支付消费流水</span>
</div>
<div class="Submenu-link">
<span class="like-icon"><img src="@/assets/images/layout/icon_nor_weishoucang.png"></span>
<span class="Submenu-link-text">豆赠送流水</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'MenuItem',
props: {
menuName: {
type: String,
default: '',
},
menuList: {
type: Array,
default: () => [],
},
},
data() {
return {
showSubMenus: false,
style: '',
};
},
mounted() {
let dom = this.$refs.MenuItem;
let offsetRight = document.body.offsetWidth - dom.offsetLeft;
if (offsetRight < 390) {
this.style = 'right: 0;';
} else if (offsetRight < 560) {
this.style = 'right: -280px;';
} else {
this.style = 'left: 0;';
}
},
methods: {
toggleSubmenus() {
this.showSubMenus = !this.showSubMenus;
},
},
};
</script>
<style lang="scss">
@import '../../../assets/styles/variables.scss';
.MenuItem {
position: relative;
width: 80px;
height: 44px;
color: #fff;
&.Selected,
&:hover {
background-color: #68aaff;
}
.IconMenus {
display: flex;
width: 100%;
height: 100%;
flex-direction: column;
justify-content: center;
align-items: center;
cursor: pointer;
.IconMenus-icon {
width: 17px;
height: 17px;
margin-bottom: 5px;
}
.IconMenus-name {
font-size: 14px;
}
}
.SubmenuBox {
background-color: #68aaff;
padding: 0 20px;
position: absolute;
top: 42px;
z-index: 5;
height: 0;
max-height: 0;
border-radius: 0 0 8px 8px;
transition: all 0.28s ease-in-out;
overflow: hidden;
&.show {
max-height: 500px;
height: auto;
}
.Submenu-title {
height: 46px;
line-height: 46px;
font-size: 18px;
color: #78fcf3;
.like-icon {
margin-left: 10px;
}
}
.Submenu-list {
display: flex;
flex-flow: wrap;
width: 560px;
.Submenu-link {
display: inline-block;
min-width: 140px;
height: 40px;
line-height: 40px;
font-size: 18px;
color: #fff;
}
.like-icon {
margin-right: 10px;
}
}
.like-icon {
display: inline-block;
width: 16px;
height: 16px;
}
.like-icon,
.Submenu-link-text {
cursor: pointer;
}
}
}
@media screen and (min-width: $bigScreenWidth) {
.MenuItem {
width: 112px;
height: 80px;
.IconMenus {
.IconMenus-icon {
width: 34px;
height: 34px;
margin-bottom: 10px;
}
.IconMenus-name {
font-size: 18px;
}
}
.SubmenuBox {
top: 80px;
}
}
}
</style>
<template>
<div class="timeBox">
<span class="time">{{ formatDate }}</span>
<span>{{ day }}</span>
<span class="time">{{ day }}</span>
<span>{{ formatTime }}</span>
</div>
</template>
......@@ -16,10 +17,13 @@ export default {
},
computed: {
formatDate() {
return this.$formatDate(this.date);
return this.$formatDate(this.date, 'yyyy-MM-dd');
},
day() {
return this.$parseTime(this.date, '周{a}');
return this.$parseTime(this.date, '星期{a}');
},
formatTime() {
return this.$formatDate(this.date, 'hh:mm:ss');
},
},
created() {
......
<template>
<div class="avatar-container">
<TimeBox />
<span class="avatar-container-line">|</span>
<span class="avatar-name">欢迎,{{userInfo.name}}</span>
<div class="avatar-name">
<span>欢迎您,{{ userInfo.name }}</span>
<span
class="avatar-quit"
class="avatar-name-icon"
@click="toggleUserMenus"
>
<img src="@/assets/images/layout/icon_xiala@2x.png" />
<div
class="UserMenus"
v-if="userMenusVisble"
>
<div
class="UserMenus-Link"
@click="showUserinfoDialog"
>
<span class="UserMenus-Link-icon">
<img src="@/assets/images/layout/icon_ziliao.png" />
</span>
修改资料
</div>
<div
class="UserMenus-Link"
@click="cellphoneDialogVisible = true"
>
<span class="UserMenus-Link-icon">
<img src="@/assets/images/layout/icon_xiugai.png" />
</span>
修改手机号
</div>
<div
class="UserMenus-Link"
@click="logout"
>退出登录
<i class="avatar-quit-icon">
<img src="@/assets/images/user/header_quit.png" />
</i>
>
<span class="UserMenus-Link-icon">
<img src="@/assets/images/layout/icon_tuichu.png" />
</span>
退出登录
</div>
</div>
</span>
</div>
<normal-dialog
title="修改密码"
:visible="dialogVisible"
width="50%"
:before-close="cancelPwdUpdate"
:close-on-click-modal="!(showSetPassword)"
:show-close="!(showSetPassword)"
:close-on-click-modal="!showSetPassword"
:show-close="!showSetPassword"
>
<el-form
:model="pwd"
......@@ -61,7 +93,9 @@
<p
class="setpwd-info"
v-if="showSetPassword"
>原始密码登陆请务必修改密码</p>
>
原始密码登陆请务必修改密码
</p>
</el-form-item>
</el-form>
<span
......@@ -86,16 +120,177 @@
>确 定</el-button>
</span>
</normal-dialog>
<normal-dialog
title="修改资料"
:visible="userInfoDialogVisible"
width="500px"
:before-close="cancelUserinfoUpdate"
class="userForm"
>
<el-form label-width="120px">
<el-form-item label="登录账户">{{userInfo.loginAccount}}</el-form-item>
<el-form-item label="姓名">
<el-input
v-model="userForm.name"
maxlength="20"
placeholder="请输入姓名"
></el-input>
</el-form-item>
<el-form-item label="运营商">{{userInfo.operateName}}</el-form-item>
<el-form-item label="手机号">{{userInfo.cellphone}}</el-form-item>
<el-form-item label="当前登录密码">
<el-input
v-model="userForm.pwd"
:type="showPwd?'text':'password'"
maxlength="20"
placeholder="请输入当前登录密码"
></el-input>
<div
class="showPassword"
@click="showPwd = !showPwd"
>
<img
v-if="showPwd"
src="@/assets/images/layout/icon_sel@2x.png"
/>
<img
v-else
src="@/assets/images/layout/icon_nor@2x.png"
>
</div>
</el-form-item>
<el-form-item label="设置新密码">
<el-input
v-model="userForm.newPwd"
:type="showNewPwd?'text':'password'"
maxlength="20"
placeholder="请输入新密码"
></el-input>
<div
class="showPassword"
@click="showNewPwd = !showNewPwd"
>
<img
v-if="showNewPwd"
src="@/assets/images/layout/icon_sel@2x.png"
/>
<img
v-else
src="@/assets/images/layout/icon_nor@2x.png"
>
</div>
</el-form-item>
<el-form-item label="确认新密码">
<el-input
v-model="userForm.checkPwd"
:type="showCheckPwd?'text':'password'"
maxlength="20"
placeholder="请再次输入新密码"
></el-input>
<div
class="showPassword"
@click="showCheckPwd = !showCheckPwd"
>
<img
v-if="showCheckPwd"
src="@/assets/images/layout/icon_sel@2x.png"
/>
<img
v-else
src="@/assets/images/layout/icon_nor@2x.png"
>
</div>
</el-form-item>
</el-form>
<div slot="footer">
<el-button
type="primary"
@click="updateUserinfoHandle"
:disabled="loading"
>确定</el-button>
<el-button @click="cancelUserinfoUpdate">取消</el-button>
</div>
</normal-dialog>
<normal-dialog
title="修改手机号"
:visible="cellphoneDialogVisible"
width="500px"
:before-close="cancelCellphoneUpdate"
class="cellphoneForm"
>
<el-form
label-width="120px"
v-loading="loading"
>
<el-form-item label="登录账户">{{userInfo.loginAccount}}</el-form-item>
<el-form-item label="姓名">{{userInfo.name}}</el-form-item>
<el-form-item label="运营商">{{userInfo.operateName}}</el-form-item>
<el-form-item label="手机号">{{userInfo.cellphone}}</el-form-item>
<el-form-item label="更换手机账户">
<el-input
v-model="cellphoneForm.cellphone"
maxlength="11"
placeholder="请输入更换手机账户"
></el-input>
</el-form-item>
<el-form-item label="输入验证码">
<div class="vcode-wrap">
<el-input
v-model="cellphoneForm.vcode"
maxlength="6"
placeholder="验证码"
></el-input>
<Vcode
class="vcode-box"
:cellphone="cellphoneForm.cellphone"
/>
</div>
</el-form-item>
</el-form>
<div slot="footer">
<el-button
type="primary"
@click="updateCellphone"
:disabled="loading"
>确定</el-button>
<el-button @click="cancelCellphoneUpdate">取消</el-button>
</div>
<!-- <normal-dialog
title="输入图形验证码"
:visible="vcodeVisible"
width="330px"
top="20vh"
:before-close="cancelVcode"
append-to-body
class="cellphoneForm"
>
<div class="img-code-box">
<div>
<el-input v-model="cellphoneForm.imgCode" />
</div>
<div class="code-img">
<CodeView :value="cellphoneForm.svcode" />
</div>
</div>
</normal-dialog> -->
</normal-dialog>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
import TimeBox from './TimeBox';
// import CodeView from '../../login/components/CodeView';
import Vcode from './Vcode';
export default {
components: {
TimeBox,
Vcode,
// CodeView,
},
data() {
const validatePass = (rule, value, callback) => {
......@@ -108,7 +303,11 @@ export default {
}
};
return {
userMenusVisble: false,
userInfoDialogVisible: false,
cellphoneDialogVisible: false,
dialogVisible: false,
vcodeVisible: false,
formLabelWidth: '200px',
pwd: {
oldPwd: '',
......@@ -123,10 +322,25 @@ export default {
{ validator: validatePass },
],
},
userForm: {
name: '',
pwd: '',
newPwd: '',
checkPwd: '',
},
showPwd: false,
showNewPwd: false,
showCheckPwd: false,
cellphoneForm: {
cellphone: '',
vcode: '',
imgCode: '',
svcode: '',
},
};
},
computed: {
...mapGetters(['userInfo']),
...mapGetters(['userInfo', 'loading']),
showSetPassword() {
return this.userInfo && this.userInfo.isSetPassword === 0;
},
......@@ -142,7 +356,10 @@ export default {
},
},
methods: {
...mapActions(['updatePassword']),
...mapActions(['updatePassword', 'updateUserinfo', 'updateUserCellphone']),
toggleUserMenus() {
this.userMenusVisble = !this.userMenusVisble;
},
cancelPwdUpdate(done) {
this.resetPwdForm();
done();
......@@ -171,6 +388,110 @@ export default {
location.reload(); // 为了重新实例化vue-router对象 避免bug
});
},
showUserinfoDialog() {
this.userForm = {
name: this.userInfo.name,
pwd: '',
newPwd: '',
checkPwd: '',
};
this.userInfoDialogVisible = true;
},
cancelUserinfoUpdate(done) {
this.resetUserForm();
typeof done === 'function' && done();
},
resetUserForm() {
this.userForm = {
name: '',
pwd: '',
newPwd: '',
checkPwd: '',
};
this.userInfoDialogVisible = false;
},
validateUserForm() {
if (!this.userForm.name) {
this.$message.error('请输入姓名');
return;
}
if (this.userForm.newPwd) {
if (!this.userForm.pwd) {
this.$message.error('请输入密码');
return;
}
if (!this.userForm.checkPwd) {
this.$message.error('请再次输入新密码');
return;
}
if (this.userForm.newPwd !== this.userForm.checkPwd) {
this.$message.error('两次输入密码不一致');
return;
}
}
return true;
},
updateUserinfoHandle() {
if (this.validateUserForm()) {
const entity = this.userForm.newPwd
? {
name: this.userForm.name,
newPwd: this.userForm.newPwd,
oldPwd: this.userForm.pwd,
}
: {
name: this.userForm.name,
};
this.updateUserinfo(entity)
.then(res => {
this.$message.success(res.msg || '修改成功');
this.cancelUserinfoUpdate();
})
.catch(err => {
console.log(err);
});
}
},
cancelCellphoneUpdate(done) {
this.resetCellphoneForm();
typeof done === 'function' && done();
},
resetCellphoneForm() {
this.cellphoneForm = {
cellphone: '',
vcode: '',
svcode: '',
};
this.cellphoneDialogVisible = false;
},
validateCellphoneForm() {
if (!this.cellphoneForm.cellphone) {
this.$message.error('请输入更换手机号');
return false;
}
if (!this.cellphoneForm.vcode) {
this.$message.error('请输入验证码');
return false;
}
return true;
},
updateCellphone() {
if (this.validateCellphoneForm()) {
const entity = {
cellphone: this.cellphoneForm.cellphone,
checkCode: this.cellphoneForm.vcode,
};
this.updateUserCellphone(entity)
.then(res => {
this.resetCellphoneForm();
console.log(res);
})
.catch(err => {
console.log(err);
});
}
},
},
};
</script>
......@@ -178,10 +499,11 @@ export default {
<style lang="scss">
@import '../../../assets/styles/variables.scss';
.avatar-container {
margin-right: 12px;
margin-left: 66px;
display: flex;
justify-content: center;
flex-direction: column;
color: #fff;
height: 22px;
line-height: 22px;
font-size: 12px;
flex: 1;
......@@ -190,7 +512,43 @@ export default {
margin: 0 20px;
}
.avatar-name {
margin-right: 25px;
display: flex;
align-items: center;
line-height: 20px;
font-size: 16px;
.avatar-name-icon {
position: relative;
margin-left: 6px;
width: 16px;
height: 16px;
cursor: pointer;
}
.UserMenus {
position: absolute;
z-index: 2;
top: 20px;
right: -10px;
width: 148px;
background-color: #68aaff;
border-radius: 8px;
font-size: 18px;
overflow: hidden;
.UserMenus-Link {
cursor: pointer;
height: 46px;
line-height: 46px;
display: flex;
align-items: center;
.UserMenus-Link-icon {
width: 16px;
height: 16px;
margin: 0 10px 0;
}
}
.UserMenus-Link:hover {
background-color: #0d48d4;
}
}
}
.avatar-quit {
cursor: pointer;
......@@ -224,11 +582,53 @@ export default {
.setpwd-info {
color: red;
}
.userForm {
.el-form-item {
margin-bottom: 12px;
}
}
.cellphoneForm {
.vcode-wrap {
display: flex;
align-items: center;
}
.el-input {
flex: 1;
}
.vcode-box {
width: 100px;
text-align: center;
cursor: pointer;
color: $menuHover;
}
}
.showPassword {
position: absolute;
top: 15px;
right: 10px;
width: 20px;
height: 12px;
}
}
.img-code-box {
display: flex;
align-items: center;
.code-img {
width: 80px;
height: 32px;
margin-left: 20px;
}
}
@media screen and (min-width: $bigScreenWidth) {
.avatar-container {
margin-right: 24px;
font-size: 16px;
font-size: 18px;
.avatar-name {
line-height: 30px;
font-size: 24px;
.UserMenus {
top: 35px;
}
}
.avatar-quit {
font-size: 14px;
}
......
<script>
import { getVcode } from '@/api/user/update';
export default {
props: {
text: String,
cellphone: String,
},
data() {
return {
defaultText: this.text ? this.text : '获取验证码',
counting: false,
count: 60,
timer: null,
showImgBox: false,
vcode: null,
inputCode: '',
};
},
methods: {
countStart() {
this.counting = true;
this.countDown();
},
countDown() {
const count = this.count;
if (count == 1) {
this.counting = false;
} else {
const timer = setTimeout(() => {
this.countDown();
}, 1000);
this.count = count - 1;
this.timer = timer;
}
},
clickHandle() {
if (this.cellphone && this.cellphone.length == 11) {
getVcode({
params: {
cellphone: this.cellphone,
},
})
.then(res => {
this.countStart();
this.$message.success(res.msg || '发送成功');
this.vcode = null;
this.inputCode = '';
})
.catch(console.error);
} else {
this.$message.error('请输入正确的手机号');
}
},
},
render(h) {
return (
<div>
{this.counting ? (
<div class="Vcode Counting">{`${this.count}S后重发`}</div>
) : (
<div class="Vcode" onClick={this.clickHandle}>
{this.defaultText}
</div>
)}
</div>
);
},
};
</script>
<style lang="scss">
.Vcode.Counting {
color: #999;
}
</style>
......@@ -5,7 +5,11 @@ import 'nprogress/nprogress.css'; // Progress 进度条样式
import { getToken } from '@/utils/auth'; // 验权
import { getAuthRoute } from './utils/route';
const allAasyncRouterMap = [];
let allAasyncRouterMap = [
...customerManage.default,
...baseManage.default,
...systemManage.default,
];
NProgress.configure({ showSpinner: false }); // NProgress Configuration
......@@ -13,9 +17,6 @@ const whiteList = process.env.VUE_APP_WHITE_LIST.split(','); // 不重定向白
const getRouteAdd = () => {
let allRoute = store.getters.asyncRoutes;
// let item = allRoute.find(
// menu => menu.menuCode === process.env.VUE_APP_MENU_CODE
// );
for (let index = 0; index < allRoute.length; index++) {
const element = allRoute[index];
if (element && element.childs) {
......
......@@ -19,6 +19,16 @@ const constantRouterMap = [
meta: { title: '首页', icon: HomeIcon },
component: { render: h => <router-view /> },
},
{
path: '/dashboard',
component: _import('Dashboard/Dashboard'),
name: 'dashboard',
meta: {
title: '数据首页',
store: require('@/containers/Dashboard/store').default,
},
hidden: true,
},
];
const asyncRouterMap = [{ path: '*', redirect: '/404', hidden: true }];
......
......@@ -12,4 +12,11 @@ let isLib = (() => {
module.exports = {
publicPath: process.env.VUE_APP_BASE_URL,
outputDir: isLib ? Path.join('dist', 'lib') : 'dist',
configureWebpack: {
externals: [
{
vue: 'Vue',
},
],
},
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment