使用vitejs+vue3+antdv重构swagger文档展示
This commit is contained in:
35
zyplayer-doc-ui/swagger-ui/src/App.vue
Normal file
35
zyplayer-doc-ui/swagger-ui/src/App.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<el-config-provider :locale="localeEl">
|
||||
<a-config-provider :locale="locale">
|
||||
<router-view></router-view>
|
||||
</a-config-provider>
|
||||
</el-config-provider>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import zhCN from 'ant-design-vue/es/locale/zh_CN';
|
||||
import zhCnEl from 'element-plus/lib/locale/lang/zh-cn';
|
||||
import 'moment/dist/locale/zh-cn';
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
locale: zhCN,
|
||||
localeEl: zhCnEl,
|
||||
};
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
html, body, #app {
|
||||
height: 100%;
|
||||
background: #f0f2f5;
|
||||
}
|
||||
.ant-btn+.ant-btn{
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
3
zyplayer-doc-ui/swagger-ui/src/api/index.js
Normal file
3
zyplayer-doc-ui/swagger-ui/src/api/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export { zyplayerApi } from './zyplayer.js';
|
||||
|
||||
|
||||
61
zyplayer-doc-ui/swagger-ui/src/api/request/interceptors.js
Normal file
61
zyplayer-doc-ui/swagger-ui/src/api/request/interceptors.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import qs from 'qs'
|
||||
import { message } from 'ant-design-vue';
|
||||
import {getZyplayerApiBaseUrl} from "./utils";
|
||||
|
||||
// 增加不需要验证结果的标记
|
||||
const noValidate = {
|
||||
"/zyplayer-doc-db/executor/execute": true,
|
||||
"/zyplayer-doc-db/datasource/test": true,
|
||||
};
|
||||
|
||||
export default function (axios) {
|
||||
axios.interceptors.request.use(
|
||||
config => {
|
||||
config.needValidateResult = true;
|
||||
// 增加不需要验证结果的标记
|
||||
if (noValidate[config.url]) {
|
||||
config.needValidateResult = false;
|
||||
}
|
||||
if (config.method === 'get') {
|
||||
config.params = config.params || {};
|
||||
config.params = {...config.params, _: (new Date()).getTime()}
|
||||
} else if (config.method === 'post') {
|
||||
config.data = config.data || {};
|
||||
if (config.data instanceof FormData) {
|
||||
// 表单,无需特殊处理
|
||||
} else if (config.data instanceof Object) {
|
||||
config.data = qs.stringify(config.data);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
error => {
|
||||
console.log(error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
axios.interceptors.response.use(
|
||||
response => {
|
||||
if (!!response.message) {
|
||||
vue.$message.error('请求错误:' + response.message);
|
||||
}else {
|
||||
if (!response.config.needValidateResult || response.data.errCode === 200) {
|
||||
return response.data;
|
||||
} else if (response.data.errCode === 400) {
|
||||
message.error('请先登录');
|
||||
let href = encodeURIComponent(window.location.href);
|
||||
window.location = getZyplayerApiBaseUrl() + "#/user/login?redirect=" + href;
|
||||
} else {
|
||||
message.error(response.data.errMsg || "未知错误");
|
||||
}
|
||||
}
|
||||
return Promise.reject('请求错误');
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error);
|
||||
message.error('请求错误:' + error.message);
|
||||
return Promise.reject(error)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
13
zyplayer-doc-ui/swagger-ui/src/api/request/utils.js
Normal file
13
zyplayer-doc-ui/swagger-ui/src/api/request/utils.js
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
/**
|
||||
* 获取zyplayer后端域名
|
||||
*/
|
||||
export function getZyplayerApiBaseUrl() {
|
||||
let env = import.meta.env.VITE_APP_ENV;
|
||||
let baseUrl = import.meta.env.VITE_APP_BASE_URL_ONLINE;
|
||||
if ("dev" === env) {
|
||||
baseUrl = import.meta.env.VITE_APP_BASE_URL_DEV;
|
||||
}
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
14
zyplayer-doc-ui/swagger-ui/src/api/request/zyplayer.js
Normal file
14
zyplayer-doc-ui/swagger-ui/src/api/request/zyplayer.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import Axios from 'axios'
|
||||
import interceptors from './interceptors'
|
||||
import {getZyplayerApiBaseUrl} from "./utils";
|
||||
|
||||
const apiClient = Axios.create({
|
||||
baseURL: getZyplayerApiBaseUrl(),
|
||||
timeout: 20000,
|
||||
headers: {'Content-type': 'application/x-www-form-urlencoded'},
|
||||
withCredentials: true
|
||||
});
|
||||
interceptors(apiClient);
|
||||
|
||||
export default apiClient;
|
||||
|
||||
8
zyplayer-doc-ui/swagger-ui/src/api/zyplayer.js
Normal file
8
zyplayer-doc-ui/swagger-ui/src/api/zyplayer.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import apiClient from './request/zyplayer.js'
|
||||
|
||||
export const zyplayerApi = {
|
||||
getSelfUserInfo: data => apiClient({url: '/user/info/selfInfo', method: 'post', data: data}),
|
||||
userLogout: data => apiClient({url: '/logout', method: 'post', data: data}),
|
||||
systemUpgradeInfo: data => apiClient({url: '/system/info/upgrade', method: 'post', data: data}),
|
||||
};
|
||||
|
||||
BIN
zyplayer-doc-ui/swagger-ui/src/assets/logo.png
Normal file
BIN
zyplayer-doc-ui/swagger-ui/src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<router-view></router-view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'EmptyLayout',
|
||||
components: {},
|
||||
props: [],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div class="footer">
|
||||
<div class="links">
|
||||
<a target="_blank" :key="index" :href="item.link ? item.link : 'javascript: void(0)'" v-for="(item, index) in linkList">
|
||||
<a-icon v-if="item.icon" :type="item.icon"/>{{item.name}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="copyright">
|
||||
Copyright<a-icon type="copyright" /> {{copyright}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'GlobalFooter',
|
||||
props: ['copyright', 'linkList']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.footer {
|
||||
padding: 0 16px;
|
||||
margin: 48px 0 24px;
|
||||
text-align: center;
|
||||
}
|
||||
.footer .copyright {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
font-size: 14px;
|
||||
}
|
||||
.footer .links {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.footer .links a:not(:last-child) {
|
||||
margin-right: 40px;
|
||||
}
|
||||
.footer .links a {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
-webkit-transition: all .3s;
|
||||
transition: all .3s;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<a-layout class="swagger-menu-trigger">
|
||||
<a-layout-sider theme="light" :trigger="null" collapsible v-model:collapsed="appMenuCollapsed" :width="rightAsideWidth" style="height: 100vh;overflow: auto;">
|
||||
<div class="logo">
|
||||
<router-link to="/doc/console">
|
||||
<img src="../../assets/logo.png">
|
||||
<h1>swagger文档管理</h1>
|
||||
</router-link>
|
||||
</div>
|
||||
<menu-layout></menu-layout>
|
||||
</a-layout-sider>
|
||||
<div ref="rightResize" class="right-resize" v-show="!appMenuCollapsed">
|
||||
<i ref="rightResizeBar">...</i>
|
||||
</div>
|
||||
<a-layout>
|
||||
<a-layout-header style="border-bottom: 2px solid #eee;background: #fff; padding: 0; box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);-webkit-box-shadow:0 1px 4px rgba(0, 21, 41, 0.08);">
|
||||
<a-row type="flex">
|
||||
<a-col flex="60px">
|
||||
<MenuUnfoldOutlined class="trigger" v-if="appMenuCollapsed" @click="appMenuCollapsed = !appMenuCollapsed"/>
|
||||
<MenuFoldOutlined class="trigger" v-else @click="appMenuCollapsed = !appMenuCollapsed"/>
|
||||
</a-col>
|
||||
<a-col flex="auto" style="text-align: center;">
|
||||
<span v-if="initialEnv === 'newGray'" class="initial-env">当前环境:灰度</span>
|
||||
</a-col>
|
||||
<a-col flex="400px" style="text-align: right;padding-right: 20px;">
|
||||
<header-avatar></header-avatar>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-layout-header>
|
||||
<a-layout-content style="height: calc(100vh - 80px);overflow: auto;background: #fff;">
|
||||
<router-view></router-view>
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
</a-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HeaderAvatar from './HeaderAvatar.vue'
|
||||
import MenuLayout from './MenuLayout.vue'
|
||||
import GlobalFooter from './GlobalFooter.vue'
|
||||
import {BarChartOutlined, MenuFoldOutlined, MenuUnfoldOutlined} from '@ant-design/icons-vue';
|
||||
|
||||
const minHeight = window.innerHeight - 64 - 122;
|
||||
export default {
|
||||
name: 'GlobalLayout',
|
||||
components: {HeaderAvatar, MenuLayout, GlobalFooter, BarChartOutlined, MenuFoldOutlined, MenuUnfoldOutlined},
|
||||
data() {
|
||||
return {
|
||||
minHeight: minHeight + 'px',
|
||||
appMenuCollapsed: false,
|
||||
rightAsideWidth: 250
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
initialEnv () {
|
||||
return this.$store.state.initialEnv;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.dragChangeRightAsideWidth();
|
||||
},
|
||||
methods: {
|
||||
dragChangeRightAsideWidth: function() {
|
||||
// 保留this引用
|
||||
let resize = this.$refs.rightResize;
|
||||
let resizeBar = this.$refs.rightResizeBar;
|
||||
resize.onmousedown = e => {
|
||||
let startX = e.clientX;
|
||||
// 颜色改变提醒
|
||||
resize.style.background = "#ccc";
|
||||
resizeBar.style.background = "#aaa";
|
||||
resize.left = resize.offsetLeft;
|
||||
document.onmousemove = e2 => {
|
||||
// 计算并应用位移量
|
||||
let endX = e2.clientX;
|
||||
let moveLen = startX - endX;
|
||||
if ((moveLen < 0 && this.rightAsideWidth < 600) || (moveLen > 0 && this.rightAsideWidth > 250)) {
|
||||
startX = endX;
|
||||
this.rightAsideWidth -= moveLen;
|
||||
}
|
||||
};
|
||||
document.onmouseup = () => {
|
||||
// 颜色恢复
|
||||
resize.style.background = "#fafafa";
|
||||
resizeBar.style.background = "#ccc";
|
||||
document.onmousemove = null;
|
||||
document.onmouseup = null;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.trigger {
|
||||
font-size: 20px;
|
||||
line-height: 64px;
|
||||
padding: 0 24px;
|
||||
cursor: pointer;
|
||||
transition: color .3s;
|
||||
}
|
||||
|
||||
.trigger:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 64px;
|
||||
position: relative;
|
||||
line-height: 64px;
|
||||
padding-left: 24px;
|
||||
-webkit-transition: all .3s;
|
||||
transition: all .3s;
|
||||
overflow: hidden;
|
||||
background: #1d4e89;
|
||||
}
|
||||
|
||||
.logo h1 {
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
margin: 0 0 0 12px;
|
||||
font-family: "Myriad Pro", "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
font-weight: 600;
|
||||
display: inline-block;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.logo img {
|
||||
width: 32px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.swagger-menu-trigger {
|
||||
min-height: 100%;
|
||||
}
|
||||
.right-resize {
|
||||
width: 5px;
|
||||
cursor: w-resize;
|
||||
background: #fafafa;
|
||||
}
|
||||
.right-resize i{
|
||||
margin-top: 300px;
|
||||
width: 5px;
|
||||
height: 35px;
|
||||
display: inline-block;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
line-height: 8px;
|
||||
border-radius: 5px;
|
||||
background: #ccc;
|
||||
color: #888;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.ant-layout-sider {
|
||||
transition: none;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<a-dropdown trigger="click">
|
||||
<a class="ant-dropdown-link" @click.prevent style="display: inline-block; height: 100%; vertical-align: initial;">
|
||||
<UserOutlined /> {{currUser.userName || '-'}}
|
||||
</a>
|
||||
<template #overlay>
|
||||
<a-menu >
|
||||
<a-menu-item @click="showConsole" key="1">控制台</a-menu-item>
|
||||
<a-menu-divider />
|
||||
<a-menu-item @click="showAbout" key="2">关于</a-menu-item>
|
||||
<a-menu-item @click="showMyInfo" key="3">我的资料</a-menu-item>
|
||||
<a-menu-item @click="userSignOut" key="4">退出登录</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
<about-dialog ref="aboutDialog"></about-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {zyplayerApi} from '../../api/index';
|
||||
import {getZyplayerApiBaseUrl} from '../../api/request/utils.js';
|
||||
import aboutDialog from '../../views/common/AboutDialog.vue'
|
||||
import {DownOutlined, UserOutlined} from '@ant-design/icons-vue';
|
||||
|
||||
export default {
|
||||
name: 'HeaderAvatar',
|
||||
data() {
|
||||
return {
|
||||
currUser: {},
|
||||
};
|
||||
},
|
||||
components: {DownOutlined, UserOutlined, aboutDialog},
|
||||
mounted() {
|
||||
this.getSelfUserInfo();
|
||||
},
|
||||
methods: {
|
||||
showAbout() {
|
||||
this.$refs.aboutDialog.show();
|
||||
},
|
||||
showConsole() {
|
||||
window.open(getZyplayerApiBaseUrl(), '_blank');
|
||||
},
|
||||
showMyInfo() {
|
||||
this.$router.push({path: '/user/myInfo'});
|
||||
},
|
||||
userSignOut() {
|
||||
zyplayerApi.userLogout().then(() => {
|
||||
location.reload();
|
||||
});
|
||||
},
|
||||
getSelfUserInfo() {
|
||||
zyplayerApi.getSelfUserInfo().then(json=>{
|
||||
this.currUser = json.data;
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.avatar {
|
||||
margin: 20px 4px 20px 0;
|
||||
color: #1890ff;
|
||||
background: hsla(0, 0%, 100%, .85);
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<template class="menu-layout-children" v-if="!menuItem.meta || !menuItem.meta.hidden">
|
||||
<template v-if="!!menuItem.children">
|
||||
<a-sub-menu :key="menuItem.path" v-if="haveShowChildren(menuItem.children)">
|
||||
<template #title>
|
||||
<template v-if="menuItem.meta">
|
||||
<SettingOutlined v-if="menuItem.meta.icon === 'SettingOutlined'"/>
|
||||
<FileTextOutlined v-if="menuItem.meta.icon === 'FileTextOutlined'"/>
|
||||
</template>
|
||||
<span>{{menuItem.name}}</span>
|
||||
</template>
|
||||
<MenuLayoutChildren :menuItem="children" v-for="children in menuItem.children"></MenuLayoutChildren>
|
||||
</a-sub-menu>
|
||||
</template>
|
||||
<a-menu-item :key="menuItem.path" v-else>
|
||||
<router-link :to="{path: menuItem.path, query: menuItem.query}">
|
||||
<template v-if="menuItem.meta">
|
||||
<DashboardOutlined v-if="menuItem.meta.icon === 'DashboardOutlined'"/>
|
||||
</template>
|
||||
<span>{{menuItem.name}}</span>
|
||||
</router-link>
|
||||
</a-menu-item>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
StarOutlined,
|
||||
SettingOutlined,
|
||||
CarryOutOutlined,
|
||||
FileTextOutlined,
|
||||
DashboardOutlined
|
||||
} from '@ant-design/icons-vue';
|
||||
|
||||
export default {
|
||||
name: 'MenuLayoutChildren',
|
||||
props: {
|
||||
menuItem: Object,
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
components: {
|
||||
StarOutlined, SettingOutlined, CarryOutOutlined, FileTextOutlined,
|
||||
DashboardOutlined
|
||||
},
|
||||
methods: {
|
||||
haveShowChildren(children) {
|
||||
return children.filter(item => (!item.meta || !item.meta.hidden)).length > 0;
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
109
zyplayer-doc-ui/swagger-ui/src/components/layouts/MenuLayout.vue
Normal file
109
zyplayer-doc-ui/swagger-ui/src/components/layouts/MenuLayout.vue
Normal file
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div class="menu-layout">
|
||||
<a-menu theme="light" mode="inline" :inline-collapsed="collapsed" v-model:openKeys="openKeys" v-model:selectedKeys="selectedKeys">
|
||||
<menu-children-layout :menuItem="menuItem" v-for="menuItem in menuData"></menu-children-layout>
|
||||
</a-menu>
|
||||
<a-directory-tree :tree-data="treeData" v-model:expandedKeys="expandedKeys" @select="docChecked">
|
||||
<a-tree-node key="0-0" title="parent 0">
|
||||
<a-tree-node key="0-0-0" is-leaf >
|
||||
<template #title>
|
||||
<router-link :to="{path: '/doc/view', query: {id: 1}}">leaf 0-0</router-link>
|
||||
</template>
|
||||
</a-tree-node>
|
||||
<a-tree-node key="0-0-1" is-leaf >
|
||||
<template #title>
|
||||
<router-link :to="{path: '/doc/view', query: {id: 2}}">leaf 0-1</router-link>
|
||||
</template>
|
||||
</a-tree-node>
|
||||
</a-tree-node>
|
||||
<a-tree-node key="0-1" title="parent 1">
|
||||
<a-tree-node key="0-1-0" title="leaf 1-0" is-leaf />
|
||||
<a-tree-node key="0-1-1" title="leaf 1-1" is-leaf />
|
||||
</a-tree-node>
|
||||
</a-directory-tree>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MenuChildrenLayout from './MenuChildrenLayout.vue'
|
||||
|
||||
export default {
|
||||
name: 'MenuLayout',
|
||||
data() {
|
||||
return {
|
||||
menuData: [],
|
||||
selectedKeys: [],
|
||||
openKeys: [],
|
||||
collapsed: false,
|
||||
// 文档树
|
||||
treeData: [
|
||||
{
|
||||
title: '用户管理接口文档',
|
||||
key: '0-0',
|
||||
children: [
|
||||
{
|
||||
title: '用户信息管理',
|
||||
key: '0-0-0',
|
||||
children: [
|
||||
{title: '/getUserInfo', key: '0-0-0-0', isLeaf: true, path: '/doc/view', query: {path: '/getUserInfo'}},
|
||||
{title: '/deleteUserInfo', key: '0-0-0-1', isLeaf: true, path: '/doc/view', query: {path: '/deleteUserInfo'}},
|
||||
{title: '/updateUserInfo', key: '0-0-0-2', isLeaf: true, path: '/doc/view', query: {path: '/updateUserInfo'}},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
expandedKeys: [],
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
'$store.state.userInfo'(userInfo) {
|
||||
}
|
||||
},
|
||||
components: {MenuChildrenLayout},
|
||||
mounted() {
|
||||
this.getMenuData();
|
||||
let meta = this.$route.meta || {};
|
||||
let path = this.$route.path;
|
||||
if (!!meta.parentPath) {
|
||||
path = meta.parentPath;
|
||||
}
|
||||
this.selectedKeys = [path];
|
||||
let matched = this.$route.matched;
|
||||
if (matched.length >= 1) {
|
||||
this.openKeys = [matched[1].path];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getMenuData() {
|
||||
let menuData = this.$router.options.routes.find((item) => item.path === '/').children[0].children;
|
||||
this.menuData = JSON.parse(JSON.stringify(menuData));
|
||||
// 模拟数据返回,暂时不以这种展示
|
||||
// setTimeout(() => {
|
||||
// this.menuData.push({
|
||||
// name: '用户管理接口',
|
||||
// meta: {icon: 'FileTextOutlined'},
|
||||
// children: [
|
||||
// {
|
||||
// path: '/doc/view?id=2',
|
||||
// name: '获取用户信息',
|
||||
// query: {id: 222}
|
||||
// }, {
|
||||
// path: '/doc/view?id=3',
|
||||
// name: '删除用户',
|
||||
// query: {id: 333}
|
||||
// }
|
||||
// ]
|
||||
// });
|
||||
// }, 1000);
|
||||
},
|
||||
docChecked(val, node) {
|
||||
if (node.node.isLeaf) {
|
||||
let dataRef = node.node.dataRef;
|
||||
this.$router.push({path: dataRef.path, query: dataRef.query});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<div class="page-layout">
|
||||
<a-tabs type="card" v-model:activeKey="activePage" closable @tab-click="changePage" @edit="removePageTab" style="padding: 5px 10px 0;">
|
||||
<a-tab-pane :tab="pageTabNameMap[item.fullPath]||item.name" :name="getRouteRealPath(item)" :fullPath="item.fullPath" :key="item.fullPath" v-for="item in pageList"/>
|
||||
</a-tabs>
|
||||
<keep-alive>
|
||||
<router-view :key="$route.fullPath"/>
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'PageTableView',
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
pageList: [],
|
||||
linkList: [],
|
||||
activePage: '',
|
||||
multiPage: true,
|
||||
ignoreParamPath: [
|
||||
"/data/export",
|
||||
],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
pageTabNameMap () {
|
||||
return this.$store.state.pageTabNameMap;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
let {name, path, fullPath} = this.$route;
|
||||
this.pageList.push({name, path, fullPath});
|
||||
let activePage = this.getRouteRealPath(this.$route);
|
||||
this.linkList.push(activePage);
|
||||
this.activePage = activePage;
|
||||
this.$router.push(this.$route.fullPath);
|
||||
},
|
||||
watch: {
|
||||
'$route': function (newRoute, oldRoute) {
|
||||
let activePage = this.getRouteRealPath(newRoute);
|
||||
this.activePage = activePage;
|
||||
if (this.linkList.indexOf(activePage) < 0) {
|
||||
this.linkList.push(activePage);
|
||||
let {name, path, fullPath} = newRoute;
|
||||
this.pageList.push({name, path, fullPath});
|
||||
}
|
||||
let pageRoute = this.pageList.find(item => this.getRouteRealPath(item) === activePage);
|
||||
pageRoute.fullPath = newRoute.fullPath;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isIgnoreParamPath(path) {
|
||||
return this.ignoreParamPath.indexOf(path) >= 0;
|
||||
},
|
||||
getRouteRealPath(route) {
|
||||
return this.isIgnoreParamPath(route.path) ? route.path : route.fullPath;
|
||||
},
|
||||
changePage(tab) {
|
||||
let checkedTab = this.pageList.find(item => item.fullPath === tab);
|
||||
this.activePage = this.getRouteRealPath(checkedTab);
|
||||
this.$router.push(checkedTab.fullPath);
|
||||
},
|
||||
editPage(key, action) {
|
||||
this[action](key);
|
||||
},
|
||||
removePageTab(key) {
|
||||
if (this.pageList.length === 1) {
|
||||
this.$message.warning('这是最后一页,不能再关闭了啦');
|
||||
return;
|
||||
}
|
||||
this.pageList = this.pageList.filter(item => this.getRouteRealPath(item) !== key);
|
||||
this.linkList = this.linkList.filter(item => item !== key);
|
||||
let index = this.linkList.indexOf(this.activePage);
|
||||
if (index < 0) {
|
||||
index = this.linkList.length - 1;
|
||||
this.activePage = this.linkList[index];
|
||||
this.$router.push(this.activePage);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.page-layout{background: #fff;}
|
||||
.ant-tabs-bar{margin-bottom: 0;}
|
||||
</style>
|
||||
24
zyplayer-doc-ui/swagger-ui/src/main.js
Normal file
24
zyplayer-doc-ui/swagger-ui/src/main.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
import { createRouter, createWebHashHistory } from 'vue-router';
|
||||
|
||||
import Antd from 'ant-design-vue';
|
||||
import 'ant-design-vue/dist/antd.css';
|
||||
import routes from './routes'
|
||||
import store from './store/index'
|
||||
import { ElConfigProvider, ElCascader, ElCascaderPanel } from 'element-plus';
|
||||
import 'element-plus/lib/theme-chalk/base.css'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
});
|
||||
const app = createApp(App);
|
||||
app.config.productionTip = false;
|
||||
app.use(Antd);
|
||||
app.use(router);
|
||||
app.use(store);
|
||||
app.component(ElCascader.name, ElCascader);
|
||||
app.component(ElCascaderPanel.name, ElCascaderPanel);
|
||||
app.component(ElConfigProvider.name, ElConfigProvider);
|
||||
app.mount('#app');
|
||||
55
zyplayer-doc-ui/swagger-ui/src/routes.js
Normal file
55
zyplayer-doc-ui/swagger-ui/src/routes.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import PageLayout from './components/layouts/PageLayout.vue'
|
||||
import EmptyLayout from './components/layouts/EmptyLayout.vue'
|
||||
|
||||
let routers = [
|
||||
{
|
||||
path: '/',
|
||||
name: '主页',
|
||||
component: () => import('./components/layouts/GlobalLayout.vue'),
|
||||
redirect: '/doc/console',
|
||||
children: [
|
||||
{
|
||||
path: '/doc',
|
||||
name: '系统配置',
|
||||
meta: {
|
||||
icon: 'SettingOutlined'
|
||||
},
|
||||
component: PageLayout,
|
||||
children: [
|
||||
{
|
||||
path: '/doc/console',
|
||||
name: '控制台',
|
||||
meta: {
|
||||
icon: 'DashboardOutlined'
|
||||
},
|
||||
component: () => import('./views/common/Console.vue')
|
||||
},
|
||||
{
|
||||
path: '/doc/setting',
|
||||
name: '系统配置',
|
||||
meta: {
|
||||
icon: 'SettingOutlined'
|
||||
},
|
||||
component: EmptyLayout,
|
||||
children: [
|
||||
{
|
||||
path: '/doc/setting/view',
|
||||
name: '展示配置',
|
||||
component: () => import('./views/common/SettingView.vue')
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/doc/view',
|
||||
name: '文档展示',
|
||||
meta: {
|
||||
hidden: true,
|
||||
},
|
||||
component: () => import('./views/doc/DocView.vue')
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
export default routers;
|
||||
48
zyplayer-doc-ui/swagger-ui/src/store/index.js
Normal file
48
zyplayer-doc-ui/swagger-ui/src/store/index.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import {createStore} from 'vuex'
|
||||
|
||||
export default createStore({
|
||||
state() {
|
||||
return {
|
||||
userInfo: {},
|
||||
pageTabNameMap: {},
|
||||
docMap: {
|
||||
'/getUserInfo': {
|
||||
name: '获取用户信息'
|
||||
},
|
||||
'/deleteUserInfo': {
|
||||
name: '删除用户信息'
|
||||
},
|
||||
'/updateUserInfo': {
|
||||
name: '修改用户信息'
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
setUserInfo(state, userInfo) {
|
||||
state.userInfo = userInfo;
|
||||
},
|
||||
addTableName(state, item) {
|
||||
let sameObj = Object.assign({}, state.pageTabNameMap);
|
||||
sameObj[item.key] = item.val;
|
||||
state.pageTabNameMap = sameObj;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
// 使用方法
|
||||
// return this.$store.state.userInfo
|
||||
// this.$store.commit('setUserInfo', 111);
|
||||
|
||||
// 动态计算值
|
||||
// computed: {
|
||||
// initialEnv () {
|
||||
// return this.$store.state.initialEnv;
|
||||
// }
|
||||
// },
|
||||
|
||||
// js文件中使用
|
||||
// import store from '../../store/index'
|
||||
// store.commit('setInitialEnv', this.initialEnv);
|
||||
|
||||
|
||||
97
zyplayer-doc-ui/swagger-ui/src/views/common/AboutDialog.vue
Normal file
97
zyplayer-doc-ui/swagger-ui/src/views/common/AboutDialog.vue
Normal file
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<!--关于弹窗-->
|
||||
<a-modal v-model:visible="aboutDialogVisible" title="关于" width="600px" :footer="null">
|
||||
<div style="">
|
||||
<div style="font-weight: bold;font-size: 25px;">zyplayer-doc</div>
|
||||
<div style="line-height: 30px;padding: 10px 0;">
|
||||
<div>版本 {{upgradeInfo.nowVersion || '1.0.0'}}</div>
|
||||
<div>版权所有 © 2018-2021 <a target="_blank" href="http://doc.zyplayer.com">doc.zyplayer.com</a></div>
|
||||
</div>
|
||||
<a-tabs type="card">
|
||||
<a-tab-pane tab="支持" key="support">
|
||||
<div style="line-height: 30px;">
|
||||
<div>文档:<a target="_blank" href="http://doc.zyplayer.com/zyplayer-doc-manage/doc-wiki#/page/share/view?pageId=1&space=23f3f59a60824d21af9f7c3bbc9bc3cb">http://doc.zyplayer.com</a></div>
|
||||
<div>主页:<a target="_blank" href="https://gitee.com/zyplayer/zyplayer-doc">https://gitee.com/zyplayer/zyplayer-doc</a></div>
|
||||
<div>反馈:<a target="_blank" href="https://gitee.com/zyplayer/zyplayer-doc/issues">https://gitee.com/zyplayer/zyplayer-doc/issues</a></div>
|
||||
<div>特性关注&技术交流QQ群:466363173</div>
|
||||
<a-divider content-position="left">UI/设计/开发/测试</a-divider>
|
||||
<div><a target="_blank" href="http://zyplayer.com">暮光:城中城</a></div>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="开源软件" key="software">
|
||||
<div style="line-height: 30px;">
|
||||
<div>此项目基于以下开源软件构建</div>
|
||||
<a-divider content-position="left">后端</a-divider>
|
||||
<div>
|
||||
<a target="_blank" href="https://spring.io/projects/spring-boot">Spring-Boot</a>、
|
||||
<a target="_blank" href="http://www.mybatis.org">MyBatis</a>、
|
||||
<a target="_blank" href="https://github.com/alibaba/druid">Druid</a>、
|
||||
<a target="_blank" href="https://mp.baomidou.com">MyBatis-Plus</a>、
|
||||
<a target="_blank" href="https://www.hutool.cn">Hutool</a>、
|
||||
<a target="_blank" href="https://github.com/alibaba/fastjson">Fastjson</a>、
|
||||
<a target="_blank" href="https://alibaba-easyexcel.github.io">Easy Excel</a>、
|
||||
<a target="_blank" href="https://swagger.io">Swagger</a>、
|
||||
<a target="_blank" href="https://dubbo.io">Dubbo</a>、
|
||||
<a target="_blank" href="http://www.eclipse.org/jgit">JGit</a>、...
|
||||
</div>
|
||||
<a-divider content-position="left">前端</a-divider>
|
||||
Vue、element-ui、wangeditor、mavon-editor、qrcodejs2、vant、vue-router、axios、vue-hljs、brace、echarts、sql-formatter、vue-clipboard2、...
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="软件更新" key="upgrade" v-if="upgradeInfo.lastVersion">
|
||||
<span slot="label">
|
||||
软件更新
|
||||
<sup class="el-badge__content el-badge__content--undefined is-fixed is-dot" style="top: 10px;right: 20px;"></sup>
|
||||
</span>
|
||||
<div style="line-height: 30px;">
|
||||
<div>当前版本:{{upgradeInfo.nowVersion}}</div>
|
||||
<div>最新版本:{{upgradeInfo.lastVersion}}</div>
|
||||
<div>升级地址:<a target="_blank" :href="upgradeInfo.upgradeUrl">{{upgradeInfo.upgradeUrl}}</a></div>
|
||||
<div>升级内容:</div>
|
||||
<pre style="margin: 0; max-height: 250px; overflow: auto;">{{upgradeInfo.upgradeContent}}</pre>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {zyplayerApi} from "../../api/index";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
aboutDialogVisible: false,
|
||||
upgradeInfo: {},
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.checkSystemUpgrade();
|
||||
},
|
||||
methods: {
|
||||
show() {
|
||||
this.aboutDialogVisible = true;
|
||||
},
|
||||
checkSystemUpgrade() {
|
||||
zyplayerApi.systemUpgradeInfo({}).then(json => {
|
||||
if (!!json.data) {
|
||||
this.upgradeInfo = json.data;
|
||||
if (!!this.upgradeInfo.upgradeContent) {
|
||||
this.upgradeInfo.upgradeContent = this.upgradeInfo.upgradeContent.replaceAll(';', '\n');
|
||||
}
|
||||
console.log("zyplayer-doc发现新版本:"
|
||||
+ "\n升级地址:" + json.data.upgradeUrl
|
||||
+ "\n当前版本:" + json.data.nowVersion
|
||||
+ "\n最新版本:" + json.data.lastVersion
|
||||
+ "\n升级内容:" + json.data.upgradeContent
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
19
zyplayer-doc-ui/swagger-ui/src/views/common/Console.vue
Normal file
19
zyplayer-doc-ui/swagger-ui/src/views/common/Console.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<div>
|
||||
控制台
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'About',
|
||||
components: {},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {},
|
||||
mounted() {
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
19
zyplayer-doc-ui/swagger-ui/src/views/common/SettingView.vue
Normal file
19
zyplayer-doc-ui/swagger-ui/src/views/common/SettingView.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<div>
|
||||
展示配置页面
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SettingView',
|
||||
components: {},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {},
|
||||
mounted() {
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
33
zyplayer-doc-ui/swagger-ui/src/views/doc/DocView.vue
Normal file
33
zyplayer-doc-ui/swagger-ui/src/views/doc/DocView.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<a-tabs v-model:activeKey="activePage" closable @tab-click="changePage" style="padding: 5px 10px 0;">
|
||||
<a-tab-pane tab="接口说明" key="doc"/>
|
||||
<a-tab-pane tab="在线调试" key="debug"/>
|
||||
</a-tabs>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'About',
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
activePage: 'doc'
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
mounted() {
|
||||
let path = this.$route.query.path;
|
||||
let docInfo = this.$store.state.docMap[path];
|
||||
if(!docInfo) {
|
||||
this.$message.error('没有找到对应的文档');
|
||||
return;
|
||||
}
|
||||
this.$store.commit('addTableName', {key: this.$route.fullPath, val: docInfo.name});
|
||||
},
|
||||
methods: {
|
||||
changePage(){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user