接入态势感知接口,获取线索附近的机场和无人机信息

main
刘妍 2025-10-15 11:39:57 +08:00
parent 4acd26e2a1
commit 97b34aeed7
10 changed files with 596 additions and 163 deletions

View File

@ -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

View File

@ -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,
});
}

View File

@ -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>;
};

View File

@ -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 {

View File

@ -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>

View File

@ -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,
};
}

View File

@ -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;
}
// 不进行任何处理,直接返回
// 用于页面代码可能需要直接获取codedatamessage这些信息时开启
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;
}
// 这里 coderesultmessage为 后台统一的字段,需要在 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 schemese.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',
// },
// });

View File

@ -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>

1
types/axios.d.ts vendored
View File

@ -28,6 +28,7 @@ export interface RequestOptions {
withToken?: boolean;
// 请求重试机制
retryRequest?: RetryRequest;
situationUrl?: string;
}
export interface RetryRequest {

2
types/config.d.ts vendored
View File

@ -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;
}