This commit is contained in:
刘霖泽 2023-03-30 17:16:01 +08:00
commit 24db25b30a
15 changed files with 624 additions and 108 deletions

View File

@ -1,5 +1,5 @@
{ {
"name": "vue-next-admin-template-js", "name": "vordm",
"version": "2.4.32", "version": "2.4.32",
"description": "vue3 vite next admin template js setup", "description": "vue3 vite next admin template js setup",
"author": "lyt_20201208", "author": "lyt_20201208",
@ -13,18 +13,20 @@
"@element-plus/icons-vue": "^2.1.0", "@element-plus/icons-vue": "^2.1.0",
"axios": "^1.3.4", "axios": "^1.3.4",
"echarts": "^5.4.2", "echarts": "^5.4.2",
"leaflet": "^1.9.3",
"element-plus": "^2.3.1", "element-plus": "^2.3.1",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"js-md5": "^0.7.3",
"mitt": "^3.0.0", "mitt": "^3.0.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"pinia": "^2.0.33", "pinia": "^2.0.33",
"qrcodejs2-fixes": "^0.0.2", "qrcodejs2-fixes": "^0.0.2",
"qs": "^6.11.1",
"screenfull": "^6.0.2", "screenfull": "^6.0.2",
"sortablejs": "^1.15.0", "sortablejs": "^1.15.0",
"vue": "^3.2.47", "vue": "^3.2.47",
"vue-clipboard3": "^2.0.0", "vue-clipboard3": "^2.0.0",
"vue-demi": "^0.13.11", "vue-demi": "^0.13.11",
"qs": "^6.11.1",
"vue-router": "^4.1.6" "vue-router": "^4.1.6"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1,4 +1,5 @@
import request from '/@/utils/request'; import request from '/@/utils/request';
import qs from 'qs'
/** /**
* 不建议写成 request.post(xxx)因为这样 post 无法 params data 同时传参 * 不建议写成 request.post(xxx)因为这样 post 无法 params data 同时传参
@ -9,14 +10,14 @@ import request from '/@/utils/request';
*/ */
export function useLoginApi() { export function useLoginApi() {
return { return {
signInByUsername: ({tenantId, deptId, roleId, username, password, type, key, code}) => { signInByUsername: ({tenantId, deptId, roleId, username, password, type, key, code, grantType}) => {
return request({ return request({
url: '/api/blade-auth/oauth/token', url: '/api/system-manager/oauth/token',
method: 'post', method: 'post',
headers: { headers: {
'Tenant-Id': tenantId, 'Tenant-Id': tenantId,
'Dept-Id': '', 'Dept-Id': deptId,
'Role-Id': '', 'Role-Id': roleId,
'Captcha-Key': key, 'Captcha-Key': key,
'Captcha-Code': code, 'Captcha-Code': code,
'Content-Type': 'application/x-www-form-urlencoded', 'Content-Type': 'application/x-www-form-urlencoded',
@ -25,7 +26,7 @@ export function useLoginApi() {
tenantId, tenantId,
username, username,
password, password,
grant_type: "captcha", grant_type: grantType,
deptId, deptId,
roleId, roleId,
scope: "all", scope: "all",
@ -34,6 +35,12 @@ export function useLoginApi() {
}); });
}, },
//获取验证码
getCaptcha: () => request({
url: '/api/system-manager/oauth/captcha',
method: 'get',
}),
signOut: (data) => { signOut: (data) => {
return request({ return request({
url: '/user/signOut', url: '/user/signOut',

51
src/api/system/user.js Normal file
View File

@ -0,0 +1,51 @@
import request from '/@/utils/request';
import qs from 'qs';
export const getUserInfo = () => {
return request({
url: '/api/system-manager/user/info',
method: 'get',
})
}
export const resetPassword = (userIds) => {
return request({
url: '/api/system-manager/user/reset-password',
method: 'post',
params: {
userIds,
}
})
}
export const updatePassword = (oldPassword, newPassword, newPassword1) => {
return request({
url: '/api/system-manager/user/update-password',
method: 'post',
params: {
oldPassword,
newPassword,
newPassword1,
}
})
}
export const getButtons = () => request({
url: '/api/system-manager/menu/buttons',
method: 'get'
});
export const refreshToken = (refresh_token, tenantId) => request({
url: '/api/system-manager/oauth/token',
method: 'post',
headers: {
'Tenant-Id': tenantId,
'Content-Type': 'application/x-www-form-urlencoded',
},
data: qs.stringify({
tenantId,
refresh_token,
grant_type: "refresh_token",
scope: "all",
})
});

29
src/components/Map.vue Normal file
View File

@ -0,0 +1,29 @@
<template>
<div ref="map" class="container"></div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import L from "leaflet";
import "leaflet/dist/leaflet.css";
const map = ref()
onMounted(() => {
const homeMap = L.map(map.value, {
preferCanvas: true,
crs: L.CRS.EPSG4326,
center: [29.563761, 106.550464],
zoom: 3,
minZoom: 1,
maxZoom: 18,
attributionControl: false, // leaflet
zoomControl: false
});
const IMG_C = "http://t0.tianditu.com/img_c/wmts?layer=img&style=default&tilematrixset=c&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=";
// const CIA_C = "http://t0.tianditu.com/cia_c/wmts?layer=cia&style=default&tilematrixset=c&Service=WMTS&Request=GetTile&Version=1.0.0&Format=tiles&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=";
const TK_KEY = "dc8182ebeca998e22154d404aa3c0c17";
L.tileLayer(IMG_C + TK_KEY, { maxZoom: 20, tileSize: 256, zoomOffset: 1 }).addTo(homeMap);
})
</script>

View File

@ -73,7 +73,7 @@ import { useUserInfo } from '/@/stores/userInfo';
import { useThemeConfig } from '/@/stores/themeConfig'; import { useThemeConfig } from '/@/stores/themeConfig';
import mittBus from '/@/utils/mitt'; import mittBus from '/@/utils/mitt';
import { Session, Local } from '/@/utils/storage'; import { Session, Local } from '/@/utils/storage';
import { refreshToken } from '/@/api/system/user.js'
// //
const UserNews = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/userNews.vue')); const UserNews = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/userNews.vue'));
const Search = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/search.vue')); const Search = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/search.vue'));
@ -83,11 +83,13 @@ const router = useRouter();
const stores = useUserInfo(); const stores = useUserInfo();
const storesThemeConfig = useThemeConfig(); const storesThemeConfig = useThemeConfig();
const { userInfos } = storeToRefs(stores); const { userInfos } = storeToRefs(stores);
const { themeConfig } = storeToRefs(storesThemeConfig); const { themeConfig, website } = storeToRefs(storesThemeConfig);
const searchRef = ref(); const searchRef = ref();
const state = reactive({ const state = reactive({
isScreenfull: false, isScreenfull: false,
disabledSize: 'large', disabledSize: 'large',
setIntervalId: null
}); });
// //
@ -145,6 +147,7 @@ const onHandleCommandClick = (path) => {
.then(async () => { .then(async () => {
// /token // /token
Session.clear(); Session.clear();
clearInterval(state.setIntervalId);
// 使 reload resetRoute() // 使 reload resetRoute()
window.location.reload(); window.location.reload();
}) })
@ -176,6 +179,20 @@ onMounted(() => {
if (Local.get('themeConfig')) { if (Local.get('themeConfig')) {
initI18nOrSize('globalComponentSize', 'disabledSize'); initI18nOrSize('globalComponentSize', 'disabledSize');
} }
//token
state.setIntervalId =setInterval(() => {
const dateTime = Session.get('token-time');
const rt = Session.get('refresh-token');
const now = new Date().getTime();
if((now - dateTime) / 1000 > website.value.tokenTime){
// token
refreshToken(rt, website.value.tenantId).then(res=>{
Session.set('token', res.access_token);
Session.set('token-time', new Date().getTime());
Session.set('refresh-token', res.refresh_token);
})
}
},10000);
}); });
</script> </script>

19
src/store/index.ts Normal file
View File

@ -0,0 +1,19 @@
import { defineStore } from "pinia";
import { Names } from "./store_name";
export const useVariableStore = defineStore(Names.TEST, {
state: () => {
return {
}
},
getters: {
},
actions: {
}
})

4
src/store/store_name.ts Normal file
View File

@ -0,0 +1,4 @@
export const enum Names {
TEST = "TEST"
}

View File

@ -10,6 +10,12 @@ import { defineStore } from 'pinia';
*/ */
export const useThemeConfig = defineStore('themeConfig', { export const useThemeConfig = defineStore('themeConfig', {
state: () => ({ state: () => ({
website: {
// 开启验证码模式
captchaMode: false,
tokenTime: 3000,
tenantId: '595035'
},
themeConfig: { themeConfig: {
// 是否开启布局配置抽屉 // 是否开启布局配置抽屉
isDrawer: false, isDrawer: false,

View File

@ -1,7 +1,6 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import Cookies from 'js-cookie';
import { Session } from '/@/utils/storage'; import { Session } from '/@/utils/storage';
import { getUserInfo, getButtons } from '/@/api/system/user.js'
/** /**
* 用户信息 * 用户信息
* @methods setUserInfos 设置用户信息 * @methods setUserInfos 设置用户信息
@ -26,47 +25,67 @@ export const useUserInfo = defineStore('userInfo', {
this.userInfos = userInfos; this.userInfos = userInfos;
} }
}, },
async Buttons() {
return new Promise((resolve) => {
getButtons().then(data => {
console.log(data)
resolve(this.formatBtns(data));
})
})
},
formatBtns(data) {
let map = [];
data.forEach(item => {
map.push(item.code)
//判断是否存在子菜单
if (item.children) {
map = map.concat(this.formatBtns(item.children));
}
})
return map;
},
// 模拟接口数据 // 模拟接口数据
// https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP // https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
async getApiUserInfo() { async getApiUserInfo() {
return new Promise((resolve) => { return new Promise((resolve) => {
setTimeout(() => { // 获取用户信息
// 模拟数据,请求接口时,记得删除多余代码及对应依赖的引入 getUserInfo().then((user) => {
const userName = Cookies.get('userName'); const arr = [];
// 模拟数据 arr.push(user.roleName);
let defaultRoles = [];
let defaultAuthBtnList = [];
// admin 页面权限标识,对应路由 meta.roles用于控制路由的显示/隐藏
let adminRoles = ['admin'];
// admin 按钮权限标识
let adminAuthBtnList = ['btn.add', 'btn.del', 'btn.edit', 'btn.link'];
// test 页面权限标识,对应路由 meta.roles用于控制路由的显示/隐藏
let testRoles = ['common'];
// test 按钮权限标识
let testAuthBtnList = ['btn.add', 'btn.link'];
// 不同用户模拟不同的用户权限
if (userName === 'admin') {
defaultRoles = adminRoles;
defaultAuthBtnList = adminAuthBtnList;
} else {
defaultRoles = testRoles;
defaultAuthBtnList = testAuthBtnList;
}
// 用户信息模拟数据
const userInfos = { const userInfos = {
userName: userName, userName: user.account,
photo: photo: user.account === 'admin'
userName === 'admin' ? 'https://img2.baidu.com/it/u=1978192862,2048448374&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500'
? 'https://img2.baidu.com/it/u=1978192862,2048448374&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500' : 'https://img2.baidu.com/it/u=2370931438,70387529&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
: 'https://img2.baidu.com/it/u=2370931438,70387529&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
time: new Date().getTime(), time: new Date().getTime(),
roles: defaultRoles, roles: arr,
authBtnList: defaultAuthBtnList, authBtnList: [],
...user
}; };
// 存储用户信息到浏览器缓存
Session.set('userInfo', userInfos); Session.set('userInfo', userInfos);
resolve(userInfos); resolve(userInfos)
}, 0); // 获取权限按钮
// this.Buttons().then((res2) => {
// // 用户信息模拟数据
// const userInfos = {
// userName: user.account,
// photo: user.account === 'admin'
// ? 'https://img2.baidu.com/it/u=1978192862,2048448374&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500'
// : 'https://img2.baidu.com/it/u=2370931438,70387529&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
// time: new Date().getTime(),
// roles: arr,
// authBtnList: res2,
// ...user
// };
// // 存储用户信息到浏览器缓存
// Session.set('userInfo', userInfos);
// resolve(userInfos)
// })
});
}); });
}, },
}, },
}); });

View File

@ -18,9 +18,10 @@ const service = axios.create({
// 添加请求拦截器 // 添加请求拦截器
service.interceptors.request.use( service.interceptors.request.use(
(config) => { (config) => {
config.headers['Authorization'] = 'Basic Vm9SRE1BZG1pbjp2b3JkbV9hZG1pbl9zZWNyZXQ=';
// 在发送请求之前做些什么 token // 在发送请求之前做些什么 token
if (Session.get('token')) { if (Session.get('token')) {
config.headers['Authorization'] = `${Session.get('token')}`; config.headers['Blade-Auth'] = `Bearer ${Session.get('token')}`;
} }
return config; return config;
}, },
@ -35,7 +36,7 @@ service.interceptors.response.use(
(response) => { (response) => {
// 对响应数据做点什么 // 对响应数据做点什么
const res = response.data; const res = response.data;
if (res.code && res.code !== 0) { if (res.code && res.code !== 200) {
// `token` 过期或者账号已在别处登录 // `token` 过期或者账号已在别处登录
if (res.code === 401 || res.code === 4001) { if (res.code === 401 || res.code === 4001) {
Session.clear(); // 清除浏览器全部临时缓存 Session.clear(); // 清除浏览器全部临时缓存
@ -43,10 +44,12 @@ service.interceptors.response.use(
ElMessageBox.alert('你已被登出,请重新登录', '提示', {}) ElMessageBox.alert('你已被登出,请重新登录', '提示', {})
.then(() => {}) .then(() => {})
.catch(() => {}); .catch(() => {});
} else if(res.code === 400){
ElMessage.error(res.msg)
} }
return Promise.reject(service.interceptors.response); return Promise.reject(service.interceptors.response);
} else { } else {
return res; return res.data || res;
} }
}, },
(error) => { (error) => {
@ -56,7 +59,8 @@ service.interceptors.response.use(
} else if (error.message == 'Network Error') { } else if (error.message == 'Network Error') {
ElMessage.error('网络连接错误'); ElMessage.error('网络连接错误');
} else { } else {
if (error.response.data) ElMessage.error(error.response.statusText); if( error.response.data.error_description ) ElMessage.error(error.response.data.error_description);
//if (error.response.data) ElMessage.error(error.response.statusText);
else ElMessage.error('接口路径找不到'); else ElMessage.error('接口路径找不到');
} }
return Promise.reject(error); return Promise.reject(error);

View File

@ -1,5 +1,315 @@
<template> <template>
<div> <div class="container">
remoteSensingData <div class="rsSelect">
<el-tabs v-model="activeName"
@tab-click="handleClick">
<el-tab-pane label="Search condition"
name="first">
<el-card class="box-card">
<span>Select time range</span>
<div class="block">
<span class="demonstration">Start time</span>
<el-date-picker style="width: 70%;"
v-model="startTime"
type="datetime"
placeholder="Select start time"
:shortcuts="shortcuts" />
</div>
<div class="block">
<span class="demonstration">End time</span>
<el-date-picker style="width: 70%;"
v-model="endTime"
type="datetime"
placeholder="Select end time"
:shortcuts="shortcuts" />
</div>
</el-card>
<el-card class="box-card"
style="margin-top: 3%;">
<span>Select a region</span>
<el-scrollbar wrap-class="list"
view-class="view-box"
:native="false">
<div class="coordinateContainer"
v-for="(coordinate, i) in coordinateList">{{
// coordinate
'Lat:' + coordinate.lat.toFixed("3") + ',&nbsp;&nbsp;&nbsp;&nbsp;Lng:' + coordinate.lng.toFixed("3")
}}
&nbsp;&nbsp;&nbsp;&nbsp;
<el-button class="el-icon-edit"
size="small"></el-button>
<el-button class="el-icon-close"
size="small"></el-button>
</div>
</el-scrollbar>
<el-button @click="addCoordinate">Add coordinates</el-button>
<el-button @click="clearCoordinate">Clear coordinates</el-button>
</el-card>
<el-card class="box-card"
style="margin-top: 3%;">
<span>Select satellite type</span>
<el-scrollbar wrap-class="sensor_list"
view-class="view-box"
:native="false">
<el-tree-select class="satelliteSelect"
v-model="satelliteSelected"
:data="sensor"
multiple
:render-after-expand="false"
show-checkbox
placeholder="Select satellite type" />
</el-scrollbar>
</el-card>
<el-button @click="startCrawl">Start Crawl</el-button>
<el-button>Cancel</el-button>
</el-tab-pane>
</el-tabs>
</div>
<Map id="map"></Map>
</div> </div>
</template> </template>
<script setup>
import { ref, reactive } from 'vue';
import Map from "/@/components/Map.vue";
const activeName = ref('first')
const startTime = ref('')
const endTime = ref('')
const addCoord = ref(false)
const satelliteSelected = ref([])
const coordinateList = ref([])
const sensor = ref([
{
value: 'landsat',
label: 'landsat',
// children: [{
// value: 1 - 1,
// label: 'LANDSAT_8_C1'
// },
// {
// value: 1 - 2,
// label: 'LANDSAT_ETM_C1'
// },
// {
// value: 1 - 3,
// label: 'LANDSAT_TM_C1'
// }
// ]
},
{
value: 'Sentinel',
label: 'Sentinel',
// children: [{
// value: 2 - 1,
// label: 'Sentinel - 2',
// children: [{
// value: 2 - 1 - 1,
// label: 'S2MSI2A'
// }]
// },
// {
// value: 2 - 2,
// label: 'Sentinel - 1',
// children: [{
// value: 2 - 2 - 1,
// label: 'SLC'
// }]
// }
// ]
},
{
value: '国产系列卫星',
label: '国产系列卫星',
children: [
{
value: 'GF - 1',
label: 'GF - 1',
},
{
value: 'GF - 2',
label: 'GF - 2',
},
{
value: 'GF - 3',
label: 'GF - 3',
},
{
value: 'GF - 4',
label: 'GF - 4',
},
{
value: 'GF - 6',
label: 'GF - 6',
},
{
value: 'ZY - 3',
label: 'ZY - 3',
},
{
value: 'ZY - 302',
label: 'ZY - 302',
},
{
value: 'ZY - 02C',
label: 'ZY - 02C',
},
],
},
{
value: '欧比特珠海一号系列卫星',
label: '欧比特珠海一号系列卫星',
children: [
{
value: 'OVS - 2A',
label: 'OVS - 2A',
},
{
value: 'OVS - 3A',
label: 'OVS - 3A',
},
{
value: 'OVS - 1A',
label: 'OVS - 1A',
},
{
value: 'OVS - 1B',
label: 'OVS - 1B',
},
{
value: 'OHS - 2A',
label: 'OHS - 2A',
},
{
value: 'OHS - 2B',
label: 'OHS - 2B',
},
{
value: 'OHS - 2C',
label: 'OHS - 2C',
},
{
value: 'OHS - 2D',
label: 'OHS - 2D',
},
],
}
])
const shortcuts = [
{
text: '1 month ago',
value: () => {
const date = new Date()
date.setTime(date.getTime() - 3600 * 1000 * 24 * 30)
return date
},
},
{
text: '3 months ago',
value: () => {
const date = new Date()
date.setTime(date.getTime() - 3600 * 1000 * 24 * 90)
return date
},
},
{
text: '6 months ago',
value: () => {
const date = new Date()
date.setTime(date.getTime() - 3600 * 1000 * 24 * 180)
return date
},
},
]
//
const addCoordinate = () => {
addCoord = !addCoord;
coordinateList = [
// '43.538', '111.530', '36.195', '120.761'
{
Lat: '43.538'
,
Lng: '111.530'
}, {
Lat: '36.195'
,
Lng: '120.761'
}
]
}
//
const clearCoordinate = () => {
coordinateList = [];
startTime = '';
endTime = '';
}
const startCrawl = () => {
console.log("start time:", startTime.value)
console.log("end time:", endTime.value)
console.log("addCoord:", addCoord.value)
console.log("satelliteSelected:", satelliteSelected.value)
}
</script>
<style scoped lang="scss">
.container {
padding: 2% 1%;
.rsSelect {
float: left;
border: 1px solid blue;
width: 30%;
height: 53rem;
span {
display: block;
margin-bottom: 3%;
}
.satelliteSelect {
width: 75%;
margin: 10px 0 10px 10px;
}
.el-tree {
margin: 10px 0 0 0;
color: black;
border-radius: 4px;
}
.el-tree-node__label {
font-size: 12px;
}
.block {
margin: 2% 0;
.demonstration {
float: left;
height: 20px;
line-height: 40px;
margin: 0 3%;
width: 20%;
}
}
.coordinateContainer {
width: 200px;
height: 200px;
border: 1px solid red;
}
}
#map {
width: 70%;
height: 53rem;
float: left;
}
}
</style>

View File

@ -1,14 +1,14 @@
<template> <template>
<el-form size="large" class="login-content-form"> <el-form size="large" class="login-content-form">
<el-form-item class="login-animation1"> <el-form-item class="login-animation1">
<el-input text placeholder="用户名 admin 或不输均为 common" v-model="state.ruleForm.userName" clearable autocomplete="off"> <el-input text placeholder="Please input username or email" v-model="state.ruleForm.userName" clearable autocomplete="off">
<template #prefix> <template #prefix>
<el-icon class="el-input__icon"><ele-User /></el-icon> <el-icon class="el-input__icon"><ele-User /></el-icon>
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item class="login-animation2"> <el-form-item class="login-animation2">
<el-input :type="state.isShowPassword ? 'text' : 'password'" placeholder="密码123456" v-model="state.ruleForm.password" autocomplete="off"> <el-input :type="state.isShowPassword ? 'text' : 'password'" placeholder="Please input password" v-model="state.ruleForm.password" autocomplete="off">
<template #prefix> <template #prefix>
<el-icon class="el-input__icon"><ele-Unlock /></el-icon> <el-icon class="el-input__icon"><ele-Unlock /></el-icon>
</template> </template>
@ -22,32 +22,34 @@
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item class="login-animation3"> <el-form-item class="login-animation3" v-if="state.captchaMode">
<el-col :span="15"> <el-col :span="15">
<el-input text maxlength="4" placeholder="请输入验证码" v-model="state.ruleForm.code" clearable autocomplete="off"> <el-input text maxlength="5" placeholder="Please input validate code" v-model="state.ruleForm.code" clearable autocomplete="off">
<template #prefix> <template #prefix>
<el-icon class="el-input__icon"><ele-Position /></el-icon> <el-icon class="el-input__icon"><ele-Position /></el-icon>
</template> </template>
</el-input> </el-input>
</el-col> </el-col>
<el-col :span="1"></el-col> <el-col :span="1"></el-col>
<el-col :span="8"> <el-col :span="8" style="width: 132px; height: 48px;">
<el-button class="login-content-code" v-waves>1234</el-button> <!-- <el-button class="login-content-code" v-waves>1234</el-button> -->
<img class="login-content-code-img" alt="" :src="state.captchaUrl" @click="getCaptchaCode" />
</el-col> </el-col>
</el-form-item> </el-form-item>
<el-form-item class="login-animation4"> <el-form-item class="login-animation4">
<el-button type="primary" class="login-content-submit" round v-waves @click="onSignIn" :loading="state.loading.signIn"> <el-button type="primary" class="login-content-submit" round v-waves @click="onSignIn" :loading="state.loading.signIn">
<span></span> <span>LOGIN</span>
</el-button> </el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
<script setup name="loginAccount"> <script setup name="loginAccount">
import { reactive, computed } from 'vue'; import { reactive, computed, onMounted } from 'vue';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import md5 from 'js-md5';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useThemeConfig } from '/@/stores/themeConfig'; import { useThemeConfig } from '/@/stores/themeConfig';
import { initFrontEndControlRoutes } from '/@/router/frontEnd'; import { initFrontEndControlRoutes } from '/@/router/frontEnd';
@ -55,71 +57,112 @@ import { initBackEndControlRoutes } from '/@/router/backEnd';
import { Session } from '/@/utils/storage'; import { Session } from '/@/utils/storage';
import { formatAxis } from '/@/utils/formatTime'; import { formatAxis } from '/@/utils/formatTime';
import { NextLoading } from '/@/utils/loading'; import { NextLoading } from '/@/utils/loading';
import { useLoginApi } from '/@/api/login';
// //
const storesThemeConfig = useThemeConfig(); const storesThemeConfig = useThemeConfig();
const { themeConfig } = storeToRefs(storesThemeConfig); const { themeConfig, website } = storeToRefs(storesThemeConfig);
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const loginApi = useLoginApi();
const state = reactive({ const state = reactive({
isShowPassword: false, isShowPassword: false,
ruleForm: { ruleForm: {
userName: 'admin', //ID
password: '123456', tenantId: website.value.tenantId,
code: '1234', //
}, userName: "",
loading: { //
signIn: false, password: "",
}, //
type: "account",
//key
key: "",
//code
code: "",
},
loading: {
signIn: false,
},
captchaMode: website.value.captchaMode,
captchaUrl: "",
}); });
const getCaptchaCode = async () => {
const res = await loginApi.getCaptcha()
state.captchaUrl = res.image;
state.ruleForm.key = res.key;
};
onMounted(() => {
if(state.captchaMode) {
getCaptchaCode();
}
});
// //
const currentTime = computed(() => { const currentTime = computed(() => {
return formatAxis(new Date()); return formatAxis(new Date());
}); });
// //
const onSignIn = async () => { const onSignIn = () => {
//
if (state.ruleForm.userName === "") {
ElMessage.error("请输入用户名");
return;
}
if (state.ruleForm.password === "") {
ElMessage.error("请输入密码");
return;
}
state.loading.signIn = true; state.loading.signIn = true;
// token loginApi.signInByUsername({
Session.set('token', Math.random().toString(36).substr(0)); tenantId: state.ruleForm.tenantId,
// `/src/stores/userInfo.ts` deptId: '',
Cookies.set('userName', state.ruleForm.userName); roleId: '',
if (!themeConfig.value.isRequestRoutes) { username: state.ruleForm.userName,
// 2 password: md5(state.ruleForm.password),
const isNoPower = await initFrontEndControlRoutes(); type: state.ruleForm.type,
signInSuccess(isNoPower); key: state.ruleForm.key,
} else { code: state.ruleForm.code,
// isRequestRoutes true grantType: state.captchaMode ? "captcha" : "password"
// router No match found for location with path "/" }).then((res) => {
const isNoPower = await initBackEndControlRoutes(); Session.set('token', res.access_token);
// initBackEndControlRoutes signInSuccess Session.set('token-time', new Date().getTime());
signInSuccess(isNoPower); Session.set('refresh-token', res.refresh_token);
} if (themeConfig.value.isRequestRoutes) {
initBackEndControlRoutes().then(() => {
signInSuccess()
}).catch(() => {state.loading.signIn = false;});
} else {
initFrontEndControlRoutes().then(() => {
signInSuccess()
}).catch(() => {state.loading.signIn = false;});
}
}).catch(()=>{
if(state.captchaMode) {
getCaptchaCode()
}
state.loading.signIn = false;
})
}; };
// //
const signInSuccess = (isNoPower) => { const signInSuccess = () => {
if (isNoPower) { //
ElMessage.warning('抱歉,您没有登录权限'); let currentTimeInfo = currentTime.value;
Session.clear(); //
// /
if (route.query?.redirect) {
router.push({
path: route.query?.redirect,
query: Object.keys(route.query?.params).length > 0 ? JSON.parse(route.query?.params) : '',
});
} else { } else {
// router.push('/');
let currentTimeInfo = currentTime.value;
//
// /
if (route.query?.redirect) {
router.push({
path: route.query?.redirect,
query: Object.keys(route.query?.params).length > 0 ? JSON.parse(route.query?.params) : '',
});
} else {
router.push('/');
}
//
const signInText = '欢迎回来!';
ElMessage.success(`${currentTimeInfo}${signInText}`);
// loading
NextLoading.start();
} }
//
const signInText = 'Welcome Back!';
ElMessage.success(`${currentTimeInfo}${signInText}`);
// loading
NextLoading.start();
state.loading.signIn = false; state.loading.signIn = false;
}; };
</script> </script>

View File

@ -22,7 +22,7 @@
<div class="login-right-warp-main-form"> <div class="login-right-warp-main-form">
<div v-if="!state.isScan"> <div v-if="!state.isScan">
<el-tabs v-model="state.tabsActiveName"> <el-tabs v-model="state.tabsActiveName">
<el-tab-pane label="账号密码登录" name="account"> <el-tab-pane label="Account Login" name="account">
<Account /> <Account />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="手机号登录" name="mobile"> <el-tab-pane label="手机号登录" name="mobile">

View File

@ -30,7 +30,7 @@ const viteConfig = defineConfig((mode) => {
hmr: true, hmr: true,
proxy: { proxy: {
'/api': { '/api': {
target: 'https://gitee.com', target: 'http://192.168.31.14:9090',
ws: true, ws: true,
changeOrigin: true, changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''), rewrite: (path) => path.replace(/^\/api/, ''),

View File

@ -1021,6 +1021,11 @@ js-cookie@^3.0.1:
resolved "https://registry.npmmirror.com/js-cookie/-/js-cookie-3.0.1.tgz#9e39b4c6c2f56563708d7d31f6f5f21873a92414" resolved "https://registry.npmmirror.com/js-cookie/-/js-cookie-3.0.1.tgz#9e39b4c6c2f56563708d7d31f6f5f21873a92414"
integrity sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw== integrity sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==
js-md5@^0.7.3:
version "0.7.3"
resolved "https://registry.npmmirror.com/js-md5/-/js-md5-0.7.3.tgz#b4f2fbb0b327455f598d6727e38ec272cd09c3f2"
integrity sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ==
js-sdsl@^4.1.4: js-sdsl@^4.1.4:
version "4.4.0" version "4.4.0"
resolved "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.4.0.tgz#8b437dbe642daa95760400b602378ed8ffea8430" resolved "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.4.0.tgz#8b437dbe642daa95760400b602378ed8ffea8430"