修改路径、换图片、图形分析

This commit is contained in:
康冉冉
2025-08-28 18:55:38 +08:00
parent 513d77f40f
commit fd38d86bf1
38 changed files with 1059 additions and 1020 deletions

View File

@@ -1,5 +1,5 @@
# 页面标题
VUE_APP_TITLE = SAAS管理平台
VUE_APP_TITLE = SAAS综合管理平台
# 开发环境配置
ENV = 'development'

View File

@@ -1,5 +1,5 @@
# 页面标题
VUE_APP_TITLE = SAAS管理平台
VUE_APP_TITLE = SAAS综合管理平台
# 生产环境配置
ENV = 'production'

View File

@@ -1,5 +1,5 @@
# 页面标题
VUE_APP_TITLE = SAAS管理平台
VUE_APP_TITLE = SAAS综合管理平台
BABEL_ENV = production

View File

@@ -1,7 +1,7 @@
{
"name": "ruoyi",
"version": "3.6.6",
"description": "SAAS管理平台",
"description": "SAAS综合管理平台",
"author": "若依",
"license": "MIT",
"scripts": {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 662 KiB

BIN
public/favicon1.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 17 KiB

BIN
src/assets/logo/logo1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
src/assets/logo/logo2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 KiB

View File

@@ -80,6 +80,12 @@ div:focus {
.plr-50 {
padding: 0 50px;
}
.p15 {
padding: 15px;
}
.p20 {
padding: 20px;
}
.fontSize15 {
font-size: 15px;
}
@@ -229,9 +235,20 @@ aside {
.w100 {
width: 100%;
}
.h40 {
height: 40%;
}
.h100 {
height: 100%;
}
.textAlignCenter {
text-align: center;
}
.pageTopForm .el-form-item--medium .el-form-item__label {
width: 80px;
overflow: hidden;
height: 36px;
}
.pageTopForm .el-form-item {
margin-left: 10px!important;
}

View File

@@ -8,9 +8,9 @@
range-separator=""
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
style="display: inline-block!important;width: 55%!important;"
style="display: inline-block!important;width: 45%!important;vertical-align: middle;"
@change="dateChange"/>
<ul style="display: inline-block">
<ul style="display: inline-block;padding-left: 10px;vertical-align: middle;">
<li :class="{ 'activesbgs' : isActive == 'DAY' }" @click="toggle('DAY',7)">前7天</li>
<li :class="{ 'activesbgs' : isActive == 'WEEK' }" @click="toggle('WEEK',15)">前15天</li>
<li :class="{ 'activesbgs' : isActive == 'MONTH' }" @click="toggle('MONTH')">前一个月</li>
@@ -97,11 +97,11 @@
</script>
<style scoped>
.ultabs {
float: right;
position: relative;
z-index: 9;
margin-top: 30px;
margin-right: 2%;
width: 500px;
float: right;
position: relative;
z-index: 9;
margin-top: -10px;
}
.ultabs ul li {
@@ -132,10 +132,4 @@
line-height: 40px !important;
border: 1px solid #5D78FF;
}
::v-deep .ultabs .el-range-editor--medium .el-range-input{
vertical-align: super!important;
}
::v-deep .ultabs .el-range-editor--medium .el-range-separator{
vertical-align: super!important;
}
</style>

View File

@@ -37,10 +37,22 @@
const pieDataListIntance = echarts.init(document.getElementById('pieChart' + this.num));
let option = {
color: dataList.color,
// title: [
// {
// text: `${dataList.centerVal}${dataList.unit}`,
// left: "16%",
// top: "43%",
// textStyle: {
// fontSize: 18,
// fontWeight: "bold",
// color: "#333",
// },
// }
// ],
legend: {
orient: 'vertical', // 垂直排列
top: 'center', // 垂直居中
right: 40, // 距离右侧40px
// orient: 'vertical', // 垂直排列
top: 'bottom', // 垂直居中
// right: 1, // 距离右侧40px
itemWidth: 12, // 图例标记宽度
itemHeight: 12, // 图例标记高度
itemGap: 20, // 图例项间距
@@ -58,8 +70,8 @@
series: [{
name: 'Access From',
type: 'pie',
radius: ['40%', '70%'],
center: dataList && dataList.center || ['20%', '50%'],
radius: dataList && dataList.radius || ['40%', '70%'],
// center: dataList && dataList.center || ['20%', '50%'],
label: {
show: false,
position: 'center'
@@ -74,18 +86,18 @@
},
data: dataList.data
}],
// graphic: [{
// type: 'text',
// left: 'center',
// top: 'middle',
// style: {
// text: `${dataList.centerVal}${dataList.unit}`,
// textBaseline: 'middle',
// textAlign: 'center',
// fontSize: 20,
// fill: '#333'
// }
// }],
graphic: [{
type: 'text',
left: 'center',
top: 'middle',
style: {
text: `${dataList.centerVal}${dataList.unit}`,
textBaseline: 'middle',
textAlign: 'center',
fontSize: 20,
fill: '#333'
}
}],
};
pieDataListIntance.setOption(option);
// window.addEventListener("resize", () => {

View File

@@ -95,7 +95,6 @@
methods: {
// 所有方法都抛出到父组件里去
handleClick(item, row) {
console.log('row==',row);
this.$emit("fnClick", item, row, this.ids, this.selectList);
},
@@ -132,7 +131,6 @@
this.selectList.forEach(val => {
this.$refs.selChangeList.toggleRowSelection(val,true);
});
console.log('selectList==',this.selectList);
},
// 提供给父组件调用的方法:返回当前表格的选中数据
getSelectedData() {

View File

@@ -1,208 +1,208 @@
<template>
<div class="navbar">
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<breadcrumb v-if="!topNav" id="breadcrumb-container" class="breadcrumb-container" />
<top-nav v-if="topNav" id="topmenu-container" class="topmenu-container" />
<div class="right-menu">
<template v-if="device!=='mobile'">
<search id="header-search" class="right-menu-item" />
<el-tooltip content="源码地址" effect="dark" placement="bottom">
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
</el-tooltip>
<el-tooltip content="文档地址" effect="dark" placement="bottom">
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
</el-tooltip>
<screenfull id="screenfull" class="right-menu-item hover-effect" />
<el-tooltip content="布局大小" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" />
</el-tooltip>
</template>
<el-dropdown class="avatar-container right-menu-item hover-effect" trigger="hover">
<div class="avatar-wrapper">
<img :src="avatar" class="user-avatar">
<span class="user-nickname"> {{ nickName }} </span>
</div>
<el-dropdown-menu slot="dropdown">
<router-link to="/user/profile">
<el-dropdown-item>个人中心</el-dropdown-item>
</router-link>
<el-dropdown-item divided @click.native="logout">
<span>退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<div class="right-menu-item hover-effect setting" @click="setLayout" v-if="setting">
<svg-icon icon-class="more-up" />
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import TopNav from '@/components/TopNav'
import Hamburger from '@/components/Hamburger'
import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect'
import Search from '@/components/HeaderSearch'
import RuoYiGit from '@/components/RuoYi/Git'
import RuoYiDoc from '@/components/RuoYi/Doc'
export default {
emits: ['setLayout'],
components: {
Breadcrumb,
TopNav,
Hamburger,
Screenfull,
SizeSelect,
Search,
RuoYiGit,
RuoYiDoc
},
computed: {
...mapGetters([
'sidebar',
'avatar',
'device',
'nickName'
]),
setting: {
get() {
return this.$store.state.settings.showSettings
}
},
topNav: {
get() {
return this.$store.state.settings.topNav
}
}
},
methods: {
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
},
setLayout(event) {
this.$emit('setLayout')
},
logout() {
this.$confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$store.dispatch('LogOut').then(() => {
location.href = '/index'
})
}).catch(() => {})
}
}
}
</script>
<style lang="scss" scoped>
.navbar {
height: 50px;
overflow: hidden;
position: relative;
background: #fff;
box-shadow: 0 1px 4px rgba(0,21,41,.08);
.hamburger-container {
line-height: 46px;
height: 100%;
float: left;
cursor: pointer;
transition: background .3s;
-webkit-tap-highlight-color:transparent;
&:hover {
background: rgba(0, 0, 0, .025)
}
}
.breadcrumb-container {
float: left;
}
.topmenu-container {
position: absolute;
left: 50px;
}
.errLog-container {
display: inline-block;
vertical-align: top;
}
.right-menu {
float: right;
height: 100%;
line-height: 50px;
&:focus {
outline: none;
}
.right-menu-item {
display: inline-block;
padding: 0 8px;
height: 100%;
font-size: 18px;
color: #5a5e66;
vertical-align: text-bottom;
&.hover-effect {
cursor: pointer;
transition: background .3s;
&:hover {
background: rgba(0, 0, 0, .025)
}
}
}
.avatar-container {
margin-right: 0px;
padding-right: 0px;
.avatar-wrapper {
margin-top: 10px;
position: relative;
.user-avatar {
cursor: pointer;
width: 30px;
height: 30px;
border-radius: 50%;
}
.user-nickname{
position: relative;
bottom: 10px;
font-size: 14px;
font-weight: bold;
}
.el-icon-caret-bottom {
cursor: pointer;
position: absolute;
right: -20px;
top: 25px;
font-size: 12px;
}
}
}
}
}
</style>
<template>
<div class="navbar">
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<breadcrumb v-if="!topNav" id="breadcrumb-container" class="breadcrumb-container" />
<top-nav v-if="topNav" id="topmenu-container" class="topmenu-container" />
<div class="right-menu">
<template v-if="device!=='mobile'">
<search id="header-search" class="right-menu-item" />
<!-- <el-tooltip content="源码地址" effect="dark" placement="bottom">-->
<!-- <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />-->
<!-- </el-tooltip>-->
<!-- <el-tooltip content="文档地址" effect="dark" placement="bottom">-->
<!-- <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />-->
<!-- </el-tooltip>-->
<screenfull id="screenfull" class="right-menu-item hover-effect" />
<el-tooltip content="布局大小" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" />
</el-tooltip>
</template>
<el-dropdown class="avatar-container right-menu-item hover-effect" trigger="hover">
<div class="avatar-wrapper">
<img :src="avatar" class="user-avatar">
<span class="user-nickname"> {{ nickName }} </span>
</div>
<el-dropdown-menu slot="dropdown">
<router-link to="/user/profile">
<el-dropdown-item>个人中心</el-dropdown-item>
</router-link>
<el-dropdown-item divided @click.native="logout">
<span>退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<div class="right-menu-item hover-effect setting" @click="setLayout" v-if="setting">
<svg-icon icon-class="more-up" />
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import TopNav from '@/components/TopNav'
import Hamburger from '@/components/Hamburger'
import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect'
import Search from '@/components/HeaderSearch'
import RuoYiGit from '@/components/RuoYi/Git'
import RuoYiDoc from '@/components/RuoYi/Doc'
export default {
emits: ['setLayout'],
components: {
Breadcrumb,
TopNav,
Hamburger,
Screenfull,
SizeSelect,
Search,
RuoYiGit,
RuoYiDoc
},
computed: {
...mapGetters([
'sidebar',
'avatar',
'device',
'nickName'
]),
setting: {
get() {
return this.$store.state.settings.showSettings
}
},
topNav: {
get() {
return this.$store.state.settings.topNav
}
}
},
methods: {
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
},
setLayout(event) {
this.$emit('setLayout')
},
logout() {
this.$confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$store.dispatch('LogOut').then(() => {
location.href = '/index'
})
}).catch(() => {})
}
}
}
</script>
<style lang="scss" scoped>
.navbar {
height: 50px;
overflow: hidden;
position: relative;
background: #fff;
box-shadow: 0 1px 4px rgba(0,21,41,.08);
.hamburger-container {
line-height: 46px;
height: 100%;
float: left;
cursor: pointer;
transition: background .3s;
-webkit-tap-highlight-color:transparent;
&:hover {
background: rgba(0, 0, 0, .025)
}
}
.breadcrumb-container {
float: left;
}
.topmenu-container {
position: absolute;
left: 50px;
}
.errLog-container {
display: inline-block;
vertical-align: top;
}
.right-menu {
float: right;
height: 100%;
line-height: 50px;
&:focus {
outline: none;
}
.right-menu-item {
display: inline-block;
padding: 0 8px;
height: 100%;
font-size: 18px;
color: #5a5e66;
vertical-align: text-bottom;
&.hover-effect {
cursor: pointer;
transition: background .3s;
&:hover {
background: rgba(0, 0, 0, .025)
}
}
}
.avatar-container {
margin-right: 0px;
padding-right: 0px;
.avatar-wrapper {
margin-top: 10px;
position: relative;
.user-avatar {
cursor: pointer;
width: 30px;
height: 30px;
border-radius: 50%;
}
.user-nickname{
position: relative;
bottom: 10px;
font-size: 14px;
font-weight: bold;
}
.el-icon-caret-bottom {
cursor: pointer;
position: absolute;
right: -20px;
top: 25px;
font-size: 12px;
}
}
}
}
}
</style>

