接入态势感知接口,获取线索附近的机场和无人机信息
parent
4acd26e2a1
commit
97b34aeed7
|
|
@ -7,6 +7,8 @@ VITE_PUBLIC_PATH = /
|
|||
# Basic interface address SPA
|
||||
#基础框架
|
||||
VITE_GLOB_API_URL = http://192.168.10.163:9620
|
||||
|
||||
VITE_GLOB_API_URL_SITUATION = http://192.168.10.163:9024
|
||||
# File upload address, optional
|
||||
# It can be forwarded by nginx or write the actual address directly
|
||||
VITE_GLOB_UPLOAD_URL= http://60.213.14.14:6070
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
import { defHttp } from '@/utils/http/axios/indexSituation';
|
||||
import { useGlobSetting } from '@/hooks/setting';
|
||||
|
||||
const { situationUrl } = useGlobSetting();
|
||||
|
||||
enum Api {
|
||||
ListDronePort = situationUrl + '/api/Manage/ListDronePort',
|
||||
Login = situationUrl + '/api/Check/Login',
|
||||
}
|
||||
situationUrl;
|
||||
export function listDronePort(params) {
|
||||
return defHttp.get({
|
||||
url: Api.ListDronePort,
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function situationLogin(params) {
|
||||
return defHttp.post({
|
||||
url: Api.Login,
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -3,8 +3,13 @@ import type { GlobConfig } from '#/config';
|
|||
import { getAppEnvConfig } from '@/utils/env';
|
||||
|
||||
export const useGlobSetting = (): Readonly<GlobConfig> => {
|
||||
const { VITE_GLOB_APP_TITLE, VITE_GLOB_API_URL, VITE_GLOB_API_URL_PREFIX, VITE_GLOB_UPLOAD_URL } =
|
||||
getAppEnvConfig();
|
||||
const {
|
||||
VITE_GLOB_APP_TITLE,
|
||||
VITE_GLOB_API_URL,
|
||||
VITE_GLOB_API_URL_PREFIX,
|
||||
VITE_GLOB_UPLOAD_URL,
|
||||
VITE_GLOB_API_URL_SITUATION,
|
||||
} = getAppEnvConfig();
|
||||
|
||||
// Take global configuration
|
||||
const glob: Readonly<GlobConfig> = {
|
||||
|
|
@ -13,6 +18,7 @@ export const useGlobSetting = (): Readonly<GlobConfig> => {
|
|||
shortName: VITE_GLOB_APP_TITLE.replace(/\s/g, '_').replace(/-/g, '_'),
|
||||
urlPrefix: VITE_GLOB_API_URL_PREFIX,
|
||||
uploadUrl: VITE_GLOB_UPLOAD_URL,
|
||||
situationUrl: VITE_GLOB_API_URL_SITUATION,
|
||||
};
|
||||
return glob as Readonly<GlobConfig>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -226,6 +226,7 @@
|
|||
clientSubscribe,
|
||||
destroyConnection,
|
||||
createSeizeConnection,
|
||||
destroySeizeConnection,
|
||||
} from '@/utils/mqtt';
|
||||
import {
|
||||
servicesTopic,
|
||||
|
|
@ -517,6 +518,43 @@
|
|||
querys.connectTime = timestampToFormattedDate(new Date().getTime());
|
||||
addOrUpdateRedisUser(querys);
|
||||
};
|
||||
let timer;
|
||||
const monitorDRC = ref(false);
|
||||
const drc_eart_beat = () => {
|
||||
monitorDRC.value = true;
|
||||
// 每隔五秒发送drc心跳包
|
||||
timer = window.setInterval(() => {
|
||||
drcSeq.value = drcSeq.value + 1;
|
||||
let drcQuerys;
|
||||
if (typeId == 'Dock 3') {
|
||||
drcQuerys = {
|
||||
bid: buildGUID(),
|
||||
tid: buildGUID(),
|
||||
timestamp: new Date().getTime(),
|
||||
method: 'heart_beat',
|
||||
data: {
|
||||
timestamp: new Date().getTime(),
|
||||
},
|
||||
seq: drcSeq.value,
|
||||
};
|
||||
} else if (typeId == 'Dock 1') {
|
||||
drcQuerys = {
|
||||
bid: buildGUID(),
|
||||
tid: buildGUID(),
|
||||
timestamp: new Date().getTime(),
|
||||
method: 'heart_beat',
|
||||
data: {
|
||||
timestamp: new Date().getTime(),
|
||||
seq: drcSeq.value,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
drcDownTopic(drcQuerys);
|
||||
}, 5000);
|
||||
// 订阅drc链路状态通知
|
||||
eventsTopicSubscribe();
|
||||
};
|
||||
onMounted(() => {
|
||||
// mqtt连接
|
||||
createConnection();
|
||||
|
|
@ -545,10 +583,46 @@
|
|||
if (rs.data.result == 0) {
|
||||
flightGrab.value = true;
|
||||
createSeizeConnection();
|
||||
createMessage.success('相机控制权获取成功');
|
||||
createMessage.success('控制权获取成功');
|
||||
drc_eart_beat();
|
||||
} else {
|
||||
flightGrab.value = false;
|
||||
createMessage.error('相机控制权获取失败,' + errorName(rs.data.result));
|
||||
createMessage.error('控制权获取失败,' + errorName(rs.data.result));
|
||||
}
|
||||
}
|
||||
// 一键返航
|
||||
if (rs.method === 'return_home') {
|
||||
if (rs.data.result == 0) {
|
||||
createMessage.success('一键返航成功');
|
||||
monitorDRC.value = false;
|
||||
} else {
|
||||
createMessage.error('一键返航失败,' + errorName(rs.data.result));
|
||||
}
|
||||
}
|
||||
if (rs.method === 'takeoff_to_point') {
|
||||
if (rs.data.result == 0) {
|
||||
createMessage.success('一键起飞成功');
|
||||
} else {
|
||||
createMessage.error('一键起飞失败,' + errorName(rs.data.result));
|
||||
}
|
||||
}
|
||||
if (rs.method === 'drc_status_notify' && monitorDRC.value) {
|
||||
if (rs.data.result == 0) {
|
||||
if (rs.data.drc_state == 0) {
|
||||
drc_eart_beat();
|
||||
}
|
||||
} else {
|
||||
drc_eart_beat();
|
||||
createMessage.error('DRC连接中断,' + errorName(rs.data.result) + ',正在重新连接');
|
||||
}
|
||||
}
|
||||
// 指点飞行
|
||||
if (rs.method == 'fly_to_point') {
|
||||
if (rs.data.result == 0) {
|
||||
createMessage.success('指点飞行成功');
|
||||
EventBus.emit('closeTranslation', null);
|
||||
} else {
|
||||
createMessage.error('指点飞行失败,' + errorName(rs.data.result));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -558,6 +632,12 @@
|
|||
console.log('dataupdate', data);
|
||||
});
|
||||
});
|
||||
onUnmounted(() => {
|
||||
window.clearInterval(timer);
|
||||
destroySeizeConnection();
|
||||
changeRedisUser(false);
|
||||
monitorDRC.value = false;
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.flight-control {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,10 @@
|
|||
destroyConnection,
|
||||
createSeizeConnection,
|
||||
} from '@/utils/mqtt';
|
||||
import { listDronePort } from '@/api/situation';
|
||||
import { airPortStore } from '@/store/modules/airport';
|
||||
|
||||
const airPortStoreVal = airPortStore();
|
||||
const props = defineProps({
|
||||
chartConfig: {
|
||||
type: Object as PropType<CreateComponentType>,
|
||||
|
|
@ -62,6 +65,8 @@
|
|||
flight_id: uuid(14, 14),
|
||||
target_latitude: Number(deliveryData.value.lat),
|
||||
target_longitude: Number(deliveryData.value.lng),
|
||||
// target_latitude: 35.133738,
|
||||
// target_longitude: 118.296717,
|
||||
target_height: 200,
|
||||
security_takeoff_height: 100,
|
||||
rth_altitude: 115,
|
||||
|
|
@ -81,12 +86,8 @@
|
|||
method: 'takeoff_to_point',
|
||||
};
|
||||
console.log(querys);
|
||||
// 新的
|
||||
// servicesTopicReize(querys);
|
||||
// services_replyTopicReize();
|
||||
// 老的
|
||||
servicesTopic(querys);
|
||||
services_replyTopic();
|
||||
// servicesTopic(querys);
|
||||
// services_replyTopic();
|
||||
};
|
||||
const dblclickBtn = (val) => {
|
||||
eventHandlerHook(
|
||||
|
|
@ -125,8 +126,19 @@
|
|||
EventBus.on(props.chartConfig.id + 'dataupdate', (data) => {
|
||||
console.log('dataupdate', data);
|
||||
deliveryData.value = data;
|
||||
listDronePort({
|
||||
lng: data.lng,
|
||||
lat: data.lat,
|
||||
}).then((res) => {
|
||||
console.log('res', res);
|
||||
airPortStoreVal.setAirPort('sn', res[0].droneportsn);
|
||||
airPortStoreVal.setUAV('sn', res[0].Sn);
|
||||
airPortStoreVal.setGateway(res[0].GateWay);
|
||||
setTimeout(() => {
|
||||
createConnection();
|
||||
}, 500);
|
||||
});
|
||||
});
|
||||
createConnection();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export function getAppEnvConfig() {
|
|||
VITE_GLOB_APP_MANAGEMENT_UNIT,
|
||||
VITE_GLOB_APP_TECHINICAL_SUPPORT,
|
||||
VITE_GLOB_APP_VERSIONS,
|
||||
VITE_GLOB_YINGXIANG_SERVER,
|
||||
VITE_GLOB_API_URL_SITUATION,
|
||||
VITE_GLOB_FILE_PREVIEW,
|
||||
VITE_GLOB_GEOSERVER_BASE_URL,
|
||||
} = ENV;
|
||||
|
|
@ -58,9 +58,9 @@ export function getAppEnvConfig() {
|
|||
VITE_GLOB_APP_MANAGEMENT_UNIT,
|
||||
VITE_GLOB_APP_TECHINICAL_SUPPORT,
|
||||
VITE_GLOB_APP_VERSIONS,
|
||||
VITE_GLOB_YINGXIANG_SERVER,
|
||||
VITE_GLOB_API_URL_SITUATION,
|
||||
VITE_GLOB_FILE_PREVIEW,
|
||||
VITE_GLOB_GEOSERVER_BASE_URL
|
||||
VITE_GLOB_GEOSERVER_BASE_URL,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,299 @@
|
|||
// axios配置 可自行根据项目进行更改,只需更改该文件即可,其他文件可以不动
|
||||
// The axios configuration can be changed according to the project, just change the file, other files can be left unchanged
|
||||
|
||||
import type { AxiosInstance, AxiosResponse } from 'axios';
|
||||
import { clone } from 'lodash-es';
|
||||
import type { RequestOptions, Result } from '#/axios';
|
||||
import type { AxiosTransform, CreateAxiosOptions } from './axiosTransform';
|
||||
import { VAxios } from './Axios';
|
||||
import { checkStatus } from './checkStatus';
|
||||
import { useGlobSetting } from '@/hooks/setting';
|
||||
import { useMessage } from '@/hooks/web/useMessage';
|
||||
import { RequestEnum, ResultEnum, ContentTypeEnum } from '@/enums/httpEnum';
|
||||
import { isString, isUndefined, isNull, isEmpty } from '@/utils/is';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { setObjToUrlParams, deepMerge } from '@/utils';
|
||||
import { useErrorLogStoreWithOut } from '@/store/modules/errorLog';
|
||||
import { useI18n } from '@/hooks/web/useI18n';
|
||||
import { joinTimestamp, formatRequestDate } from './helper';
|
||||
import { useUserStoreWithOut } from '@/store/modules/user';
|
||||
import { AxiosRetry } from '@/utils/http/axios/axiosRetry';
|
||||
import axios from 'axios';
|
||||
|
||||
const globSetting = useGlobSetting();
|
||||
const urlPrefix = globSetting.urlPrefix;
|
||||
const { createMessage, createErrorModal, createSuccessModal } = useMessage();
|
||||
|
||||
/**
|
||||
* @description: 数据处理,方便区分多种处理方式
|
||||
*/
|
||||
const transform: AxiosTransform = {
|
||||
/**
|
||||
* @description: 处理响应数据。如果数据不是预期格式,可直接抛出错误
|
||||
*/
|
||||
transformResponseHook: (res: AxiosResponse<Result>, options: RequestOptions) => {
|
||||
const { t } = useI18n();
|
||||
const { isTransformResponse, isReturnNativeResponse } = options;
|
||||
// 是否返回原生响应头 比如:需要获取响应头时使用该属性
|
||||
if (isReturnNativeResponse) {
|
||||
return res;
|
||||
}
|
||||
// 不进行任何处理,直接返回
|
||||
// 用于页面代码可能需要直接获取code,data,message这些信息时开启
|
||||
if (!isTransformResponse) {
|
||||
return res.data;
|
||||
}
|
||||
// 错误的时候返回
|
||||
const { data } = res;
|
||||
|
||||
if (!data) {
|
||||
// return '[HTTP] Request has no return value';
|
||||
throw new Error(t('sys.api.apiRequestFailed'));
|
||||
}
|
||||
if (!data.code && !data.result) {
|
||||
return data;
|
||||
}
|
||||
// 这里 code,result,message为 后台统一的字段,需要在 types.ts内修改为项目自己的接口返回格式
|
||||
const { code, result, message } = data;
|
||||
// 这里逻辑可以根据项目进行修改
|
||||
const hasSuccess = data && Reflect.has(data, 'code') && code === ResultEnum.SUCCESS;
|
||||
if (hasSuccess) {
|
||||
let successMsg = message;
|
||||
|
||||
if (isNull(successMsg) || isUndefined(successMsg) || isEmpty(successMsg)) {
|
||||
successMsg = t(`sys.api.operationSuccess`);
|
||||
}
|
||||
|
||||
if (options.successMessageMode === 'modal') {
|
||||
createSuccessModal({ title: t('sys.api.successTip'), content: successMsg });
|
||||
} else if (options.successMessageMode === 'message') {
|
||||
createMessage.success(successMsg);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// 在此处根据自己项目的实际情况对不同的code执行不同的操作
|
||||
// 如果不希望中断当前请求,请return数据,否则直接抛出异常即可
|
||||
let timeoutMsg = '';
|
||||
switch (code) {
|
||||
case ResultEnum.TIMEOUT:
|
||||
timeoutMsg = t('sys.api.timeoutMessage');
|
||||
const userStore = useUserStoreWithOut();
|
||||
userStore.logout(true);
|
||||
break;
|
||||
default:
|
||||
if (message) {
|
||||
timeoutMsg = message;
|
||||
}
|
||||
}
|
||||
|
||||
// errorMessageMode='modal'的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误
|
||||
// errorMessageMode='none' 一般是调用时明确表示不希望自动弹出错误提示
|
||||
if (options.errorMessageMode === 'modal') {
|
||||
createErrorModal({ title: t('sys.api.errorTip'), content: timeoutMsg });
|
||||
} else if (options.errorMessageMode === 'message') {
|
||||
createMessage.error(timeoutMsg);
|
||||
}
|
||||
|
||||
throw new Error(timeoutMsg || t('sys.api.apiRequestFailed'));
|
||||
},
|
||||
|
||||
// 请求之前处理config
|
||||
beforeRequestHook: (config, options) => {
|
||||
const {
|
||||
situationUrl,
|
||||
joinPrefix,
|
||||
joinParamsToUrl,
|
||||
formatDate,
|
||||
joinTime = true,
|
||||
urlPrefix,
|
||||
} = options;
|
||||
|
||||
if (joinPrefix) {
|
||||
config.url = `${urlPrefix}${config.url}`;
|
||||
}
|
||||
|
||||
if (situationUrl && isString(situationUrl)) {
|
||||
config.url = `${situationUrl}${config.url}`;
|
||||
}
|
||||
const params = config.params || {};
|
||||
const data = config.data || false;
|
||||
formatDate && data && !isString(data) && formatRequestDate(data);
|
||||
if (config.method?.toUpperCase() === RequestEnum.GET) {
|
||||
if (!isString(params)) {
|
||||
// 给 get 请求加上时间戳参数,避免从缓存中拿数据。
|
||||
config.params = Object.assign(params || {}, joinTimestamp(joinTime, false));
|
||||
} else {
|
||||
// 兼容restful风格
|
||||
config.url = config.url + params + `${joinTimestamp(joinTime, true)}`;
|
||||
config.params = undefined;
|
||||
}
|
||||
} else {
|
||||
if (!isString(params)) {
|
||||
formatDate && formatRequestDate(params);
|
||||
if (
|
||||
Reflect.has(config, 'data') &&
|
||||
config.data &&
|
||||
(Object.keys(config.data).length > 0 || config.data instanceof FormData)
|
||||
) {
|
||||
config.data = data;
|
||||
config.params = params;
|
||||
} else {
|
||||
// 非GET请求如果没有提供data,则将params视为data
|
||||
config.data = params;
|
||||
config.params = undefined;
|
||||
}
|
||||
if (joinParamsToUrl) {
|
||||
config.url = setObjToUrlParams(
|
||||
config.url as string,
|
||||
Object.assign({}, config.params, config.data),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// 兼容restful风格
|
||||
config.url = config.url + params;
|
||||
config.params = undefined;
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
|
||||
/**
|
||||
* @description: 请求拦截器处理
|
||||
*/
|
||||
requestInterceptors: (config, options) => {
|
||||
// 请求之前处理config
|
||||
// const token = getToken();
|
||||
const token = localStorage.getItem('X-Token-Situation');
|
||||
if (token && (config as Recordable)?.requestOptions?.withToken !== false) {
|
||||
// jwt token
|
||||
(config as Recordable).headers.Authorization = options.authenticationScheme
|
||||
? `${options.authenticationScheme} ${token}`
|
||||
: token;
|
||||
config.headers['X-Token'] = token;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
|
||||
/**
|
||||
* @description: 响应拦截器处理
|
||||
*/
|
||||
responseInterceptors: (res: AxiosResponse<any>) => {
|
||||
return res;
|
||||
},
|
||||
|
||||
/**
|
||||
* @description: 响应错误处理
|
||||
*/
|
||||
responseInterceptorsCatch: (axiosInstance: AxiosInstance, error: any) => {
|
||||
const { t } = useI18n();
|
||||
const errorLogStore = useErrorLogStoreWithOut();
|
||||
errorLogStore.addAjaxErrorInfo(error);
|
||||
const { response, code, message, config } = error || {};
|
||||
const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none';
|
||||
const msg: string = response?.data?.error?.message ?? '';
|
||||
const err: string = error?.toString?.() ?? '';
|
||||
let errMessage = '';
|
||||
|
||||
if (axios.isCancel(error)) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
try {
|
||||
if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
|
||||
errMessage = t('sys.api.apiTimeoutMessage');
|
||||
}
|
||||
if (err?.includes('Network Error')) {
|
||||
errMessage = t('sys.api.networkExceptionMsg');
|
||||
}
|
||||
|
||||
if (errMessage) {
|
||||
if (errorMessageMode === 'modal') {
|
||||
createErrorModal({ title: t('sys.api.errorTip'), content: errMessage });
|
||||
} else if (errorMessageMode === 'message') {
|
||||
createMessage.error(errMessage);
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(error as unknown as string);
|
||||
}
|
||||
|
||||
checkStatus(error?.response?.status, msg, errorMessageMode);
|
||||
|
||||
// 添加自动重试机制 保险起见 只针对GET请求
|
||||
const retryRequest = new AxiosRetry();
|
||||
const { isOpenRetry } = config.requestOptions.retryRequest;
|
||||
config.method?.toUpperCase() === RequestEnum.GET &&
|
||||
isOpenRetry &&
|
||||
// @ts-ignore
|
||||
retryRequest.retry(axiosInstance, error);
|
||||
return Promise.reject(error);
|
||||
},
|
||||
};
|
||||
|
||||
function createAxios(opt?: Partial<CreateAxiosOptions>) {
|
||||
return new VAxios(
|
||||
// 深度合并
|
||||
deepMerge(
|
||||
{
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
|
||||
// authentication schemes,e.g: Bearer
|
||||
// authenticationScheme: 'Bearer',
|
||||
authenticationScheme: '',
|
||||
timeout: 30 * 1000,
|
||||
// 基础接口地址
|
||||
// baseURL: globSetting.apiUrl,
|
||||
|
||||
headers: {
|
||||
'Content-Type': ContentTypeEnum.JSON,
|
||||
'T-Token': localStorage.getItem('X-Token-Situation'),
|
||||
},
|
||||
// 如果是form-data格式
|
||||
// headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED },
|
||||
// 数据处理方式
|
||||
transform: clone(transform),
|
||||
// 配置项,下面的选项都可以在独立的接口请求中覆盖
|
||||
requestOptions: {
|
||||
// 默认将prefix 添加到url
|
||||
joinPrefix: true,
|
||||
// 是否返回原生响应头 比如:需要获取响应头时使用该属性
|
||||
isReturnNativeResponse: false,
|
||||
// 需要对返回数据进行处理
|
||||
isTransformResponse: true,
|
||||
// post请求的时候添加参数到url
|
||||
joinParamsToUrl: false,
|
||||
// 格式化提交参数时间
|
||||
formatDate: true,
|
||||
// 消息提示类型
|
||||
errorMessageMode: 'message',
|
||||
// 接口地址
|
||||
apiUrl: globSetting.situationUrl,
|
||||
// 接口拼接地址
|
||||
urlPrefix: urlPrefix,
|
||||
// 是否加入时间戳
|
||||
joinTime: true,
|
||||
// 忽略重复请求
|
||||
ignoreCancelToken: true,
|
||||
// 是否携带token
|
||||
withToken: true,
|
||||
retryRequest: {
|
||||
isOpenRetry: true,
|
||||
count: 5,
|
||||
waitTime: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
opt || {},
|
||||
),
|
||||
);
|
||||
}
|
||||
export const defHttp = createAxios();
|
||||
|
||||
// other api url
|
||||
// export const otherHttp = createAxios({
|
||||
// requestOptions: {
|
||||
// apiUrl: 'xxx',
|
||||
// urlPrefix: 'xxx',
|
||||
// },
|
||||
// });
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="login-form">
|
||||
<div class="content" :style="{transform: `scale(${ratio})`}">
|
||||
<div class="content" :style="{ transform: `scale(${ratio})` }">
|
||||
<div class="title">
|
||||
<div class="title-span">用户登录</div>
|
||||
<div class="title-line"></div>
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
v-model:value="formData.account"
|
||||
placeholder="请输入账户"
|
||||
class=""
|
||||
style="height: 61.8px;"
|
||||
style="height: 61.8px"
|
||||
>
|
||||
<template #prefix>
|
||||
<div class="icon-div">
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
visibilityToggle
|
||||
v-model:value="formData.password"
|
||||
placeholder="请输入密码"
|
||||
style="height: 61.8px;"
|
||||
style="height: 61.8px"
|
||||
>
|
||||
<template #prefix>
|
||||
<div class="icon-div">
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
</FormItem>
|
||||
<div class="control-password">
|
||||
<div><a-checkbox v-model:checked="rememberMe">记住密码</a-checkbox></div>
|
||||
<div style="cursor: pointer;">忘记密码</div>
|
||||
<div style="cursor: pointer">忘记密码</div>
|
||||
</div>
|
||||
<a-form-item>
|
||||
<a-button
|
||||
|
|
@ -75,13 +75,15 @@
|
|||
import { useDesign } from '@/hooks/web/useDesign';
|
||||
import { useI18n } from '@/hooks/web/useI18n';
|
||||
import { getAppEnvConfig } from '@/utils/env';
|
||||
import { useFormRules, useFormValid } from './useLogin';
|
||||
import { useFormRules, useFormValid } from './useLogin';
|
||||
import { useMessage } from '@/hooks/web/useMessage';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { Form, Input } from 'ant-design-vue';
|
||||
import { useLoginButtonLoadingStore } from '@/store/modules/loginButtonLoading'
|
||||
import { useLoginButtonLoadingStore } from '@/store/modules/loginButtonLoading';
|
||||
import { situationLogin } from '@/api/situation';
|
||||
import md5 from 'js-md5';
|
||||
|
||||
const loginButtonLoadingStore = useLoginButtonLoadingStore()
|
||||
const loginButtonLoadingStore = useLoginButtonLoadingStore();
|
||||
|
||||
const { VITE_GLOB_APP_MANAGEMENT_UNIT, VITE_GLOB_APP_TECHINICAL_SUPPORT } = getAppEnvConfig();
|
||||
defineProps({
|
||||
|
|
@ -108,11 +110,11 @@ const loginButtonLoadingStore = useLoginButtonLoadingStore()
|
|||
|
||||
// 分辨率
|
||||
const defaultWidth = 1920;
|
||||
const ratio = ref(1)
|
||||
const ratio = ref(1);
|
||||
const updateWindowSize = () => {
|
||||
let widthRatio = window.innerWidth / defaultWidth;
|
||||
console.log(window.innerWidth,defaultWidth, widthRatio,)
|
||||
ratio.value = widthRatio >=1? widthRatio : 1
|
||||
console.log(window.innerWidth, defaultWidth, widthRatio);
|
||||
ratio.value = widthRatio >= 1 ? widthRatio : 1;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
|
|
@ -137,12 +139,18 @@ const loginButtonLoadingStore = useLoginButtonLoadingStore()
|
|||
console.log(userInfo);
|
||||
localStorage.setItem('fireUserLoginName', userInfo.name);
|
||||
if (userInfo) {
|
||||
localStorage.setItem('userid', userInfo.id);
|
||||
localStorage.setItem('userid', userInfo.id);
|
||||
notification.success({
|
||||
message: t('sys.login.loginSuccessTitle'),
|
||||
description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.name}`,
|
||||
duration: 3,
|
||||
});
|
||||
situationLogin({
|
||||
account: 'System',
|
||||
password: md5('123456'),
|
||||
}).then((res) => {
|
||||
localStorage.setItem('X-Token-Situation', res.token);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
createErrorModal({
|
||||
|
|
@ -156,162 +164,162 @@ const loginButtonLoadingStore = useLoginButtonLoadingStore()
|
|||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
.login-out-div{
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
.login-image{
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.image-content{
|
||||
width: calc(1292 / 1920 * 100vw);
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
background-image: url('/public/login/login_background.png');
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.source{
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
border-top: 1px solid #207442;
|
||||
height: 98px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: AlibabaPuHuiTiR;
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
.login-form{
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
width: calc(628 / 1920 * 100vw);
|
||||
min-width: 628px;
|
||||
height: 100vh;
|
||||
background-color: #ffffff;
|
||||
.login-out-div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.content{
|
||||
width: 406.6px;
|
||||
transform-origin: center;
|
||||
.title{
|
||||
width: 100%;
|
||||
position: relative;
|
||||
height: 36px;
|
||||
margin-bottom: 11px;
|
||||
.title-span{
|
||||
font-family: AlibabaPuHuiTiBold;
|
||||
font-weight: bold;
|
||||
font-size: 37px;
|
||||
color: #333333;
|
||||
line-height: 36px;
|
||||
background: #ffffff;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
z-index: 2;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 0px 25px;
|
||||
}
|
||||
.title-line{
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: #333333;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
z-index: 1;
|
||||
}
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
.login-image {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.image-content {
|
||||
width: calc(1292 / 1920 * 100vw);
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
background-image: url('/public/login/login_background.png');
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.sub-title{
|
||||
font-family: PingFangSCLight;
|
||||
font-weight: 300;
|
||||
font-size: 16px;
|
||||
color: #333333;
|
||||
line-height: 13px;
|
||||
.source {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
border-top: 1px solid #207442;
|
||||
height: 98px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 57px;
|
||||
align-items: center;
|
||||
font-family: AlibabaPuHuiTiR;
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
color: #ffffff;
|
||||
}
|
||||
.login-use-form{
|
||||
.ant-input-affix-wrapper:not(.ant-input-affix-wrapper-disabled):hover {
|
||||
border-color: #55d187;
|
||||
box-shadow: 0 0 8px rgba(85, 209, 135, 0.5);
|
||||
}
|
||||
.ant-input-affix-wrapper:not(.ant-input-affix-wrapper-disabled):focus {
|
||||
border-color: #55d187;
|
||||
box-shadow: 0 0 8px rgba(85, 209, 135, 0.5);
|
||||
}
|
||||
.ant-input-affix-wrapper-focused{
|
||||
border-color: #55d187;
|
||||
box-shadow: 0 0 8px rgba(85, 209, 135, 0.5);
|
||||
}
|
||||
.ant-form-item{
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.icon-div{
|
||||
height: 33px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 9px;
|
||||
padding-right: 20px;
|
||||
border-right: 1px solid #EAEAEA;
|
||||
margin-right: 15px;
|
||||
.account-icon{
|
||||
width: 15px;
|
||||
height: 16px;
|
||||
background-image: url('/public/login/account.png');
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.login-form {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
width: calc(628 / 1920 * 100vw);
|
||||
min-width: 628px;
|
||||
height: 100vh;
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.content {
|
||||
width: 406.6px;
|
||||
transform-origin: center;
|
||||
.title {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
height: 36px;
|
||||
margin-bottom: 11px;
|
||||
.title-span {
|
||||
font-family: AlibabaPuHuiTiBold;
|
||||
font-weight: bold;
|
||||
font-size: 37px;
|
||||
color: #333333;
|
||||
line-height: 36px;
|
||||
background: #ffffff;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
z-index: 2;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 0px 25px;
|
||||
}
|
||||
.password-icon{
|
||||
width: 15px;
|
||||
height: 16px;
|
||||
background-image: url('/public/login/password.png');
|
||||
background-size: 100% 100%;
|
||||
.title-line {
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: #333333;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
.control-password{
|
||||
.sub-title {
|
||||
font-family: PingFangSCLight;
|
||||
font-weight: 300;
|
||||
font-size: 16px;
|
||||
color: #333333;
|
||||
line-height: 13px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-family: Microsoft YaHei;
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
color: #878686;
|
||||
padding-top: 7px;
|
||||
margin-bottom: 62px;
|
||||
span{
|
||||
justify-content: center;
|
||||
margin-bottom: 57px;
|
||||
}
|
||||
.login-use-form {
|
||||
.ant-input-affix-wrapper:not(.ant-input-affix-wrapper-disabled):hover {
|
||||
border-color: #55d187;
|
||||
box-shadow: 0 0 8px rgba(85, 209, 135, 0.5);
|
||||
}
|
||||
.ant-input-affix-wrapper:not(.ant-input-affix-wrapper-disabled):focus {
|
||||
border-color: #55d187;
|
||||
box-shadow: 0 0 8px rgba(85, 209, 135, 0.5);
|
||||
}
|
||||
.ant-input-affix-wrapper-focused {
|
||||
border-color: #55d187;
|
||||
box-shadow: 0 0 8px rgba(85, 209, 135, 0.5);
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.icon-div {
|
||||
height: 33px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 9px;
|
||||
padding-right: 20px;
|
||||
border-right: 1px solid #eaeaea;
|
||||
margin-right: 15px;
|
||||
.account-icon {
|
||||
width: 15px;
|
||||
height: 16px;
|
||||
background-image: url('/public/login/account.png');
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.password-icon {
|
||||
width: 15px;
|
||||
height: 16px;
|
||||
background-image: url('/public/login/password.png');
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
.control-password {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-family: Microsoft YaHei;
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
color: #878686;
|
||||
padding-top: 7px;
|
||||
margin-bottom: 62px;
|
||||
span {
|
||||
justify-content: space-between;
|
||||
font-family: Microsoft YaHei;
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
color: #878686;
|
||||
}
|
||||
/* 修改 Checkbox 选中颜色 */
|
||||
.ant-checkbox-checked .ant-checkbox-inner {
|
||||
background-color: #008b47 !important; /* 选中时的背景色 */
|
||||
border-color: #008b47 !important; /* 选中时的边框色 */
|
||||
}
|
||||
/* 修改 Hover 时的颜色 */
|
||||
.ant-checkbox:hover .ant-checkbox-inner {
|
||||
border-color: #55d187 !important;
|
||||
}
|
||||
}
|
||||
/* 修改 Checkbox 选中颜色 */
|
||||
.ant-checkbox-checked .ant-checkbox-inner {
|
||||
background-color: #008B47 !important; /* 选中时的背景色 */
|
||||
border-color: #008B47 !important; /* 选中时的边框色 */
|
||||
.login-button {
|
||||
height: 65px;
|
||||
border-radius: 33px;
|
||||
background: linear-gradient(87deg, #008b47, #039d52);
|
||||
font-family: Microsoft YaHei Light;
|
||||
font-weight: 300;
|
||||
font-size: 15px;
|
||||
color: #ffffff;
|
||||
}
|
||||
/* 修改 Hover 时的颜色 */
|
||||
.ant-checkbox:hover .ant-checkbox-inner {
|
||||
border-color: #55d187 !important;
|
||||
}
|
||||
}
|
||||
.login-button{
|
||||
height: 65px;
|
||||
border-radius: 33px;
|
||||
background: linear-gradient(87deg, #008B47, #039D52);
|
||||
font-family: Microsoft YaHei Light;
|
||||
font-weight: 300;
|
||||
font-size: 15px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ export interface RequestOptions {
|
|||
withToken?: boolean;
|
||||
// 请求重试机制
|
||||
retryRequest?: RetryRequest;
|
||||
situationUrl?: string;
|
||||
}
|
||||
|
||||
export interface RetryRequest {
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ export interface GlobConfig {
|
|||
urlPrefix?: string;
|
||||
// Project abbreviation
|
||||
shortName: string;
|
||||
situationUrl: string;
|
||||
}
|
||||
export interface GlobEnvConfig {
|
||||
// Site title
|
||||
|
|
@ -166,4 +167,5 @@ export interface GlobEnvConfig {
|
|||
VITE_GLOB_APP_MANAGEMENT_UNIT?: string;
|
||||
VITE_GLOB_APP_TECHINICAL_SUPPORT?: string;
|
||||
VITE_GLOB_APP_VERSIONS?: string;
|
||||
VITE_GLOB_API_URL_SITUATION?: string;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue