up
45
src/App.vue
@ -1,16 +1,7 @@
|
||||
<template>
|
||||
<VScaleScreen fullScreen width="1920" height="1080">
|
||||
<VScaleScreen width="100%" height="100%">
|
||||
<div class="center">
|
||||
<div ref="head" class="headers">
|
||||
种植业生产监管数字化系统
|
||||
<span @click="exitMaximize" class="exit">
|
||||
<img
|
||||
src="@/assets/svg/quxiaoquanping.svg"
|
||||
style="width: 14px; height: 14px; cursor: pointer"
|
||||
/>
|
||||
退出全屏
|
||||
</span>
|
||||
</div>
|
||||
<Headers />
|
||||
<router-view />
|
||||
</div>
|
||||
</VScaleScreen>
|
||||
@ -19,8 +10,8 @@
|
||||
<script setup>
|
||||
import useSettingsStore from '@/store/modules/settings';
|
||||
import { handleThemeStyle } from '@/utils/theme';
|
||||
|
||||
import VScaleScreen from 'v-scale-screen';
|
||||
import Headers from '@/components/heades/index';
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
@ -34,34 +25,4 @@ onMounted(() => {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.headers {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
background-image: url('@/assets/images/header.png');
|
||||
background-size: 100% 100%;
|
||||
justify-content: center;
|
||||
opacity: 1;
|
||||
text-shadow: 0px 0px 6px 0px rgba(41, 255, 255, 1);
|
||||
font-weight: 400;
|
||||
font-size: 21px;
|
||||
letter-spacing: 4px;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
transform: translate(0, -100%);
|
||||
.exit {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
color: rgba(41, 255, 219, 1);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
39
src/api/crops/classify.js
Normal file
@ -0,0 +1,39 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
|
||||
export function getarea(query) {
|
||||
return request({
|
||||
url: '/crops/area',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getTownship() {
|
||||
return request({
|
||||
url: 'http://121.36.229.60:9080/geoserver/shuzisannong/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=shuzisannong%3Ahuangdaoqu_town&maxFeatures=50&outputFormat=application%2Fjson',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
export function getvillage() {
|
||||
return request({
|
||||
url: 'http://121.36.229.60:9080/geoserver/shuzisannong/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=shuzisannong%3Ahuangdaoqu_village&maxFeatures=1180&outputFormat=application%2Fjson',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
export function getareas() {
|
||||
return request({
|
||||
url: 'http://121.36.229.60:9080/geoserver/shuzisannong/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=shuzisannong%3Afenlei&maxFeatures=1180&outputFormat=application%2Fjson',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
export function dow() {
|
||||
return request({
|
||||
url: 'http://118.24.27.47:6802/crops/export_area?subregion=1&parent=黄岛区&time=2023-04-19',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获取路由
|
||||
export const getRouters = () => {
|
||||
export const getRouters = (query) => {
|
||||
return request({
|
||||
url: '/getRouters',
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
BIN
src/assets/images/1.jpg
Executable file
After Width: | Height: | Size: 509 KiB |
BIN
src/assets/images/below.png
Executable file
After Width: | Height: | Size: 4.2 KiB |
BIN
src/assets/images/login-background.jpg
Executable file → Normal file
Before Width: | Height: | Size: 509 KiB After Width: | Height: | Size: 7.0 MiB |
BIN
src/assets/images/start.png
Executable file
After Width: | Height: | Size: 4.1 KiB |
BIN
src/assets/images/suspend.png
Executable file
After Width: | Height: | Size: 3.8 KiB |
BIN
src/assets/images/upper.png
Executable file
After Width: | Height: | Size: 4.2 KiB |
@ -1,28 +1,44 @@
|
||||
<template>
|
||||
<div @click="max">
|
||||
<svg-icon :icon-class="isFullscreen ? 'exit-fullscreen' : 'fullscreen'" @click="toggle" />
|
||||
<svg-icon :icon-class="isFullscreen ? 'exit-fullscreen' : 'fullscreen'" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
import { onMounted, ref } from 'vue';
|
||||
import useSettingsStore from '@/store/modules/settings';
|
||||
const settingsStore = useSettingsStore();
|
||||
const { isFullscreen, enter, exit, toggle } = useFullscreen();
|
||||
let navbar = null;
|
||||
let container = null;
|
||||
let hasLogo = null;
|
||||
onMounted(() => {
|
||||
navbar = document.querySelector('.navbar');
|
||||
container = document.querySelector('#tags-view-container');
|
||||
hasLogo = document.querySelector('.has-logo');
|
||||
});
|
||||
|
||||
//获取dom
|
||||
let navbar = null;
|
||||
let app_main = null;
|
||||
let headers = null;
|
||||
let leftWra = null;
|
||||
let rightWra = null;
|
||||
let flag = ref(true);
|
||||
let leftment = null;
|
||||
let main_container = null;
|
||||
onMounted(() => {
|
||||
navbar = document.querySelector('.navDiv');
|
||||
app_main = document.querySelector('.app-main');
|
||||
headers = document.querySelector('.headers');
|
||||
leftWra = document.querySelector('.leftWra');
|
||||
rightWra = document.querySelector('.rightWra');
|
||||
leftment = document.querySelector('.leftment');
|
||||
main_container = document.querySelector('.main-container');
|
||||
});
|
||||
//隐藏导航栏
|
||||
const max = () => {
|
||||
console.log(hasLogo.style);
|
||||
navbar.style.display = 'none';
|
||||
container.style.display = 'none';
|
||||
hasLogo.style.left = '-100px';
|
||||
app_main.style.height = '100%';
|
||||
headers.style.transform = `translate(0, 0)`;
|
||||
leftment.style.display = 'none';
|
||||
main_container.style.marginLeft = '0';
|
||||
document.querySelector('.leftWra').style.top = '80px';
|
||||
document.querySelector('.rightWra').style.top = '80px';
|
||||
// settingsStore.changeSetting({ key: 'topNav', value: flag.value });
|
||||
};
|
||||
</script>
|
||||
|
||||
|
186
src/components/TimeLine/TimeLine.vue
Normal file
@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<div class="timeline">
|
||||
<el-slider
|
||||
v-model="value2"
|
||||
:step="step"
|
||||
:marks="marks"
|
||||
show-stops
|
||||
:show-tooltip="false"
|
||||
:min="min"
|
||||
:max="max"
|
||||
></el-slider>
|
||||
<div class="optionWrapper">
|
||||
<img @click="leftHandle" src="@/assets/images/upper.png" alt="《" />
|
||||
<img @click="autoPlay" v-if="!times" src="@/assets/images/start.png" alt="||" />
|
||||
<img @click="pausePlay" v-if="times" src="@/assets/images/suspend.png" alt="||" />
|
||||
<img @click="rightHandle" src="@/assets/images/below.png" alt="》" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/*
|
||||
dataSource=[
|
||||
{name:'year1',value:''}
|
||||
]
|
||||
*/
|
||||
|
||||
export default {
|
||||
props: ['dataSource', 'theme'],
|
||||
data() {
|
||||
return {
|
||||
value2: 0, //当前的值
|
||||
marks: {}, //时间轴刻度
|
||||
step: 10,
|
||||
times: null,
|
||||
min: 0,
|
||||
max: 100,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
// 监听数值变化进行操作
|
||||
value2: function (val, oldVal) {
|
||||
// 筛选出原始数据
|
||||
const oldData = this.dataSource.find(item => item.name === this.marks[val].label);
|
||||
this.$emit('dataHandle', oldData);
|
||||
},
|
||||
dataSource: function (val, oldVal) {
|
||||
//源数据监听
|
||||
this.dataHandleInit();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.dataHandleInit(); //
|
||||
},
|
||||
methods: {
|
||||
dataHandleInit() {
|
||||
const dataSource = [
|
||||
{ name: '11/25' },
|
||||
{ name: '11/25' },
|
||||
{ name: '11/25' },
|
||||
{ name: '11/25' },
|
||||
{ name: '11/25' },
|
||||
];
|
||||
const markNum = dataSource.map(item => item.name);
|
||||
this.max = (markNum.length - 1) * 10; //时间轴最大值
|
||||
const splitNumber = 10;
|
||||
// const splitNumber = 100 / (markNum.length - 1)
|
||||
// this.step = splitNumber //确定间隔长度
|
||||
let num = 0;
|
||||
let marks = {};
|
||||
// 排序,确定marks
|
||||
dataSource
|
||||
.sort((a, b) => Number(a.name) - Number(b.name))
|
||||
.forEach((item, index) => {
|
||||
if (dataSource.length < 10) {
|
||||
marks[num] = { label: item.name };
|
||||
} else {
|
||||
marks[num] = {
|
||||
label: item.name,
|
||||
style: {
|
||||
top: index % 2 === 1 ? '-40px' : '0px',
|
||||
},
|
||||
};
|
||||
}
|
||||
num += splitNumber;
|
||||
});
|
||||
this.marks = marks; //赋值mark
|
||||
},
|
||||
// 上一个
|
||||
leftHandle() {
|
||||
// 判断是不是第一个
|
||||
if (this.value2 === 0) {
|
||||
this.value2 = this.max;
|
||||
} else {
|
||||
this.value2 -= this.step;
|
||||
}
|
||||
},
|
||||
// 下一个
|
||||
rightHandle() {
|
||||
// 判断是否是最后一个
|
||||
if (this.value2 === this.max) {
|
||||
// 跳转到第一个
|
||||
this.value2 = 0;
|
||||
} else {
|
||||
this.value2 += this.step;
|
||||
}
|
||||
},
|
||||
// 自动播放
|
||||
autoPlay() {
|
||||
this.times = setInterval(() => {
|
||||
this.rightHandle();
|
||||
}, 1000 * 2);
|
||||
},
|
||||
// 暂停播放
|
||||
pausePlay() {
|
||||
clearInterval(this.times);
|
||||
this.times = null;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.timeline {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// padding: 0 4em;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
::v-deep .el-slider {
|
||||
flex: 1;
|
||||
padding: 2em;
|
||||
|
||||
.el-slider__runway {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
min-width: 200px;
|
||||
width: 90%;
|
||||
.el-slider__bar {
|
||||
background-color: rgba(108, 177, 184, 1);
|
||||
border-radius: 5px;
|
||||
}
|
||||
// 点
|
||||
.el-slider__stop {
|
||||
background-color: rgba(108, 177, 184, 1);
|
||||
height: 10px;
|
||||
width: 1px;
|
||||
// top: -2px;
|
||||
}
|
||||
|
||||
.el-slider__button {
|
||||
display: none;
|
||||
// background: linear-gradient(180deg, rgba(101, 220, 252, 1) 0%, rgba(67, 148, 171, 1) 100%);
|
||||
// box-shadow: 0px 2px 4px 0px rgba(29, 142, 173, 0.6);
|
||||
// filter: blur(0px);
|
||||
}
|
||||
|
||||
// marks字
|
||||
.el-slider__marks-text {
|
||||
color: rgba(222, 244, 255, 1);
|
||||
text-align: left;
|
||||
left: 13%;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.optionWrapper {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
color: white;
|
||||
width: fit-content;
|
||||
height: 100%;
|
||||
|
||||
& > img {
|
||||
// width: 40px;
|
||||
height: 48%;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
71
src/components/heades/index.vue
Normal file
@ -0,0 +1,71 @@
|
||||
/
|
||||
<template>
|
||||
<div ref="head" class="headers">
|
||||
种植业生产监管数字化系统
|
||||
<span @click="exitMaximize" class="exit">
|
||||
<img
|
||||
src="@/assets/svg/quxiaoquanping.svg"
|
||||
style="width: 14px; height: 14px; cursor: pointer"
|
||||
/>
|
||||
退出全屏
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import useSettingsStore from '@/store/modules/settings';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import usePermissionStore from '@/store/modules/permission';
|
||||
const settingsStore = useSettingsStore();
|
||||
const appStore = useAppStore();
|
||||
const permissionStore = usePermissionStore();
|
||||
let flag = ref(false);
|
||||
onMounted(() => {
|
||||
// console.log(document.querySelector('.menubar'));
|
||||
});
|
||||
const exitMaximize = () => {
|
||||
document.querySelector('.navDiv').style.display = '';
|
||||
document.querySelector('.app-main').style.height = 'calc(100% - 50px)';
|
||||
document.querySelector('.headers').style.transform = `translate(0, -100%)`;
|
||||
document.querySelector('.leftWra').style.top = '10px';
|
||||
document.querySelector('.rightWra').style.top = '10px';
|
||||
document.querySelector('.leftment').style.display = 'block';
|
||||
document.querySelector('.main-container').style.marginLeft =
|
||||
document.querySelector('.leftment').style.width;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.headers {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
background-image: url('@/assets/images/header.png');
|
||||
background-size: 100% 100%;
|
||||
justify-content: center;
|
||||
opacity: 1;
|
||||
text-shadow: 0px 0px 6px 0px rgba(41, 255, 255, 1);
|
||||
font-weight: 400;
|
||||
font-size: 21px;
|
||||
letter-spacing: 4px;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
transform: translate(0, -100%);
|
||||
.exit {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
color: rgba(41, 255, 219, 1);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div id="cesiumContainer"></div>
|
||||
<div style="width: 100%; height: 100%" id="cesiumContainer"></div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
24
src/hooks/useEcharts.js
Executable file
@ -0,0 +1,24 @@
|
||||
import { onActivated, onDeactivated, onBeforeUnmount } from "vue";
|
||||
// import echarts from "@/plugins/echarts";
|
||||
export const useEcharts = (myChart, options) => {
|
||||
if (options && typeof options === "object") {
|
||||
myChart.setOption(options);
|
||||
}
|
||||
const echartsResize = () => {
|
||||
myChart && myChart.resize();
|
||||
};
|
||||
|
||||
window.addEventListener("resize", echartsResize);
|
||||
|
||||
onActivated(() => {
|
||||
window.addEventListener("resize", echartsResize);
|
||||
});
|
||||
|
||||
onDeactivated(() => {
|
||||
window.removeEventListener("resize", echartsResize);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener("resize", echartsResize);
|
||||
});
|
||||
};
|
@ -3,7 +3,6 @@
|
||||
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
|
||||
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!settingsStore.topNav" />
|
||||
<top-nav id="topmenu-container" class="topmenu-container" v-if="settingsStore.topNav" />
|
||||
|
||||
<div class="right-menu">
|
||||
<template v-if="appStore.device !== 'mobile'">
|
||||
<header-search id="header-search" class="right-menu-item" />
|
||||
|
@ -2,12 +2,12 @@
|
||||
<div class="sidebar-logo-container" :class="{ 'collapse': collapse }" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
|
||||
<transition name="sidebarLogoFade">
|
||||
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
|
||||
<img v-if="logo" :src="logo" class="sidebar-logo" />
|
||||
<h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }}</h1>
|
||||
<!-- <img v-if="logo" :src="logo" class="sidebar-logo" /> -->
|
||||
<!-- <h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }}</h1> -->
|
||||
</router-link>
|
||||
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
|
||||
<img v-if="logo" :src="logo" class="sidebar-logo" />
|
||||
<h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }}</h1>
|
||||
<!-- <img v-if="logo" :src="logo" class="sidebar-logo" /> -->
|
||||
<h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">种植业生产监管数字化系统</h1>
|
||||
</router-link>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div :class="{ 'has-logo': showLogo }" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
|
||||
<div class="leftment" :class="{ 'has-logo': showLogo }" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
|
||||
<logo v-if="showLogo" :collapse="isCollapse" />
|
||||
<el-scrollbar :class="sideTheme" wrap-class="scrollbar-wrapper">
|
||||
<el-menu
|
||||
|
@ -3,7 +3,7 @@
|
||||
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
|
||||
<sidebar v-if="!sidebar.hide" class="sidebar-container" />
|
||||
<div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
|
||||
<div :class="{ 'fixed-header': fixedHeader }">
|
||||
<div class="navDiv" :class="{ 'fixed-header': fixedHeader }">
|
||||
<navbar @setLayout="setLayout" />
|
||||
<tags-view v-if="needTagsView" />
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import axios from 'axios'
|
||||
import { ElNotification , ElMessageBox, ElMessage, ElLoading } from 'element-plus'
|
||||
import { ElNotification, ElMessageBox, ElMessage, ElLoading } from 'element-plus'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import errorCode from '@/utils/errorCode'
|
||||
import { tansParams, blobValidate } from '@/utils/ruoyi'
|
||||
@ -15,7 +15,7 @@ axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
|
||||
// 创建axios实例
|
||||
const service = axios.create({
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
baseURL: import.meta.env.VITE_APP_BASE_API,
|
||||
baseURL: serverAPI.baseUrl,
|
||||
// 超时
|
||||
timeout: 10000
|
||||
})
|
||||
@ -61,46 +61,46 @@ service.interceptors.request.use(config => {
|
||||
}
|
||||
return config
|
||||
}, error => {
|
||||
console.log(error)
|
||||
Promise.reject(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;
|
||||
ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
|
||||
isRelogin.show = false;
|
||||
useUserStore().logOut().then(() => {
|
||||
location.href = '/index';
|
||||
})
|
||||
// 未设置状态码则默认成功状态
|
||||
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;
|
||||
ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
|
||||
isRelogin.show = false;
|
||||
useUserStore().logOut().then(() => {
|
||||
location.href = '/index';
|
||||
})
|
||||
}).catch(() => {
|
||||
isRelogin.show = false;
|
||||
});
|
||||
}
|
||||
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
|
||||
} else if (code === 500) {
|
||||
ElMessage({ message: msg, type: 'error' })
|
||||
return Promise.reject(new Error(msg))
|
||||
} else if (code === 601) {
|
||||
ElMessage({ message: msg, type: 'warning' })
|
||||
return Promise.reject(new Error(msg))
|
||||
} else if (code !== 200) {
|
||||
ElNotification.error({ title: msg })
|
||||
return Promise.reject('error')
|
||||
} else {
|
||||
return Promise.resolve(res.data)
|
||||
}
|
||||
},
|
||||
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
|
||||
} else if (code === 500) {
|
||||
ElMessage({ message: msg, type: 'error' })
|
||||
return Promise.reject(new Error(msg))
|
||||
} else if (code === 601) {
|
||||
ElMessage({ message: msg, type: 'warning' })
|
||||
return Promise.reject(new Error(msg))
|
||||
} else if (code !== 200) {
|
||||
ElNotification.error({ title: msg })
|
||||
return Promise.reject('error')
|
||||
} else {
|
||||
return Promise.resolve(res.data)
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
let { message } = error;
|
||||
|
@ -1,94 +1,102 @@
|
||||
<template>
|
||||
<div class="login">
|
||||
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
|
||||
<h3 class="title">若依后台管理系统</h3>
|
||||
<el-form-item prop="username">
|
||||
<el-input
|
||||
v-model="loginForm.username"
|
||||
type="text"
|
||||
size="large"
|
||||
auto-complete="off"
|
||||
placeholder="账号"
|
||||
>
|
||||
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
v-model="loginForm.password"
|
||||
type="password"
|
||||
size="large"
|
||||
auto-complete="off"
|
||||
placeholder="密码"
|
||||
@keyup.enter="handleLogin"
|
||||
>
|
||||
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code" v-if="captchaEnabled">
|
||||
<el-input
|
||||
v-model="loginForm.code"
|
||||
size="large"
|
||||
auto-complete="off"
|
||||
placeholder="验证码"
|
||||
style="width: 63%"
|
||||
@keyup.enter="handleLogin"
|
||||
>
|
||||
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
|
||||
</el-input>
|
||||
<div class="login-code">
|
||||
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
|
||||
<div class="login">
|
||||
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
|
||||
<h3 class="title">登陆</h3>
|
||||
<el-form-item prop="username">
|
||||
<el-input
|
||||
v-model="loginForm.username"
|
||||
type="text"
|
||||
size="large"
|
||||
auto-complete="off"
|
||||
placeholder="账号"
|
||||
>
|
||||
<template #prefix>
|
||||
<svg-icon icon-class="user" class="el-input__icon input-icon" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
v-model="loginForm.password"
|
||||
type="password"
|
||||
size="large"
|
||||
auto-complete="off"
|
||||
placeholder="密码"
|
||||
@keyup.enter="handleLogin"
|
||||
>
|
||||
<template #prefix>
|
||||
<svg-icon icon-class="password" class="el-input__icon input-icon" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code" v-if="captchaEnabled">
|
||||
<el-input
|
||||
v-model="loginForm.code"
|
||||
size="large"
|
||||
auto-complete="off"
|
||||
placeholder="验证码"
|
||||
style="width: 63%"
|
||||
@keyup.enter="handleLogin"
|
||||
>
|
||||
<template #prefix>
|
||||
<svg-icon icon-class="validCode" class="el-input__icon input-icon" />
|
||||
</template>
|
||||
</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="large"
|
||||
type="primary"
|
||||
style="width: 100%"
|
||||
@click.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-2022 ruoyi.vip All Rights Reserved.</span>
|
||||
</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="large"
|
||||
type="primary"
|
||||
style="width:100%;"
|
||||
@click.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-2022 ruoyi.vip All Rights Reserved.</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getCodeImg } from "@/api/login";
|
||||
import Cookies from "js-cookie";
|
||||
import { encrypt, decrypt } from "@/utils/jsencrypt";
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import { getCodeImg } from '@/api/login';
|
||||
import Cookies from 'js-cookie';
|
||||
import { encrypt, decrypt } from '@/utils/jsencrypt';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
|
||||
const userStore = useUserStore()
|
||||
const userStore = useUserStore();
|
||||
const router = useRouter();
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
const loginForm = ref({
|
||||
username: "admin",
|
||||
password: "admin123",
|
||||
rememberMe: false,
|
||||
code: "",
|
||||
uuid: ""
|
||||
username: 'admin',
|
||||
password: 'admin123',
|
||||
rememberMe: false,
|
||||
code: '',
|
||||
uuid: '',
|
||||
});
|
||||
|
||||
const loginRules = {
|
||||
username: [{ required: true, trigger: "blur", message: "请输入您的账号" }],
|
||||
password: [{ required: true, trigger: "blur", message: "请输入您的密码" }],
|
||||
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
|
||||
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
|
||||
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
|
||||
code: [{ required: true, trigger: 'change', message: '请输入验证码' }],
|
||||
};
|
||||
|
||||
const codeUrl = ref("");
|
||||
const codeUrl = ref('');
|
||||
const loading = ref(false);
|
||||
// 验证码开关
|
||||
const captchaEnabled = ref(true);
|
||||
@ -97,119 +105,122 @@ const register = ref(false);
|
||||
const redirect = ref(undefined);
|
||||
|
||||
function handleLogin() {
|
||||
proxy.$refs.loginRef.validate(valid => {
|
||||
if (valid) {
|
||||
loading.value = true;
|
||||
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
|
||||
if (loginForm.value.rememberMe) {
|
||||
Cookies.set("username", loginForm.value.username, { expires: 30 });
|
||||
Cookies.set("password", encrypt(loginForm.value.password), { expires: 30 });
|
||||
Cookies.set("rememberMe", loginForm.value.rememberMe, { expires: 30 });
|
||||
} else {
|
||||
// 否则移除
|
||||
Cookies.remove("username");
|
||||
Cookies.remove("password");
|
||||
Cookies.remove("rememberMe");
|
||||
}
|
||||
// 调用action的登录方法
|
||||
userStore.login(loginForm.value).then(() => {
|
||||
router.push({ path: redirect.value || "/" });
|
||||
}).catch(() => {
|
||||
loading.value = false;
|
||||
// 重新获取验证码
|
||||
if (captchaEnabled.value) {
|
||||
getCode();
|
||||
proxy.$refs.loginRef.validate(valid => {
|
||||
if (valid) {
|
||||
loading.value = true;
|
||||
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
|
||||
if (loginForm.value.rememberMe) {
|
||||
Cookies.set('username', loginForm.value.username, { expires: 30 });
|
||||
Cookies.set('password', encrypt(loginForm.value.password), { expires: 30 });
|
||||
Cookies.set('rememberMe', loginForm.value.rememberMe, { expires: 30 });
|
||||
} else {
|
||||
// 否则移除
|
||||
Cookies.remove('username');
|
||||
Cookies.remove('password');
|
||||
Cookies.remove('rememberMe');
|
||||
}
|
||||
// 调用action的登录方法
|
||||
userStore
|
||||
.login(loginForm.value)
|
||||
.then(() => {
|
||||
router.push({ path: redirect.value || '/' });
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
// 重新获取验证码
|
||||
if (captchaEnabled.value) {
|
||||
getCode();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getCode() {
|
||||
getCodeImg().then(res => {
|
||||
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled;
|
||||
if (captchaEnabled.value) {
|
||||
codeUrl.value = "data:image/gif;base64," + res.img;
|
||||
loginForm.value.uuid = res.uuid;
|
||||
}
|
||||
});
|
||||
getCodeImg().then(res => {
|
||||
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled;
|
||||
if (captchaEnabled.value) {
|
||||
codeUrl.value = 'data:image/gif;base64,' + res.img;
|
||||
loginForm.value.uuid = res.uuid;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getCookie() {
|
||||
const username = Cookies.get("username");
|
||||
const password = Cookies.get("password");
|
||||
const rememberMe = Cookies.get("rememberMe");
|
||||
loginForm.value = {
|
||||
username: username === undefined ? loginForm.value.username : username,
|
||||
password: password === undefined ? loginForm.value.password : decrypt(password),
|
||||
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
|
||||
};
|
||||
const username = Cookies.get('username');
|
||||
const password = Cookies.get('password');
|
||||
const rememberMe = Cookies.get('rememberMe');
|
||||
loginForm.value = {
|
||||
username: username === undefined ? loginForm.value.username : username,
|
||||
password: password === undefined ? loginForm.value.password : decrypt(password),
|
||||
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe),
|
||||
};
|
||||
}
|
||||
|
||||
getCode();
|
||||
getCookie();
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
<style lang="scss" scoped>
|
||||
.login {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
background-image: url("../assets/images/login-background.jpg");
|
||||
background-size: cover;
|
||||
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;
|
||||
margin: 0px auto 30px auto;
|
||||
text-align: center;
|
||||
color: #707070;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
border-radius: 6px;
|
||||
background: #ffffff;
|
||||
width: 400px;
|
||||
padding: 25px 25px 5px 25px;
|
||||
.el-input {
|
||||
height: 40px;
|
||||
input {
|
||||
height: 40px;
|
||||
border-radius: 6px;
|
||||
background: #ffffff;
|
||||
width: 400px;
|
||||
padding: 25px 25px 5px 25px;
|
||||
.el-input {
|
||||
height: 40px;
|
||||
input {
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
.input-icon {
|
||||
height: 39px;
|
||||
width: 14px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
}
|
||||
.input-icon {
|
||||
height: 39px;
|
||||
width: 14px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
}
|
||||
.login-tip {
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
color: #bfbfbf;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
.login-code {
|
||||
width: 33%;
|
||||
height: 40px;
|
||||
float: right;
|
||||
img {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
width: 33%;
|
||||
height: 40px;
|
||||
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;
|
||||
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: 40px;
|
||||
padding-left: 12px;
|
||||
height: 40px;
|
||||
padding-left: 12px;
|
||||
}
|
||||
</style>
|
||||
|