✨ 添加系统设置页面.
This commit is contained in:
@@ -12,7 +12,6 @@ import com.orion.lang.utils.crypto.Caesars;
|
|||||||
*/
|
*/
|
||||||
public class Mixes {
|
public class Mixes {
|
||||||
|
|
||||||
|
|
||||||
private Mixes() {
|
private Mixes() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
### 查询应用信息
|
### 查询应用信息
|
||||||
GET {{baseUrl}}/infra/system/app-info
|
GET {{baseUrl}}/infra/system-setting/app-info
|
||||||
Authorization: {{token}}
|
Authorization: {{token}}
|
||||||
|
|
||||||
@@ -4,7 +4,7 @@ import com.orion.visor.framework.log.core.annotation.IgnoreLog;
|
|||||||
import com.orion.visor.framework.log.core.enums.IgnoreLogMode;
|
import com.orion.visor.framework.log.core.enums.IgnoreLogMode;
|
||||||
import com.orion.visor.framework.web.core.annotation.RestWrapper;
|
import com.orion.visor.framework.web.core.annotation.RestWrapper;
|
||||||
import com.orion.visor.module.infra.entity.vo.AppInfoVO;
|
import com.orion.visor.module.infra.entity.vo.AppInfoVO;
|
||||||
import com.orion.visor.module.infra.service.SystemService;
|
import com.orion.visor.module.infra.service.SystemSettingService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -27,18 +27,18 @@ import javax.annotation.Resource;
|
|||||||
@Validated
|
@Validated
|
||||||
@RestWrapper
|
@RestWrapper
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/infra/system")
|
@RequestMapping("/infra/system-setting")
|
||||||
@SuppressWarnings({"ELValidationInJSP", "SpringElInspection"})
|
@SuppressWarnings({"ELValidationInJSP", "SpringElInspection"})
|
||||||
public class SystemController {
|
public class SystemSettingController {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private SystemService systemService;
|
private SystemSettingService systemSettingService;
|
||||||
|
|
||||||
@IgnoreLog(IgnoreLogMode.RET)
|
@IgnoreLog(IgnoreLogMode.RET)
|
||||||
@GetMapping("/app-info")
|
@GetMapping("/app-info")
|
||||||
@Operation(summary = "查询应用信息")
|
@Operation(summary = "查询应用信息")
|
||||||
public AppInfoVO getAppInfo() {
|
public AppInfoVO getAppInfo() {
|
||||||
return systemService.getAppInfo();
|
return systemSettingService.getAppInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ import com.orion.visor.module.infra.entity.vo.AppInfoVO;
|
|||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
* @since 2024/6/17 18:10
|
* @since 2024/6/17 18:10
|
||||||
*/
|
*/
|
||||||
public interface SystemService {
|
public interface SystemSettingService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取应用信息
|
* 获取应用信息
|
||||||
@@ -7,7 +7,7 @@ import com.orion.visor.framework.common.constant.AppConst;
|
|||||||
import com.orion.visor.framework.common.constant.Const;
|
import com.orion.visor.framework.common.constant.Const;
|
||||||
import com.orion.visor.framework.common.utils.Mixes;
|
import com.orion.visor.framework.common.utils.Mixes;
|
||||||
import com.orion.visor.module.infra.entity.vo.AppInfoVO;
|
import com.orion.visor.module.infra.entity.vo.AppInfoVO;
|
||||||
import com.orion.visor.module.infra.service.SystemService;
|
import com.orion.visor.module.infra.service.SystemSettingService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,7 +18,7 @@ import org.springframework.stereotype.Service;
|
|||||||
* @since 2024/6/17 18:10
|
* @since 2024/6/17 18:10
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class SystemServiceImpl implements SystemService {
|
public class SystemSettingServiceImpl implements SystemSettingService {
|
||||||
|
|
||||||
private String uuid;
|
private String uuid;
|
||||||
|
|
||||||
@@ -13,7 +13,9 @@ export interface HttpResponse<T = unknown> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
axios.defaults.timeout = 10000;
|
axios.defaults.timeout = 10000;
|
||||||
|
axios.defaults.setAuthorization = true;
|
||||||
axios.defaults.promptBizErrorMessage = true;
|
axios.defaults.promptBizErrorMessage = true;
|
||||||
|
axios.defaults.promptRequestErrorMessage = true;
|
||||||
axios.defaults.baseURL = httpBaseUrl;
|
axios.defaults.baseURL = httpBaseUrl;
|
||||||
|
|
||||||
axios.interceptors.request.use(
|
axios.interceptors.request.use(
|
||||||
@@ -24,8 +26,11 @@ axios.interceptors.request.use(
|
|||||||
if (!config.headers) {
|
if (!config.headers) {
|
||||||
config.headers = {};
|
config.headers = {};
|
||||||
}
|
}
|
||||||
|
// 设置 Authorization 头
|
||||||
|
if (config.setAuthorization === true) {
|
||||||
config.headers.Authorization = `Bearer ${token}`;
|
config.headers.Authorization = `Bearer ${token}`;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
@@ -46,7 +51,7 @@ axios.interceptors.response.use(
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
// 异常判断
|
// 异常判断
|
||||||
if ([401, 700, 701, 702].includes(code)) {
|
if ([401, 700, 701, 702, 1000, 1001].includes(code)) {
|
||||||
// 提示
|
// 提示
|
||||||
Message.error({
|
Message.error({
|
||||||
content: res.msg || 'Error',
|
content: res.msg || 'Error',
|
||||||
@@ -60,7 +65,10 @@ axios.interceptors.response.use(
|
|||||||
window.sessionStorage.setItem(reLoginTipsKey, res.msg);
|
window.sessionStorage.setItem(reLoginTipsKey, res.msg);
|
||||||
}
|
}
|
||||||
// 登出
|
// 登出
|
||||||
|
const responseUrl = response.request?.responseURL;
|
||||||
|
if (!responseUrl || !responseUrl.includes('/logout')) {
|
||||||
await useUserStore().logout();
|
await useUserStore().logout();
|
||||||
|
}
|
||||||
// 重新加载自动跳转登录页面
|
// 重新加载自动跳转登录页面
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
@@ -76,10 +84,13 @@ axios.interceptors.response.use(
|
|||||||
return Promise.reject(new Error(res.msg || 'Error'));
|
return Promise.reject(new Error(res.msg || 'Error'));
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
|
// 判断是否弹出请求错误信息
|
||||||
|
if (error.config.promptRequestErrorMessage) {
|
||||||
Message.error({
|
Message.error({
|
||||||
content: error.msg || '请求失败',
|
content: error.msg || '请求失败',
|
||||||
duration: 5 * 1000,
|
duration: 5 * 1000,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
38
orion-visor-ui/src/api/system/setting.ts
Normal file
38
orion-visor-ui/src/api/system/setting.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用信息查询响应
|
||||||
|
*/
|
||||||
|
export interface AppInfoResponse {
|
||||||
|
version: string;
|
||||||
|
uuid: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仓库版本信息查询响应
|
||||||
|
*/
|
||||||
|
export interface RepoReleaseResponse {
|
||||||
|
tag_name: string;
|
||||||
|
body: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询应用信息
|
||||||
|
*/
|
||||||
|
export function getSystemAppInfo() {
|
||||||
|
return axios.get<AppInfoResponse>('/infra/system-setting/app-info');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取仓库最后版本信息
|
||||||
|
*/
|
||||||
|
export function getRepoLatestRelease() {
|
||||||
|
return axios.get<RepoReleaseResponse>('https://gitee.com/api/v5/repos/dromara/orion-visor/releases/latest', {
|
||||||
|
// 不添加请求头 否则会报 401
|
||||||
|
setAuthorization: false,
|
||||||
|
// 返回原始输出
|
||||||
|
unwrap: true,
|
||||||
|
// 不提示请求错误信息 可能会 403
|
||||||
|
promptRequestErrorMessage: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -21,6 +21,11 @@ const SYSTEM: AppRouteRecordRaw = {
|
|||||||
path: '/dict-value',
|
path: '/dict-value',
|
||||||
component: () => import('@/views/system/dict-value/index.vue'),
|
component: () => import('@/views/system/dict-value/index.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'systemSetting',
|
||||||
|
path: '/system-setting',
|
||||||
|
component: () => import('@/views/system/setting/index.vue'),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
4
orion-visor-ui/src/types/axios.d.ts
vendored
4
orion-visor-ui/src/types/axios.d.ts
vendored
@@ -4,9 +4,13 @@ import type { AxiosRequestConfig } from 'axios';
|
|||||||
declare module 'axios' {
|
declare module 'axios' {
|
||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
export interface AxiosRequestConfig {
|
export interface AxiosRequestConfig {
|
||||||
|
// 是否添加 Authorization
|
||||||
|
setAuthorization?: boolean;
|
||||||
// 是否使用原始返回
|
// 是否使用原始返回
|
||||||
unwrap?: boolean;
|
unwrap?: boolean;
|
||||||
// 是否提示业务错误信息
|
// 是否提示业务错误信息
|
||||||
promptBizErrorMessage?: boolean;
|
promptBizErrorMessage?: boolean;
|
||||||
|
// 是否提示请求错误信息
|
||||||
|
promptRequestErrorMessage?: boolean;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
126
orion-visor-ui/src/views/system/setting/components/about.vue
Normal file
126
orion-visor-ui/src/views/system/setting/components/about.vue
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
<template>
|
||||||
|
<div class="main-container">
|
||||||
|
<h3>关于 Orion Visor</h3>
|
||||||
|
<!-- 不一致提示 -->
|
||||||
|
<a-alert v-if="app.version && webVersion !== app.version"
|
||||||
|
class="alert-wrapper">
|
||||||
|
当前前端版本与后端版本不一致, 请使用 Ctrl + F5 刷新页面
|
||||||
|
</a-alert>
|
||||||
|
<!-- 升级提示 -->
|
||||||
|
<a v-if="app.version && repo.tag_name && ('v' + app.version) !== repo.tag_name"
|
||||||
|
class="alert-href"
|
||||||
|
target="_blank"
|
||||||
|
:href="`https://github.com/dromara/orion-visor/releases/tag/${repo.tag_name}`">
|
||||||
|
<a-alert class="alert-wrapper">
|
||||||
|
新版本已发布, 请及时升级版本
|
||||||
|
</a-alert>
|
||||||
|
</a>
|
||||||
|
<!-- 系统信息 -->
|
||||||
|
<a-descriptions class="detail-container"
|
||||||
|
size="large"
|
||||||
|
:align="{ label: 'right', value: 'left' }"
|
||||||
|
:label-style="{ width: '134px' }"
|
||||||
|
:column="1">
|
||||||
|
<!-- 机器码 -->
|
||||||
|
<a-descriptions-item label="机器码">
|
||||||
|
<span class="text-copy span-blue uuid-wrapper" @click="copy(app.uuid, '已复制')">
|
||||||
|
{{ app.uuid }}
|
||||||
|
</span>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<!-- 当前前端版本 -->
|
||||||
|
<a-descriptions-item label="当前前端版本">
|
||||||
|
{{ 'v' + webVersion }}
|
||||||
|
</a-descriptions-item>
|
||||||
|
<!-- 当前后端版本 -->
|
||||||
|
<a-descriptions-item label="当前后端版本">
|
||||||
|
{{ 'v' + app.version }}
|
||||||
|
</a-descriptions-item>
|
||||||
|
<!-- 当前后端版本 -->
|
||||||
|
<a-descriptions-item label="最新发布版本">
|
||||||
|
{{ repo.tag_name }}
|
||||||
|
</a-descriptions-item>
|
||||||
|
<!-- 当前后端版本 -->
|
||||||
|
<a-descriptions-item label="最新更新日志">
|
||||||
|
<a-textarea class="release-node"
|
||||||
|
v-model="repo.body"
|
||||||
|
:auto-size="{ minRows: 3, maxRows: 16 }"
|
||||||
|
readonly>
|
||||||
|
</a-textarea>
|
||||||
|
</a-descriptions-item>
|
||||||
|
</a-descriptions>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'systemSettingAbout',
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { AppInfoResponse, RepoReleaseResponse } from '@/api/system/setting';
|
||||||
|
import { onMounted, reactive } from 'vue';
|
||||||
|
import { getRepoLatestRelease, getSystemAppInfo } from '@/api/system/setting';
|
||||||
|
import { copy } from '@/hooks/copy';
|
||||||
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
|
const webVersion = import.meta.env.VITE_APP_VERSION;
|
||||||
|
|
||||||
|
const app = reactive<AppInfoResponse>({
|
||||||
|
version: '',
|
||||||
|
uuid: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const repo = reactive<RepoReleaseResponse>({
|
||||||
|
tag_name: '',
|
||||||
|
body: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载应用信息
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
const { data } = await getSystemAppInfo();
|
||||||
|
app.version = data.version;
|
||||||
|
app.uuid = data.uuid;
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载仓库信息
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
const { data } = await getRepoLatestRelease();
|
||||||
|
repo.tag_name = data.tag_name;
|
||||||
|
repo.body = data.body;
|
||||||
|
} catch (e) {
|
||||||
|
Message.error('获取仓库信息失败, 请等待后重试');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@release-node-width: 528px;
|
||||||
|
@label-width: 134px;
|
||||||
|
|
||||||
|
.main-container {
|
||||||
|
padding-left: 16px;
|
||||||
|
|
||||||
|
.alert-href {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-wrapper {
|
||||||
|
width: @release-node-width + @label-width;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uuid-wrapper {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.release-node {
|
||||||
|
width: @release-node-width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
52
orion-visor-ui/src/views/system/setting/index.vue
Normal file
52
orion-visor-ui/src/views/system/setting/index.vue
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<template>
|
||||||
|
<div class="tabs-container">
|
||||||
|
<a-tabs type="rounded"
|
||||||
|
size="medium"
|
||||||
|
position="left"
|
||||||
|
:lazy-load="true"
|
||||||
|
:destroy-on-hide="true">
|
||||||
|
<!-- 关于 -->
|
||||||
|
<a-tab-pane key="about" title="关于">
|
||||||
|
<about />
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'systemSetting'
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import About from './components/about.vue';
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.tabs-container {
|
||||||
|
background: var(--color-bg-2);
|
||||||
|
margin: 16px;
|
||||||
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-tabs-nav-tab-list) {
|
||||||
|
width: 88px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-tabs-pane) {
|
||||||
|
border-left: 1px var(--color-neutral-3) solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-tabs-tab) {
|
||||||
|
user-select: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user