push
This commit is contained in:
8
nervui-slb/.env
Normal file
8
nervui-slb/.env
Normal file
@@ -0,0 +1,8 @@
|
||||
# port
|
||||
VITE_PORT = 5000
|
||||
|
||||
# spa-title
|
||||
VITE_GLOB_APP_TITLE = nervui-slb
|
||||
|
||||
# spa shortname
|
||||
VITE_GLOB_APP_SHORT_NAME = nervui-slb
|
||||
20
nervui-slb/.env.development
Normal file
20
nervui-slb/.env.development
Normal file
@@ -0,0 +1,20 @@
|
||||
# Whether to open mock
|
||||
VITE_USE_MOCK = true
|
||||
|
||||
# public path
|
||||
VITE_PUBLIC_PATH = /nervui-slb/
|
||||
|
||||
# Cross-domain proxy, you can configure multiple
|
||||
# Please note that no line breaks
|
||||
|
||||
# Delete console
|
||||
VITE_DROP_CONSOLE = false
|
||||
|
||||
# Basic interface address SPA
|
||||
VITE_GLOB_API_URL=/basic-api
|
||||
|
||||
# File upload address, optional
|
||||
VITE_GLOB_UPLOAD_URL=/upload
|
||||
|
||||
# Interface prefix
|
||||
VITE_GLOB_API_URL_PREFIX=
|
||||
35
nervui-slb/.env.production
Normal file
35
nervui-slb/.env.production
Normal file
@@ -0,0 +1,35 @@
|
||||
# Whether to open mock
|
||||
VITE_USE_MOCK = true
|
||||
|
||||
# public path
|
||||
VITE_PUBLIC_PATH = /nervui-slb/
|
||||
|
||||
# Delete console
|
||||
VITE_DROP_CONSOLE = true
|
||||
|
||||
# Whether to enable gzip or brotli compression
|
||||
# Optional: gzip | brotli | none
|
||||
# If you need multiple forms, you can use `,` to separate
|
||||
VITE_BUILD_COMPRESS = 'none'
|
||||
|
||||
# Whether to delete origin files when using compress, default false
|
||||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
|
||||
|
||||
# Basic interface address SPA
|
||||
VITE_GLOB_API_URL=/basic-api
|
||||
|
||||
# File upload address, optional
|
||||
# It can be forwarded by nginx or write the actual address directly
|
||||
VITE_GLOB_UPLOAD_URL=/upload
|
||||
|
||||
# Interface prefix
|
||||
VITE_GLOB_API_URL_PREFIX=
|
||||
|
||||
# Whether to enable image compression
|
||||
VITE_USE_IMAGEMIN= true
|
||||
|
||||
# use pwa
|
||||
VITE_USE_PWA = false
|
||||
|
||||
# Is it compatible with older browsers
|
||||
VITE_LEGACY = false
|
||||
1
nervui-slb/.version
Normal file
1
nervui-slb/.version
Normal file
@@ -0,0 +1 @@
|
||||
1.0.34
|
||||
74
nervui-slb/build.sh
Normal file
74
nervui-slb/build.sh
Normal file
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
SOURCE="$0"
|
||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
|
||||
if [ -z $WORKSPACE ];then
|
||||
echo "WORKSPACE not exists"
|
||||
else
|
||||
set DIR=$WORKSPACE
|
||||
fi
|
||||
|
||||
echo "current dir"
|
||||
echo "$DIR"
|
||||
|
||||
cd "$DIR"
|
||||
projectname=$(basename `pwd`)
|
||||
|
||||
npm run slb-build
|
||||
|
||||
if [ -d "$DIR/dist" ];then
|
||||
|
||||
cd "$DIR/dist"
|
||||
|
||||
# copy module.json
|
||||
cp ../module.json ./
|
||||
|
||||
# package
|
||||
VERSION=$(cat ../.version)
|
||||
lastdir=../release/
|
||||
if [ -d ${lastdir} ];then
|
||||
echo "删除旧release文件夹"
|
||||
rm -rf ${lastdir}
|
||||
else
|
||||
echo "文件夹不存在!"
|
||||
fi
|
||||
mkdir -p ${lastdir}
|
||||
|
||||
dir=../release/nerv/$projectname/$VERSION
|
||||
mkdir -p ${dir}
|
||||
tar -zcvf "${dir}/$projectname-$VERSION.tgz" ./*
|
||||
|
||||
templatedir=../release/resources/templates/nerv/$projectname/$VERSION/$projectname
|
||||
mkdir -p ${templatedir}
|
||||
cp -r ../resources/templates/* ${templatedir}
|
||||
|
||||
cd ../
|
||||
|
||||
releasefile=nerv-$projectname-$VERSION.tgz
|
||||
if [ -f ${releasefile} ];then
|
||||
echo "删除旧包!"
|
||||
rm -rf ${releasefile}
|
||||
fi
|
||||
|
||||
tar -zcvf ${releasefile} ./release/* release.yaml
|
||||
|
||||
mkdir -p ./release/nervui
|
||||
cp -r ./release/nerv/* ./release/nervui
|
||||
|
||||
if [ -f ${releasefile} ];then
|
||||
echo "编译成功!"
|
||||
mv ${releasefile} ./release
|
||||
else
|
||||
echo "编译失败!!!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
else
|
||||
echo "编译失败!!!"
|
||||
exit 1
|
||||
fi
|
||||
13
nervui-slb/index.html
Normal file
13
nervui-slb/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon-stack.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>负载均衡</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="./src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
77
nervui-slb/module.json
Normal file
77
nervui-slb/module.json
Normal file
@@ -0,0 +1,77 @@
|
||||
[
|
||||
{
|
||||
"catalog": "网络",
|
||||
"icon": "",
|
||||
"name": "slb",
|
||||
"label": "负载均衡",
|
||||
"menus": [
|
||||
{
|
||||
"name": "listener",
|
||||
"label": "监听器",
|
||||
"url": "/slb/listener",
|
||||
"operation": {
|
||||
"resource": "listener",
|
||||
"method": "list"
|
||||
},
|
||||
"submenus": [
|
||||
{
|
||||
"label": "管理",
|
||||
"notResource": true,
|
||||
"isOperation": true,
|
||||
"operation": {
|
||||
"resource": "manage",
|
||||
"method": "list"
|
||||
},
|
||||
"submenus": [
|
||||
{
|
||||
"label": "基本信息",
|
||||
"operation": {
|
||||
"method": "list",
|
||||
"resource": "listenerBasicInfo"
|
||||
},
|
||||
"notResource": true,
|
||||
"submenus":[]
|
||||
},
|
||||
{
|
||||
"label": "后端服务器",
|
||||
"operation": {
|
||||
"method": "list",
|
||||
"resource": "listenerRealServer"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "后端服务器组",
|
||||
"name": "realServerGroup",
|
||||
"url": "/slb/realServerGroup",
|
||||
"operation": {
|
||||
"method": "list",
|
||||
"resource": "listener"
|
||||
},
|
||||
"submenus": [{
|
||||
"label": "管理",
|
||||
"notResource": true,
|
||||
"isOperation": true,
|
||||
"operation": {
|
||||
"resource": "manage",
|
||||
"method": "list"
|
||||
},
|
||||
"submenus": [
|
||||
{
|
||||
"label": "后端服务器",
|
||||
"operation": {
|
||||
"method": "list",
|
||||
"resource": "realServer"
|
||||
},
|
||||
"submenus":[]
|
||||
}
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
16
nervui-slb/package.json
Normal file
16
nervui-slb/package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "nerv-lib",
|
||||
"version": "1.0.27",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"start": "vite serve --config ./vite.config.ts",
|
||||
"build": "cross-env NODE_ENV=production vite build",
|
||||
"dev": "vite",
|
||||
"lint:eslint-fix": "eslint --cache --max-warnings 0 \"{src,mock}/**/*.{vue,ts,tsx}\" --fix",
|
||||
"serve": "vite preview"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {}
|
||||
}
|
||||
BIN
nervui-slb/public/asset/image/login/login-background.jpeg
Normal file
BIN
nervui-slb/public/asset/image/login/login-background.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 126 KiB |
BIN
nervui-slb/public/asset/image/login/logo-data.png
Normal file
BIN
nervui-slb/public/asset/image/login/logo-data.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
nervui-slb/public/asset/image/login/logo-paas.png
Normal file
BIN
nervui-slb/public/asset/image/login/logo-paas.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
BIN
nervui-slb/public/favicon-stack.ico
Normal file
BIN
nervui-slb/public/favicon-stack.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
BIN
nervui-slb/public/favicon.ico
Normal file
BIN
nervui-slb/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
12
nervui-slb/release.yaml
Normal file
12
nervui-slb/release.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
# 上传release目录信息到nerv-file仓库
|
||||
release:
|
||||
- {src: release, dest: /upload/pkg, include: [".*(.tgz)$"]}
|
||||
- {src: release/resources/templates, dest: /upload/templates}
|
||||
register:
|
||||
name: nervui-slb
|
||||
version: 1.0.34
|
||||
components:
|
||||
- type: nervui-slb
|
||||
resources:
|
||||
- {type: template, relativePath: /nervui-slb/deploy.json}
|
||||
|
||||
18
nervui-slb/src/App.vue
Normal file
18
nervui-slb/src/App.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<ns-application />
|
||||
</template>
|
||||
|
||||
<script lang="ts" type="module">
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'App',
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
50
nervui-slb/src/api/index.ts
Normal file
50
nervui-slb/src/api/index.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/***
|
||||
*配置接口 格式 module:Array<resource>
|
||||
*/
|
||||
export const apiModule = {
|
||||
pension: [
|
||||
'User',
|
||||
'CurrentUser',
|
||||
'Gaffer',
|
||||
// 'Organizational',
|
||||
// 'Device',
|
||||
// 'Region',
|
||||
// 'Owner',
|
||||
// 'AllList',
|
||||
// 'VisitorRecord',
|
||||
// 'Room',
|
||||
// 'Device',
|
||||
// 'CommunityVisitor',
|
||||
// 'AccessControlGroup',
|
||||
// 'AccessControlLeft',
|
||||
// 'AccessControlRight',
|
||||
// 'AccessControlRightIdentity',
|
||||
// 'Visitor',
|
||||
// 'DeviceListByDeviceCategory',
|
||||
// 'Perimeter',
|
||||
// 'AccessControlRightVisitorIdentity',
|
||||
// 'BedChoose',
|
||||
// 'Gateway',
|
||||
// 'FileUpload',
|
||||
// 'User',
|
||||
// 'CurrentUser',
|
||||
// 'Organizational',
|
||||
// 'Device',
|
||||
// 'Region',
|
||||
// 'Owner',
|
||||
// 'AllList',
|
||||
// 'VisitorRecord',
|
||||
// 'Room',
|
||||
// 'Device',
|
||||
// 'CommunityVisitor',
|
||||
// 'AccessControlGroup',
|
||||
// 'AccessControlLeft',
|
||||
// 'AccessControlRight',
|
||||
// 'AccessControlRightIdentity',
|
||||
// 'Visitor',
|
||||
// 'DeviceListByDeviceCategory',
|
||||
// 'BedChoose',
|
||||
// 'Perimeter',
|
||||
// 'OrganizationConfig',
|
||||
],
|
||||
};
|
||||
15
nervui-slb/src/api/user.ts
Normal file
15
nervui-slb/src/api/user.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { http } from '/nerv-lib/paas';
|
||||
|
||||
enum Api {
|
||||
USER_LOGIN = '/api/passport/objs/login', //用户登录
|
||||
USER_INFO = '/api/webui/webui/objs/PassportUserInfo', //获取用户信息
|
||||
}
|
||||
export const userLogin = (data: RoomListModel) => http.post(Api.USER_LOGIN, data);
|
||||
export const userInfo = () => http.get(Api.USER_INFO);
|
||||
/**
|
||||
* @description 用户登录
|
||||
* @property `[fatherRegionUuid]` 父级区域唯一标识
|
||||
*/
|
||||
interface RoomListModel {
|
||||
data: string;
|
||||
}
|
||||
4
nervui-slb/src/config/app.config.ts
Normal file
4
nervui-slb/src/config/app.config.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export const appConfig = {
|
||||
projectType: 'web',
|
||||
timeout: 10 * 1000,
|
||||
};
|
||||
2
nervui-slb/src/config/index.ts
Normal file
2
nervui-slb/src/config/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
import { appConfig } from '/@/config/app.config';
|
||||
export { appConfig };
|
||||
17
nervui-slb/src/main.ts
Normal file
17
nervui-slb/src/main.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { createApp } from 'vue';
|
||||
import App from '/@/App.vue';
|
||||
import { paasInit } from '/nerv-lib/paas';
|
||||
import { apiModule } from '/@/api';
|
||||
import { appConfig } from '/@/config';
|
||||
import '/@/theme/theme.scss';
|
||||
|
||||
// const modules = import.meta.globEager('/src/router/**/*.ts');
|
||||
const modules = undefined;
|
||||
const app = createApp(App);
|
||||
paasInit({
|
||||
app,
|
||||
apiModule,
|
||||
appConfig,
|
||||
modules,
|
||||
});
|
||||
app.mount('#app');
|
||||
@@ -0,0 +1,35 @@
|
||||
echo "=====================================================create====================================================="
|
||||
|
||||
#!/usr/bin/env bash
|
||||
|
||||
function create() {
|
||||
|
||||
if [ -d "$nervui_app_home" ];then
|
||||
echo "$nervui_app_home exists!"
|
||||
else
|
||||
echo "start mkdir $nervui_app_home"
|
||||
mkdir -p "$nervui_app_home"
|
||||
fi
|
||||
|
||||
pkg_file_name=${pkg_url##*/}
|
||||
pkg_file_path="$nervui_app_home$pkg_file_name"
|
||||
|
||||
|
||||
echo "start download $pkg_url"
|
||||
curl -L -o $pkg_file_path $pkg_url
|
||||
|
||||
|
||||
echo "start install $pkg_file_path"
|
||||
tar -xf $pkg_file_path -C $nervui_app_home
|
||||
|
||||
}
|
||||
|
||||
if [ "$pkg_url" == "" ]; then
|
||||
echo {\"error\":\"pkg_url is empty\"}
|
||||
exit 1
|
||||
elif [ "$nervui_app_home" == "" ]; then
|
||||
echo {\"error\":\"nervui_app_home is empty\"}
|
||||
exit 1
|
||||
else
|
||||
create
|
||||
fi
|
||||
@@ -0,0 +1 @@
|
||||
echo "=====================================================delete====================================================="
|
||||
@@ -0,0 +1 @@
|
||||
echo "=====================================================setup====================================================="
|
||||
@@ -0,0 +1 @@
|
||||
echo "=====================================================start====================================================="
|
||||
@@ -0,0 +1 @@
|
||||
echo "=====================================================stop====================================================="
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name":"/nervui/nervui-gateway-api",
|
||||
"operations": [
|
||||
{
|
||||
"name": "Create",
|
||||
"type": "shell",
|
||||
"implementor": "create.sh"
|
||||
},
|
||||
{
|
||||
"name": "Delete",
|
||||
"type": "shell",
|
||||
"implementor": "delete.sh"
|
||||
},
|
||||
{
|
||||
"name": "Setup",
|
||||
"type": "shell",
|
||||
"implementor": "setup.sh"
|
||||
},
|
||||
{
|
||||
"name": "Start",
|
||||
"type": "shell",
|
||||
"implementor": "start.sh"
|
||||
},
|
||||
{
|
||||
"name": "Stop",
|
||||
"type": "shell",
|
||||
"implementor": "stop.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
64
nervui-slb/src/resources/templates/deploy.json
Normal file
64
nervui-slb/src/resources/templates/deploy.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"name": "/nervui/nervui-gateway-api",
|
||||
"version": 1,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "server_ip",
|
||||
"type": "string",
|
||||
"required":true,
|
||||
"description":"应用安装IP地址",
|
||||
"inputType":"ipSelectType"
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"type": "string",
|
||||
"required":true,
|
||||
"description":"软件版本",
|
||||
"inputType":"versionSelectType"
|
||||
},
|
||||
{
|
||||
"name": "install_dir",
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"defaultValue": "/data",
|
||||
"inputType": "textInputType",
|
||||
"description": "安装目录"
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"name": "nervui-gateway-api",
|
||||
"type": "/nerv/nerv-orchestrator/cluster/Nervui",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "file_repository",
|
||||
"value": "${nerv_file_repository}"
|
||||
},
|
||||
{
|
||||
"name": "install_dir",
|
||||
"value": "${install_dir}"
|
||||
},
|
||||
{
|
||||
"name": "pkg_url",
|
||||
"value": "/api/pkg/nerv/nervui-gateway-api/${version}/nervui-gateway-api-${version}.tgz"
|
||||
}
|
||||
],
|
||||
"dependencies": [
|
||||
{
|
||||
"type": "contained",
|
||||
"target": "host"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "host",
|
||||
"type": "/nerv/nerv-orchestrator/compute/Host",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "address",
|
||||
"value": "${server_ip}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
9
nervui-slb/src/router/index.ts
Normal file
9
nervui-slb/src/router/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
const RootRoute = {
|
||||
path: '/root',
|
||||
name: 'root',
|
||||
redirect: '/slb',
|
||||
meta: {
|
||||
title: 'Root',
|
||||
},
|
||||
};
|
||||
export default RootRoute;
|
||||
385
nervui-slb/src/router/slbManage/slbManage.ts
Normal file
385
nervui-slb/src/router/slbManage/slbManage.ts
Normal file
@@ -0,0 +1,385 @@
|
||||
/** @format */
|
||||
|
||||
import { NsViewContent, NsViewDetail, NsViewSideNav } from '/nerv-lib/paas';
|
||||
|
||||
const SideNav = () => Promise.resolve(NsViewSideNav);
|
||||
const Base = () => Promise.resolve(NsViewContent);
|
||||
const Detail = () => Promise.resolve(NsViewDetail);
|
||||
const slb = {
|
||||
path: '/slb',
|
||||
name: 'slb',
|
||||
component: SideNav,
|
||||
redirect: { name: 'listener' },
|
||||
meta: {
|
||||
sideMenus: {
|
||||
title: '负载均衡',
|
||||
name: 'slb',
|
||||
menus: [
|
||||
{
|
||||
name: 'listener',
|
||||
label: '监听器',
|
||||
url: '/slb/listener',
|
||||
module: 'vm',
|
||||
},
|
||||
{
|
||||
name: 'realServerGroup',
|
||||
label: '后端服务组',
|
||||
url: '/slb/realServerGroup',
|
||||
module: 'vm',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'listener',
|
||||
name: 'listenerModule',
|
||||
component: Base,
|
||||
redirect: { name: 'listener' },
|
||||
children: [
|
||||
//监听器列表
|
||||
{
|
||||
path: 'list',
|
||||
name: 'listener',
|
||||
component: () => import('/@/view/listenerManage/list.vue'),
|
||||
},
|
||||
//新增监听器
|
||||
{
|
||||
path: 'add',
|
||||
name: 'listenerAdd',
|
||||
component: () => import('/@/view/listenerManage/add.vue'),
|
||||
},
|
||||
//编辑监听器
|
||||
{
|
||||
path: 'edit/:ID',
|
||||
name: 'listenerEdit',
|
||||
component: () => import('/@/view/listenerManage/edit.vue'),
|
||||
},
|
||||
//监听器管理模块
|
||||
{
|
||||
path: 'manage/:ID/:rsgID/:pageTitle',
|
||||
name: 'listenerManage',
|
||||
component: Base,
|
||||
meta: {
|
||||
sideMenus: {
|
||||
title: '管理',
|
||||
name: 'listenerManage',
|
||||
backTo: 'listener',
|
||||
menus: [
|
||||
{
|
||||
name: 'listenerBasicInfo',
|
||||
label: '基本信息',
|
||||
url: 'listenerBasicInfo',
|
||||
module: 'vm',
|
||||
},
|
||||
{
|
||||
name: 'listenerRealServer',
|
||||
label: '后端服务器',
|
||||
url: 'listenerRealServer',
|
||||
module: 'list',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
children: [
|
||||
//监听器基本信息
|
||||
{
|
||||
path: 'listenerBasicInfo',
|
||||
name: 'listenerBasicInfo',
|
||||
component: Detail,
|
||||
props: {
|
||||
title: 'pageTitle',
|
||||
api: '/api/slb/objs/Listener/:ID',
|
||||
detail: [
|
||||
{
|
||||
title: '监听器',
|
||||
items: [
|
||||
{
|
||||
label: '项目',
|
||||
name: 'projectName',
|
||||
},
|
||||
{
|
||||
label: '名称',
|
||||
name: 'name',
|
||||
},
|
||||
{
|
||||
label: 'slb集群项目',
|
||||
name: 'clusterProjectName',
|
||||
},
|
||||
{
|
||||
label: 'slb集群',
|
||||
name: 'clusterName',
|
||||
},
|
||||
{
|
||||
label: '前端协议',
|
||||
name: 'frontEndProtocol',
|
||||
},
|
||||
{
|
||||
label: '端口',
|
||||
name: 'frontEndPort',
|
||||
},
|
||||
{
|
||||
label: '证书域名',
|
||||
ifShow: (record: any) => {
|
||||
return record.frontEndProtocol === 'https';
|
||||
},
|
||||
name: 'domain',
|
||||
},
|
||||
{
|
||||
label: '安全类型',
|
||||
name: 'securityType',
|
||||
ifShow: (record: any) => {
|
||||
return record.frontEndProtocol === 'https';
|
||||
},
|
||||
format: (value: any) => {
|
||||
switch (value) {
|
||||
case 'TLS_1_0':
|
||||
return '安全策略TLS-1-0';
|
||||
break;
|
||||
case 'TLS_1_1':
|
||||
return '安全策略TLS-1-1';
|
||||
break;
|
||||
case 'TLS_1_2':
|
||||
return '安全策略TLS-1-2';
|
||||
break;
|
||||
case 'TLS_1_2_Strict':
|
||||
return '安全策略TLS-1-2-Stric';
|
||||
break;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '双向认证',
|
||||
name: 'isMutualAuth',
|
||||
ifShow: (record: any) => {
|
||||
return record.frontEndProtocol === 'https';
|
||||
},
|
||||
format: (value: any) => {
|
||||
if (value) {
|
||||
return '是';
|
||||
} else {
|
||||
return '否';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '监听器模式',
|
||||
name: 'mode',
|
||||
format: (value: any) => {
|
||||
if (value === 'master-slave') {
|
||||
return '主从模式';
|
||||
} else {
|
||||
return '负载模式';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '分配VIP',
|
||||
name: 'isNeedVIP',
|
||||
ifShow: (record: any) => {
|
||||
return record.mode === 'master-slave';
|
||||
},
|
||||
format: (value: any) => {
|
||||
if (value) {
|
||||
return '是';
|
||||
} else {
|
||||
return '否';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '转发方式',
|
||||
name: 'trafficDistrStrategy',
|
||||
format: (value: any) => {
|
||||
switch (value) {
|
||||
case 'rr':
|
||||
return '轮询';
|
||||
break;
|
||||
case 'wrr':
|
||||
return '加权轮询';
|
||||
break;
|
||||
case 'lc':
|
||||
return '最少链接';
|
||||
break;
|
||||
case 'wlc':
|
||||
return '加权最少链接';
|
||||
break;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
label: '描述 ',
|
||||
name: 'description',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: '后端服务器',
|
||||
items: [
|
||||
{
|
||||
label: '后端服务器组',
|
||||
name: 'rsgName',
|
||||
},
|
||||
{
|
||||
label: '后端协议',
|
||||
name: 'backEndProtocol',
|
||||
},
|
||||
{
|
||||
label: '后端端口',
|
||||
name: 'backEndPort',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: '健康检查',
|
||||
items: [
|
||||
{
|
||||
label: '是否开启',
|
||||
name: 'isHealthCheck',
|
||||
format: (value: any) => {
|
||||
if (value) {
|
||||
return '是';
|
||||
} else {
|
||||
return '否';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '协议',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck;
|
||||
},
|
||||
name: 'healthProtocol',
|
||||
},
|
||||
{
|
||||
label: '端口',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck;
|
||||
},
|
||||
name: 'healthPort',
|
||||
},
|
||||
{
|
||||
label: '检查间隔(s)',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck;
|
||||
},
|
||||
name: 'healthInterval',
|
||||
},
|
||||
{
|
||||
label: '超时间隔(s)',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck;
|
||||
},
|
||||
name: 'healthTimeOut',
|
||||
},
|
||||
{
|
||||
label: '健康检查URL',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck && record.healthProtocol === 'http';
|
||||
},
|
||||
name: 'healthUrl',
|
||||
},
|
||||
{
|
||||
label: '最大重复次数',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck;
|
||||
},
|
||||
name: 'healthFailTimes',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
//后端服务器
|
||||
{
|
||||
path: 'listenerRealServer',
|
||||
name: 'listenerRealServer',
|
||||
component: () => import('/@/view/listenerManage/listenerRealServer.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
//后端服务器组管理
|
||||
{
|
||||
path: 'realServerGroup',
|
||||
name: 'realServerGroupModule',
|
||||
component: Base,
|
||||
children: [
|
||||
//后端服务器组列表
|
||||
{
|
||||
path: 'list',
|
||||
name: 'realServerGroup',
|
||||
component: () => import('/@/view/realServerGroup/list.vue'),
|
||||
},
|
||||
//新增后端服务器组
|
||||
{
|
||||
path: 'add',
|
||||
name: 'realServerGroupAdd',
|
||||
component: () => import('/@/view/realServerGroup/add.vue'),
|
||||
},
|
||||
//编辑后端服务器组
|
||||
{
|
||||
path: 'edit/:ID',
|
||||
name: 'realServerGroupEdit',
|
||||
component: () => import('/@/view/realServerGroup/edit.vue'),
|
||||
},
|
||||
//后端服务器组 的管理模块
|
||||
{
|
||||
path: 'manage/:ID/:projectName/:pageTitle',
|
||||
name: 'realServerGroupManage',
|
||||
component: Base,
|
||||
meta: {
|
||||
sideMenus: {
|
||||
title: '管理',
|
||||
name: 'realServerGroupManage',
|
||||
backTo: 'realServerGroup',
|
||||
menus: [
|
||||
{
|
||||
name: 'realServer',
|
||||
label: '后端服务器',
|
||||
url: 'realServer',
|
||||
module: 'vm',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'realServer',
|
||||
name: 'realServerModule',
|
||||
component: Base,
|
||||
redirect: { name: 'realServer' },
|
||||
children: [
|
||||
//后端服务器列表
|
||||
{
|
||||
path: 'list',
|
||||
name: 'realServer',
|
||||
component: () => import('/@/view/realServerGroup/realServerManage/list.vue'),
|
||||
},
|
||||
//新增后端服务器
|
||||
{
|
||||
path: 'add',
|
||||
name: 'realServerAdd',
|
||||
component: () => import('/@/view/realServerGroup/realServerManage/add.vue'),
|
||||
},
|
||||
{
|
||||
path: 'edit/:editId/:ip',
|
||||
name: 'realServerEdit',
|
||||
component: () => import('/@/view/realServerGroup/realServerManage/edit.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
export default slb;
|
||||
0
nervui-slb/src/theme/global.scss
Normal file
0
nervui-slb/src/theme/global.scss
Normal file
2
nervui-slb/src/theme/theme.scss
Normal file
2
nervui-slb/src/theme/theme.scss
Normal file
@@ -0,0 +1,2 @@
|
||||
@import "variable";
|
||||
@import "global";
|
||||
0
nervui-slb/src/theme/variable.less
Normal file
0
nervui-slb/src/theme/variable.less
Normal file
0
nervui-slb/src/theme/variable.scss
Normal file
0
nervui-slb/src/theme/variable.scss
Normal file
1008
nervui-slb/src/view/listenerManage/add.vue
Normal file
1008
nervui-slb/src/view/listenerManage/add.vue
Normal file
File diff suppressed because it is too large
Load Diff
349
nervui-slb/src/view/listenerManage/component/detail.vue
Normal file
349
nervui-slb/src/view/listenerManage/component/detail.vue
Normal file
@@ -0,0 +1,349 @@
|
||||
<!-- @format -->
|
||||
|
||||
<template>
|
||||
<div class="ns-detail">
|
||||
<div v-for="(detailGroup, index) in detail" :key="index">
|
||||
<a-descriptions :title="detailGroup.title" class="detail_item">
|
||||
<template v-if="detailGroup.items">
|
||||
<template v-for="(item, index) in detailGroup.items" :key="index">
|
||||
<a-descriptions-item
|
||||
v-if="item.ifShow ? item.ifShow(dataRef) : !item.ifShow"
|
||||
:label="item.label">
|
||||
<template v-if="!item.type">
|
||||
<span>{{
|
||||
item.format ? item.format(dataRef[item.name]) : dataRef[item.name]
|
||||
}}</span>
|
||||
</template>
|
||||
|
||||
<template v-else-if="item.type === 'image'">
|
||||
<a-image
|
||||
:width="100"
|
||||
:src="item.value"
|
||||
fallback="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg==" />
|
||||
</template>
|
||||
<template v-else-if="item.type === 'table'">
|
||||
<ns-basic-table
|
||||
class="ns-detail-table"
|
||||
:dataSource="dataRef[item.props.listField]"
|
||||
:columns="item.props.columns"
|
||||
:pagination="false"
|
||||
:rowKey="item.props.rowKey" />
|
||||
</template>
|
||||
</a-descriptions-item>
|
||||
</template>
|
||||
</template>
|
||||
</a-descriptions>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, unref } from 'vue';
|
||||
export default defineComponent({
|
||||
name: 'ApiCusDetail',
|
||||
props: {
|
||||
dataSource: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
setup(props, context) {
|
||||
const getDetail = ref('');
|
||||
const dataRef = unref(props.dataSource);
|
||||
const detail = [
|
||||
{
|
||||
title: '监听器',
|
||||
items: [
|
||||
{
|
||||
label: '项目',
|
||||
name: 'projectName',
|
||||
},
|
||||
{
|
||||
label: '名称',
|
||||
name: 'name',
|
||||
},
|
||||
{
|
||||
label: 'slb集群项目',
|
||||
name: 'clusterProjectName',
|
||||
},
|
||||
{
|
||||
label: 'slb集群',
|
||||
name: 'clusterName',
|
||||
},
|
||||
{
|
||||
label: '前端协议',
|
||||
name: 'frontEndProtocol',
|
||||
},
|
||||
{
|
||||
label: '端口',
|
||||
name: 'frontEndPort',
|
||||
},
|
||||
{
|
||||
label: '证书域名',
|
||||
ifShow: (record: any) => {
|
||||
return record.frontEndProtocol === 'https';
|
||||
},
|
||||
name: 'domain',
|
||||
},
|
||||
{
|
||||
label: '安全类型',
|
||||
name: 'securityType',
|
||||
ifShow: (record: any) => {
|
||||
return record.frontEndProtocol === 'https';
|
||||
},
|
||||
format: (value: any) => {
|
||||
switch (value) {
|
||||
case 'TLS_1_0':
|
||||
return '安全策略TLS-1-0';
|
||||
break;
|
||||
case 'TLS_1_1':
|
||||
return '安全策略TLS-1-1';
|
||||
break;
|
||||
case 'TLS_1_2':
|
||||
return '安全策略TLS-1-2';
|
||||
break;
|
||||
case 'TLS_1_2_Strict':
|
||||
return '安全策略TLS-1-2-Stric';
|
||||
break;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '双向认证',
|
||||
name: 'isMutualAuth',
|
||||
ifShow: (record: any) => {
|
||||
return record.frontEndProtocol === 'https';
|
||||
},
|
||||
format: (value: any) => {
|
||||
if (value) {
|
||||
return '是';
|
||||
} else {
|
||||
return '否';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '监听器模式',
|
||||
name: 'mode',
|
||||
format: (value: any) => {
|
||||
if (value === 'master-slave') {
|
||||
return '主从模式';
|
||||
} else {
|
||||
return '负载模式';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '分配VIP',
|
||||
name: 'isNeedVIP',
|
||||
ifShow: (record: any) => {
|
||||
return record.mode === 'master-slave';
|
||||
},
|
||||
format: (value: any) => {
|
||||
if (value) {
|
||||
return '是';
|
||||
} else {
|
||||
return '否';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '转发方式',
|
||||
name: 'trafficDistrStrategy',
|
||||
format: (value: any) => {
|
||||
switch (value) {
|
||||
case 'rr':
|
||||
return '轮询';
|
||||
break;
|
||||
case 'wrr':
|
||||
return '加权轮询';
|
||||
break;
|
||||
case 'lc':
|
||||
return '最少链接';
|
||||
break;
|
||||
case 'wlc':
|
||||
return '加权最少链接';
|
||||
break;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
label: '描述 ',
|
||||
name: 'description',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: '后端服务器',
|
||||
items: [
|
||||
{
|
||||
label: '后端服务器组',
|
||||
name: 'rsgName',
|
||||
},
|
||||
{
|
||||
label: '后端协议',
|
||||
name: 'backEndProtocol',
|
||||
},
|
||||
{
|
||||
label: '后端端口',
|
||||
name: 'backEndPort',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: '健康检查',
|
||||
items: [
|
||||
{
|
||||
label: '是否开启',
|
||||
name: 'isHealthCheck',
|
||||
format: (value: any) => {
|
||||
if (value) {
|
||||
return '是';
|
||||
} else {
|
||||
return '否';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '协议',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck;
|
||||
},
|
||||
name: 'healthProtocol',
|
||||
},
|
||||
{
|
||||
label: '端口',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck;
|
||||
},
|
||||
name: 'healthPort',
|
||||
},
|
||||
{
|
||||
label: '检查间隔(s)',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck;
|
||||
},
|
||||
name: 'healthInterval',
|
||||
},
|
||||
{
|
||||
label: '超时间隔(s)',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck;
|
||||
},
|
||||
name: 'healthTimeOut',
|
||||
},
|
||||
{
|
||||
label: '健康检查URL',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck && record.healthProtocol === 'http';
|
||||
},
|
||||
name: 'healthUrl',
|
||||
},
|
||||
{
|
||||
label: '最大重复次数',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck;
|
||||
},
|
||||
name: 'healthFailTimes',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return {
|
||||
dataRef,
|
||||
detail,
|
||||
getDetail,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
// .detail_item {
|
||||
// border-bottom: 1px solid #c9d8db;
|
||||
// }
|
||||
.ant-page-header {
|
||||
padding: 0 24px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
// :deep(.ant-page-header-heading-extra) {
|
||||
// margin-right: auto !important;
|
||||
// margin-left: 0;
|
||||
// }
|
||||
:deep(.ant-skeleton-paragraph) {
|
||||
display: inline;
|
||||
// display: flex;
|
||||
// flex-wrap: wrap;
|
||||
}
|
||||
|
||||
:deep(.ant-skeleton-paragraph li:nth-child(n)) {
|
||||
float: left;
|
||||
display: inline;
|
||||
margin-right: 130px;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
:deep(.ant-skeleton-paragraph li:nth-child(3n + 1)) {
|
||||
clear: both;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
:deep(.ant-skeleton-content) {
|
||||
padding: 0 8px 10px 10px;
|
||||
}
|
||||
|
||||
.ns-detail {
|
||||
padding: 0 24px 24px 24px;
|
||||
}
|
||||
|
||||
.ns-detail-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-table-wrapper) {
|
||||
padding: 0;
|
||||
}
|
||||
:deep(.ant-tabs-tab) {
|
||||
padding: 8px 20px 8px 20px;
|
||||
margin-right: 5px !important;
|
||||
}
|
||||
.step {
|
||||
width: 100%;
|
||||
min-height: 200px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid rgba(232, 232, 232, 1);
|
||||
border-radius: 5px;
|
||||
.step-header {
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
font-size: 13px;
|
||||
line-height: 50px;
|
||||
padding-left: 20px;
|
||||
background: rgba(242, 242, 242, 1);
|
||||
}
|
||||
.content {
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
.content-item {
|
||||
width: 100%;
|
||||
|
||||
span {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.FCKEditor {
|
||||
width: 100%;
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #c9d8db;
|
||||
}
|
||||
</style>
|
||||
28
nervui-slb/src/view/listenerManage/component/step.vue
Normal file
28
nervui-slb/src/view/listenerManage/component/step.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<div style="margin-bottom: 20px">
|
||||
<a-steps :current="current">
|
||||
<a-step title="配置监听器" />
|
||||
<a-step title="配置后端服务器" />
|
||||
<a-step title="健康检查" />
|
||||
<a-step title="配置审核" />
|
||||
</a-steps>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NsStep',
|
||||
props: {
|
||||
current: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
stepList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
setup() {},
|
||||
});
|
||||
</script>
|
||||
877
nervui-slb/src/view/listenerManage/edit.vue
Normal file
877
nervui-slb/src/view/listenerManage/edit.vue
Normal file
@@ -0,0 +1,877 @@
|
||||
<!-- @format -->
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<page-title title="编辑" />
|
||||
<a-page-header>
|
||||
<template #extra>
|
||||
<ns-button @click="navigateBack">返回</ns-button>
|
||||
</template>
|
||||
</a-page-header>
|
||||
<NsStep
|
||||
:current="data.current"
|
||||
style="width: 96%; margin: auto; margin-left: 24px; min-width: 600px" />
|
||||
<ns-form
|
||||
v-if="isEdit"
|
||||
style="margin-top: 30px; margin-left: 24px"
|
||||
ref="mainRef"
|
||||
formLayout="修改"
|
||||
:schemas="formSchema"
|
||||
:model="data"
|
||||
v-bind="$attrs" />
|
||||
<ApiCusDetail v-if="data.current === 3" :dataSource="data" />
|
||||
|
||||
<div class="floor_button">
|
||||
<div class="submit">
|
||||
<ns-button @click="backStep" v-if="data.current">上一步</ns-button>
|
||||
<ns-button @click="stepSubmit" :disabled="!isDisable" type="primary">{{
|
||||
data.current === 3 ? '保存' : '下一步'
|
||||
}}</ns-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
// import { useNavigate } from '/nerv-lib/paas';
|
||||
import ApiCusDetail from './component/detail.vue';
|
||||
import { http } from '/nerv-lib/paas';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { NsMessage } from '/nerv-lib/paas';
|
||||
import { defineComponent, reactive, ref, provide, watch, computed } from 'vue';
|
||||
import NsStep from './component/step.vue';
|
||||
import { authorizationService } from '/nerv-base/store/modules/authorization-service';
|
||||
interface listenerInfo {
|
||||
current: number;
|
||||
/******************配置监听器 *******************/
|
||||
ID: number;
|
||||
name: string;
|
||||
projectName?: string;
|
||||
clusterProjectName: string;
|
||||
clusterName: string;
|
||||
description: string; //描述
|
||||
frontEndPort: number; //前端端口
|
||||
frontEndProtocol: string;
|
||||
domain?: string; //域名
|
||||
securityType?: string; //安全策略
|
||||
mode: string;
|
||||
isNeedVIP?: boolean; //是否需要vip
|
||||
trafficDistrStrategy: string; //转发规则 rr/wrr/wlc/lc
|
||||
isMutualAuth?: boolean; //是否开启双向认证
|
||||
/******************配置后端服务器****************/
|
||||
rsgID: number; //后端服务器组ID
|
||||
backEndProtocol: string; //后端协议
|
||||
backEndPort: number; //后端端口
|
||||
/*********************健康检查*******************/
|
||||
isHealthCheck: boolean; //启用
|
||||
healthProtocol: string; //协议
|
||||
healthPort: number; //端口
|
||||
healthInterval: number; //检查间隔(秒)
|
||||
healthTimeOut: number; //超时间隔(秒)
|
||||
healthFailTimes: number; //最大重试次数
|
||||
healthUrl?: string; //检查url
|
||||
}
|
||||
export default defineComponent({
|
||||
name: 'ListenerEdit',
|
||||
components: { NsStep, ApiCusDetail },
|
||||
setup() {
|
||||
const isEdit = ref(false);
|
||||
const router = useRouter();
|
||||
const clusterAddr = ref('');
|
||||
const projectIDs = ref('');
|
||||
const initIds = ref('');
|
||||
// const { navigateBack } = useNavigate();
|
||||
const navigateBack = () => {
|
||||
router.back();
|
||||
};
|
||||
const mainRef = ref();
|
||||
const errorItem = ref({});
|
||||
const backStep = () => {
|
||||
data.current--;
|
||||
};
|
||||
const editId = parseInt(router.currentRoute.value.params.ID);
|
||||
http.get(`/api/slb/objs/Listener/${editId}`).then((res) => {
|
||||
/******************配置监听器 *******************/
|
||||
data.projectName = res.projectName;
|
||||
data.name = res.name;
|
||||
data.projectID = res.projectID;
|
||||
initIds.value = res.projectID;
|
||||
//projectIDs.value = res.projectID;
|
||||
data.clusterProjectID = res.clusterProjectID;
|
||||
clusterAddr.value = res.clusterAddr;
|
||||
data.clusterProjectName = res.clusterProjectName;
|
||||
data.description = res.description;
|
||||
data.clusterName = res.clusterName;
|
||||
data.frontEndPort = res.frontEndPort;
|
||||
data.frontEndProtocol = res.frontEndProtocol;
|
||||
data.securityType = res.securityType;
|
||||
data.mode = res.mode;
|
||||
data.trafficDistrStrategy = res.trafficDistrStrategy;
|
||||
if (res.frontEndProtocol === 'https') {
|
||||
data.isMutualAuth = res.isMutualAuth;
|
||||
data.backEndProtocol = res.backEndProtocol;
|
||||
data.backEndPort = res.backEndPort;
|
||||
data.domain = res.domain;
|
||||
}
|
||||
if (res.mode === 'master-slave') {
|
||||
data.isNeedVIP = res.isNeedVIP;
|
||||
}
|
||||
if (res.frontEndProtocol === 'tcp' || res.frontEndProtocol === 'udp') {
|
||||
modeList.value = [
|
||||
{
|
||||
label: '主从模式',
|
||||
value: 'master-slave',
|
||||
},
|
||||
];
|
||||
trafficDistrStrategyList.value = [
|
||||
{
|
||||
label: '轮询',
|
||||
value: 'rr',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/******************配置后端服务器****************/
|
||||
data.rsgID = res.rsgID;
|
||||
data.rsgName = res.rsgName;
|
||||
data.backEndProtocol = res.backEndProtocol;
|
||||
data.backEndPort = res.backEndPort;
|
||||
/*********************健康检查*******************/
|
||||
data.isHealthCheck = res.isHealthCheck;
|
||||
if (res.isHealthCheck && res.isHealthCheck !== undefined) {
|
||||
data.healthProtocol = res.healthProtocol;
|
||||
data.healthPort = res.healthPort;
|
||||
data.healthInterval = res.healthInterval;
|
||||
data.healthTimeOut = res.healthTimeOut;
|
||||
data.healthFailTimes = res.healthFailTimes;
|
||||
if ((res.healthProtocol = 'http')) {
|
||||
data.healthUrl = res.healthUrl;
|
||||
}
|
||||
}
|
||||
isEdit.value = true;
|
||||
});
|
||||
const trafficDistrStrategyList = ref([
|
||||
{
|
||||
label: '轮询',
|
||||
value: 'rr',
|
||||
},
|
||||
{
|
||||
label: '加权轮询',
|
||||
value: 'wrr',
|
||||
},
|
||||
// {
|
||||
// label: '最少链接',
|
||||
// value: 'lc',
|
||||
// },
|
||||
{
|
||||
label: '加权最少链接',
|
||||
value: 'wlc',
|
||||
},
|
||||
]);
|
||||
const modeList = ref([
|
||||
{
|
||||
label: '主从模式',
|
||||
value: 'master-slave',
|
||||
},
|
||||
// {
|
||||
// label: '负载模式',
|
||||
// value: 'Loadbalance',
|
||||
// },
|
||||
]);
|
||||
const stepSubmit = () => {
|
||||
const checkField = ref('');
|
||||
switch (data.current) {
|
||||
case 0:
|
||||
checkField.value = 'ListenerCheck';
|
||||
break;
|
||||
case 1:
|
||||
checkField.value = 'RealServerCheck';
|
||||
break;
|
||||
case 2:
|
||||
checkField.value = 'HealthCheck';
|
||||
break;
|
||||
}
|
||||
if (data.current > 2) {
|
||||
submit();
|
||||
} else {
|
||||
http
|
||||
.post('/api/slb/objs/Listener/PreValidate', data, {
|
||||
headers: { CheckField: checkField.value },
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
errorItem.value = {};
|
||||
|
||||
data.current < 3 ? data.current++ : '';
|
||||
if (data.current === 1) {
|
||||
projectIDs.value = initIds.value;
|
||||
console.log(
|
||||
(formSchema.filter((x) => x.field === 'rsgID')[0].componentProps.immediate =
|
||||
true),
|
||||
);
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
if (error?.response?.data?.fieldErrors) {
|
||||
errorItem.value = error?.response?.data?.fieldErrors;
|
||||
let checkValue = [];
|
||||
switch (data.current) {
|
||||
case 0:
|
||||
checkValue = ['name', 'frontEndPort'];
|
||||
mainRef.value.triggerSubmit(checkValue);
|
||||
break;
|
||||
case 1:
|
||||
checkValue = ['backEndPort'];
|
||||
mainRef.value.triggerSubmit(checkValue);
|
||||
break;
|
||||
case 2:
|
||||
checkValue = [''];
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
function submit() {
|
||||
mainRef.value
|
||||
.triggerSubmit()
|
||||
.then((data) => {
|
||||
http.put('/api/slb/objs/Listener', data).then((res) => {
|
||||
NsMessage.success('操作成功', 1, () => {
|
||||
navigateBack();
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
let data = reactive<listenerInfo>({
|
||||
current: 0,
|
||||
ID: editId,
|
||||
});
|
||||
const current = ref(0);
|
||||
const isDisable = computed(() => {
|
||||
switch (data.current) {
|
||||
case 0:
|
||||
let pattern = /^[a-zA-Z][\d\a-zA-Z-]{0,32}$/;
|
||||
const ischeck =
|
||||
data.name &&
|
||||
data.frontEndPort &&
|
||||
pattern.test(data.name) &&
|
||||
data.clusterName &&
|
||||
!(data.frontEndPort < 30000) &&
|
||||
!(data.frontEndPort > 32767) &&
|
||||
data.frontEndProtocol &&
|
||||
data.mode &&
|
||||
data.trafficDistrStrategy;
|
||||
if (data.frontEndProtocol === 'https') {
|
||||
return ischeck && data.securityType && data.domain;
|
||||
} else {
|
||||
return ischeck;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
return data.rsgID && data.backEndProtocol && data.backEndPort;
|
||||
break;
|
||||
case 2:
|
||||
if (data.isHealthCheck) {
|
||||
const ischeck2 =
|
||||
data.healthProtocol &&
|
||||
data.healthPort &&
|
||||
data.healthInterval &&
|
||||
data.healthTimeOut &&
|
||||
data.healthFailTimes;
|
||||
|
||||
if (data.healthProtocol === 'http') {
|
||||
return ischeck2 && data.healthUrl;
|
||||
} else {
|
||||
return ischeck2;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
});
|
||||
const formSchema = reactive([
|
||||
/******************************配置监听器******************************* */
|
||||
{
|
||||
field: 'ID',
|
||||
component: 'NsInputText',
|
||||
show: false,
|
||||
viewOnly: false,
|
||||
},
|
||||
{
|
||||
label: '项目',
|
||||
field: 'projectName',
|
||||
component: 'NsInputText' /* todo 需要根据权限过滤 */,
|
||||
show: (record: any) => {
|
||||
return record.current === 0;
|
||||
},
|
||||
viewOnly: true,
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
label: '名称',
|
||||
component: 'NsInputText',
|
||||
show: (record) => {
|
||||
return record.current === 0;
|
||||
},
|
||||
viewOnly: true,
|
||||
},
|
||||
{
|
||||
label: '集群项目',
|
||||
field: 'clusterProjectName',
|
||||
component: 'NsInputText',
|
||||
show: (record: any) => {
|
||||
return record.current === 0;
|
||||
},
|
||||
viewOnly: true,
|
||||
},
|
||||
{
|
||||
field: 'clusterName',
|
||||
label: '集群',
|
||||
component: 'NsInputText',
|
||||
show: (record: any) => {
|
||||
return record.current === 0;
|
||||
},
|
||||
viewOnly: true,
|
||||
},
|
||||
{
|
||||
field: 'frontEndProtocol',
|
||||
label: '前端协议',
|
||||
component: 'NsInputText',
|
||||
show: (record: any) => {
|
||||
return record.current === 0;
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '域名',
|
||||
field: 'domain',
|
||||
component: 'NsSelectApi' /* todo 需要根据权限过滤 */,
|
||||
ifShow: (record: any) => {
|
||||
return record.frontEndProtocol === 'https';
|
||||
},
|
||||
show: (record: any) => {
|
||||
return record.current === 0 && record.frontEndProtocol === 'https';
|
||||
},
|
||||
defaultParams: {
|
||||
content: clusterAddr,
|
||||
},
|
||||
componentProps: {
|
||||
api: '/api/dns/dns/objs/record/listName',
|
||||
showSearch: true,
|
||||
dropdownReload: true,
|
||||
filterOption: (input: string, option: any) => {
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||
},
|
||||
immediate: true,
|
||||
resultField: 'name',
|
||||
placeholder: '请选择域名',
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择域名',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '前端端口',
|
||||
field: 'frontEndPort',
|
||||
show: (record: any) => {
|
||||
return record.current === 0;
|
||||
},
|
||||
component: 'NsInputNumber' /* todo 需要根据权限过滤 */,
|
||||
componentProps: {
|
||||
min: 1,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '前端端口必填',
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
trigger: 'change',
|
||||
validator: async (rule, value) => {
|
||||
console.log(errorItem);
|
||||
if (Object.keys(errorItem.value).indexOf('frontEndPort') !== -1) {
|
||||
const errorInfo = errorItem.value['frontEndPort'];
|
||||
delete errorItem.value['frontEndPort'];
|
||||
return Promise.reject(errorInfo);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
trigger: 'change',
|
||||
validator: async (rule, value) => {
|
||||
if (value < 30000 || value > 32767) {
|
||||
return Promise.reject('前端端口号的范围是30000~32767');
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
field: 'securityType',
|
||||
label: '安全类型',
|
||||
component: 'NsSelect',
|
||||
ifShow: (record: any) => {
|
||||
return record.frontEndProtocol === 'https';
|
||||
},
|
||||
show: (record: any) => {
|
||||
return record.current === 0 && record.frontEndProtocol === 'https';
|
||||
},
|
||||
componentProps: {
|
||||
placeholder: '请选择安全类型',
|
||||
options: [
|
||||
{
|
||||
label: '安全策略TLS-1-0',
|
||||
value: 'TLS_1_0',
|
||||
},
|
||||
{
|
||||
label: '安全策略TLS-1-1',
|
||||
value: 'TLS_1_1',
|
||||
},
|
||||
{
|
||||
label: '安全策略TLS-1-2',
|
||||
value: 'TLS_1_2',
|
||||
},
|
||||
{
|
||||
label: '安全策略TLS-1-2-Strict',
|
||||
value: 'TLS_1_2_Strict',
|
||||
},
|
||||
],
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择安全类型',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
field: 'isMutualAuth',
|
||||
label: '双向认证',
|
||||
class: 'NsSwitch',
|
||||
component: 'NsSwitch',
|
||||
ifShow: (record: any) => {
|
||||
return record.frontEndProtocol === 'https';
|
||||
},
|
||||
componentProps: {
|
||||
checkedChildren: '开',
|
||||
},
|
||||
show: (record: any) => {
|
||||
return record.current === 0 && record.frontEndProtocol === 'https';
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'mode',
|
||||
label: '监听器模式',
|
||||
component: 'NsSelect',
|
||||
show: (record: any) => {
|
||||
return record.current === 0;
|
||||
},
|
||||
componentProps: {
|
||||
placeholder: '请选择',
|
||||
options: modeList,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择监听器模式',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
field: 'isNeedVIP',
|
||||
label: '是否绑定VIP',
|
||||
component: 'NsSwitch',
|
||||
class: 'NsSwitch',
|
||||
show: (record: any) => {
|
||||
return record.current === 0 && record.mode === 'master-slave';
|
||||
},
|
||||
componentProps: {
|
||||
checkedChildren: '开',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'trafficDistrStrategy',
|
||||
label: '分配策略类型',
|
||||
component: 'NsSelect',
|
||||
show: (record: any) => {
|
||||
return record.current === 0;
|
||||
},
|
||||
componentProps: {
|
||||
placeholder: '请选择分配策略类型',
|
||||
options: trafficDistrStrategyList,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择分配策略类型',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
field: 'description',
|
||||
label: '描述',
|
||||
show: (record: any) => {
|
||||
return record.current === 0;
|
||||
},
|
||||
component: 'NsTextarea',
|
||||
componentProps: {
|
||||
showCount: true,
|
||||
maxlength: 200,
|
||||
},
|
||||
rules: [{}],
|
||||
},
|
||||
/******************************配置后端服务器******************************* */
|
||||
{
|
||||
field: 'rsgID',
|
||||
label: '后端服务器组',
|
||||
component: 'NsSelectApi',
|
||||
addModel: {
|
||||
rsgName: 'Name',
|
||||
},
|
||||
defaultParams: {
|
||||
projectID: projectIDs,
|
||||
},
|
||||
|
||||
show: (record: any) => {
|
||||
return record.current === 1;
|
||||
},
|
||||
componentProps: {
|
||||
api: '/api/slb/objs/RealServerGroup/ListWithSuccess',
|
||||
resultField: 'data',
|
||||
autoClearValue: true,
|
||||
showSearch: true,
|
||||
dropdownReload: true,
|
||||
labelField: 'Name',
|
||||
// filterData: (item) => {
|
||||
// return authorizationService().checkPermission('slb', 'realServerGroup');
|
||||
// },
|
||||
immediate: false,
|
||||
valueField: 'ID',
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择后端服务器组',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
// field: 'rsgName',
|
||||
// label: '后端服务器组',
|
||||
// component: 'NsInputText',
|
||||
// viewOnly: true,
|
||||
// ifShow: () => {
|
||||
// return !authorizationService().checkPermission('slb', 'realServerGroup');
|
||||
// },
|
||||
// show: (record: any) => {
|
||||
// return record.current === 1;
|
||||
// },
|
||||
// },
|
||||
{
|
||||
field: 'backEndProtocol',
|
||||
label: '后端协议',
|
||||
component: 'NsSelect',
|
||||
show: (record: any) => {
|
||||
return record.current === 1;
|
||||
},
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
options: [
|
||||
{
|
||||
label: 'TCP',
|
||||
value: 'tcp',
|
||||
},
|
||||
{
|
||||
label: 'UDP',
|
||||
value: 'udp',
|
||||
},
|
||||
{
|
||||
label: 'HTTP',
|
||||
value: 'http',
|
||||
},
|
||||
// {
|
||||
// label: 'HTTPS',
|
||||
// value: 'https',
|
||||
// },
|
||||
],
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择后端协议',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '后端端口',
|
||||
field: 'backEndPort',
|
||||
show: (record: any) => {
|
||||
return record.current === 1;
|
||||
},
|
||||
component: 'NsInputNumber' /* todo 需要根据权限过滤 */,
|
||||
componentProps: {
|
||||
onChange: (val) => {
|
||||
data.healthPort = val;
|
||||
},
|
||||
min: 1,
|
||||
max: 65535,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '后端端口必填',
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
trigger: 'change',
|
||||
validator: async (rule, value) => {
|
||||
if (Object.keys(errorItem.value).indexOf('backEndPort') !== -1) {
|
||||
const errorInfo = errorItem.value['backEndPort'];
|
||||
delete errorItem.value['backEndPort'];
|
||||
return Promise.reject(errorInfo);
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
/******************************健康检查******************************* */
|
||||
{
|
||||
field: 'isHealthCheck',
|
||||
label: '启用',
|
||||
component: 'NsSwitch',
|
||||
class: 'NsSwitch',
|
||||
show: (record: any) => {
|
||||
return record.current === 2;
|
||||
},
|
||||
componentProps: {
|
||||
checkedChildren: '开',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'healthProtocol',
|
||||
label: '协议',
|
||||
component: 'NsSelect',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck;
|
||||
},
|
||||
show: (record: any) => {
|
||||
return record.current === 2 && record.isHealthCheck;
|
||||
},
|
||||
componentProps: {
|
||||
placeholder: '请选择',
|
||||
options: [
|
||||
{
|
||||
label: 'TCP',
|
||||
value: 'tcp',
|
||||
},
|
||||
{
|
||||
label: 'UDP',
|
||||
value: 'udp',
|
||||
},
|
||||
{
|
||||
label: 'HTTP',
|
||||
value: 'http',
|
||||
},
|
||||
// {
|
||||
// label: 'HTTPS',
|
||||
// value: 'https',
|
||||
// },
|
||||
],
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择协议',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '端口',
|
||||
field: 'healthPort',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck;
|
||||
},
|
||||
show: (record: any) => {
|
||||
return record.current === 2 && record.isHealthCheck;
|
||||
},
|
||||
component: 'NsInputNumber',
|
||||
componentProps: {
|
||||
min: 1,
|
||||
max: 65535,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '端口必填',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '检查间隔(秒)',
|
||||
field: 'healthInterval',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck;
|
||||
},
|
||||
show: (record: any) => {
|
||||
return record.current === 2 && record.isHealthCheck;
|
||||
},
|
||||
component: 'NsInputNumber',
|
||||
componentProps: {
|
||||
min: 1,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '检查间隔必填',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '超时间隔(秒)',
|
||||
field: 'healthTimeOut',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck;
|
||||
},
|
||||
show: (record: any) => {
|
||||
return record.current === 2 && record.isHealthCheck;
|
||||
},
|
||||
component: 'NsInputNumber',
|
||||
componentProps: {
|
||||
min: 1,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '超时间隔必填',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
field: 'healthUrl',
|
||||
label: '健康检查URL',
|
||||
component: 'NsInput',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck && record.healthProtocol === 'http';
|
||||
},
|
||||
show: (record: any) => {
|
||||
return record.current === 2 && record.isHealthCheck && record.healthProtocol === 'http';
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '健康检查URL必填',
|
||||
trigger: 'blur',
|
||||
},
|
||||
// {
|
||||
// trigger: 'change',
|
||||
// validator: async (rule, value) => {
|
||||
// if (Object.keys(errorItem.value).indexOf('routePath') !== -1) {
|
||||
// const errorInfo = errorItem.value['routePath'];
|
||||
// delete errorItem.value['routePath'];
|
||||
// return Promise.reject(errorInfo);
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
{
|
||||
trigger: 'blur',
|
||||
validator: async (rule, value) => {
|
||||
if (value) {
|
||||
if (!/^\/[a-zA-Z\/0-9_\.\-\#\%]{0,127}$/.test(value)) {
|
||||
return Promise.reject(
|
||||
'健康检查URL必须以/开头,只能包含字母数字或_.-#%,长度限制在1-128字符之间',
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '最大重试次数',
|
||||
field: 'healthFailTimes',
|
||||
ifShow: (record: any) => {
|
||||
return record.isHealthCheck;
|
||||
},
|
||||
show: (record: any) => {
|
||||
return record.current === 2 && record.isHealthCheck;
|
||||
},
|
||||
component: 'NsInputNumber',
|
||||
componentProps: {
|
||||
min: 1,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '最大重试次数必填',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
return {
|
||||
authorizationService,
|
||||
backStep,
|
||||
navigateBack,
|
||||
isEdit,
|
||||
stepSubmit,
|
||||
isDisable,
|
||||
mainRef,
|
||||
submit,
|
||||
current,
|
||||
data,
|
||||
formSchema,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
:deep(.NsSwitch) {
|
||||
.ant-switch {
|
||||
width: 20px !important;
|
||||
}
|
||||
}
|
||||
:deep(.ant-page-header-heading) {
|
||||
justify-content: unset !important;
|
||||
}
|
||||
.floor_button {
|
||||
width: 100%;
|
||||
margin-top: 60px;
|
||||
margin-bottom: 30px;
|
||||
display: flex;
|
||||
.submit {
|
||||
margin-left: auto !important;
|
||||
.ant-btn {
|
||||
width: 150px !important;
|
||||
margin-right: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
138
nervui-slb/src/view/listenerManage/list.vue
Normal file
138
nervui-slb/src/view/listenerManage/list.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<ns-view-list-table v-bind="tableConfig" rowKey="ID" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import moment from 'moment';
|
||||
import { useRouter } from 'vue-router';
|
||||
export default defineComponent({
|
||||
name: 'ListenerList',
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
const tableConfig = {
|
||||
api: '/api/slb/objs/Listener',
|
||||
params: {
|
||||
order: 'created_at desc',
|
||||
},
|
||||
title: '监听器',
|
||||
refreshTime: 5,
|
||||
rowSelection: null,
|
||||
resultField: 'data',
|
||||
columns: [
|
||||
{
|
||||
title: '项目',
|
||||
dataIndex: 'projectName',
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: 'slb集群所属项目',
|
||||
dataIndex: 'clusterProjectName',
|
||||
},
|
||||
{
|
||||
title: 'slb集群',
|
||||
dataIndex: 'clusterName',
|
||||
},
|
||||
{
|
||||
title: '访问地址',
|
||||
dataIndex: 'vip',
|
||||
},
|
||||
{
|
||||
title: '前端协议',
|
||||
dataIndex: 'frontEndProtocol',
|
||||
},
|
||||
{
|
||||
title: '前端端口',
|
||||
dataIndex: 'frontEndPort',
|
||||
},
|
||||
{
|
||||
title: '后端服务器组',
|
||||
dataIndex: 'rsgName',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
transform: {
|
||||
pipe: 'state',
|
||||
messageField: 'reason',
|
||||
},
|
||||
},
|
||||
// {
|
||||
// title: '创建人',
|
||||
// dataIndex: 'CreatedBy',
|
||||
// },
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'CreatedAt',
|
||||
sorter: true,
|
||||
customRender: (text: any) => {
|
||||
return moment(text.record.CreatedAt).format('YYYY-MM-DD HH:mm:ss');
|
||||
},
|
||||
},
|
||||
],
|
||||
columnActions: {
|
||||
title: '操作',
|
||||
actions: [
|
||||
{
|
||||
label: '删除',
|
||||
name: 'listenerRemove',
|
||||
confirm: true,
|
||||
isReload: true,
|
||||
ifShow: (record: any) => {
|
||||
return record.status !== 'Creating';
|
||||
},
|
||||
api: { method: 'delete', url: '/api/slb/objs/Listener/:ID' },
|
||||
},
|
||||
{
|
||||
label: '编辑',
|
||||
name: 'listenerEdit',
|
||||
ifShow: (record: any) => {
|
||||
return record.status === 'Succeed';
|
||||
},
|
||||
route: 'edit/:ID',
|
||||
},
|
||||
{
|
||||
label: '管理',
|
||||
name: 'listenerManage',
|
||||
ifShow: (record: any) => {
|
||||
return record.status === 'Succeed';
|
||||
},
|
||||
handle: (record: any) => {
|
||||
const title = `${record.name}`;
|
||||
router.push({
|
||||
name: 'listenerManage',
|
||||
params: {
|
||||
ID: record.ID,
|
||||
rsgID: record.rsgID,
|
||||
pageTitle: title,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
headerActions: [
|
||||
{
|
||||
label: '添加监听器',
|
||||
name: 'listenerAdd',
|
||||
type: 'primary',
|
||||
route: 'add',
|
||||
},
|
||||
],
|
||||
formConfig: {},
|
||||
|
||||
rowKey: 'ID',
|
||||
};
|
||||
|
||||
return {
|
||||
moment,
|
||||
tableConfig,
|
||||
};
|
||||
},
|
||||
methods: {},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
100
nervui-slb/src/view/listenerManage/listenerRealServer.vue
Normal file
100
nervui-slb/src/view/listenerManage/listenerRealServer.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<ns-view-list-table v-bind="tableConfig" rowKey="ID">
|
||||
<template #healthStatus="{ record }">
|
||||
<span :style="{ color: dealColor(record.healthStatus) }">{{ record.healthStatus }}</span>
|
||||
</template>
|
||||
</ns-view-list-table>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, reactive, provide } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import moment from 'moment';
|
||||
export default defineComponent({
|
||||
name: 'ListenerRealServer',
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
const ID = parseInt(router.currentRoute.value.params.rsgID);
|
||||
const listenerID = parseInt(router.currentRoute.value.params.ID);
|
||||
|
||||
const dealColor = (val) => {
|
||||
switch (val) {
|
||||
case 'Active':
|
||||
return '#17be6b';
|
||||
break;
|
||||
case 'Abnormal':
|
||||
return '#ffd591';
|
||||
break;
|
||||
case 'Fail':
|
||||
return 'red';
|
||||
break;
|
||||
case 'Unknow':
|
||||
return '#d9d9d9';
|
||||
break;
|
||||
}
|
||||
};
|
||||
const tableConfig = {
|
||||
api: '/api/slb/objs/Listener/RealServer',
|
||||
params: {
|
||||
listenerID: listenerID,
|
||||
rsgID: ID,
|
||||
order: 'created_at desc',
|
||||
},
|
||||
title: router.currentRoute.value.params.pageTitle,
|
||||
rowSelection: null,
|
||||
refreshTime: 5,
|
||||
resultField: 'data',
|
||||
columns: [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: '真实服务器IP',
|
||||
dataIndex: 'ip',
|
||||
},
|
||||
{
|
||||
title: '权重',
|
||||
dataIndex: 'weight',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'healthStatus',
|
||||
slots: { customRender: 'healthStatus' },
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
dataIndex: 'description',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
dataIndex: 'CreatedBy',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'CreatedAt',
|
||||
sorter: true,
|
||||
customRender: (text: any) => {
|
||||
return moment(text.record.CreatedAt).format('YYYY-MM-DD HH:mm:ss');
|
||||
},
|
||||
},
|
||||
],
|
||||
formConfig: {
|
||||
schemas: [],
|
||||
params: {},
|
||||
},
|
||||
rowKey: 'uuid',
|
||||
};
|
||||
|
||||
return {
|
||||
dealColor,
|
||||
moment,
|
||||
tableConfig,
|
||||
};
|
||||
},
|
||||
methods: {},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
122
nervui-slb/src/view/realServerGroup/add.vue
Normal file
122
nervui-slb/src/view/realServerGroup/add.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<!-- @format -->
|
||||
|
||||
<template>
|
||||
<NsViewAddForm
|
||||
:schemas="formSchema"
|
||||
:model="data"
|
||||
formLayout="修改"
|
||||
title="新增后端服务器组"
|
||||
api="/api/slb/objs/RealServerGroup" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, provide, reactive, ref } from 'vue';
|
||||
|
||||
import { authorizationService } from '/nerv-lib/paas';
|
||||
export default defineComponent({
|
||||
name: 'RealServerGroupAdd',
|
||||
setup() {
|
||||
const mainRef = ref();
|
||||
|
||||
const data = reactive({});
|
||||
|
||||
const formSchema = ref([
|
||||
{
|
||||
label: '所属项目',
|
||||
field: 'projectID',
|
||||
component: 'NsSelectApi' /* todo 需要根据权限过滤 */,
|
||||
componentProps: {
|
||||
api: {
|
||||
url: '/api/passport/passport/objs/Authorization/CheckAuthorization',
|
||||
method: 'POST',
|
||||
},
|
||||
showSearch: true,
|
||||
filterOption: (input: string, option: any) => {
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||
},
|
||||
filterData: (item) => {
|
||||
return authorizationService().checkPermission(
|
||||
'slb',
|
||||
'realServerGroup',
|
||||
'add',
|
||||
item.projectname,
|
||||
);
|
||||
},
|
||||
autoSelectFirst: true,
|
||||
resultField: 'projects',
|
||||
labelField: 'projectname',
|
||||
valueField: 'projectid',
|
||||
immediate: true,
|
||||
placeholder: '请选择项目',
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
type: 'number',
|
||||
required: true,
|
||||
message: '项目必填',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
field: 'name',
|
||||
label: '服务器组名称',
|
||||
component: 'NsInput',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '服务器组名称必填',
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
pattern: /^[a-z][\d\a-z-]{5,31}$/,
|
||||
message: '支持小写字母、数字输入和短划线(-),必须以小写字母开头,长度6-32字符',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
label: '描述',
|
||||
field: 'description',
|
||||
component: 'NsTextarea' /* todo 需要根据权限过滤 */,
|
||||
componentProps: {
|
||||
showCount: true,
|
||||
maxlength: 255,
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
return {
|
||||
data,
|
||||
mainRef,
|
||||
|
||||
formSchema,
|
||||
};
|
||||
},
|
||||
beforeCreate() {},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-col {
|
||||
flex: 0 0 120px !important;
|
||||
}
|
||||
.ant-page-header {
|
||||
padding: 0 24px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
:deep(.ant-page-header-heading-extra) {
|
||||
margin-right: auto !important;
|
||||
margin-left: 0;
|
||||
}
|
||||
.createApp {
|
||||
position: fixed;
|
||||
top: 165px;
|
||||
left: 620px;
|
||||
}
|
||||
</style>
|
||||
67
nervui-slb/src/view/realServerGroup/edit.vue
Normal file
67
nervui-slb/src/view/realServerGroup/edit.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<!-- @format -->
|
||||
|
||||
<template>
|
||||
<NsViewEditForm
|
||||
:schemas="formSchema"
|
||||
:model="data"
|
||||
formLayout="修改"
|
||||
title="编辑后端服务器组"
|
||||
:getApi="getApi"
|
||||
api="/api/slb/objs/RealServerGroup" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, provide, reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
export default defineComponent({
|
||||
name: 'RealServerGroupEdit',
|
||||
setup() {
|
||||
const mainRef = ref();
|
||||
const router = useRouter();
|
||||
const getApi = `/api/slb/objs/RealServerGroup/${router.currentRoute.value.params.ID}`;
|
||||
const data = reactive({});
|
||||
|
||||
const formSchema = ref([
|
||||
{
|
||||
field: 'ID',
|
||||
component: 'NsInputText',
|
||||
show: false,
|
||||
viewOnly: false,
|
||||
},
|
||||
{
|
||||
label: '所属项目',
|
||||
field: 'projectName',
|
||||
component: 'NsInputText' /* todo 需要根据权限过滤 */,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'name',
|
||||
label: '服务器组名称',
|
||||
component: 'NsInputText',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
label: '描述',
|
||||
field: 'description',
|
||||
component: 'NsTextarea' /* todo 需要根据权限过滤 */,
|
||||
componentProps: {
|
||||
showCount: true,
|
||||
maxlength: 255,
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
return {
|
||||
data,
|
||||
mainRef,
|
||||
getApi,
|
||||
formSchema,
|
||||
};
|
||||
},
|
||||
beforeCreate() {},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
125
nervui-slb/src/view/realServerGroup/list.vue
Normal file
125
nervui-slb/src/view/realServerGroup/list.vue
Normal file
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<ns-view-list-table v-bind="tableConfig" rowKey="ID" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, reactive, provide } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import moment from 'moment';
|
||||
export default defineComponent({
|
||||
name: 'RealServerGroupList',
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
const tableConfig = {
|
||||
api: '/api/slb/objs/RealServerGroup',
|
||||
params: {
|
||||
order: 'created_at desc',
|
||||
},
|
||||
title: '后端服务器组管理',
|
||||
rowSelection: null,
|
||||
refreshTime: 5,
|
||||
resultField: 'data',
|
||||
columns: [
|
||||
{
|
||||
title: '项目',
|
||||
dataIndex: 'projectName',
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
dataIndex: 'description',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
transform: {
|
||||
pipe: 'state',
|
||||
messageField: 'reason',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
dataIndex: 'CreatedBy',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'CreatedAt',
|
||||
sorter: true,
|
||||
|
||||
customRender: (text: any) => {
|
||||
return moment(text.record.CreatedAt).format('YYYY-MM-DD HH:mm:ss');
|
||||
},
|
||||
},
|
||||
],
|
||||
columnActions: {
|
||||
title: '操作',
|
||||
actions: [
|
||||
{
|
||||
label: '删除',
|
||||
name: 'realServerGroupRemove',
|
||||
confirm: true,
|
||||
isReload: true,
|
||||
ifShow: (record: any) => {
|
||||
return record.status !== 'Creating';
|
||||
},
|
||||
dynamicDisabled: (record: any) => {
|
||||
return record.soldStatus === 1;
|
||||
},
|
||||
api: { method: 'delete', url: '/api/slb/objs/RealServerGroup/:ID' },
|
||||
},
|
||||
{
|
||||
label: '编辑',
|
||||
name: 'realServerGroupEdit',
|
||||
ifShow: (record: any) => {
|
||||
return record.status === 'Succeed';
|
||||
},
|
||||
route: `/slb/realServerGroup/edit/:ID`,
|
||||
},
|
||||
{
|
||||
label: '管理',
|
||||
name: 'realServerGroupManage',
|
||||
ifShow: (record: any) => {
|
||||
return record.status === 'Succeed';
|
||||
},
|
||||
handle: (record) => {
|
||||
const title = `${record.projectName} > ${record.name}`;
|
||||
router.push({
|
||||
name: 'realServerGroupManage',
|
||||
params: {
|
||||
ID: record.ID,
|
||||
pageTitle: title,
|
||||
projectName: record.projectName,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
headerActions: [
|
||||
{
|
||||
label: '添加',
|
||||
name: 'realServerGroupAdd',
|
||||
type: 'primary',
|
||||
route: `/slb/realServerGroup/add`,
|
||||
},
|
||||
],
|
||||
formConfig: {
|
||||
schemas: [],
|
||||
params: {},
|
||||
},
|
||||
rowKey: 'uuid',
|
||||
};
|
||||
return {
|
||||
moment,
|
||||
tableConfig,
|
||||
};
|
||||
},
|
||||
methods: {},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
141
nervui-slb/src/view/realServerGroup/realServerManage/add.vue
Normal file
141
nervui-slb/src/view/realServerGroup/realServerManage/add.vue
Normal file
@@ -0,0 +1,141 @@
|
||||
<!-- @format -->
|
||||
|
||||
<template>
|
||||
<NsViewAddForm
|
||||
:schemas="formSchema"
|
||||
:model="data"
|
||||
formLayout="修改"
|
||||
title="添加后端服务器"
|
||||
api="/api/slb/objs/RealServer" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
export default defineComponent({
|
||||
name: 'RealServerAdd',
|
||||
setup() {
|
||||
const mainRef = ref();
|
||||
const router = useRouter();
|
||||
const data = reactive({});
|
||||
const params = router.currentRoute.value.params;
|
||||
let formSchema = ref([
|
||||
{
|
||||
field: 'rsgID',
|
||||
component: 'NsInputText',
|
||||
show: false,
|
||||
viewOnly: false,
|
||||
defaultValue: parseInt(params.ID),
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
label: '服务器名称',
|
||||
component: 'NsInput',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '服务器名称必填',
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
pattern: /^[a-z][\d\a-z-]{5,31}$/,
|
||||
message: '支持小写字母、数字输入和短划线(-),必须以小写字母开头,长度6-32字符',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
field: 'ip',
|
||||
label: '真实服务IP',
|
||||
class: 'NsInputIp',
|
||||
component: 'NsInputIp',
|
||||
componentProps: {
|
||||
placeholder: '请输入',
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '真实服务IP必填',
|
||||
trigger: 'change',
|
||||
},
|
||||
{
|
||||
trigger: 'change',
|
||||
validator: async (rule, value) => {
|
||||
if (value) {
|
||||
var isTrue = true;
|
||||
value.split('.').forEach((item) => {
|
||||
if (item == '') {
|
||||
isTrue = false;
|
||||
}
|
||||
});
|
||||
if (!isTrue) {
|
||||
return Promise.reject('请输入正确的IP格式');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
label: '权重',
|
||||
field: 'weight',
|
||||
component: 'NsInputNumber' /* todo 需要根据权限过滤 */,
|
||||
componentProps: {
|
||||
min: 0,
|
||||
max: 65535,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '权重必填',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
label: '描述',
|
||||
field: 'description',
|
||||
component: 'NsTextarea' /* todo 需要根据权限过滤 */,
|
||||
componentProps: {
|
||||
showCount: true,
|
||||
maxlength: 255,
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
return {
|
||||
data,
|
||||
mainRef,
|
||||
formSchema,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-col {
|
||||
flex: 0 0 120px !important;
|
||||
}
|
||||
.ant-page-header {
|
||||
padding: 0 24px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
:deep(.ant-page-header-heading-extra) {
|
||||
margin-right: auto !important;
|
||||
margin-left: 0;
|
||||
}
|
||||
.createApp {
|
||||
position: fixed;
|
||||
top: 165px;
|
||||
left: 620px;
|
||||
}
|
||||
:deep(.NsInputIp .ant-form-item-control-input-content) {
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
115
nervui-slb/src/view/realServerGroup/realServerManage/edit.vue
Normal file
115
nervui-slb/src/view/realServerGroup/realServerManage/edit.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<!-- @format -->
|
||||
|
||||
<template>
|
||||
<NsViewEditForm
|
||||
:schemas="formSchema"
|
||||
:model="data"
|
||||
formLayout="修改"
|
||||
title="编辑后端服务器"
|
||||
:getApi="getApi"
|
||||
api="/api/slb/objs/RealServer" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, provide, reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
export default defineComponent({
|
||||
name: 'RealServerEdit',
|
||||
setup() {
|
||||
const mainRef = ref();
|
||||
const router = useRouter();
|
||||
const getApi = `/api/slb/objs/RealServer/${router.currentRoute.value.params.editId}`;
|
||||
|
||||
const data = reactive({});
|
||||
|
||||
const formSchema = ref([
|
||||
{
|
||||
field: 'ID',
|
||||
component: 'NsInputText',
|
||||
show: false,
|
||||
viewOnly: false,
|
||||
defaultValue: parseInt(router.currentRoute.value.params.editId),
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
label: '服务器名称',
|
||||
component: 'NsInputText',
|
||||
},
|
||||
{
|
||||
field: 'ip',
|
||||
label: '真实服务IP',
|
||||
component: 'NsInputIp',
|
||||
class: 'NsInputIp',
|
||||
componentProps: {
|
||||
modelValue: router.currentRoute.value.params.ip,
|
||||
placeholder: '请输入',
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '真实服务IP必填',
|
||||
trigger: 'change',
|
||||
},
|
||||
{
|
||||
trigger: 'change',
|
||||
validator: async (rule, value) => {
|
||||
if (value) {
|
||||
var isTrue = true;
|
||||
value.split('.').forEach((item) => {
|
||||
if (item == '') {
|
||||
isTrue = false;
|
||||
}
|
||||
});
|
||||
if (!isTrue) {
|
||||
return Promise.reject('请输入正确的IP格式');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
label: '权重',
|
||||
field: 'weight',
|
||||
component: 'NsInputNumber' /* todo 需要根据权限过滤 */,
|
||||
componentProps: {
|
||||
min: 0,
|
||||
max: 65535,
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
type: 'number',
|
||||
message: '权重必填',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
label: '描述',
|
||||
field: 'description',
|
||||
component: 'NsTextarea' /* todo 需要根据权限过滤 */,
|
||||
componentProps: {
|
||||
showCount: true,
|
||||
maxlength: 255,
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
return {
|
||||
data,
|
||||
mainRef,
|
||||
getApi,
|
||||
formSchema,
|
||||
};
|
||||
},
|
||||
beforeCreate() {},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.NsInputIp .ant-form-item-control-input-content) {
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
127
nervui-slb/src/view/realServerGroup/realServerManage/list.vue
Normal file
127
nervui-slb/src/view/realServerGroup/realServerManage/list.vue
Normal file
@@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<ns-view-list-table v-bind="tableConfig" rowKey="ID" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, reactive, provide } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import moment from 'moment';
|
||||
export default defineComponent({
|
||||
name: 'RealServerList',
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
const ID = parseInt(router.currentRoute.value.params.ID);
|
||||
const tableConfig = {
|
||||
api: '/api/slb/objs/RealServer',
|
||||
params: {
|
||||
rsgID: ID,
|
||||
order: 'created_at desc',
|
||||
},
|
||||
title: router.currentRoute.value.params.pageTitle,
|
||||
rowSelection: null,
|
||||
refreshTime: 5,
|
||||
resultField: 'data',
|
||||
columns: [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
title: '真实服务器IP',
|
||||
dataIndex: 'ip',
|
||||
},
|
||||
|
||||
{
|
||||
title: '权重',
|
||||
dataIndex: 'weight',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
transform: {
|
||||
pipe: 'state',
|
||||
messageField: 'reason',
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
title: '描述',
|
||||
dataIndex: 'description',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
dataIndex: 'CreatedBy',
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'CreatedAt',
|
||||
sorter: true,
|
||||
customRender: (text: any) => {
|
||||
return moment(text.record.CreatedAt).format('YYYY-MM-DD HH:mm:ss');
|
||||
},
|
||||
},
|
||||
],
|
||||
columnActions: {
|
||||
title: '操作',
|
||||
actions: [
|
||||
{
|
||||
label: '删除',
|
||||
name: 'realServerRemove',
|
||||
confirm: true,
|
||||
isReload: true,
|
||||
ifShow: (record: any) => {
|
||||
return record.status !== 'Creating';
|
||||
},
|
||||
dynamicDisabled: (record: any) => {
|
||||
return record.soldStatus === 1;
|
||||
},
|
||||
api: { method: 'delete', url: '/api/slb/objs/RealServer/:ID' },
|
||||
},
|
||||
{
|
||||
label: '编辑',
|
||||
name: 'realServerEdit',
|
||||
ifShow: (record: any) => {
|
||||
return record.status === 'Succeed';
|
||||
},
|
||||
handle: (record) => {
|
||||
router.push({
|
||||
name: 'realServerEdit',
|
||||
params: {
|
||||
editId: record.ID,
|
||||
ip: record.ip,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
headerActions: [
|
||||
{
|
||||
label: '添加',
|
||||
name: 'realServerAdd',
|
||||
type: 'primary',
|
||||
handle: (record) => {
|
||||
router.push({
|
||||
name: 'realServerAdd',
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
formConfig: {
|
||||
schemas: [],
|
||||
params: {},
|
||||
},
|
||||
rowKey: 'uuid',
|
||||
};
|
||||
|
||||
return {
|
||||
moment,
|
||||
tableConfig,
|
||||
};
|
||||
},
|
||||
methods: {},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
48
nervui-slb/tsconfig.json
Normal file
48
nervui-slb/tsconfig.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"baseUrl": "./",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"jsx": "preserve",
|
||||
"lib": ["esnext", "dom"],
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"strictFunctionTypes": false,
|
||||
"target": "esnext",
|
||||
"types": ["vite/client"],
|
||||
"typeRoots": [
|
||||
"../node_modules/@types",
|
||||
"../node_modules/@vue",
|
||||
"../type"
|
||||
],
|
||||
"paths": {
|
||||
"/@/*": [
|
||||
"src/*"
|
||||
],
|
||||
"/nerv-lib/*": [
|
||||
"../lib/*"
|
||||
],
|
||||
"/nerv-base/*": [
|
||||
"../lib/paas/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*",
|
||||
"type/**/*",
|
||||
"mock/**/*",
|
||||
"vite.config.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"**/*.js"
|
||||
]
|
||||
}
|
||||
19
nervui-slb/vite.config.ts
Normal file
19
nervui-slb/vite.config.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import configFun from '../build/vite-default.config';
|
||||
const dirname = __dirname;
|
||||
const proxy = {
|
||||
'/api/slb': {
|
||||
target: 'http://100.86.226.6:30573',
|
||||
changeOrigin: true,
|
||||
rewrite: (path: any) => path.replace(/^\/api\/slb/, '/api'),
|
||||
},
|
||||
'/api': {
|
||||
target: 'http://portal.cloud.sh.dingcloud.com:30080',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/api/dns': {
|
||||
target: 'http://portal.cloud.sh.dingcloud.com:30080',
|
||||
changeOrigin: true,
|
||||
// rewrite: (path) => path.replace(/^\/api\/dns/, '/api/dns'),
|
||||
},
|
||||
};
|
||||
export default configFun({ dirname, serviceMode: 'paas', baseDir: '../', proxy });
|
||||
Reference in New Issue
Block a user