This commit is contained in:
xuziqiang
2024-05-15 17:29:42 +08:00
commit d0155dbe3c
7296 changed files with 1832517 additions and 0 deletions

8
resource-service/.env Normal file
View File

@@ -0,0 +1,8 @@
# port
VITE_PORT = 4100
# spa-title
VITE_GLOB_APP_TITLE = Resource Service
# spa shortname
VITE_GLOB_APP_SHORT_NAME = resource-service

View File

@@ -0,0 +1,22 @@
# Whether to open mock
VITE_USE_MOCK = true
# public path
VITE_PUBLIC_PATH = /
# Cross-domain proxy, you can configure multiple
# Please note that no line breaks
VITE_PROXY = {"/api": { "target": "http://portal.cloud.dev2.dingcloud.com:30080", "changeOrigin": true }}
# VITE_PROXY=[["/api","https://vvbin.cn/test"]]
# 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=

View File

@@ -0,0 +1,35 @@
# Whether to open mock
VITE_USE_MOCK = true
# public path
VITE_PUBLIC_PATH = /
# 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

View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Nrs</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./src/main.ts"></script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1,89 @@
<template>
<!-- 开发测试用 -->
<a-config-provider :locale="locale">
<router-view />
</a-config-provider>
<!-- 测试配置文件使用 -->
<!--<ns-application :locale="locale" />-->
</template>
<script lang="ts" type="module">
import { defineComponent, watch, ref } from 'vue';
import zhCN from 'ant-design-vue/lib/locale/zh_CN';
import { useRoute } from 'vue-router';
import { configRegist } from '/nerv-lib/paas/store/modules/config-service';
// import { useRouter } from 'vue-router';
// import Cookies from 'js-cookie';
// import { message } from 'ant-design-vue';
export default defineComponent({
name: 'App',
setup() {
const route = useRoute();
const configMap = configRegist();
configMap.setSideMenu({
title: '云主机',
name: 'instance',
menus: [
{
name: 'instance-list',
label: '实例管理',
url: 'instance-list',
Module: 'vm',
},
{
name: 'keypair',
label: '密钥对',
url: 'key',
Module: 'vm',
},
{
name: 'Image',
label: '镜像管理',
url: 'Image',
Module: 'vm',
},
],
});
configMap.setSideMenu({
title: '云主机2',
name: 'menu2',
menus: [
{
name: 'VM',
label: '实例管理',
url: 'VM',
Module: 'vm',
},
{
name: 'keypair',
label: '密钥对',
url: 'key',
Module: 'vm',
},
{
name: 'Image',
label: '镜像管理',
url: 'Image',
Module: 'vm',
},
],
});
const cachedViews = ['Status'];
watch(
() => route.path,
(e) => {}
);
return {
cachedViews,
locale: zhCN,
};
},
});
</script>
<style>
#app {
width: 100%;
height: 100%;
}
</style>

View 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',
],
};

View File

@@ -0,0 +1,15 @@
import { http } from '/nerv-lib/util/http';
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;
}

View File

@@ -0,0 +1,6 @@
export const appConfig = {
projectType: 'web',
baseApi: '/api',
baseHeader: '/home',
baseRouter: '/home/index',
};

View File

@@ -0,0 +1,2 @@
import { appConfig } from '/@/config/app.config';
export { appConfig };

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
{
"path": "/keypair",
"name": "keypair",
"component": "list"
}

View File

@@ -0,0 +1,13 @@
import { createApp } from 'vue';
import App from '/@/App.vue';
import { paasInit } from '/nerv-lib/paas';
import { apiModule } from '/@/api';
import { appConfig } from '/@/config';
const app = createApp(App);
paasInit({
app,
apiModule,
appConfig,
});
app.mount('#app');

View File