View File

@@ -5,6 +5,7 @@ Vue.use(Router)
/* Layout */
import Layout from '@/layout'
import DialogView from '@/views/disRevenue/earnManage/server/dialogView.vue'
/**
* Note: 路由配置项
@@ -87,6 +88,11 @@ export const constantRoutes = [
meta: { title: '个人中心', icon: 'user' }
}
]
},
{
path: '/dialog-view',
component: DialogView,
name: 'DialogView'
}
]
@@ -191,6 +197,20 @@ export const dynamicRoutes = [
}
]
},
{
path: '/disRevenue/earnManage/server/graphicAnalysis',
component: Layout,
hidden: true,
permissions: ['disRevenue:earnManage:server:graphicAnalysis'],
children: [
{
path: 'index/:dialogVal?',
component: () => import('@/views/disRevenue/earnManage/server/dialogView'),
name: 'DialogView',
meta: { title: '图形分析', activeMenu: '/disRevenue/earnManage/server' }
}
]
},
// 交换机宽带收益
{
path: '/disRevenue/earnManage/switch/list',

View File

@@ -1,152 +1,152 @@
import axios from 'axios'
import { Notification, MessageBox, Message, Loading } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { tansParams, blobValidate } from "@/utils/ruoyi"
import cache from '@/plugins/cache'
import { saveAs } from 'file-saver'
let downloadLoadingInstance
// 是否显示重新登录
export let isRelogin = { show: false }
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例
const service = axios.create({
// axios中请求配置有baseURL选项表示请求URL公共部分
baseURL: process.env.VUE_APP_BASE_API,
// 超时
timeout: 10000
})
// request拦截器
service.interceptors.request.use(config => {
// 是否需要设置 token
const isToken = (config.headers || {}).isToken === false
// 是否需要防止数据重复提交
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
if (getToken() && !isToken) {
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
}
// get请求映射params参数
if (config.method === 'get' && config.params) {
let url = config.url + '?' + tansParams(config.params)
url = url.slice(0, -1)
config.params = {}
config.url = url
}
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
const requestObj = {
url: config.url,
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
time: new Date().getTime()
}
const requestSize = Object.keys(JSON.stringify(requestObj)).length // 请求数据大小
const limitSize = 5 * 1024 * 1024 // 限制存放数据5M
if (requestSize >= limitSize) {
console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制无法进行防重复提交验证。')
return config
}
const sessionObj = cache.session.getJSON('sessionObj')
if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
cache.session.setJSON('sessionObj', requestObj)
} else {
const s_url = sessionObj.url // 请求地址
const s_data = sessionObj.data // 请求数据
const s_time = sessionObj.time // 请求时间
const interval = 1000 // 间隔时间(ms),小于此时间视为重复提交
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
const message = '数据正在处理,请勿重复提交'
console.warn(`[${s_url}]: ` + message)
return Promise.reject(new Error(message))
} else {
cache.session.setJSON('sessionObj', requestObj)
}
}
}
return config
}, error => {
console.log(error)
Promise.reject(error)
})
// 响应拦截器
service.interceptors.response.use(res => {
// 未设置状态码则默认成功状态
const code = res.data.code || 200
// 获取错误信息
const msg = errorCode[code] || res.data.msg || errorCode['default']
// 二进制数据则直接返回
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
return res.data
}
if (code === 401) {
if (!isRelogin.show) {
isRelogin.show = true
MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
isRelogin.show = false
store.dispatch('LogOut').then(() => {
location.href = '/index'
})
}).catch(() => {
isRelogin.show = false
})
}
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
} else if (code === 500) {
Message({ message: msg, type: 'error' })
return Promise.reject(new Error(msg))
} else if (code === 601) {
Message({ message: msg, type: 'warning' })
return Promise.reject('error')
} else if (code !== 200) {
Notification.error({ title: msg })
return Promise.reject('error')
} else {
return res.data
}
},
error => {
console.log('err' + error)
let { message } = error
if (message == "Network Error") {
message = "后端接口连接异常"
} else if (message.includes("timeout")) {
message = "系统接口请求超时"
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常"
}
Message({ message: message, type: 'error', duration: 5 * 1000 })
return Promise.reject(error)
}
)
// 通用下载方法
export function download(url, params, filename, config) {
downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
return service.post(url, params, {
transformRequest: [(params) => { return tansParams(params) }],
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'blob',
...config
}).then(async (data) => {
const isBlob = blobValidate(data)
if (isBlob) {
const blob = new Blob([data])
saveAs(blob, filename)
} else {
const resText = await data.text()
const rspObj = JSON.parse(resText)
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
Message.error(errMsg)
}
downloadLoadingInstance.close()
}).catch((r) => {
console.error(r)
Message.error('下载文件出现错误,请联系管理员!')
downloadLoadingInstance.close()
})
}
export default service
import axios from 'axios'
import { Notification, MessageBox, Message, Loading } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { tansParams, blobValidate } from "@/utils/ruoyi"
import cache from '@/plugins/cache'
import { saveAs } from 'file-saver'
let downloadLoadingInstance
// 是否显示重新登录
export let isRelogin = { show: false }
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例
const service = axios.create({
// axios中请求配置有baseURL选项表示请求URL公共部分
baseURL: process.env.VUE_APP_BASE_API,
// 超时
timeout: 10000
})
// request拦截器
service.interceptors.request.use(config => {
// 是否需要设置 token
const isToken = (config.headers || {}).isToken === false
// 是否需要防止数据重复提交
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
if (getToken() && !isToken) {
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
}
// get请求映射params参数
if (config.method === 'get' && config.params) {
let url = config.url + '?' + tansParams(config.params)
url = url.slice(0, -1)
config.params = {}
config.url = url
}
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
const requestObj = {
url: config.url,
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
time: new Date().getTime()
}
const requestSize = Object.keys(JSON.stringify(requestObj)).length // 请求数据大小
const limitSize = 5 * 1024 * 1024 // 限制存放数据5M
if (requestSize >= limitSize) {
console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制无法进行防重复提交验证。')
return config
}
const sessionObj = cache.session.getJSON('sessionObj')
if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
cache.session.setJSON('sessionObj', requestObj)
} else {
const s_url = sessionObj.url // 请求地址
const s_data = sessionObj.data // 请求数据
const s_time = sessionObj.time // 请求时间
const interval = 1000 // 间隔时间(ms),小于此时间视为重复提交
// if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
// const message = '数据正在处理,请勿重复提交'
// console.warn(`[${s_url}]: ` + message)
// return Promise.reject(new Error(message))
// } else {
cache.session.setJSON('sessionObj', requestObj)
// }
}
}
return config
}, error => {
console.log(error)
Promise.reject(error)
})
// 响应拦截器
service.interceptors.response.use(res => {
// 未设置状态码则默认成功状态
const code = res.data.code || 200
// 获取错误信息
const msg = errorCode[code] || res.data.msg || errorCode['default']
// 二进制数据则直接返回
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
return res.data
}
if (code === 401) {
if (!isRelogin.show) {
isRelogin.show = true
MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
isRelogin.show = false
store.dispatch('LogOut').then(() => {
location.href = '/index'
})
}).catch(() => {
isRelogin.show = false
})
}
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
} else if (code === 500) {
Message({ message: msg, type: 'error' })
return Promise.reject(new Error(msg))
} else if (code === 601) {
Message({ message: msg, type: 'warning' })
return Promise.reject('error')
} else if (code !== 200) {
Notification.error({ title: msg })
return Promise.reject('error')
} else {
return res.data
}
},
error => {
console.log('err' + error)
let { message } = error
if (message == "Network Error") {
message = "后端接口连接异常"
} else if (message.includes("timeout")) {
message = "系统接口请求超时"
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常"
}
Message({ message: message, type: 'error', duration: 5 * 1000 })
return Promise.reject(error)
}
)
// 通用下载方法
export function download(url, params, filename, config) {
downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
return service.post(url, params, {
transformRequest: [(params) => { return tansParams(params) }],
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'blob',
...config
}).then(async (data) => {
const isBlob = blobValidate(data)
if (isBlob) {
const blob = new Blob([data])
saveAs(blob, filename)
} else {
const resText = await data.text()
const rspObj = JSON.parse(resText)
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
Message.error(errMsg)
}
downloadLoadingInstance.close()
}).catch((r) => {
console.error(r)
Message.error('下载文件出现错误,请联系管理员!')
downloadLoadingInstance.close()
})
}
export default service

View File

@@ -52,7 +52,7 @@
countBusinessName(dataVal).then(response => {
addBusiness(dataVal).then(response => {
this.$modal.msgSuccess(response.msg);
this.$router.push("/disRevenue/earnManage/business");
this.$router.push("/earnManage/business");
this.loading = false;
}).catch(() => {
this.$modal.msgError("操作失败");
@@ -64,7 +64,7 @@
});
break;
case 'cancle':
this.$router.push("/disRevenue/earnManage/business");
this.$router.push("/earnManage/business");
break;
default:
}

View File

@@ -1,5 +1,5 @@
<template>
<div class="app-container">
<div class="app-container pageTopForm">
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="130px">
<el-form-item label="业务名称" prop="businessName">
<el-col :span="4">

View File

@@ -1,5 +1,5 @@
<template>
<div class="app-container">
<div class="app-container pageTopForm">
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="130px">
<el-form-item label="节点名称" prop="nodeName">
<el-col :span="4">

View File

@@ -74,7 +74,7 @@
calculateAvg(dataVal).then(response => {
this.$modal.msgSuccess(response.msg);
if (this.paramsData && this.paramsData.resourceType === '1') {
this.$router.push("/disRevenue/earnManage/server");
this.$router.push("/earnManage/server");
}
// else {
// this.$router.push("/disRevenue/earnManage/switch");
@@ -85,7 +85,7 @@
break;
case 'cancle':
if (this.paramsData && this.paramsData.resourceType === '1') {
this.$router.push("/disRevenue/earnManage/server");
this.$router.push("/earnManage/server");
}
// else {
// this.$router.push("/disRevenue/earnManage/switch");

View File

@@ -0,0 +1,121 @@
<template>
<div class="app-container">
<div style="height: 90px;">
<el-form ref="noticeRef" :model="form" label-width="80px">
<el-form-item label="节点名称" prop="noticeType">
<el-select v-model="form.noticeType" multiple placeholder="请选择节点名称">
<el-option
v-for="item in selectChangeList"
:key="item.id"
:label="item.nodeName"
:value="item.id"/>
</el-select>
</el-form-item>
</el-form>
<el-switch v-for="item of switchData" v-model="item.type" :activeText="item.name" class="mr20" />
</div>
<div style="height: calc(100vh - 130px);overflow: scroll;">
<template v-for="(item,index) of selectChoose">
<EchartsLine v-show="switchData[0].type" :chartData="chartDataEvent"
:lineData="lineDataParams" :title="'【' + item.nodeName + '】【' + item.businessName + '】' + switchData[0].name" class="w100 h40 mt20 mb20" style="border: 1.5px solid #878787;"></EchartsLine>
<EchartsLine v-show="switchData[1].type" :chartData="chartDataEvent"
:lineData="lineDataParams" :title="'【' + item.nodeName + '】【' + item.businessName + '】' + switchData[1].name" class="w100 h40 mt20 mb20" style="border: 1.5px solid #878787;"></EchartsLine>
<EchartsBar v-show="switchData[2].type" :chartData="chartDataEvent"
:barData="lineDataParams" :title="'【' + item.nodeName + '】【' + item.businessName + '】' + switchData[2].name" class="w100 h40 mt20 mb20" style="border: 1.5px solid #878787;"></EchartsBar>
</template>
</div>
<!-- <template #footer>-->
<!-- <div class="dialog-footer">-->
<!-- &lt;!&ndash; <el-button type="primary" @click="submitForm"> </el-button>&ndash;&gt;-->
<!-- <el-button @click="cancel"> </el-button>-->
<!-- </div>-->
<!-- </template>-->
</div>
</template>
<script setup>
import Form from '@/components/form/index.vue';
import EchartsLine from "@/components/echartsList/line.vue";
import EchartsBar from "@/components/echartsList/bar.vue";
export default {
name: 'DialogView',
components: {Form, EchartsLine, EchartsBar},
data() {
return {
paramsData: {},
form: {},
storageKey: '',
selectChangeList: [],
switchData: [
{id: 'ninetyFiveDay', type: true, name: '95宽带值Mbps/日'},
{id: 'ninetyFiveMonth', type: true, name: '95宽带值Mbps/月'},
{id: 'packageEnd', type: true, name: '包端宽带值Mbps/日'}
],
selectChoose: [],
lineDataParams: {
lineXData: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
data: [820, 932, 901, 934, 1290, 1330, 1320]
},
}
},
created() {},
mounted() {
this.storageKey = this.$route.query && this.$route.query['storageKey'];
if (this.storageKey) {
this.paramsData = localStorage.getItem(this.storageKey);
if (this.paramsData) {
this.processData(JSON.parse(this.paramsData));
}
}
},
destroyed() {
localStorage.removeItem(this.storageKey);
},
methods: {
processData(list) {
this.selectChangeList = list;
if (list.length >=2) {
this.form.noticeType = [list[0].id, list[1].id];
} else {
this.form.noticeType = [list[0].id];
}
this.form.noticeType.forEach(item => {
list.some(val => {
if (item === val.id) {
this.selectChoose.push(val);
return true;
}
});
});
},
chartDataEvent(val) {
// console.log('val===',val);
return val;
},
// 监听事件
callback(result, dataVal, formVal) {
if (result && result.fnCode) {
switch (result.fnCode) {
case 'submit':
break;
case 'cancle':
break;
default:
}
}
}
}
}
</script>
<style scoped>
::v-deep .ultabs .el-range-editor .el-range-input {
vertical-align: super!important;
}
::v-deep .ultabs .el-date-editor .el-range-separator {
vertical-align: super!important;
}
::-webkit-scrollbar {
width: 0px!important;
height: 0px!important;
}
</style>

View File

@@ -1,7 +1,7 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" label-width="auto" class="demo-ruleForm">
<el-col :span="7">
<div class="app-container pageTopForm">
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" label-width="70px" class="demo-ruleForm">
<el-col :span="8">
<el-form-item label="节点名称" prop="nodeName">
<el-input
v-model="queryParams.nodeName"
@@ -11,17 +11,7 @@
</el-input>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item label="硬件SN" prop="hardwareSn">
<el-input
v-model="queryParams.hardwareSn"
placeholder="请输入硬件SN"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
</el-col>
<el-col :span="7">
<el-col :span="8">
<el-form-item label="类型" prop="bandwidthType">
<el-select
v-model="queryParams.bandwidthType"
@@ -35,8 +25,8 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="7" v-show="queryParams.bandwidthType === '1'">
<el-form-item label="95宽带值Mbps/日" prop="bandwidth95Daily">
<el-col :span="8" v-show="queryParams.bandwidthType === '1'">
<el-form-item label="95宽带值Mbps/日" title="95宽带值Mbps/日" prop="bandwidth95Daily">
<el-date-picker
v-model="queryParams.bandwidth95Daily"
type="daterange"
@@ -47,7 +37,7 @@
end-placeholder="结束日期"/>
</el-form-item>
</el-col>
<el-col :span="7" v-show="queryParams.bandwidthType === '2'">
<el-col :span="8" v-show="queryParams.bandwidthType === '2'">
<el-form-item label="95宽带值Mbps/月" prop="bandwidth95Monthly">
<el-date-picker
v-model="queryParams.bandwidth95Monthly"
@@ -58,7 +48,7 @@
end-placeholder="结束月份"/>
</el-form-item>
</el-col>
<el-col :span="7" v-show="queryParams.bandwidthType === '3'">
<el-col :span="8" v-show="queryParams.bandwidthType === '3'">
<el-form-item label="包端带宽值Mbps/日" prop="packageBandwidthDaily">
<el-date-picker
v-model="queryParams.packageBandwidthDaily"
@@ -70,7 +60,17 @@
end-placeholder="结束日期"/>
</el-form-item>
</el-col>
<el-col :span="7">
<el-col :span="8">
<el-form-item label="硬件SN" prop="hardwareSn">
<el-input
v-model="queryParams.hardwareSn"
placeholder="请输入硬件SN"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item class="lastBtnSty">
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
@@ -80,37 +80,6 @@
<!-- 表格数据 -->
<TableList :columns="columns" :config="config" :queryParams="queryParams" :tableList="tableList" @fnClick="callback" @fnRenderList="getList" @value-change="handleValueChange"></TableList>
<!-- 图形分析 -->
<el-dialog :title="title" :visible.sync="open" width="780px" append-to-body fullscreen>
<el-form v-if="open" ref="noticeRef" :model="form" label-width="80px">
<el-form-item label="节点名称" prop="noticeType">
<el-select v-model="form.noticeType" multiple placeholder="请选择节点名称">
<el-option
v-for="item in selectChangeList"
:key="item.id"
:label="item.nodeName"
:value="item.id"/>
</el-select>
</el-form-item>
</el-form>
<div>
<el-switch v-for="item of switchData" v-model="item.type" :activeText="item.name" class="mr20" />
<div v-for="(item,index) of selectChoose">
<EchartsLine v-show="switchData[0].type" :chartData="chartDataEvent"
:lineData="lineDataParams" :title="'【' + item.nodeName + '】【' + item.businessName + '】' + switchData[0].name" class="mt20 mb20" style="width: 100%;height: 420px;border: 1.5px solid #878787;"></EchartsLine>
<EchartsLine v-show="switchData[1].type" :chartData="chartDataEvent"
:lineData="lineDataParams" :title="'【' + item.nodeName + '】【' + item.businessName + '】' + switchData[1].name" class="mt20 mb20" style="width: 100%;height: 420px;border: 1.5px solid #878787;"></EchartsLine>
<EchartsBar v-show="switchData[2].type" :chartData="chartDataEvent"
:barData="lineDataParams" :title="'【' + item.nodeName + '】【' + item.businessName + '】' + switchData[2].name" class="mt20 mb20" style="width: 100%;height: 420px;border: 1.5px solid #878787;"></EchartsBar>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<!-- <el-button type="primary" @click="submitForm"> </el-button>-->
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
@@ -126,23 +95,8 @@
data() {
return {
tableList: [],
selectChangeList: [],
loading: true,
showSearch: true,
ids: [],
single: true,
multiple: true,
total: 0,
dateRange: [],
open: false,
title: '',
switchData: [
{id: 'ninetyFiveDay', type: true, name: '95宽带值Mbps/日'},
{id: 'ninetyFiveMonth', type: true, name: '95宽带值Mbps/月'},
{id: 'packageEnd', type: true, name: '包端宽带值Mbps/日'}
],
lineDataParams: {},
selectChoose: [],
// 列显隐信息
columns: {
id: {label: `ID`},
@@ -179,7 +133,6 @@
]
}
},
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
@@ -231,40 +184,24 @@
/** 重置按钮操作 */
resetQuery() {
this.dateRange = [];
this.resetForm("queryRef");
this.handleQuery();
},
/** 图形分析 */
graphicAnalysis(list) {
this.open = true;
this.title = "图形分析";
this.selectChangeList = list;
if (list.length >=2) {
this.form.noticeType = [list[0].id, list[1].id];
} else {
this.form.noticeType = [list[0].id];
}
this.form.noticeType.forEach(item => {
list.some(val => {
if (item === val.id) {
this.selectChoose.push(val);
return true;
}
});
});
this.lineDataParams = {
lineXData: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
data: [820, 932, 901, 934, 1290, 1330, 1320]
}
},
/** 取消按钮 */
cancel() {
this.$nextTick(() => {
this.open = false;
// 生成唯一 key避免数据冲突
const storageKey = `temp_data_${Date.now()}`;
// 1. 将数据存入 localStorage需序列化
localStorage.setItem(storageKey, JSON.stringify(list));
// 1. 用 Vue Router 解析目标路由的完整 URL
const routeLocation = this.$router.resolve({
name: 'DialogView',
query: { storageKey }
});
// 2. 打开新窗口routeLocation.href 是完整路径)
window.open(routeLocation.href, '_blank');
// _blank新标签页_self当前窗口默认
},
chartDataEvent(val) {

View File

@@ -1,5 +1,5 @@
<template>
<div class="app-container">
<div class="app-container pageTopForm">
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="auto" class="demo-ruleForm">
<!-- <el-col :span="7">-->
<el-form-item label="节点名称" prop="nodeName">

View File

@@ -1,5 +1,5 @@
<template>
<div class="app-container">
<div class="app-container pageTopForm">
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" label-width="auto" class="demo-ruleForm">
<el-col :span="6">
<el-form-item label="交换机名称" prop="uplinkSwitch">
@@ -101,35 +101,6 @@
<dict-tag :options="dict.type.rm_topology_type" :value="row.interfaceLinkDeviceType"/>
</template>
</TableList>
<!-- 图形分析 -->
<el-dialog :title="title" :visible.sync="open" width="780px" append-to-body fullscreen>
<el-form v-if="open" ref="noticeRef" :model="form" label-width="80px">
<el-form-item label="节点名称" prop="noticeType">
<el-select v-model="form.noticeType" multiple placeholder="请选择节点名称">
<el-option
v-for="item in selectChangeList"
:key="item.id"
:label="item.uplinkSwitch"
:value="item.id"/>
</el-select>
</el-form-item>
</el-form>
<div>
<el-switch v-for="item of switchData" v-model="item.type" :activeText="item.name" class="mr20" />
<div v-for="(item,index) of selectChoose">
<EchartsLine v-show="switchData[0].type" :chartData="chartDataEvent"
:lineData="lineDataParams" :title="'【' + item.nodeName + '】【' + item.businessName + '】' + switchData[0].name" class="mt20 mb20" style="width: 100%;height: 420px;border: 1.5px solid #878787;"></EchartsLine>
<EchartsLine v-show="switchData[1].type" :chartData="chartDataEvent"
:lineData="lineDataParams" :title="'【' + item.nodeName + '】【' + item.businessName + '】' + switchData[1].name" class="mt20 mb20" style="width: 100%;height: 420px;border: 1.5px solid #878787;"></EchartsLine>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<!-- <el-button type="primary" @click="submitForm"> </el-button>-->
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
@@ -145,22 +116,8 @@
data() {
return {
tableList: [],
selectChangeList: [],
loading: true,
showSearch: true,
ids: [],
single: true,
multiple: true,
total: 0,
dateRange: [],
open: false,
title: '',
switchData: [
{id: 'ninetyFiveDay', type: true, name: '95宽带值Mbps/日'},
{id: 'ninetyFiveMonth', type: true, name: '95宽带值Mbps/月'},
],
lineDataParams: {},
selectChoose: [],
uplinkList:[], // 交换机名称
// 列显隐信息
columns: {
@@ -199,7 +156,6 @@
]
}
},
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
@@ -242,40 +198,24 @@
/** 重置按钮操作 */
resetQuery() {
this.dateRange.value = [];
this.resetForm("queryRef");
this.handleQuery();
},
/** 图形分析 */
graphicAnalysis(list) {
this.open = true;
this.title = "图形分析";
this.selectChangeList = list;
if (list.length >=2) {
this.form.noticeType = [list[0].id, list[1].id];
} else {
this.form.noticeType = [list[0].id];
}
this.form.noticeType.forEach(item => {
list.some(val => {
if (item === val.id) {
this.selectChoose.push(val);
return true;
}
});
});
this.lineDataParams = {
lineXData: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
data: [820, 932, 901, 934, 1290, 1330, 1320]
}
},
/** 取消按钮 */
cancel() {
this.$nextTick(() => {
this.open = false;
// 生成唯一 key避免数据冲突
const storageKey = `temp_data_${Date.now()}`;
// 1. 将数据存入 localStorage需序列化
localStorage.setItem(storageKey, JSON.stringify(list));
// 1. 用 Vue Router 解析目标路由的完整 URL
const routeLocation = this.$router.resolve({
name: 'DialogView',
query: { storageKey }
});
// 2. 打开新窗口routeLocation.href 是完整路径)
window.open(routeLocation.href, '_blank');
// _blank新标签页_self当前窗口默认
},
chartDataEvent(val) {
// console.log('val===',val);

View File

@@ -71,13 +71,13 @@
}
fnType(dataVal).then(response => {
this.$modal.msgSuccess(response.msg);
this.$router.push("/disRevenue/resource/group")
this.$router.push("/resource/group")
}).catch(() => {
this.$modal.msgError("操作失败")
});
break;
case 'cancle':
this.$router.push("/disRevenue/resource/group");
this.$router.push("/resource/group");
break;
default:
}

View File

@@ -1,5 +1,5 @@
<template>
<div class="app-container">
<div class="app-container pageTopForm">
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="130px">
<el-form-item label="资源组名称" prop="groupName">
<el-col :span="4">

View File

@@ -351,7 +351,7 @@
},
// 返回
goBack() {
this.$router.push({path:'/disRevenue/resource/monitorStategy'});
this.$router.push({path:'/resource/monitorStategy'});
},
// 监听事件
callback(result, dataVal, formVal) {

View File

@@ -1,5 +1,5 @@
<template>
<div class="app-container">
<div class="app-container pageTopForm">
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" label-width="auto">
<el-col :span="8">
<el-form-item label="搜索" prop="switchName">

View File

@@ -326,7 +326,7 @@
},
// 返回
goBack() {
this.$router.push({path:'/disRevenue/resource/monitorTemp'});
this.$router.push({path:'/resource/monitorTemp'});
},
// 监听事件
callback(result, dataVal, formVal) {

View File

@@ -1,5 +1,5 @@
<template>
<div class="app-container">
<div class="app-container pageTopForm">
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="130px">
<el-form-item label="模版名称" prop="switchName">
<el-col :span="4">

View File

@@ -112,13 +112,13 @@
}
fnType(dataVal).then(response => {
this.$modal.msgSuccess(response.msg);
this.$router.push("/disRevenue/resource/register")
this.$router.push("/resource/register")
}).catch(() => {
this.$modal.msgError("操作失败")
});
break;
case 'cancle':
this.$router.push("/disRevenue/resource/register")
this.$router.push("/resource/register")
break;
default:

View File

@@ -1,5 +1,5 @@
<template>
<div class="app-container">
<div class="app-container pageTopForm">
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="auto">
<el-form-item label="名称" prop="nameKey">
<el-col>

View File

@@ -1,7 +1,7 @@
<template>
<div class="app-container">
<div class="app-container pageTopForm">
<div style="height: 200px;">
<EchartsPie v-for="item of dataList" :dataList="item" class="w30 h100 disInlineBlock"></EchartsPie>
<EchartsPie v-for="item of dataList" :dataList="item" style="width: 33%;" class="h100 disInlineBlock"></EchartsPie>
</div>
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" label-width="auto">
<el-col :span="7">
@@ -102,7 +102,7 @@
dataList: [{
centerVal: '56',
unit: '台',
center: ['30%', '50%'],
center: ['20%', '50%'],
color: ['#31bb42', '#f96602'],
data: [
{ value: 36, name: '在线服务器' },
@@ -111,7 +111,7 @@
},{
centerVal: '10',
unit: '台',
center: ['30%', '50%'],
center: ['20%', '50%'],
color: ['#1c7dbc', '#f80a4f'],
data: [
{ value: 8, name: '在线交换机' },

View File

@@ -73,13 +73,13 @@
}
fnType(dataVal).then(response => {
this.$modal.msgSuccess(response.msg);
this.$router.push("/disRevenue/resource/topology")
this.$router.push("/resource/topology")
}).catch(() => {
this.$modal.msgError("操作失败")
});
break;
case 'cancle':
this.$router.push("/disRevenue/resource/topology");
this.$router.push("/resource/topology");
break;
default:
}

View File

@@ -1,5 +1,5 @@
<template>
<div class="app-container">
<div class="app-container pageTopForm">
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="130px">
<el-form-item label="交换机名称" prop="switchName">
<el-col :span="4">

View File

@@ -1,221 +1,221 @@
<template>
<div class="login">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">{{title}}</h3>
<el-form-item prop="username">
<el-input
v-model="loginForm.username"
type="text"
auto-complete="off"
placeholder="账号"
>
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
auto-complete="off"
placeholder="密码"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input
v-model="loginForm.code"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
<el-form-item style="width:100%;">
<el-button
:loading="loading"
size="medium"
type="primary"
style="width:100%;"
@click.native.prevent="handleLogin"
>
<span v-if="!loading"> </span>
<span v-else> 中...</span>
</el-button>
<div style="float: right;" v-if="register">
<router-link class="link-type" :to="'/register'">立即注册</router-link>
</div>
</el-form-item>
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2018-2025 ruoyi.vip All Rights Reserved.</span>
</div>
</div>
</template>
<script>
import { getCodeImg } from "@/api/login"
import Cookies from "js-cookie"
import { encrypt, decrypt } from '@/utils/jsencrypt'
export default {
name: "Login",
data() {
return {
title: process.env.VUE_APP_TITLE,
codeUrl: "",
loginForm: {
username: "admin",
password: "admin123",
rememberMe: false,
code: "",
uuid: ""
},
loginRules: {
username: [
{ required: true, trigger: "blur", message: "请输入您的账号" }
],
password: [
{ required: true, trigger: "blur", message: "请输入您的密码" }
],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
},
loading: false,
// 验证码开关
captchaEnabled: true,
// 注册开关
register: false,
redirect: undefined
}
},
watch: {
$route: {
handler: function(route) {
this.redirect = route.query && route.query.redirect
},
immediate: true
}
},
created() {
this.getCode()
this.getCookie()
},
methods: {
getCode() {
getCodeImg().then(res => {
this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled
if (this.captchaEnabled) {
this.codeUrl = "data:image/gif;base64," + res.img
this.loginForm.uuid = res.uuid
}
})
},
getCookie() {
const username = Cookies.get("username")
const password = Cookies.get("password")
const rememberMe = Cookies.get('rememberMe')
this.loginForm = {
username: username === undefined ? this.loginForm.username : username,
password: password === undefined ? this.loginForm.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
}
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
if (this.loginForm.rememberMe) {
Cookies.set("username", this.loginForm.username, { expires: 30 })
Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 })
Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 })
} else {
Cookies.remove("username")
Cookies.remove("password")
Cookies.remove('rememberMe')
}
this.$store.dispatch("Login", this.loginForm).then(() => {
this.$router.push({ path: this.redirect || "/" }).catch(()=>{})
}).catch(() => {
this.loading = false
if (this.captchaEnabled) {
this.getCode()
}
})
}
})
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss">
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.login-form {
border-radius: 6px;
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
z-index: 1;
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 38px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 38px;
}
</style>
<template>
<div class="login">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">{{title}}</h3>
<el-form-item prop="username">
<el-input
v-model="loginForm.username"
type="text"
auto-complete="off"
placeholder="账号"
>
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
auto-complete="off"
placeholder="密码"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input
v-model="loginForm.code"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
<el-form-item style="width:100%;">
<el-button
:loading="loading"
size="medium"
type="primary"
style="width:100%;"
@click.native.prevent="handleLogin"
>
<span v-if="!loading"> </span>
<span v-else> 中...</span>
</el-button>
<div style="float: right;" v-if="register">
<router-link class="link-type" :to="'/register'">立即注册</router-link>
</div>
</el-form-item>
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2018-2025 ZhiRongYun All Rights Reserved.</span>
</div>
</div>
</template>
<script>
import { getCodeImg } from "@/api/login"
import Cookies from "js-cookie"
import { encrypt, decrypt } from '@/utils/jsencrypt'
export default {
name: "Login",
data() {
return {
title: process.env.VUE_APP_TITLE,
codeUrl: "",
loginForm: {
username: "admin",
password: "admin123",
rememberMe: false,
code: "",
uuid: ""
},
loginRules: {
username: [
{ required: true, trigger: "blur", message: "请输入您的账号" }
],
password: [
{ required: true, trigger: "blur", message: "请输入您的密码" }
],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
},
loading: false,
// 验证码开关
captchaEnabled: true,
// 注册开关
register: false,
redirect: undefined
}
},
watch: {
$route: {
handler: function(route) {
this.redirect = route.query && route.query.redirect
},
immediate: true
}
},
created() {
this.getCode()
this.getCookie()
},
methods: {
getCode() {
getCodeImg().then(res => {
this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled
if (this.captchaEnabled) {
this.codeUrl = "data:image/gif;base64," + res.img
this.loginForm.uuid = res.uuid
}
})
},
getCookie() {
const username = Cookies.get("username")
const password = Cookies.get("password")
const rememberMe = Cookies.get('rememberMe')
this.loginForm = {
username: username === undefined ? this.loginForm.username : username,
password: password === undefined ? this.loginForm.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
}
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
if (this.loginForm.rememberMe) {
Cookies.set("username", this.loginForm.username, { expires: 30 })
Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 })
Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 })
} else {
Cookies.remove("username")
Cookies.remove("password")
Cookies.remove('rememberMe')
}
this.$store.dispatch("Login", this.loginForm).then(() => {
this.$router.push({ path: this.redirect || "/" }).catch(()=>{})
}).catch(() => {
this.loading = false
if (this.captchaEnabled) {
this.getCode()
}
})
}
})
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss">
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.login-form {
border-radius: 6px;
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
z-index: 1;
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 38px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 38px;
}
</style>

