mirror of
https://gitee.com/bootx/dax-pay-ui.git
synced 2025-09-02 10:26:32 +00:00
站内支持API接口地址切换 (#3162)
* feat: 站内切换接口API * feat: 站内切换接口API * feat: 站内支持API接口地址切换,解决冲突,新增开关显示 (cherry picked from commit c6d60b6cfd50bf8e19233a21640ecf1d41c01cc8)
This commit is contained in:
@@ -11,6 +11,7 @@ export const ROLES_KEY = 'ROLES__KEY__';
|
|||||||
|
|
||||||
// project config key
|
// project config key
|
||||||
export const PROJ_CFG_KEY = 'PROJ__CFG__KEY__';
|
export const PROJ_CFG_KEY = 'PROJ__CFG__KEY__';
|
||||||
|
export const API_ADDRESS = 'API_ADDRESS__';
|
||||||
|
|
||||||
// lock info
|
// lock info
|
||||||
export const LOCK_INFO_KEY = 'LOCK__INFO__KEY__';
|
export const LOCK_INFO_KEY = 'LOCK__INFO__KEY__';
|
||||||
|
@@ -48,6 +48,8 @@ export function useHeaderSetting() {
|
|||||||
|
|
||||||
const getShowDoc = computed(() => appStore.getHeaderSetting.showDoc);
|
const getShowDoc = computed(() => appStore.getHeaderSetting.showDoc);
|
||||||
|
|
||||||
|
const getShowApi = computed(() => appStore.getHeaderSetting.showApi);
|
||||||
|
|
||||||
const getHeaderTheme = computed(() => appStore.getHeaderSetting.theme);
|
const getHeaderTheme = computed(() => appStore.getHeaderSetting.theme);
|
||||||
|
|
||||||
const getShowHeader = computed(() => appStore.getHeaderSetting.show);
|
const getShowHeader = computed(() => appStore.getHeaderSetting.show);
|
||||||
@@ -86,6 +88,7 @@ export function useHeaderSetting() {
|
|||||||
setHeaderSetting,
|
setHeaderSetting,
|
||||||
|
|
||||||
getShowDoc,
|
getShowDoc,
|
||||||
|
getShowApi,
|
||||||
getShowSearch,
|
getShowSearch,
|
||||||
getHeaderTheme,
|
getHeaderTheme,
|
||||||
getUseLockPage,
|
getUseLockPage,
|
||||||
|
82
src/layouts/default/header/components/ChangeApi/index.vue
Normal file
82
src/layouts/default/header/components/ChangeApi/index.vue
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<template>
|
||||||
|
<BasicModal
|
||||||
|
:title="t('layout.header.dropdownChangeApi')"
|
||||||
|
v-bind="$attrs"
|
||||||
|
@register="register"
|
||||||
|
@ok="handelSubmit"
|
||||||
|
@cancel="handelCancel"
|
||||||
|
>
|
||||||
|
<BasicForm @register="registerForm">
|
||||||
|
<template #api="{ model, field }">
|
||||||
|
<RadioGroup v-model:value="model[field]">
|
||||||
|
<Radio :style="radioStyle" :value="key" v-for="(val, key) in addresses" :key="key"
|
||||||
|
>{{ key }}: {{ val }}</Radio
|
||||||
|
>
|
||||||
|
</RadioGroup>
|
||||||
|
</template>
|
||||||
|
</BasicForm>
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { Radio } from 'ant-design-vue';
|
||||||
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
|
import { BasicModal, useModalInner } from '/@/components/Modal/index';
|
||||||
|
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useAppStore } from '/@/store/modules/app';
|
||||||
|
import type { ApiAddress } from '/#/store';
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const RadioGroup = Radio.Group;
|
||||||
|
const { t } = useI18n();
|
||||||
|
const [register, { closeModal }] = useModalInner(async () => {
|
||||||
|
initData();
|
||||||
|
});
|
||||||
|
// perf 能读取所有.env.xxx文件最好, 另外key与--mode XXX最好相同
|
||||||
|
const addresses = ref({
|
||||||
|
development: 'http://www.a.com',
|
||||||
|
test: 'http://www.b.com',
|
||||||
|
prod: 'http://www.c.com',
|
||||||
|
});
|
||||||
|
const radioStyle = ref({
|
||||||
|
display: 'flex',
|
||||||
|
height: '30px',
|
||||||
|
lineHeight: '30px',
|
||||||
|
});
|
||||||
|
const [registerForm, { validateFields, setFieldsValue }] = useForm({
|
||||||
|
showActionButtonGroup: false,
|
||||||
|
schemas: [
|
||||||
|
{
|
||||||
|
field: 'api',
|
||||||
|
label: t('layout.header.dropdownChangeApi'),
|
||||||
|
colProps: {
|
||||||
|
span: 24,
|
||||||
|
},
|
||||||
|
defaultValue: import.meta.env.MODE || 'development', // 当前环境
|
||||||
|
required: true,
|
||||||
|
component: 'Input',
|
||||||
|
slot: 'api',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const handelSubmit = async () => {
|
||||||
|
const values = await validateFields();
|
||||||
|
appStore.setApiAddress({
|
||||||
|
key: values.api,
|
||||||
|
val: addresses.value[values.api],
|
||||||
|
});
|
||||||
|
location.reload();
|
||||||
|
};
|
||||||
|
const handelCancel = () => {
|
||||||
|
closeModal();
|
||||||
|
};
|
||||||
|
const initData = () => {
|
||||||
|
const { key = '' } = appStore.getApiAddress as ApiAddress;
|
||||||
|
if (key) {
|
||||||
|
setFieldsValue({
|
||||||
|
api: key,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="less"></style>
|
@@ -18,6 +18,12 @@
|
|||||||
v-if="getShowDoc"
|
v-if="getShowDoc"
|
||||||
/>
|
/>
|
||||||
<MenuDivider v-if="getShowDoc" />
|
<MenuDivider v-if="getShowDoc" />
|
||||||
|
<MenuItem
|
||||||
|
v-if="getShowApi"
|
||||||
|
key="api"
|
||||||
|
:text="t('layout.header.dropdownChangeApi')"
|
||||||
|
icon="ant-design:swap-outlined"
|
||||||
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
v-if="getUseLockPage"
|
v-if="getUseLockPage"
|
||||||
key="lock"
|
key="lock"
|
||||||
@@ -33,6 +39,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
<LockAction @register="register" />
|
<LockAction @register="register" />
|
||||||
|
<ChangeApi @register="registerApi" />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
// components
|
// components
|
||||||
@@ -55,7 +62,7 @@
|
|||||||
|
|
||||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||||
|
|
||||||
type MenuEvent = 'logout' | 'doc' | 'lock';
|
type MenuEvent = 'logout' | 'doc' | 'lock' | 'api';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'UserDropdown',
|
name: 'UserDropdown',
|
||||||
@@ -65,6 +72,7 @@
|
|||||||
MenuItem: createAsyncComponent(() => import('./DropMenuItem.vue')),
|
MenuItem: createAsyncComponent(() => import('./DropMenuItem.vue')),
|
||||||
MenuDivider: Menu.Divider,
|
MenuDivider: Menu.Divider,
|
||||||
LockAction: createAsyncComponent(() => import('../lock/LockModal.vue')),
|
LockAction: createAsyncComponent(() => import('../lock/LockModal.vue')),
|
||||||
|
ChangeApi: createAsyncComponent(() => import('../ChangeApi/index.vue')),
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
theme: propTypes.oneOf(['dark', 'light']),
|
theme: propTypes.oneOf(['dark', 'light']),
|
||||||
@@ -72,7 +80,7 @@
|
|||||||
setup() {
|
setup() {
|
||||||
const { prefixCls } = useDesign('header-user-dropdown');
|
const { prefixCls } = useDesign('header-user-dropdown');
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { getShowDoc, getUseLockPage } = useHeaderSetting();
|
const { getShowDoc, getUseLockPage, getShowApi } = useHeaderSetting();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
const getUserInfo = computed(() => {
|
const getUserInfo = computed(() => {
|
||||||
@@ -81,11 +89,16 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [register, { openModal }] = useModal();
|
const [register, { openModal }] = useModal();
|
||||||
|
const [registerApi, { openModal: openApiModal }] = useModal();
|
||||||
|
|
||||||
function handleLock() {
|
function handleLock() {
|
||||||
openModal(true);
|
openModal(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleApi() {
|
||||||
|
openApiModal(true, {});
|
||||||
|
}
|
||||||
|
|
||||||
// login out
|
// login out
|
||||||
function handleLoginOut() {
|
function handleLoginOut() {
|
||||||
userStore.confirmLoginOut();
|
userStore.confirmLoginOut();
|
||||||
@@ -107,6 +120,9 @@
|
|||||||
case 'lock':
|
case 'lock':
|
||||||
handleLock();
|
handleLock();
|
||||||
break;
|
break;
|
||||||
|
case 'api':
|
||||||
|
handleApi();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +132,9 @@
|
|||||||
getUserInfo,
|
getUserInfo,
|
||||||
handleMenuClick,
|
handleMenuClick,
|
||||||
getShowDoc,
|
getShowDoc,
|
||||||
|
getShowApi,
|
||||||
register,
|
register,
|
||||||
|
registerApi,
|
||||||
getUseLockPage,
|
getUseLockPage,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
"onlineDocument": "Document"
|
"onlineDocument": "Document"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
|
"dropdownChangeApi": "Change Api",
|
||||||
"dropdownItemDoc": "Document",
|
"dropdownItemDoc": "Document",
|
||||||
"dropdownItemLoginOut": "Log Out",
|
"dropdownItemLoginOut": "Log Out",
|
||||||
"tooltipErrorLog": "Error log",
|
"tooltipErrorLog": "Error log",
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
"onlineDocument": "在线文档"
|
"onlineDocument": "在线文档"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
|
"dropdownChangeApi": "切换API",
|
||||||
"dropdownItemDoc": "文档",
|
"dropdownItemDoc": "文档",
|
||||||
"dropdownItemLoginOut": "退出系统",
|
"dropdownItemLoginOut": "退出系统",
|
||||||
"tooltipErrorLog": "错误日志",
|
"tooltipErrorLog": "错误日志",
|
||||||
|
@@ -74,6 +74,7 @@ const setting: ProjectConfig = {
|
|||||||
showNotice: true,
|
showNotice: true,
|
||||||
// Whether to display the menu search
|
// Whether to display the menu search
|
||||||
showSearch: true,
|
showSearch: true,
|
||||||
|
showApi: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Menu configuration
|
// Menu configuration
|
||||||
|
@@ -5,13 +5,13 @@ import type {
|
|||||||
TransitionSetting,
|
TransitionSetting,
|
||||||
MultiTabsSetting,
|
MultiTabsSetting,
|
||||||
} from '/#/config';
|
} from '/#/config';
|
||||||
import type { BeforeMiniState } from '/#/store';
|
import type { BeforeMiniState, ApiAddress } from '/#/store';
|
||||||
|
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { store } from '/@/store';
|
import { store } from '/@/store';
|
||||||
|
|
||||||
import { ThemeEnum } from '/@/enums/appEnum';
|
import { ThemeEnum } from '/@/enums/appEnum';
|
||||||
import { APP_DARK_MODE_KEY, PROJ_CFG_KEY } from '/@/enums/cacheEnum';
|
import { APP_DARK_MODE_KEY, PROJ_CFG_KEY, API_ADDRESS } from '/@/enums/cacheEnum';
|
||||||
import { Persistent } from '/@/utils/cache/persistent';
|
import { Persistent } from '/@/utils/cache/persistent';
|
||||||
import { darkMode } from '/@/settings/designSetting';
|
import { darkMode } from '/@/settings/designSetting';
|
||||||
import { resetRouter } from '/@/router';
|
import { resetRouter } from '/@/router';
|
||||||
@@ -63,6 +63,9 @@ export const useAppStore = defineStore({
|
|||||||
getMultiTabsSetting(): MultiTabsSetting {
|
getMultiTabsSetting(): MultiTabsSetting {
|
||||||
return this.getProjectConfig.multiTabsSetting;
|
return this.getProjectConfig.multiTabsSetting;
|
||||||
},
|
},
|
||||||
|
getApiAddress() {
|
||||||
|
return JSON.parse(localStorage.getItem(API_ADDRESS) || '{}');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
setPageLoading(loading: boolean): void {
|
setPageLoading(loading: boolean): void {
|
||||||
@@ -103,6 +106,9 @@ export const useAppStore = defineStore({
|
|||||||
clearTimeout(timeId);
|
clearTimeout(timeId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setApiAddress(config: ApiAddress): void {
|
||||||
|
localStorage.setItem(API_ADDRESS, JSON.stringify(config));
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import type { GlobEnvConfig } from '/#/config';
|
import type { GlobEnvConfig } from '/#/config';
|
||||||
import pkg from '../../package.json';
|
import pkg from '../../package.json';
|
||||||
|
import { API_ADDRESS } from '/@/enums/cacheEnum';
|
||||||
|
|
||||||
export function getCommonStoragePrefix() {
|
export function getCommonStoragePrefix() {
|
||||||
const { VITE_GLOB_APP_TITLE } = getAppEnvConfig();
|
const { VITE_GLOB_APP_TITLE } = getAppEnvConfig();
|
||||||
@@ -29,9 +30,12 @@ export function getAppEnvConfig() {
|
|||||||
? // Get the global configuration (the configuration will be extracted independently when packaging)
|
? // Get the global configuration (the configuration will be extracted independently when packaging)
|
||||||
(import.meta.env as unknown as GlobEnvConfig)
|
(import.meta.env as unknown as GlobEnvConfig)
|
||||||
: (window[ENV_NAME] as unknown as GlobEnvConfig);
|
: (window[ENV_NAME] as unknown as GlobEnvConfig);
|
||||||
const { VITE_GLOB_APP_TITLE, VITE_GLOB_API_URL, VITE_GLOB_API_URL_PREFIX, VITE_GLOB_UPLOAD_URL } =
|
const { VITE_GLOB_APP_TITLE, VITE_GLOB_API_URL_PREFIX, VITE_GLOB_UPLOAD_URL } = ENV;
|
||||||
ENV;
|
let { VITE_GLOB_API_URL } = ENV;
|
||||||
|
if (localStorage.getItem(API_ADDRESS)) {
|
||||||
|
const address = JSON.parse(localStorage.getItem(API_ADDRESS) || '{}');
|
||||||
|
if (address?.key) VITE_GLOB_API_URL = address?.val;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
VITE_GLOB_APP_TITLE,
|
VITE_GLOB_APP_TITLE,
|
||||||
VITE_GLOB_API_URL,
|
VITE_GLOB_API_URL,
|
||||||
|
1
types/config.d.ts
vendored
1
types/config.d.ts
vendored
@@ -57,6 +57,7 @@ export interface HeaderSetting {
|
|||||||
// Show message center button
|
// Show message center button
|
||||||
showNotice: boolean;
|
showNotice: boolean;
|
||||||
showSearch: boolean;
|
showSearch: boolean;
|
||||||
|
showApi: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LocaleSetting {
|
export interface LocaleSetting {
|
||||||
|
5
types/store.d.ts
vendored
5
types/store.d.ts
vendored
@@ -10,6 +10,11 @@ export interface LockInfo {
|
|||||||
isLock?: boolean;
|
isLock?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ApiAddress {
|
||||||
|
key: string;
|
||||||
|
val: string;
|
||||||
|
}
|
||||||
|
|
||||||
// Error-log information
|
// Error-log information
|
||||||
export interface ErrorLogInfo {
|
export interface ErrorLogInfo {
|
||||||
// Type of error
|
// Type of error
|
||||||
|
Reference in New Issue
Block a user