@@ -0,0 +1,133 @@
const dashboard = {
path: '/add',
name: 'add',
component: () => import('/nerv-lib/paas/view/service/list-table.vue'),
props: {
api: '/api/iaas/iaas/objs/VM',
params: {
region: 'cn_hd_2',
order: 'created_at%20desc',
},
dynamicParams: 'ID',
resultField: 'data',
columns: [
{
title: '项目',
dataIndex: 'projectName',
},
{
title: '实例名称',
dataIndex: 'name',
},
{
title: '可用区',
dataIndex: 'availabilityZone',
width: 80,
},
{
title: 'IP地址',
dataIndex: 'ip',
width: 110,
},
{
title: '浮动IP',
dataIndex: 'elasticIp',
width: 110,
},
{
title: '状态',
dataIndex: 'status',
transform: {
pipe: 'state',
messageField: 'UpdatedAt',
},
},
{
title: '创建人',
dataIndex: 'CreatedBy',
},
{
title: '创建时间',
sorter: true,
defaultSortOrder: 'descend',
dataIndex: 'CreatedAt',
transform: {
pipe: 'date',
params: {
format: 'YYYY-MM-DD HH:mm:ss',
},
},
},
{
title: '修改人',
dataIndex: 'UpdatedBy',
},
{
title: '修改时间',
sorter: true,
transform: {
pipe: 'date',
params: {
format: 'YYYY-MM-DD HH:mm:ss',
},
},
dataIndex: 'UpdatedAt',
},
],
columnActions: {
width: 240,
title: '操作',
actions: [
{
label: '启动',
name: 'start',
dynamicDisabled: true,
confirm: true,
showField: 'status',
showValue: ['SHUTOFF'],
},
{
label: '查看',
name: 'detail',
route: '/instance/instance-detail/:ID',
},
],
},
headerActions: [
{
label: '新增',
name: 'instance-add',
type: 'primary',
route: 'add',
},
],
formConfig: {
schemas: [
{
field: 'visitorName',
label: '访客姓名',
component: 'NsInput',
defaultValue: '123',
componentProps: {
placeholder: '请输入访客姓名',
},
rules: [
{
message: '请输入 输入框1',
trigger: 'change',
},
{
min: 3,
max: 5,
message: 'Length should be 3 to 5',
trigger: 'blur',
},
],
},
],
},
rowKey: 'ID',
},
children: [],
};
export default dashboard;

View File

@@ -0,0 +1,42 @@
const Application = import('/nerv-lib/paas/view/system/application');
const SideNav = import('/nerv-lib/paas/view/system/side-nav/side-nav.vue');
const dashboard = {
path: '/application',
name: 'application',
component: Application,
redirect: '/application/vm',
children: [
{
path: 'vm',
name: 'vm',
component: SideNav,
redirect: '/application/vm/VM',
children: [
{
path: 'VM',
name: 'VM',
component: () => import('/@/view/form/index.vue'),
children: [
{
path: 'menu2',
name: 'menu2',
component: SideNav,
},
],
},
{
path: 'key',
name: 'key',
component: () => import('/@/view/form/add.vue'),
},
{
path: 'Image',
name: 'Image',
component: () => import('/@/view/form/index.vue'),
},
],
},
],
};
export default dashboard;

View File

@@ -0,0 +1,10 @@
const newForm = {
path: '/new',
name: 'new',
component: () => import('/@/view/form/new.vue'),
meta: {
icon: 'ion:grid-outline',
title: '表单',
},
};
export default newForm;

View File

@@ -0,0 +1,9 @@
const RootRoute = {
path: '/',
name: 'root',
redirect: '/instance/instance-list',
meta: {
title: 'Root',
},
};
export default RootRoute;

View File

View File

@@ -0,0 +1,2 @@
@import "variable";
@import "global";

View File

View File

View File