View File

@@ -1,211 +1,211 @@
<template>
<div class="register">
<el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form">
<h3 class="title">{{title}}</h3>
<el-form-item prop="username">
<el-input v-model="registerForm.username" type="text" auto-complete="off" placeholder="账号">
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="registerForm.password"
type="password"
auto-complete="off"
placeholder="密码"
@keyup.enter.native="handleRegister"
>
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="confirmPassword">
<el-input
v-model="registerForm.confirmPassword"
type="password"
auto-complete="off"
placeholder="确认密码"
@keyup.enter.native="handleRegister"
>
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input
v-model="registerForm.code"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter.native="handleRegister"
>
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<div class="register-code">
<img :src="codeUrl" @click="getCode" class="register-code-img"/>
</div>
</el-form-item>
<el-form-item style="width:100%;">
<el-button
:loading="loading"
size="medium"
type="primary"
style="width:100%;"
@click.native.prevent="handleRegister"
>
<span v-if="!loading"> </span>
<span v-else> 中...</span>
</el-button>
<div style="float: right;">
<router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
</div>
</el-form-item>
</el-form>
<!-- 底部 -->
<div class="el-register-footer">
<span>Copyright © 2018-2025 ruoyi.vip All Rights Reserved.</span>
</div>
</div>
</template>
<script>
import { getCodeImg, register } from "@/api/login"
export default {
name: "Register",
data() {
const equalToPassword = (rule, value, callback) => {
if (this.registerForm.password !== value) {
callback(new Error("两次输入的密码不一致"))
} else {
callback()
}
}
return {
title: process.env.VUE_APP_TITLE,
codeUrl: "",
registerForm: {
username: "",
password: "",
confirmPassword: "",
code: "",
uuid: ""
},
registerRules: {
username: [
{ required: true, trigger: "blur", message: "请输入您的账号" },
{ min: 2, max: 20, message: '用户账号长度必须介于 2 和 20 之间', trigger: 'blur' }
],
password: [
{ required: true, trigger: "blur", message: "请输入您的密码" },
{ min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
],
confirmPassword: [
{ required: true, trigger: "blur", message: "请再次输入您的密码" },
{ required: true, validator: equalToPassword, trigger: "blur" }
],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
},
loading: false,
captchaEnabled: true
}
},
created() {
this.getCode()
},
methods: {
getCode() {
getCodeImg().then(res => {
this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled
if (this.captchaEnabled) {
this.codeUrl = "data:image/gif;base64," + res.img
this.registerForm.uuid = res.uuid
}
})
},
handleRegister() {
this.$refs.registerForm.validate(valid => {
if (valid) {
this.loading = true
register(this.registerForm).then(res => {
const username = this.registerForm.username
this.$alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", '系统提示', {
dangerouslyUseHTMLString: true,
type: 'success'
}).then(() => {
this.$router.push("/login")
}).catch(() => {})
}).catch(() => {
this.loading = false
if (this.captchaEnabled) {
this.getCode()
}
})
}
})
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss">
.register {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.register-form {
border-radius: 6px;
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
}
}
.register-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.register-code {
width: 33%;
height: 38px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-register-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.register-code-img {
height: 38px;
}
</style>
<template>
<div class="register">
<el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form">
<h3 class="title">{{title}}</h3>
<el-form-item prop="username">
<el-input v-model="registerForm.username" type="text" auto-complete="off" placeholder="账号">
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="registerForm.password"
type="password"
auto-complete="off"
placeholder="密码"
@keyup.enter.native="handleRegister"
>
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="confirmPassword">
<el-input
v-model="registerForm.confirmPassword"
type="password"
auto-complete="off"
placeholder="确认密码"
@keyup.enter.native="handleRegister"
>
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input
v-model="registerForm.code"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter.native="handleRegister"
>
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<div class="register-code">
<img :src="codeUrl" @click="getCode" class="register-code-img"/>
</div>
</el-form-item>
<el-form-item style="width:100%;">
<el-button
:loading="loading"
size="medium"
type="primary"
style="width:100%;"
@click.native.prevent="handleRegister"
>
<span v-if="!loading"> </span>
<span v-else> 中...</span>
</el-button>
<div style="float: right;">
<router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
</div>
</el-form-item>
</el-form>
<!-- 底部 -->
<div class="el-register-footer">
<span>Copyright © 2018-2025 ZhiRongYun All Rights Reserved.</span>
</div>
</div>
</template>
<script>
import { getCodeImg, register } from "@/api/login"
export default {
name: "Register",
data() {
const equalToPassword = (rule, value, callback) => {
if (this.registerForm.password !== value) {
callback(new Error("两次输入的密码不一致"))
} else {
callback()
}
}
return {
title: process.env.VUE_APP_TITLE,
codeUrl: "",
registerForm: {
username: "",
password: "",
confirmPassword: "",
code: "",
uuid: ""
},
registerRules: {
username: [
{ required: true, trigger: "blur", message: "请输入您的账号" },
{ min: 2, max: 20, message: '用户账号长度必须介于 2 和 20 之间', trigger: 'blur' }
],
password: [
{ required: true, trigger: "blur", message: "请输入您的密码" },
{ min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
],
confirmPassword: [
{ required: true, trigger: "blur", message: "请再次输入您的密码" },
{ required: true, validator: equalToPassword, trigger: "blur" }
],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
},
loading: false,
captchaEnabled: true
}
},
created() {
this.getCode()
},
methods: {
getCode() {
getCodeImg().then(res => {
this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled
if (this.captchaEnabled) {
this.codeUrl = "data:image/gif;base64," + res.img
this.registerForm.uuid = res.uuid
}
})
},
handleRegister() {
this.$refs.registerForm.validate(valid => {
if (valid) {
this.loading = true
register(this.registerForm).then(res => {
const username = this.registerForm.username
this.$alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", '系统提示', {
dangerouslyUseHTMLString: true,
type: 'success'
}).then(() => {
this.$router.push("/login")
}).catch(() => {})
}).catch(() => {
this.loading = false
if (this.captchaEnabled) {
this.getCode()
}
})
}
})
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss">
.register {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
}
.register-form {
border-radius: 6px;
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
}
}
.register-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.register-code {
width: 33%;
height: 38px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-register-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.register-code-img {
height: 38px;
}
</style>

View File

@@ -7,7 +7,7 @@ function resolve(dir) {
const CompressionPlugin = require('compression-webpack-plugin')
const name = process.env.VUE_APP_TITLE || 'SAAS管理平台' // 网页标题
const name = process.env.VUE_APP_TITLE || 'SAAS综合管理平台' // 网页标题
const port = process.env.port || process.env.npm_config_port || 80 // 端口
@@ -32,9 +32,9 @@ module.exports = {
port: port,
open: true,
proxy: {
// detail: https://cli.vuejs.org/config/#devserver-proxy
// detail: https://cli.vuejs.org/config/#devserver-proxy http://192.168.9.143:8080
[process.env.VUE_APP_BASE_API]: {
target: `http://192.168.9.143:8080`,
target: `http://192.168.9.137:8080`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''