@@ -0,0 +1,293 @@
<template>
<ns-view-add-form :schemas="formSchema" :model="data" :formLayout="formLayout"
title="添加页面" api="123"
/>
</template>
<script lang="ts">
import {defineComponent, provide, reactive, ref} from 'vue';
import {NsModal} from '/nerv-lib/component/modal';
export default defineComponent({
props: {
data: Object
},
setup() {
const formLayout = 'ns-vertical-form';
let formSchema = ref([
{
field: 'volume',
label: '容量',
component: 'NsSlider',
componentProps: {
min: 1,
max: 150,
defaultValue: 10,
}
},
{
field: 'flavor',
label: '实例规格',
component: 'NsFilterTable',
componentProps: {
tableConfig: {
api: '/api/iaas/iaas/objs/Flavor',
rowSelection: {
type: 'radio',
},
params: {
pageSize: 100000,
},
columns: [
{
title: '规格名称',
dataIndex: 'name',
},
{
title: 'VCPU数量',
dataIndex: 'count',
},
{
title: '内存',
dataIndex: 'ram',
},
],
rowKey: 'ID',
},
formConfig: {
schemas: [
{
field: 'cpu',
label: 'CPU',
component: 'NsSelectApi',
defaultValue: ' ',
autoAddLink: true,
dynamicParams: {
ram: 'fieldLink.ram.ram',
},
immediate: true,
immediateName: 'onSelect',
componentProps: {
api: '/api/iaas/iaas/objs/FlavorCPU',
resultField: "data",
labelField: "cpuCount",
valueField: "cpuCount",
placeholder: "请选择CsPU",
firstOption: {
label: '全部',
value: ' ',
}
}
},
{
field: 'ram',
label: '内存',
component: 'NsSelectApi',
defaultValue: ' ',
autoAddLink: true,
dynamicParams: {
cpu: 'fieldLink.cpu.cpuCount',
},
immediate: true,
immediateName: 'onSelect',
componentProps: {
api: '/api/iaas/iaas/objs/FlavorRam',
resultField: "data",
labelField: "ram",
valueField: "ram",
placeholder: "请选择内存",
firstOption: {
label: '全部',
value: ' ',
}
}
},
],
}
}
},
{
field: 'system-disk',
label: '系统盘',
component: 'NsDiskCombination',
componentProps: {
remove: false,
combinationOptions: [
{
field: 'type',
label: '',
component: 'NsSelect',
componentProps: {
label: 'type',
options: [
{
"value": "ssd",
"label": "SSD"
},
{
"value": "local-ssd",
"label": "本地盘-SSD"
}
],
defaultValue: 'SSD',
}
},
{
field: 'size',
label: '大小',
component: 'NsInputNumber',
defaultValue: 10,
rules: [
{
"type": "number",
"required": true,
"message": "请输入大小"
},
{
"type": "number",
"min": 10,
"max": 16384
}
]
}
]
}
},
{
field: 'disk',
label: '数据盘',
component: 'NsDiskCombination',
componentProps: {
add: true,
addName: '增加一块数据盘',
// addIcon: 'add',
limitCount: 5,
limitMsg: '您还可以增加的数据盘块数为:',
combinationOptions: [
{
field: 'type',
label: '',
component: 'NsSelect',
componentProps: {
options: [
{
"value": "SSD",
"label": "SSD"
},
{
"value": "local-ssd",
"label": "本地盘-SSD"
}
],
defaultValue: 'SSD',
},
rules: [
{
required: true,
message: "请选择"
},
]
},
{
field: 'size',
label: '大小',
component: 'NsInputNumber',
defaultValue: 10,
rules: [
{
type: "number",
required: true,
message: "请输入大小"
},
{
type: "number",
min: 10,
max: 16384,
message: '取值范围在1026348',
}
]
},
{
label: "数量",
field: "count",
component: "NsInputNumber",
defaultValue: 1,
rules: [
{
type: "number",
required: true,
message: '请输入数量',
},
{
type: "number",
min: 1,
max: 15,
message: '取值范围在115',
}
]
},
]
}
},
{
field: 'port',
component: 'NsRange',
label: '端口范围',
componentProps: {
min: {
defaultValue: 10,
rules: [
{
required: true,
message: '请输入最小值',
},
{
type: "number",
min: 5,
max: 200,
message: '取值范围在5200',
},
]
},
max: {
defaultValue: 150,
rules: [
{
required: true,
message: '请输入最大值',
},
{
type: "number",
min: 1,
max: 65535,
message: '取值范围在165535',
}
],
}
}
}
]);
const confirm = () => {
NsModal.confirm({
title: 'Confirm',
content: 'Bla bla ...',
okText: '确认',
cancelText: '取消',
});
};
return {
formSchema,
formLayout,
confirm,
};
},
beforeCreate() {
},
});
</script>

View File

@@ -0,0 +1,144 @@
<template>
<!-- 按钮 -->
<NsButton>default</NsButton>
<ns-button type="primary" size="large">prime</ns-button>
<ns-button type="primary" size="large" :loading="true">loading</ns-button>
<!--复选框-->
<ns-checkbox v-model:checked="checkAll" :indeterminate="indeterminate" @change="onCheckAllChange">
Check all
</ns-checkbox>
<ns-checkbox-group v-model:value="checkedList" :options="plainOptions" />
<!--单选-->
<div style="margin-top: 20px">
<a-radio-group v-model:value="radio.radioValue" @change="onChangeRadio">
<a-radio :value="0">北京</a-radio>
<a-radio :value="1">上海</a-radio>
</a-radio-group>
</div>
<!--滑动输入条-->
<div style="margin-top: 20px; width: 300px">
<!--<a-slider :value="0" :min="1" :max="20" />-->
<ns-slider></ns-slider>
<!--<ns-slider></ns-slider>-->
</div>
<!--输入框-->
<div style="margin-top: 20px; width: 300px">
<ns-input placeholder="请输入" @change="inputChange" v-model:value="inputValue" />
</div>
<!--密码框-->
<div style="margin-top: 20px; width: 300px">
<ns-input-password />
</div>
<!--开关-->
<div style="margin-top: 20px">
<ns-switch
checked-children=""
un-checked-children=""
:checked="checked"
@change="onSwitchChange"
/>
</div>
<!--下拉选项-->
<div style="margin-top: 20px">
<ns-input>
<template #addonBefore>
<a-select v-model:value="value3" style="width: 90px">
<a-select-option value="Http://">Http://</a-select-option>
<a-select-option value="Https://">Https://</a-select-option>
</a-select>
</template>
<template #addonAfter>
<a-select style="width: 80px">
<a-select-option value=".com">.com</a-select-option>
<a-select-option value=".jp">.jp</a-select-option>
<a-select-option value=".cn">.cn</a-select-option>
<a-select-option value=".org">.org</a-select-option>
</a-select>
</template>
</ns-input>
</div>
<!-- 日期选择 -->
<div style="margin-top: 16px">
<a-space direction="vertical">
<ns-date-picker />
<ns-month-picker placeholder="Select month" />
<ns-range-picker />
<ns-week-picker placeholder="Select week" />
</a-space>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, ref, toRefs, watch } from 'vue';
const plainOptions = ['Apple', 'Pear', 'Orange'];
export default defineComponent({
setup: () => {
const value3 = ref<string>('jack');
//复选框
const state = reactive({
indeterminate: true,
checkAll: false,
checkedList: ['Apple', 'Orange'],
});
const onCheckAllChange = (e: any) => {
Object.assign(state, {
checkedList: e.target.checked ? plainOptions : [],
indeterminate: false,
});
};
watch(
() => state.checkedList,
(val) => {
state.indeterminate = !!val.length && val.length < plainOptions.length;
state.checkAll = val.length === plainOptions.length;
}
);
// 单选
const radio = reactive({
radioValue: 1,
});
const onChangeRadio = function (e) {
console.log('radio: ' + e.target.value);
};
//开关
const switchState = reactive({
checked: true,
});
const onSwitchChange = function (e) {
switchState.checked = e;
};
//输入框
const inputState = reactive({
inputValue: 'hello',
});
const inputChange = function (e) {
console.log(e.target.value);
};
return {
...toRefs(state),
plainOptions,
onCheckAllChange,
...toRefs(switchState),
switchState,
onSwitchChange,
inputState,
inputChange,
value3,
radio,
onChangeRadio,
};
},
});
</script>

View File

@@ -0,0 +1,96 @@
<template>
<div>
<ns-form :schemas="formConfig.schemas" />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'new',
setup() {
const formConfig = {
schemas: [
{
field: 'cpu',
label: 'CPU',
component: 'NsSelectApi',
autoAddLink: true,
dynamicParams: {
ram: 'fieldLink.ram.ram',
},
componentProps: {
api: '/api/iaas/iaas/objs/FlavorCPU',
resultField: 'data',
labelField: 'cpuCount',
valueField: 'cpuCount',
// immediate: true,
placeholder: '请选择CPU',
firstOption: {
label: '全部',
value: ' ',
},
},
},
{
field: 'ram',
label: '内存',
component: 'NsSelectApi',
autoAddLink: true,
// // 值依赖
dynamicParams: {
cpu: 'fieldLink.cpu.cpuCount',
},
componentProps: {
api: '/api/iaas/iaas/objs/FlavorRam',
resultField: 'data',
labelField: 'ram',
valueField: 'ram',
// immediate: true,
placeholder: '请选择内存',
firstOption: {
label: '全部',
value: ' ',
},
onSelect: () => {
// unref(nsTableRef).triggerSubmit();
},
},
},
{
field: 'ram1',
label: '内存11',
component: 'NsSelectApi',
autoAddLink: true,
// // 值依赖
// dynamicParams: {
// cpu: 'fieldLink.cpu.cpuCount',
// },
componentProps: {
api: '/api/iaas/iaas/objs/FlavorRam',
resultField: 'data',
labelField: 'ram',
valueField: 'ram',
// immediate: true,
placeholder: '请选择内存',
// firstOption: {
// label: '全部',
// value: ' ',
// },
onSelect: () => {
// unref(nsTableRef).triggerSubmit();
},
},
},
],
params: {},
};
return {
formConfig,
};
},
});
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,10 @@
<template>
<div>测试内容</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'Test',
});
</script>

View 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"
]
}

View File

@@ -0,0 +1,3 @@
import configFun from '../build/vite-default.config';
const dirname = __dirname;
export default configFun({ dirname, serviceMode: 'paas', baseDir: '../' });