├── .editorconfig
├── .env.development
├── .env.production
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── babel.config.js
├── mock
├── index.js
├── license.js
├── mock-server.js
├── result-holder.js
├── user-management.js
├── user-token.js
├── user.js
└── utils.js
├── nginx.conf
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── font_2474164_6bnyueo2zk9.css
├── font_2474164_6bnyueo2zk9.ttf
├── font_2474164_6bnyueo2zk9.woff
├── font_2474164_6bnyueo2zk9.woff2
└── index.html
├── src
├── App.vue
├── api
│ ├── auth.js
│ ├── authorization.js
│ ├── backup-account.js
│ ├── cluster-member.js
│ ├── cluster-resource.js
│ ├── cluster.js
│ ├── cluster
│ │ ├── backup.js
│ │ ├── cluster.js
│ │ ├── grade.js
│ │ ├── log.js
│ │ ├── monitor.js
│ │ ├── node.js
│ │ ├── security.js
│ │ ├── storage.js
│ │ ├── tasks.js
│ │ └── tool.js
│ ├── credentials.js
│ ├── hosts.js
│ ├── ip-pool.js
│ ├── license.js
│ ├── manifest.js
│ ├── msg-subscribe.js
│ ├── personal-setting.js
│ ├── plan.js
│ ├── project-member.js
│ ├── project-resource.js
│ ├── projects.js
│ ├── region.js
│ ├── system-log.js
│ ├── system-setting.js
│ ├── template-config.js
│ ├── theme.js
│ ├── user-management.js
│ ├── user-message.js
│ ├── user-token.js
│ ├── user.js
│ ├── vm-config.js
│ ├── xpack
│ │ └── multi-cluster.js
│ └── zone.js
├── assets
│ ├── KobeOperator-login.jpg
│ ├── KubeOperator-about-background.png
│ ├── KubeOperator-assist-white.png
│ ├── KubeOperator-black.png
│ ├── KubeOperator-red.png
│ ├── KubeOperator-white.png
│ ├── font
│ │ └── Roboto
│ │ │ ├── Roboto-Regular.ttf
│ │ │ └── index.css
│ ├── iconfont
│ │ ├── alicdn
│ │ │ ├── font_985780_km7mi63cihi.eot
│ │ │ ├── font_985780_km7mi63cihi.svg
│ │ │ ├── font_985780_km7mi63cihi.ttf
│ │ │ ├── font_985780_km7mi63cihi.woff
│ │ │ └── font_985780_km7mi63cihi_iefix.eot
│ │ ├── demo.css
│ │ ├── demo_index.html
│ │ ├── iconfont.css
│ │ ├── iconfont.js
│ │ ├── iconfont.json
│ │ ├── iconfont.ttf
│ │ ├── iconfont.woff
│ │ └── iconfont.woff2
│ ├── images
│ │ └── tools
│ │ │ ├── chartmuseum.png
│ │ │ ├── docker-registry.png
│ │ │ ├── elasticsearch.png
│ │ │ ├── gatekeeper.jpg
│ │ │ ├── grafana.png
│ │ │ ├── kubeapps.png
│ │ │ ├── kubepi.png
│ │ │ ├── kubernetes.png
│ │ │ ├── loki.png
│ │ │ ├── prometheus.png
│ │ │ └── registry.png
│ └── login-desc.png
├── business
│ ├── app-layout
│ │ ├── header-components
│ │ │ ├── Help.vue
│ │ │ ├── LanguageSwitch.vue
│ │ │ ├── PersonalSetting.vue
│ │ │ ├── ProjectSwitch.vue
│ │ │ └── StationLetter.vue
│ │ └── horizontal-layout
│ │ │ ├── HorizontalHeader.vue
│ │ │ └── index.vue
│ ├── authorization
│ │ ├── index.vue
│ │ ├── management
│ │ │ ├── index.vue
│ │ │ ├── members
│ │ │ │ └── index.vue
│ │ │ └── resources
│ │ │ │ └── index.vue
│ │ └── projects
│ │ │ ├── create
│ │ │ └── index.vue
│ │ │ ├── edit
│ │ │ └── index.vue
│ │ │ └── index.vue
│ ├── automatic
│ │ ├── ip-pools
│ │ │ ├── create
│ │ │ │ └── index.vue
│ │ │ ├── index.vue
│ │ │ └── ips
│ │ │ │ ├── create
│ │ │ │ └── index.vue
│ │ │ │ └── index.vue
│ │ ├── plans
│ │ │ ├── create
│ │ │ │ └── index.vue
│ │ │ ├── edit
│ │ │ │ └── index.vue
│ │ │ └── index.vue
│ │ ├── regions
│ │ │ ├── create
│ │ │ │ └── index.vue
│ │ │ ├── edit
│ │ │ │ └── index.vue
│ │ │ └── index.vue
│ │ ├── template-configs
│ │ │ ├── index.vue
│ │ │ └── operate
│ │ │ │ └── index.vue
│ │ ├── vm-configs
│ │ │ ├── create
│ │ │ │ └── index.vue
│ │ │ ├── edit
│ │ │ │ └── index.vue
│ │ │ └── index.vue
│ │ └── zones
│ │ │ ├── create
│ │ │ └── index.vue
│ │ │ ├── edit
│ │ │ └── index.vue
│ │ │ └── index.vue
│ ├── backup-account
│ │ ├── create
│ │ │ └── index.vue
│ │ ├── edit
│ │ │ └── index.vue
│ │ └── index.vue
│ ├── clusters
│ │ ├── create
│ │ │ └── index.vue
│ │ ├── detail
│ │ │ ├── backup
│ │ │ │ ├── index.vue
│ │ │ │ ├── logs
│ │ │ │ │ └── index.vue
│ │ │ │ ├── velero_backup.vue
│ │ │ │ ├── velero_config.vue
│ │ │ │ └── velero_restore.vue
│ │ │ ├── component
│ │ │ │ ├── index.vue
│ │ │ │ ├── istio
│ │ │ │ │ ├── detail.vue
│ │ │ │ │ └── index.vue
│ │ │ │ └── metallb
│ │ │ │ │ └── index.vue
│ │ │ ├── grade
│ │ │ │ └── index.vue
│ │ │ ├── index.vue
│ │ │ ├── log
│ │ │ │ ├── index.vue
│ │ │ │ ├── logging
│ │ │ │ │ └── index.vue
│ │ │ │ └── loki
│ │ │ │ │ └── index.vue
│ │ │ ├── monitor
│ │ │ │ └── index.vue
│ │ │ ├── node
│ │ │ │ ├── detail
│ │ │ │ │ └── index.vue
│ │ │ │ └── index.vue
│ │ │ ├── overview
│ │ │ │ ├── index.vue
│ │ │ │ └── ko-detail.vue
│ │ │ ├── security
│ │ │ │ └── index.vue
│ │ │ ├── storage
│ │ │ │ ├── class-create
│ │ │ │ │ └── index.vue
│ │ │ │ ├── index.vue
│ │ │ │ ├── provisioner-create
│ │ │ │ │ └── index.vue
│ │ │ │ └── provisioner-detail
│ │ │ │ │ └── index.vue
│ │ │ ├── task
│ │ │ │ ├── detail
│ │ │ │ │ └── index.vue
│ │ │ │ └── index.vue
│ │ │ └── tool
│ │ │ │ └── index.vue
│ │ ├── import
│ │ │ ├── index.vue
│ │ │ └── ko-import.vue
│ │ ├── index.vue
│ │ └── upgrade
│ │ │ └── index.vue
│ ├── dashboard
│ │ └── index.vue
│ ├── directive
│ │ ├── ClickOutsideDemo.vue
│ │ └── PermissionDemo.vue
│ ├── hosts
│ │ ├── create
│ │ │ └── index.vue
│ │ ├── edit
│ │ │ └── index.vue
│ │ └── index.vue
│ ├── login
│ │ └── index.vue
│ ├── manifest
│ │ └── index.vue
│ ├── msg-subscribe
│ │ └── index.vue
│ ├── system-log
│ │ └── index.vue
│ ├── system-setting
│ │ ├── credential
│ │ │ ├── create
│ │ │ │ └── index.vue
│ │ │ ├── edit
│ │ │ │ └── index.vue
│ │ │ └── index.vue
│ │ ├── index.vue
│ │ ├── kubepi
│ │ │ └── index.vue
│ │ ├── ldap
│ │ │ └── index.vue
│ │ ├── license
│ │ │ └── index.vue
│ │ ├── message
│ │ │ └── index.vue
│ │ ├── ntp
│ │ │ └── index.vue
│ │ └── registry
│ │ │ ├── create
│ │ │ └── index.vue
│ │ │ ├── edit
│ │ │ └── index.vue
│ │ │ └── index.vue
│ ├── users
│ │ ├── create
│ │ │ └── index.vue
│ │ ├── edit
│ │ │ └── index.vue
│ │ └── index.vue
│ ├── xpack
│ │ ├── index.vue
│ │ ├── multi-cluster
│ │ │ ├── create
│ │ │ │ └── index.vue
│ │ │ ├── dialog
│ │ │ │ ├── RelationsManagement.vue
│ │ │ │ ├── RepositoryErrorMessage.vue
│ │ │ │ └── SyncLogDetail.vue
│ │ │ ├── edit
│ │ │ │ └── index.vue
│ │ │ ├── index.vue
│ │ │ └── log
│ │ │ │ └── index.vue
│ │ └── theme
│ │ │ └── index.vue
│ └── xterm
│ │ └── index.vue
├── components
│ ├── back-button
│ │ └── index.vue
│ ├── batch-delete
│ │ └── index.vue
│ ├── cloud-providers
│ │ └── index.vue
│ ├── complex-table
│ │ └── index.vue
│ ├── detail-card
│ │ ├── ItemValue.vue
│ │ └── index.vue
│ ├── k8s-page
│ │ └── index.vue
│ ├── ko-logs
│ │ └── index.vue
│ ├── ko-status
│ │ └── index.vue
│ ├── layout
│ │ ├── LayoutContent.vue
│ │ ├── LayoutHeader.vue
│ │ ├── LayoutMain.vue
│ │ ├── LayoutSidebar.vue
│ │ ├── LayoutView.vue
│ │ ├── index.vue
│ │ └── sidebar
│ │ │ ├── FixiOSBug.js
│ │ │ ├── Item.vue
│ │ │ ├── Link.vue
│ │ │ ├── Logo.vue
│ │ │ ├── SidebarItem.vue
│ │ │ ├── SidebarToggleButton.vue
│ │ │ └── index.vue
│ └── redirect
│ │ └── index.vue
├── directive
│ ├── click-outside
│ │ └── index.js
│ ├── index.js
│ └── permission
│ │ └── index.js
├── filters
│ └── index.js
├── i18n
│ ├── index.js
│ ├── lang
│ │ ├── en-US.js
│ │ ├── zh-CN.js
│ │ └── zh-TW.js
│ └── 国际化规范.md
├── icons
│ └── index.js
├── main.js
├── permission.js
├── plugins
│ ├── index.js
│ ├── message.js
│ └── request.js
├── router
│ ├── index.js
│ └── modules
│ │ ├── authorization.js
│ │ ├── automatic.js
│ │ ├── backup-account.js
│ │ ├── clusters.js
│ │ ├── hosts.js
│ │ ├── manifest.js
│ │ ├── msg-subscribe.js
│ │ ├── setting.js
│ │ ├── system-log.js
│ │ ├── users.js
│ │ └── x-pack.js
├── store
│ ├── getters.js
│ ├── index.js
│ └── modules
│ │ ├── app.js
│ │ ├── license.js
│ │ ├── permission.js
│ │ ├── theme.js
│ │ ├── user-token.js
│ │ └── user.js
├── styles
│ ├── business
│ │ ├── app.scss
│ │ └── header-menu.scss
│ ├── common
│ │ ├── mixins.scss
│ │ └── variables.scss
│ └── index.scss
└── utils
│ ├── format_ansible_err.js
│ ├── format_conversion.js
│ ├── format_date.js
│ ├── global_variable.js
│ ├── permisstion.js
│ ├── rules.js
│ ├── sort.js
│ ├── token.js
│ └── validate.js
└── vue.config.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | end_of_line = lf
9 | insert_final_newline = true
10 | trim_trailing_whitespace = true
11 |
12 | [*.md]
13 | insert_final_newline = false
14 | trim_trailing_whitespace = false
15 |
--------------------------------------------------------------------------------
/.env.development:
--------------------------------------------------------------------------------
1 | # just a flag
2 | ENV = 'development'
3 |
4 | # base api, e.g., '/dev'
5 | VUE_APP_PUBLIC_PATH = '/ui'
6 |
--------------------------------------------------------------------------------
/.env.production:
--------------------------------------------------------------------------------
1 | # just a flag
2 | ENV = 'production'
3 |
4 | # base api, e.g., '/prod'
5 | VUE_APP_PUBLIC_PATH = '/ui'
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
25 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:14-alpine3.15 as stage-build
2 |
3 | ARG NPM_REGISTRY="https://registry.npmmirror.com"
4 | ENV NPM_REGISTY=$NPM_REGISTRY
5 |
6 | RUN set -ex \
7 | && npm config set registry ${NPM_REGISTRY}
8 |
9 | WORKDIR /data
10 |
11 | RUN apk update && \
12 | apk upgrade
13 |
14 | COPY ./package.json /data/package.json
15 | COPY ./package-lock.json /data/package-lock.json
16 | RUN npm install
17 | COPY . /data
18 | RUN npm run-script build
19 |
20 | FROM nginx:alpine
21 |
22 | COPY --from=stage-build /data/dist /opt/neeko
23 | COPY nginx.conf /etc/nginx/conf.d/default.conf
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NEEKO
2 |
3 | Neeko 是 KubeOperator 的新版前端 UI 项目, 主要使用 [Vue](https://cn.vuejs.org/), [Element UI](https://github.com/fit2cloud-ui/fit2cloud-ui/) 完成。
4 |
5 | ## 开发运行
6 |
7 | ```
8 | 0. 前置条件: 部署运行好 KubeOperator API 服务器
9 |
10 | 1. 安装依赖
11 | $ npm install
12 |
13 | 2. 运行
14 | $ npm run serve
15 |
16 | 3. 构建
17 | $ npm run build
18 | ```
19 |
20 | ## 致谢
21 | - [Vue](https://cn.vuejs.org) 前端框架
22 | - [FIT2CLOUD UI](https://github.com/fit2cloud-ui/fit2cloud-ui/) FIT2CLOUD UI组件库
23 | - [Vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) 项目脚手架
24 |
25 |
26 | ## Copyright
27 | Copyright (c) 2014-2024 飞致云 FIT2CLOUD, All rights reserved.
28 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/mock/index.js:
--------------------------------------------------------------------------------
1 | const Mock = require('mockjs')
2 | const {param2Obj} = require('./utils')
3 |
4 | const user = require('./user')
5 | const userManagement = require('./user-management')
6 |
7 | const mocks = [
8 | ...user,
9 | ...userManagement,
10 | ]
11 |
12 | // for front mock
13 | // please use it cautiously, it will redefine XMLHttpRequest,
14 | // which will cause many of your third-party libraries to be invalidated(like progress event).
15 | function mockXHR() {
16 | // mock patch
17 | // https://github.com/nuysoft/Mock/issues/300
18 | Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
19 | Mock.XHR.prototype.send = function () {
20 | if (this.custom.xhr) {
21 | this.custom.xhr.withCredentials = this.withCredentials || false
22 |
23 | if (this.responseType) {
24 | this.custom.xhr.responseType = this.responseType
25 | }
26 | }
27 | this.proxy_send(...arguments)
28 | }
29 |
30 | function XHR2ExpressReqWrap(respond) {
31 | return function (options) {
32 | let result;
33 | if (respond instanceof Function) {
34 | const {body, type, url} = options
35 | // https://expressjs.com/en/4x/api.html#req
36 | result = respond({
37 | method: type,
38 | body: JSON.parse(body),
39 | query: param2Obj(url)
40 | })
41 | } else {
42 | result = respond
43 | }
44 | return Mock.mock(result)
45 | }
46 | }
47 |
48 | for (const i of mocks) {
49 | Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
50 | }
51 | }
52 |
53 | module.exports = {
54 | mocks,
55 | mockXHR
56 | }
57 |
--------------------------------------------------------------------------------
/mock/license.js:
--------------------------------------------------------------------------------
1 | const {success, error} = require("./result-holder")
2 |
3 | const licenses = {
4 | valid: {
5 | status: "valid",
6 | license: {
7 | "corporation": "xxxxxxxxxxxx",
8 | "expired": "2030-07-03",
9 | "licenseVersion": "v2",
10 | "product": "cmp",
11 | "generateTime": "1593763389356",
12 | "edition": "Enterprise",
13 | "count": 11
14 | },
15 | message: ""
16 | },
17 | invalid: {
18 | status: "invalid",
19 | license: {},
20 | message: "license has invalid"
21 | },
22 | expired: {
23 | status: "expired",
24 | license: {
25 | "corporation": "xxxxxxxxxxxx",
26 | "expired": "2020-07-03",
27 | "licenseVersion": "v2",
28 | "product": "cmp",
29 | "generateTime": "1593763389356",
30 | "edition": "Enterprise",
31 | "count": 11
32 | },
33 | message: "license has expired since 2020-07-03"
34 | },
35 | }
36 |
37 | module.exports = [
38 | {
39 | url: '/samples/license/save',
40 | type: 'post',
41 | response: config => {
42 | const {license} = config.body
43 | const data = licenses[license];
44 |
45 | if (!data) {
46 | return success(licenses.invalid)
47 | }
48 | return success(data)
49 | }
50 | },
51 | ]
52 |
--------------------------------------------------------------------------------
/mock/mock-server.js:
--------------------------------------------------------------------------------
1 | const chokidar = require('chokidar')
2 | const bodyParser = require('body-parser')
3 | const chalk = require('chalk')
4 | const path = require('path')
5 | const Mock = require('mockjs')
6 |
7 | const mockDir = path.join(process.cwd(), 'mock')
8 |
9 | function registerRoutes(app) {
10 | let mockLastIndex
11 | const { mocks } = require('./index.js')
12 | const mocksForServer = mocks.map(route => {
13 | return responseFake(route.url, route.type, route.response)
14 | })
15 | for (const mock of mocksForServer) {
16 | app[mock.type](mock.url, mock.response)
17 | mockLastIndex = app._router.stack.length
18 | }
19 | const mockRoutesLength = Object.keys(mocksForServer).length
20 | return {
21 | mockRoutesLength: mockRoutesLength,
22 | mockStartIndex: mockLastIndex - mockRoutesLength
23 | }
24 | }
25 |
26 | function unregisterRoutes() {
27 | Object.keys(require.cache).forEach(i => {
28 | if (i.includes(mockDir)) {
29 | delete require.cache[require.resolve(i)]
30 | }
31 | })
32 | }
33 |
34 | // for mock server
35 | const responseFake = (url, type, respond) => {
36 | return {
37 | url: new RegExp(`${url}`),
38 | type: type || 'get',
39 | response(req, res) {
40 | console.log('request invoke:' + req.path)
41 | res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
42 | }
43 | }
44 | }
45 |
46 | module.exports = app => {
47 | // parse app.body
48 | // https://expressjs.com/en/4x/api.html#req.body
49 | app.use(bodyParser.json())
50 | app.use(bodyParser.urlencoded({
51 | extended: true
52 | }))
53 |
54 | const mockRoutes = registerRoutes(app)
55 | var mockRoutesLength = mockRoutes.mockRoutesLength
56 | var mockStartIndex = mockRoutes.mockStartIndex
57 |
58 | // watch files, hot reload mock server
59 | chokidar.watch(mockDir, {
60 | ignored: /mock-server/,
61 | ignoreInitial: true
62 | }).on('all', (event, path) => {
63 | if (event === 'change' || event === 'add') {
64 | try {
65 | // remove mock routes stack
66 | app._router.stack.splice(mockStartIndex, mockRoutesLength)
67 |
68 | // clear routes cache
69 | unregisterRoutes()
70 |
71 | const mockRoutes = registerRoutes(app)
72 | mockRoutesLength = mockRoutes.mockRoutesLength
73 | mockStartIndex = mockRoutes.mockStartIndex
74 |
75 | console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
76 | } catch (error) {
77 | console.log(chalk.redBright(error))
78 | }
79 | }
80 | })
81 | }
82 |
--------------------------------------------------------------------------------
/mock/result-holder.js:
--------------------------------------------------------------------------------
1 | class ResultHolder {
2 | constructor(success, data, message) {
3 | this.success = success;
4 | this.data = data;
5 | this.message = message;
6 | }
7 | }
8 |
9 | const success = data => {
10 | return new ResultHolder(true, data)
11 | }
12 |
13 | const error = message => {
14 | return new ResultHolder(false, undefined, message)
15 | }
16 |
17 | module.exports = {
18 | success,
19 | error
20 | }
21 |
--------------------------------------------------------------------------------
/mock/user-management.js:
--------------------------------------------------------------------------------
1 | const {success} = require("./result-holder")
2 | const users = [
3 | {
4 | id: "admin",
5 | name: 'Administrator',
6 | email: "admin@fit2cloud.com",
7 | roles: ['admin'],
8 | language: "zh-CN"
9 | }, {
10 | id: "editor",
11 | name: 'Editor',
12 | email: "editor@fit2cloud.com",
13 | roles: ['editor'],
14 | language: "zh-CN"
15 | }, {
16 | id: "readonly",
17 | name: 'Readonly User',
18 | email: "readonly@fit2cloud.com",
19 | roles: ['readonly'],
20 | language: "zh-CN"
21 | }
22 | ]
23 |
24 | for (let i = 0; i < 300; i++) {
25 | let id = "user-" + i
26 | let name = id;
27 | let email = id + "@fit2cloud.com"
28 | let roles = ['readonly']
29 | let language = "zh-CN"
30 | let createTime = new Date().getTime()
31 | users.push({id, name, email, roles, language, createTime})
32 | }
33 |
34 | module.exports = [
35 | // get user list
36 | {
37 | url: '/samples/user-management/list/\.*',
38 | type: 'get',
39 | response: (config) => {
40 | let path = config.originalUrl.split("/")
41 | let page = Number.parseInt(path[4])
42 | let size = Number.parseInt(path[5])
43 | let start = (page - 1) * size
44 | let end = page * size
45 |
46 | let data = {
47 | items: users.slice(start, end),
48 | total: users.length
49 | }
50 | return success(data)
51 | }
52 | },
53 | ]
54 |
55 |
--------------------------------------------------------------------------------
/mock/user-token.js:
--------------------------------------------------------------------------------
1 | const {success, error} = require("./result-holder")
2 | const TOKEN_KEY = "App-Token"
3 |
4 | /* 前后端分离,用Token验证登录*/
5 | const tokens = {
6 | admin: {
7 | token: 'admin-token'
8 | },
9 | editor: {
10 | token: 'editor-token'
11 | },
12 | readonly: {
13 | token: 'readonly-token'
14 | }
15 | }
16 |
17 | const users = {
18 | 'admin-token': {
19 | id: "admin",
20 | name: 'Administrator',
21 | email: "admin@fit2cloud.com",
22 | roles: ['admin'],
23 | language: "zh-CN"
24 | },
25 | 'editor-token': {
26 | id: "editor",
27 | name: 'Editor',
28 | email: "editor@fit2cloud.com",
29 | roles: ['editor'],
30 | language: "zh-CN"
31 | },
32 | 'readonly-token': {
33 | id: "readonly",
34 | name: 'Readonly User',
35 | email: "readonly@fit2cloud.com",
36 | roles: ['readonly'],
37 | language: "zh-CN"
38 | }
39 | }
40 |
41 | module.exports = [
42 | // user login
43 | {
44 | url: '/samples/user-token/login',
45 | type: 'post',
46 | response: config => {
47 | const {username} = config.body
48 | const {token} = tokens[username];
49 |
50 | // mock error
51 | if (!token) {
52 | return error("用户名或密码错误")
53 | }
54 | return success(token)
55 | }
56 | },
57 |
58 | // get user info
59 | {
60 | url: '/samples/user-token/info',
61 | type: 'get',
62 | response: (config) => {
63 | let token = config.headers[TOKEN_KEY]
64 | const info = users[token]
65 |
66 | // mock error
67 | if (!info) {
68 | return error("无法获取用户[" + token + "]详细信息")
69 | }
70 |
71 | return success(info)
72 | }
73 | },
74 |
75 | // update user info
76 | {
77 | url: '/samples/user/info/update',
78 | type: 'put',
79 | response: config => {
80 | let token = config.headers[TOKEN_KEY]
81 | const {language} = config.body
82 | users[token].language = language;
83 |
84 | return success(users[token])
85 | }
86 | },
87 |
88 | // user logout
89 | {
90 | url: '/samples/user/logout',
91 | type: 'post',
92 | response: () => {
93 | // do something
94 | return success()
95 | }
96 | }
97 | ]
98 |
--------------------------------------------------------------------------------
/mock/user.js:
--------------------------------------------------------------------------------
1 | const {success, error} = require("./result-holder")
2 |
3 | /* 前后端不分离的接口,用Session验证登录*/
4 | let currentUser
5 |
6 | const users = {
7 | admin: {
8 | id: "admin",
9 | name: 'Administrator',
10 | email: "admin@fit2cloud.com",
11 | roles: ['admin'],
12 | language: "zh-CN"
13 | },
14 | editor: {
15 | id: "editor",
16 | name: 'Editor',
17 | email: "editor@fit2cloud.com",
18 | roles: ['editor'],
19 | language: "zh-CN"
20 | },
21 | readonly: {
22 | id: "readonly",
23 | name: 'Readonly User',
24 | email: "readonly@fit2cloud.com",
25 | roles: ['readonly'],
26 | language: "zh-CN"
27 | }
28 | }
29 |
30 | module.exports = [
31 | // user login
32 | {
33 | url: '/samples/user/login',
34 | type: 'post',
35 | response: config => {
36 | const {username} = config.body
37 | const user = users[username];
38 |
39 | // mock error
40 | if (!user) {
41 | return error("用户名或密码错误")
42 | }
43 | currentUser = user;
44 | return success(user)
45 | }
46 | },
47 |
48 | {
49 | url: '/samples/user/is-login',
50 | type: 'get',
51 | response: () => {
52 | if (currentUser) {
53 | return success()
54 | } else {
55 | return error()
56 | }
57 | }
58 | },
59 |
60 | // get user info
61 | {
62 | url: '/samples/user/current',
63 | type: 'get',
64 | response: () => {
65 | const info = currentUser
66 |
67 | // mock error
68 | if (!info) {
69 | return error("用户未登录")
70 | }
71 |
72 | return success(info)
73 | }
74 | },
75 |
76 | // update user info
77 | {
78 | url: '/samples/user/info/update',
79 | type: 'put',
80 | response: config => {
81 | const {language} = config.body
82 | if (currentUser) {
83 | currentUser.language = language;
84 | }
85 | return success(currentUser)
86 | }
87 | },
88 |
89 | // user logout
90 | {
91 | url: '/samples/user/logout',
92 | type: 'post',
93 | response: () => {
94 | currentUser = undefined;
95 | return success()
96 | }
97 | }
98 | ]
99 |
--------------------------------------------------------------------------------
/mock/utils.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @param {string} url
3 | * @returns {Object}
4 | */
5 | function param2Obj(url) {
6 | const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
7 | if (!search) {
8 | return {}
9 | }
10 | const obj = {}
11 | const searchArr = search.split('&')
12 | searchArr.forEach(v => {
13 | const index = v.indexOf('=')
14 | if (index !== -1) {
15 | const name = v.substring(0, index)
16 | const val = v.substring(index + 1, v.length)
17 | obj[name] = val
18 | }
19 | })
20 | return obj
21 | }
22 |
23 | /**
24 | * This is just a simple version of deep copy
25 | * Has a lot of edge cases bug
26 | * If you want to use a perfect deep copy, use lodash's _.cloneDeep
27 | * @param {Object} source
28 | * @returns {Object}
29 | */
30 | function deepClone(source) {
31 | if (!source && typeof source !== 'object') {
32 | throw new Error('error arguments', 'deepClone')
33 | }
34 | const targetObj = source.constructor === Array ? [] : {}
35 | Object.keys(source).forEach(keys => {
36 | if (source[keys] && typeof source[keys] === 'object') {
37 | targetObj[keys] = deepClone(source[keys])
38 | } else {
39 | targetObj[keys] = source[keys]
40 | }
41 | })
42 | return targetObj
43 | }
44 |
45 | module.exports = {
46 | param2Obj,
47 | deepClone
48 | }
49 |
--------------------------------------------------------------------------------
/nginx.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 |
4 | location /ui/ {
5 | try_files $uri / /index.html;
6 | alias /opt/neeko/;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "neeko",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "@fortawesome/fontawesome-svg-core": "^1.2.34",
12 | "@fortawesome/free-brands-svg-icons": "^5.15.2",
13 | "@fortawesome/free-regular-svg-icons": "^5.15.2",
14 | "@fortawesome/free-solid-svg-icons": "^5.15.2",
15 | "@fortawesome/vue-fontawesome": "^2.0.2",
16 | "axios": "^0.21.1",
17 | "core-js": "^3.6.5",
18 | "echarts": "^4.9.0",
19 | "element-ui": "2.15.8",
20 | "fit2cloud-ui": "^1.8.0",
21 | "ipaddr.js": "^2.0.0",
22 | "js-cookie": "^2.2.1",
23 | "normalize.css": "^8.0.1",
24 | "nprogress": "^0.2.0",
25 | "sass": "^1.53.0",
26 | "vue": "^2.6.11",
27 | "vue-codemirror": "^4.0.6",
28 | "vue-i18n": "^8.22.4",
29 | "vuex": "^3.6.0",
30 | "xterm": "^4.11.0"
31 | },
32 | "devDependencies": {
33 | "@vue/cli-plugin-babel": "~4.5.0",
34 | "@vue/cli-plugin-eslint": "~4.5.0",
35 | "@vue/cli-service": "~4.5.0",
36 | "babel-eslint": "^10.1.0",
37 | "eslint": "^6.7.2",
38 | "eslint-plugin-vue": "^6.2.2",
39 | "mockjs": "^1.1.0",
40 | "sass-loader": "^10.1.0",
41 | "vue-template-compiler": "^2.6.11"
42 | },
43 | "eslintConfig": {
44 | "root": true,
45 | "env": {
46 | "node": true
47 | },
48 | "extends": [
49 | "plugin:vue/essential",
50 | "eslint:recommended"
51 | ],
52 | "parserOptions": {
53 | "parser": "babel-eslint"
54 | },
55 | "rules": {}
56 | },
57 | "browserslist": [
58 | "> 1%",
59 | "last 2 versions",
60 | "not dead"
61 | ]
62 | }
63 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/public/favicon.ico
--------------------------------------------------------------------------------
/public/font_2474164_6bnyueo2zk9.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/public/font_2474164_6bnyueo2zk9.ttf
--------------------------------------------------------------------------------
/public/font_2474164_6bnyueo2zk9.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/public/font_2474164_6bnyueo2zk9.woff
--------------------------------------------------------------------------------
/public/font_2474164_6bnyueo2zk9.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/public/font_2474164_6bnyueo2zk9.woff2
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | KubeOperator
8 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
--------------------------------------------------------------------------------
/src/api/auth.js:
--------------------------------------------------------------------------------
1 | import {get, post, del} from "@/plugins/request"
2 |
3 | const authUrl = "/api/v1/auth/session"
4 | const codeUrl = "/api/v1/captcha"
5 | const forgetPassword = "/api/v1/user/forgot/password"
6 |
7 | export function login(data) {
8 | return post(authUrl, data)
9 | }
10 |
11 | export function logout() {
12 | return del(authUrl)
13 | }
14 |
15 | export function isLogin() {
16 | return get(`${authUrl}/status`)
17 | }
18 |
19 | export function getSession() {
20 | return get(authUrl)
21 | }
22 |
23 | export function getCaptcha() {
24 | return get(`${codeUrl}`)
25 | }
26 |
27 | export function resetPassword(data) {
28 | return post(`${forgetPassword}`,data)
29 | }
30 |
--------------------------------------------------------------------------------
/src/api/authorization.js:
--------------------------------------------------------------------------------
1 | import {get} from "@/plugins/request"
2 |
3 | const authorizationUrl = "/api/v1/projects"
4 |
5 | export function getResourceTree () {
6 | return get(`${authorizationUrl}/tree`)
7 | }
8 |
--------------------------------------------------------------------------------
/src/api/backup-account.js:
--------------------------------------------------------------------------------
1 | import {del, get, patch, post} from "@/plugins/request"
2 |
3 | const backupAccountUrl="/api/v1/backupaccounts"
4 |
5 |
6 | export function getBackupAccounts(currentPage,pageSize) {
7 | return get(`${backupAccountUrl}/?pageNum=${currentPage}&pageSize=${pageSize}`)
8 | }
9 |
10 | export function createBackupAccounts(data) {
11 | return post(`${backupAccountUrl}`,data)
12 | }
13 |
14 | export function listBuckets(data) {
15 | return post(`${backupAccountUrl}/buckets`,data)
16 | }
17 |
18 | export function updateBackupAccounts(name, data) {
19 | return patch(`${backupAccountUrl}/${name}`,data)
20 | }
21 |
22 | export function deleteBackupAccounts(name) {
23 | return del(`${backupAccountUrl}/${name}`)
24 | }
25 |
26 | export function searchBackupAccounts(currentPage, pageSize, conditions) {
27 | return post(`${backupAccountUrl}/search?pageNum=${currentPage}&pageSize=${pageSize}`, conditions)
28 | }
29 |
30 | export function getBackupAccountByName(name) {
31 | return get(`${backupAccountUrl}/${name}`)
32 | }
33 |
--------------------------------------------------------------------------------
/src/api/cluster-member.js:
--------------------------------------------------------------------------------
1 | import {del, get, post} from "@/plugins/request"
2 |
3 | const clusterMemberUrl = (projectName, clusterName) => {
4 | return `/api/v1/projects/${projectName}/clusters/${clusterName}/members`
5 | }
6 |
7 | export function listClusterMembers (projectName, clusterName, currentPage, pageSize) {
8 | return get(`${clusterMemberUrl(projectName, clusterName)}?pageNum=${currentPage}&pageSize=${pageSize}`)
9 | }
10 |
11 | export function createClusterMember (projectName, clusterName, data) {
12 | return post(`${clusterMemberUrl(projectName, clusterName)}`, data)
13 | }
14 |
15 | export function deleteClusterMember (projectName, clusterName, name) {
16 | return del(`${clusterMemberUrl(projectName, clusterName)}/${name}`)
17 | }
18 |
19 | export function searchUsers (projectName, name) {
20 | return get(`${clusterMemberUrl(projectName)}/users?name=${name}`)
21 | }
22 |
23 | export function searchUsersByProject (projectName, clusterName, name) {
24 | return get(`${clusterMemberUrl(projectName, clusterName)}/search?name=${name}`)
25 | }
26 |
--------------------------------------------------------------------------------
/src/api/cluster-resource.js:
--------------------------------------------------------------------------------
1 | import {del, get, post} from "@/plugins/request"
2 |
3 | const clusterResourceUrl = (projectName,clusterName) => {
4 | return `/api/v1/projects/${projectName}/clusters/${clusterName}/resources`
5 | }
6 |
7 | export function listClusterResources (projectName,clusterName, resourceType, currentPage, pageSize) {
8 | return get(`${clusterResourceUrl(projectName,clusterName)}?pageNum=${currentPage}&pageSize=${pageSize}&resourceType=${resourceType}`)
9 | }
10 |
11 | export function listClusterResourcesAll (projectName,clusterName, resourceType) {
12 | return get(`${clusterResourceUrl(projectName,clusterName)}?resourceType=${resourceType}`)
13 | }
14 |
15 | export function createClusterResource (projectName,clusterName, data) {
16 | return post(`${clusterResourceUrl(projectName,clusterName)}`, data)
17 | }
18 |
19 | export function deleteClusterResource (projectName,clusterName, name, resourceType) {
20 | return del(`${clusterResourceUrl(projectName,clusterName)}/${name}?resourceType=${resourceType}`)
21 | }
22 |
23 | export function getResourceAddList (projectName,clusterName, resourceType) {
24 | return get(`${clusterResourceUrl(projectName,clusterName)}/list?resourceType=${resourceType}`)
25 | }
26 |
--------------------------------------------------------------------------------
/src/api/cluster.js:
--------------------------------------------------------------------------------
1 | import {get, post, del} from "@/plugins/request"
2 |
3 | const clusterUrl = "/api/v1/clusters"
4 | const componentUrl = "/api/v1/components"
5 |
6 | export function getClusterByName(clusterName) {
7 | return get(`${clusterUrl}/${clusterName}`)
8 | }
9 |
10 | export function getClusterByProject(projectNames) {
11 | return get(`${clusterUrl}/name/${projectNames}`)
12 | }
13 |
14 | export function checkClusterNameExistence(clusterName) {
15 | return get(`${clusterUrl}/existence/${clusterName}`)
16 | }
17 |
18 | export function listClusters(page, size) {
19 | return get(`${clusterUrl}?pageNum=${page}&pageSize=${size}`)
20 | }
21 |
22 | export function searchClusters(page, size, condition, isPolling) {
23 | return post(`${clusterUrl}/search?pageNum=${page}&pageSize=${size}&isPolling=${isPolling}`, condition)
24 | }
25 |
26 | export function createCluster(data) {
27 | return post(`${clusterUrl}`, data)
28 | }
29 |
30 | export function healthCheck(clusterName) {
31 | return get(`${clusterUrl}/health/${clusterName}`)
32 | }
33 |
34 | export function clusterRecover(clusterName, data) {
35 | return post(`${clusterUrl}/recover/${clusterName}`, data)
36 | }
37 |
38 | export function deleteCluster(clusterName, force, uninstall) {
39 | return del(`${clusterUrl}/${clusterName}?force=${force}&uninstall=${uninstall}`)
40 | }
41 |
42 | export function importCluster(data) {
43 | return post(`${clusterUrl}/import/`, data)
44 | }
45 |
46 | export function allClusters() {
47 | return get(`${clusterUrl}`)
48 | }
49 |
50 | export function initCluster(clusterName) {
51 | return post(`${clusterUrl}/init/${clusterName}/`, {})
52 | }
53 |
54 | export function upgradeCluster(clusterName, version) {
55 | let req = {
56 | clusterName: clusterName,
57 | version: version,
58 | }
59 | return post(`${clusterUrl}/upgrade/`, req)
60 | }
61 |
62 | export function getClusterStatus(clusterName) {
63 | return get(`${clusterUrl}/status/${clusterName}`)
64 | }
65 |
66 | export function getSecret(clusterName) {
67 | return get(`${clusterUrl}/secret/${clusterName}`)
68 | }
69 |
70 | export function getClusterInfo(data) {
71 | return post(clusterUrl + "/load", data)
72 | }
73 |
74 | export function handleGpu(clusterName, handle) {
75 | return post(`${clusterUrl}/gpu/${clusterName}/${handle}`)
76 | }
77 |
78 | export function getGpuStatu(clusterName) {
79 | return get(`${clusterUrl}/gpu/${clusterName}`)
80 | }
81 |
82 | export function getComponents(cluster) {
83 | return get(`${componentUrl}?cluster=${cluster}`)
84 | }
85 |
86 | export function syncComponents(data) {
87 | return post(`${componentUrl}/sync`, data)
88 | }
89 |
90 | export function createComponent(data) {
91 | return post(`${componentUrl}`, data)
92 | }
93 |
94 | export function deleteComponent(cluster, name) {
95 | return del(`${componentUrl}/${cluster}/${name}`)
96 | }
--------------------------------------------------------------------------------
/src/api/cluster/backup.js:
--------------------------------------------------------------------------------
1 | import {del, get, post} from "@/plugins/request"
2 |
3 | const fileUrl = "/api/v1/clusters/backup/files"
4 | const logUrl = "/api/v1/clusters/log"
5 | const strategyUrl = "/api/v1/clusters/backup/strategy"
6 | const clusterUrl = "/api/v1/clusters/backupaccounts"
7 | const VeleroUrl = "/api/v1/clusters/velero"
8 |
9 |
10 |
11 | export function listBackupByPage (clusterName, page, size) {
12 | const itemUrl = `${fileUrl}?pageNum=${page}&pageSize=${size}&clusterName=${clusterName}`
13 | return get(itemUrl)
14 | }
15 |
16 | export function getStrategy (clusterName) {
17 | const itemUrl = `${strategyUrl}/${clusterName}`
18 | return get(itemUrl)
19 | }
20 |
21 | export function getBackupLog (clusterName) {
22 | return get(`${logUrl}/${clusterName}`)
23 | }
24 |
25 | export function createStrategy (data) {
26 | const itemUrl = `${strategyUrl}`
27 | return post(itemUrl, data)
28 | }
29 |
30 | export function startBackup (data) {
31 | const itemUrl = `${fileUrl}/backup`
32 | return post(itemUrl, data)
33 | }
34 |
35 | export function startRestore (data) {
36 | const itemUrl = `${fileUrl}/restore`
37 | return post(itemUrl, data)
38 | }
39 |
40 | export function localRestore (data) {
41 | const itemUrl = `${fileUrl}/restore/local`
42 | return post(itemUrl, data)
43 | }
44 |
45 | export function listBackupAccounts (name) {
46 | return get(`${clusterUrl}/${name}`)
47 | }
48 |
49 | export function deleteBackupFile(name) {
50 | return del(`${fileUrl}/${name}`)
51 | }
52 |
53 | export function getVeleroBackups(cluster) {
54 | return get(`${VeleroUrl}/${cluster}/backups`)
55 | }
56 |
57 | export function getVeleroBackupLogs(cluster,backup){
58 | return get(`${VeleroUrl}/${cluster}/backup/logs?name=${backup}`)
59 | }
60 |
61 | export function createVeleroBackup(cluster, type, item) {
62 | return post(`${VeleroUrl}/${cluster}/${type}/create`,item)
63 | }
64 |
65 | export function deleteVeleroBackup(cluster, type, backup) {
66 | return del(`${VeleroUrl}/${cluster}/${type}/del?name=${backup}`)
67 | }
68 |
69 | export function getRestores(cluster){
70 | return get(`${VeleroUrl}/${cluster}/restore`)
71 | }
72 |
73 | export function getVeleroRestoreDescribe(cluster,restore){
74 | return get(`${VeleroUrl}/${cluster}/restore/describe?name=${restore}`)
75 | }
76 |
77 | export function getVeleroRestoreLogs(cluster,restore){
78 | return get(`${VeleroUrl}/${cluster}/restore/logs?name=${restore}`)
79 | }
80 |
81 | export function delVeleroRestore(cluster,restore) {
82 | return del(`${VeleroUrl}/${cluster}/restore/del?name=${restore}`)
83 | }
84 |
85 | export function restore(cluster,item) {
86 | return post(`${VeleroUrl}/${cluster}/restore/create`,item)
87 | }
88 |
89 | export function veleroInstall(cluster,item) {
90 | return post(`${VeleroUrl}/${cluster}/velero/install/config`,item)
91 | }
92 |
93 | export function getVeleroConfig(cluster) {
94 | return get(`${VeleroUrl}/${cluster}/velero/install/config`)
95 | }
96 |
97 | export function veleroUninstall(cluster) {
98 | return del(`${VeleroUrl}/${cluster}/velero/uninstall`)
99 | }
100 |
--------------------------------------------------------------------------------
/src/api/cluster/cluster.js:
--------------------------------------------------------------------------------
1 | import {get, post} from "@/plugins/request"
2 |
3 | const kubernetesUrl = "/api/v1/kubernetes/search"
4 | const kubernetesCreateUrl = "/api/v1/kubernetes/create"
5 | const kubernetesDeleteUrl = "/api/v1/kubernetes/delete"
6 | const metricUrl = "/api/v1/kubernetes/search/metric/{cluster_name}"
7 |
8 | export function listResource(data) {
9 | return post(kubernetesUrl, data)
10 | }
11 |
12 | export function deleteResoure(data) {
13 | return post(kubernetesDeleteUrl, data)
14 | }
15 |
16 | export function listNamespace(clusterName) {
17 | let search = {
18 | kind: "namespacelist",
19 | cluster: clusterName,
20 | continue: "",
21 | limit: 0,
22 | namespace: "",
23 | name: "",
24 | }
25 | return post(kubernetesUrl, search)
26 | }
27 |
28 | export function listDeployment(clusterName, namespace) {
29 | let search = {
30 | kind: "deploymentlist",
31 | cluster: clusterName,
32 | continue: "",
33 | limit: 0,
34 | namespace: namespace,
35 | name: "",
36 | }
37 | return post(kubernetesUrl, search)
38 | }
39 |
40 | export function listPod(clusterName, namespace) {
41 | let search = {
42 | kind: "podlist",
43 | cluster: clusterName,
44 | continue: "",
45 | limit: 0,
46 | namespace: namespace,
47 | name: "",
48 | }
49 | return post(kubernetesUrl, search)
50 | }
51 |
52 | export function listNode(clusterName) {
53 | let search = {
54 | kind: "nodelist",
55 | cluster: clusterName,
56 | continue: "",
57 | limit: 0,
58 | namespace: "",
59 | name: "",
60 | }
61 | return post(kubernetesUrl, search)
62 | }
63 |
64 | export function listStorageClass(clusterName) {
65 | let search = {
66 | kind: "storageclasslist",
67 | cluster: clusterName,
68 | continue: "",
69 | limit: 0,
70 | namespace: "",
71 | name: "",
72 | }
73 | return post(kubernetesUrl, search)
74 | }
75 |
76 | export function getMetric(clusterName) {
77 | return post(metricUrl.replace("{cluster_name}", clusterName))
78 | }
79 |
80 | export function createStorageClass(data) {
81 | return post(kubernetesCreateUrl + "/sc", data)
82 | }
83 |
84 | export function createSecret(data) {
85 | return post(kubernetesCreateUrl + "/secret", data)
86 | }
87 |
88 | export function getClusterToken(clusterName) {
89 | return get(`/api/v1/clusters/webkubectl/${clusterName}?l=zh-CN`)
90 | }
91 |
92 | export function getDashboard(clusterName){
93 | return get(`/api/v1/clusters/dashboard/${clusterName}?l=zh-CN`)
94 | }
95 |
--------------------------------------------------------------------------------
/src/api/cluster/grade.js:
--------------------------------------------------------------------------------
1 | import {get} from "@/plugins/request"
2 |
3 | const baseUrl = "/api/v1/clusters/grade"
4 |
5 | export function getGrade(clusterName) {
6 | const gradeUrl = `${baseUrl}/${clusterName}`
7 | return get(gradeUrl)
8 | }
9 |
--------------------------------------------------------------------------------
/src/api/cluster/log.js:
--------------------------------------------------------------------------------
1 | import {post} from "@/plugins/request"
2 |
3 | const efBaseUrl = "/proxy/logging/{cluster_name}/{index_name}/_search?pretty=true"
4 | const lokiBaseUrl = "/proxy/loki/{cluster_name}/"
5 |
6 | export function EfSearch(clusterName, queryArry, queryIndex, beginDate, endDate, pageFrom, pageSize) {
7 | const index = queryIndex
8 | const query = {
9 | from: (pageFrom - 1) * pageSize,
10 | size: pageSize,
11 | query: {
12 | bool: {
13 | must: queryArry,
14 | filter: {
15 | range: {
16 | "@timestamp": {
17 | gte: beginDate,
18 | lte: endDate,
19 | format: "yyyy.MM.dd",
20 | time_zone: "+08:00"
21 | }
22 | }
23 | }
24 | }
25 | },
26 | sort: [
27 | {"@timestamp": "desc"},
28 | ]
29 | }
30 | return post(efBaseUrl.replace("{cluster_name}", clusterName).replace("{index_name}", index) + "&ignore_unavailable=true", query)
31 | }
32 | export function LokiLabels(clusterName) {
33 | return post(lokiBaseUrl.replace("{cluster_name}", clusterName) + "loki/api/v1/labels", "")
34 | }
35 | export function LokiLabelValues(clusterName, label) {
36 | return post(lokiBaseUrl.replace("{cluster_name}", clusterName) + "loki/api/v1/label/{label}/values".replace("{label}", label), "")
37 | }
38 | export function LokiSearch(clusterName, params) {
39 | return post(lokiBaseUrl.replace("{cluster_name}", clusterName) + "loki/api/v1/query_range?" + params, "")
40 | }
41 |
--------------------------------------------------------------------------------
/src/api/cluster/monitor.js:
--------------------------------------------------------------------------------
1 | import {post} from "@/plugins/request"
2 |
3 | const baseUrl = "/api/v1/clusters/monitor/search/{cluster_name}"
4 |
5 | export function Monitor(clusterName, data) {
6 | return post(baseUrl.replace("{cluster_name}", clusterName), data)
7 | }
8 |
--------------------------------------------------------------------------------
/src/api/cluster/node.js:
--------------------------------------------------------------------------------
1 | import {get, post} from "@/plugins/request"
2 | const kubernetesUrl = "/api/v1/kubernetes"
3 |
4 |
5 | const clusterUrl = "/api/v1/clusters"
6 | const baseUrl = "/api/v1/clusters/node/{clusterName}"
7 | const detailUrl = "/api/v1/clusters/node/detail/{clusterName}/{node}"
8 | const batchUrl = "/api/v1/clusters/node/batch/{clusterName}"
9 | const recreateUrl = "/api/v1/clusters/node/recreate/{clusterName}"
10 |
11 | export function cordonNode(data) {
12 | let headers = {"Content-Type": "application/strategic-merge-patch+json"}
13 | return post(kubernetesUrl + "/cordon", data, headers)
14 | }
15 |
16 | export function evictionNode(data) {
17 | return post(kubernetesUrl + "/evict", data)
18 | }
19 |
20 | export function listNodeInDB(clusterName) {
21 | return get(`/api/v1/clusters/node/${clusterName}`)
22 | }
23 |
24 | export function listNodesByPage(clusterName, pageNum, pageSize, isPolling) {
25 | return get(baseUrl.replace("{clusterName}", clusterName) + `?pageNum=${pageNum}&pageSize=${pageSize}&isPolling=${isPolling}`)
26 | }
27 |
28 | export function nodeBatchOperation(clusterName, data) {
29 | return post(batchUrl.replace("{clusterName}", clusterName), data)
30 | }
31 |
32 | export function getNodeStatus(clusterName, node) {
33 | return get(`${clusterUrl}/node/status/${clusterName}/${node}`)
34 | }
35 |
36 | export function getNodeByName(clusterName, node) {
37 | return get(detailUrl.replace("{clusterName}", clusterName).replace("{node}", node))
38 | }
39 |
40 | export function nodeReCreate(clusterName, data) {
41 | return post(recreateUrl.replace("{clusterName}", clusterName), data)
42 | }
--------------------------------------------------------------------------------
/src/api/cluster/security.js:
--------------------------------------------------------------------------------
1 | import {get, post, del} from "@/plugins/request"
2 |
3 | const url = "/api/v1/clusters/cis/{cluster_name}"
4 | const detailUrl = "/api/v1/clusters/cisdetail/{cluster_name}"
5 | const reportlUrl = "/api/v1/clusters/cisreport/{cluster_name}"
6 |
7 | export function listCisByPage(clusterName, page, size) {
8 | return get(url.replace("{cluster_name}", clusterName) + `?pageNum=${page}&pageSize=${size}`)
9 | }
10 |
11 | export function cisCreate(clusterName, data) {
12 | return post(url.replace("{cluster_name}", clusterName), data)
13 | }
14 |
15 | export function cisDelete(clusterName, id) {
16 | return del(url.replace("{cluster_name}", clusterName) + `/${id}`)
17 | }
18 |
19 | export function getCisDetail(clusterName, id) {
20 | return get(detailUrl.replace("{cluster_name}", clusterName) + `/${id}`)
21 | }
22 |
23 | export function getCisReport(clusterName, id, format) {
24 | let url = reportlUrl.replace("{cluster_name}", clusterName) + `/${id}`
25 | if (format) {
26 | url += `?format=${format}`
27 | }
28 | return window.open(url)
29 | }
30 |
--------------------------------------------------------------------------------
/src/api/cluster/storage.js:
--------------------------------------------------------------------------------
1 | import {get, post} from "@/plugins/request"
2 |
3 | const provisionerUrl = "/api/v1/clusters/provisioner/{cluster_name}"
4 |
5 | export function listProvisioner(clusterName) {
6 | return get(provisionerUrl.replace("{cluster_name}", clusterName))
7 | }
8 |
9 | export function createProvisioner(clusterName, item) {
10 | return post(provisionerUrl.replace("{cluster_name}", clusterName), item)
11 | }
12 |
13 | export function syncProvisioner(clusterName, hosts) {
14 | const syncUrl = "/api/v1/clusters/provisioner/sync/{cluster_name}"
15 | const url = syncUrl.replace("{cluster_name}", clusterName)
16 | return post(url, hosts)
17 | }
18 |
19 | export function deleteProvisioner(clusterName, item) {
20 | const deleteUrl = "/api/v1/clusters/provisioner/delete/{cluster_name}"
21 | const url = deleteUrl.replace("{cluster_name}", clusterName)
22 | return post(url, item)
23 | }
--------------------------------------------------------------------------------
/src/api/cluster/tasks.js:
--------------------------------------------------------------------------------
1 | import {get, post} from "@/plugins/request"
2 |
3 | const taskUrl = "/api/v1/tasks"
4 | const taskLoggerUrl = "/api/v1/tasks"
5 |
6 | export function getTasks(page, size, cluster, logtype) {
7 | return post(`${taskUrl}?cluster=${cluster}&logtype=${logtype}&pageNum=${page}&pageSize=${size}`)
8 | }
9 |
10 | export function openLoggerWithID(clusterId, logId) {
11 | window.open(`/ui/#/logger?clusterId=${clusterId}&logId=${logId}`, "_blank", "height=865, width=800, top=0, left=0, toolbar=no, menubar=no, scrollbars=no, resizable=yes,location=no, status=no")
12 | }
13 |
14 | export function openLoggerWithName(clusterName, logId) {
15 | window.open(`/ui/#/logger?clusterName=${clusterName}&logId=${logId}`, "_blank", "height=865, width=800, top=0, left=0, toolbar=no, menubar=no, scrollbars=no, resizable=yes,location=no, status=no")
16 | }
17 |
18 | export function getLogById(clusterId, logId) {
19 | return get(`${taskLoggerUrl}/log1/${clusterId}/${logId}`)
20 | }
21 |
22 | export function getDetailById(logId) {
23 | return get(`${taskLoggerUrl}/detail/${logId}`)
24 | }
25 |
26 | export function getLogByName(clusterName, logId) {
27 | return get(`${taskLoggerUrl}/log2/${clusterName}/${logId}`)
28 | }
29 |
30 | export function getBackupLogs(page, size, clusterName) {
31 | return get(`${taskLoggerUrl}/backup/logs/${clusterName}?pageNum=${page}&pageSize=${size}`)
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/src/api/cluster/tool.js:
--------------------------------------------------------------------------------
1 | import {get, post} from "@/plugins/request"
2 |
3 | const toolUrl = "/api/v1/clusters/tool"
4 |
5 | export function listTool(clusterName) {
6 | return get(`${toolUrl}/${clusterName}`)
7 | }
8 |
9 | export function enableTool(clusterName, data) {
10 | return post(`${toolUrl}/enable/${clusterName}`, data)
11 | }
12 |
13 | export function disableTool(clusterName, data) {
14 | return post(`${toolUrl}/disable/${clusterName}`, data)
15 | }
16 |
17 | export function upgradeTool(clusterName, data) {
18 | return post(`${toolUrl}/upgrade/${clusterName}`, data)
19 | }
20 |
21 | export function getNodePort(clusterName, toolName) {
22 | return get(`${toolUrl}/port/${clusterName}/${toolName}`)
23 | }
24 |
25 | export function syncTool(clusterName, data) {
26 | return post(`${toolUrl}/sync/${clusterName}`, data)
27 | }
28 |
29 | export function getFlex(clusterName) {
30 | return get(`${toolUrl}/flex/${clusterName}`)
31 | }
32 |
33 | export function enableFlex(clusterName) {
34 | return post(`${toolUrl}/flex/enable/${clusterName}`)
35 | }
36 |
37 | export function disableFlex(clusterName) {
38 | return post(`${toolUrl}/flex/disable/${clusterName}`)
39 | }
40 |
--------------------------------------------------------------------------------
/src/api/credentials.js:
--------------------------------------------------------------------------------
1 | import {get, patch, post, del} from "@/plugins/request"
2 |
3 | const settingUrl = "/api/v1/credentials"
4 |
5 | // Registry
6 | export function listCredentials(currentPage, pageSize) {
7 | return get(`${settingUrl}/?pageNum=${currentPage}&pageSize=${pageSize}`)
8 | }
9 |
10 | export function listCredentialAll() {
11 | return get(`${settingUrl}`)
12 | }
13 |
14 | export function searchCredential(currentPage, pageSize, conditions) {
15 | return post(`${settingUrl}/search?pageNum=${currentPage}&pageSize=${pageSize}`, conditions)
16 | }
17 |
18 | export function createCredentials(data) {
19 | return post(settingUrl,data)
20 | }
21 |
22 | export function updateCredentials(name, data) {
23 | return patch(`${settingUrl}/${name}`,data)
24 | }
25 |
26 | export function deleteCredentials(name) {
27 | return del(`${settingUrl}/${name}`)
28 | }
29 |
30 | export function listAllCredentials() {
31 | return get(`${settingUrl}`)
32 | }
33 |
34 | export function getCredentialByName(name) {
35 | return get(`${settingUrl}/${name}`)
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/src/api/hosts.js:
--------------------------------------------------------------------------------
1 | import {get, post, del, patch} from "@/plugins/request"
2 |
3 | const hostUrl = "/api/v1/hosts"
4 |
5 | export function createHost(data) {
6 | return post(hostUrl, data)
7 | }
8 |
9 | export function deleteHost(name) {
10 | return del(`${hostUrl}/${name}`)
11 | }
12 |
13 | export function listHosts(currentPage, pageSize) {
14 | return get(`${hostUrl}?pageNum=${currentPage}&pageSize=${pageSize}`)
15 | }
16 |
17 | export function searchHosts(currentPage, pageSize,condition) {
18 | return post(`${hostUrl}/search?pageNum=${currentPage}&pageSize=${pageSize}`,condition)
19 | }
20 |
21 | export function getHostByName(name) {
22 | return get(`${hostUrl}/${name}`)
23 | }
24 |
25 | export function updateHost(host) {
26 | return patch(`${hostUrl}/`, host)
27 | }
28 |
29 | export function syncHosts(hosts) {
30 | const itemUrl = `${hostUrl}/sync/`
31 | return post(itemUrl, hosts)
32 | }
33 |
34 | export function importHosts(file) {
35 | const itemUrl = `${hostUrl}/upload`
36 | return post(itemUrl, file)
37 | }
38 |
39 | export function batchHosts(data) {
40 | const itemUrl = `${hostUrl}/batch`
41 | return post(itemUrl, data)
42 | }
--------------------------------------------------------------------------------
/src/api/ip-pool.js:
--------------------------------------------------------------------------------
1 | import {get, del, post, patch} from "@/plugins/request"
2 |
3 | const ipPoolUrl = "/api/v1/ippools"
4 |
5 | export function listIpPools (page, size) {
6 | return get(`${ipPoolUrl}?pageNum=${page}&pageSize=${size}`)
7 | }
8 |
9 | export function listAllIpPools () {
10 | return get(`${ipPoolUrl}`)
11 | }
12 |
13 | export function deleteIpPoolBy (name) {
14 | return del(`${ipPoolUrl}/${name}`)
15 | }
16 |
17 | export function createIpPool (data) {
18 | return post(ipPoolUrl, data)
19 | }
20 |
21 | export function searchIpPool (currentPage, pageSize, conditions) {
22 | return post(`${ipPoolUrl}/search?pageNum=${currentPage}&pageSize=${pageSize}`, conditions)
23 |
24 | }
25 |
26 | export function listIps (ipPoolName, page, size) {
27 | return get(`ippools/${ipPoolName}/ips?pageNum=${page}&pageSize=${size}`)
28 | }
29 |
30 | export function deleteIpBy (ipPoolName, ip) {
31 | return del(`${ipPoolUrl}/${ipPoolName}/ips/${ip}`)
32 | }
33 |
34 | export function createIp (ipPoolName, data) {
35 | return post(`${ipPoolUrl}/${ipPoolName}/ips`, data)
36 | }
37 |
38 | export function syncIp (ipPoolName) {
39 | return patch(`${ipPoolUrl}/${ipPoolName}/ips/sync`)
40 | }
41 |
42 | export function searchIp (currentPage, pageSize, ipPoolName, conditions) {
43 | return post(`${ipPoolUrl}/${ipPoolName}/ips/search?pageNum=${currentPage}&pageSize=${pageSize}`, conditions)
44 | }
45 |
46 | export function updateIp (ipPoolName, name, data) {
47 | return patch(`${ipPoolUrl}/${ipPoolName}/ips/${name}`,data)
48 | }
49 |
--------------------------------------------------------------------------------
/src/api/license.js:
--------------------------------------------------------------------------------
1 | import {get, post} from "@/plugins/request"
2 |
3 | const licenseUrl = "/api/v1/license"
4 |
5 | export function getLicense() {
6 | return get(`${licenseUrl}`)
7 | }
8 |
9 | export function importLicense(data) {
10 | return post(licenseUrl,data)
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/manifest.js:
--------------------------------------------------------------------------------
1 | import {get, patch} from "@/plugins/request"
2 |
3 | const baseUrl = "/api/v1/manifests";
4 |
5 | export function manifestGroup() {
6 | return get(`${baseUrl}/group`)
7 | }
8 |
9 | export function listActive() {
10 | return get(`${baseUrl}/active`);
11 | }
12 |
13 | export function changeStatus(versionName, manifest) {
14 | return patch(`${baseUrl}/${versionName}`, manifest)
15 | }
16 |
--------------------------------------------------------------------------------
/src/api/msg-subscribe.js:
--------------------------------------------------------------------------------
1 | import {post, get} from "@/plugins/request"
2 |
3 | const subscribeUrl = "/api/v1/msg/subscribes"
4 |
5 | export function searchMsgSubscribe (currentPage, pageSize, type, resourceName, conditions) {
6 | return post(`${subscribeUrl}/search?type=${type}&resourceName=${resourceName}&pageNum=${currentPage}&pageSize=${pageSize}`, conditions)
7 | }
8 |
9 | export function updateMsgSubScribe (data) {
10 | return post(`${subscribeUrl}/update`, data)
11 | }
12 |
13 | export function addSubscribeUser (data) {
14 | return post(`${subscribeUrl}/user`, data)
15 | }
16 |
17 | export function deleteSubscribeUser (data) {
18 | return post(`${subscribeUrl}/delete/user`, data)
19 | }
20 |
21 | export function searchMsgSubscribeByName (type, resourceName, name) {
22 | return post(`${subscribeUrl}/search?type=${type}&resourceName=${resourceName}`, {
23 | quick: {
24 | field: "quick",
25 | value: name
26 | }
27 | })
28 | }
29 |
30 | export function getAddSubscribeUsers (search, subscribeId, resourceName) {
31 | return get(`${subscribeUrl}/users?user=${search}&subscribeId=${subscribeId}&resourceName=${resourceName}`)
32 | }
33 |
34 | export function getSubScribeUsers (currentPage, pageSize, subscribeId, conditions) {
35 | return post(`${subscribeUrl}/users?subscribeId=${subscribeId}&pageNum=${currentPage}&pageSize=${pageSize}`, conditions)
36 | }
37 |
--------------------------------------------------------------------------------
/src/api/personal-setting.js:
--------------------------------------------------------------------------------
1 | import {post} from "@/plugins/request"
2 |
3 | export function changePassword(data) {
4 | return post('/api/v1/users/change/password', data)
5 | }
6 |
--------------------------------------------------------------------------------
/src/api/plan.js:
--------------------------------------------------------------------------------
1 | import {get, del, post, patch} from "@/plugins/request"
2 |
3 | const planUrl = "/api/v1/plans"
4 |
5 | export function listPlans (page, size) {
6 | return get(`${planUrl}?pageNum=${page}&pageSize=${size}`)
7 | }
8 |
9 | export function deletePlanBy (name) {
10 | return del(planUrl + "/" + name)
11 | }
12 |
13 | export function searchPlans (page, size, condition) {
14 | return post(`${planUrl}/search?pageNum=${page}&pageSize=${size}`, condition)
15 | }
16 |
17 | export function listVmConfigs (regionName) {
18 | return get(`${planUrl}/configs/${regionName}`)
19 | }
20 |
21 | export function createPlan (data) {
22 | return post(`${planUrl}`, data)
23 | }
24 |
25 | export function getPlanBy (name) {
26 | return get(`${planUrl}/${name}`)
27 | }
28 |
29 | export function updatePlanBy (name, data) {
30 | return patch(`${planUrl}/${name}`, data)
31 | }
32 |
--------------------------------------------------------------------------------
/src/api/project-member.js:
--------------------------------------------------------------------------------
1 | import {del, get, post} from "@/plugins/request"
2 |
3 | const projectMemberUrl = (project_name) => {
4 | return `/api/v1/projects/${project_name}/members`
5 | }
6 |
7 |
8 | export function listProjectMembers(project_name, currentPage, pageSize) {
9 | return get(`${projectMemberUrl(project_name)}?pageNum=${currentPage}&pageSize=${pageSize}`)
10 | }
11 |
12 | export function createProjectMember(project_name, data) {
13 | return post(`${projectMemberUrl(project_name)}`, data)
14 | }
15 |
16 | export function deleteProjectMember(project_name, name) {
17 | return del(`${projectMemberUrl(project_name)}/${name}`)
18 | }
19 |
20 | export function updateProjectMember(project_name, name, data) {
21 | return get(`${projectMemberUrl(project_name)}/${name}`, data)
22 | }
23 |
24 | export function listUsers(project_name, name) {
25 | return get(`${projectMemberUrl(project_name)}/users?name=${name}`)
26 | }
27 |
--------------------------------------------------------------------------------
/src/api/project-resource.js:
--------------------------------------------------------------------------------
1 | import {del, get, post} from "@/plugins/request"
2 |
3 |
4 | const projectResourceUrl = (project_name) => {
5 | return `/api/v1/projects/${project_name}/resources`
6 | }
7 |
8 | export function listProjectResources (project_name, resourceType, currentPage, pageSize) {
9 | return get(`${projectResourceUrl(project_name)}?pageNum=${currentPage}&pageSize=${pageSize}&resourceType=${resourceType}`)
10 | }
11 |
12 | export function listProjectResourcesAll (project_name, resourceType) {
13 | return get(`${projectResourceUrl(project_name)}?resourceType=${resourceType}`)
14 | }
15 |
16 | export function getResourceList (project_name, resourceType) {
17 | return get(`${projectResourceUrl(project_name)}/list?resourceType=${resourceType}`)
18 | }
19 |
20 | export function createProjectResource (project_name, data) {
21 | return post(`${projectResourceUrl(project_name)}`, data)
22 | }
23 |
24 | export function deleteProjectResource (project_name, name,resourceType) {
25 | return del(`${projectResourceUrl(project_name)}/${name}?resourceType=${resourceType}`)
26 | }
27 |
--------------------------------------------------------------------------------
/src/api/projects.js:
--------------------------------------------------------------------------------
1 | import {get, post, del, patch} from "@/plugins/request"
2 |
3 | const projectUrl = "/api/v1/projects"
4 |
5 | export function createProject (data) {
6 | return post(projectUrl, data)
7 | }
8 |
9 | export function listProjects (currentPage, pageSize) {
10 | return get(`${projectUrl}?pageNum=${currentPage}&pageSize=${pageSize}`)
11 | }
12 |
13 | export function getProjectsHasClusters() {
14 | return get(`${projectUrl}/clusters`)
15 | }
16 |
17 | export function getProject (name) {
18 | return get(`${projectUrl}/${name}`)
19 | }
20 |
21 | export function updateProject (name, data) {
22 | return patch(`${projectUrl}/${name}`, data)
23 | }
24 |
25 | export function deleteProject (name) {
26 | return del(`${projectUrl}/${name}`)
27 | }
28 |
29 | export function allProjects () {
30 | return get(`${projectUrl}`)
31 | }
32 |
33 | export function searchProject (currentPage, pageSize, condition) {
34 | return post(`${projectUrl}/search?pageNum=${currentPage}&pageSize=${pageSize}`, condition)
35 | }
36 |
--------------------------------------------------------------------------------
/src/api/region.js:
--------------------------------------------------------------------------------
1 | import {get, del, post, patch} from "@/plugins/request"
2 |
3 | const regionUrl = "/api/v1/regions"
4 |
5 | export function listRegions (page, size) {
6 | return get(`${regionUrl}/search?pageNum=${page}&pageSize=${size}`)
7 | }
8 |
9 | export function deleteRegionBy (name) {
10 | return del(regionUrl + "/" + name)
11 | }
12 |
13 | export function searchRegion (page, size, condition) {
14 | return post(`${regionUrl}/search?pageNum=${page}&pageSize=${size}`, condition)
15 | }
16 |
17 | export function listAllRegions () {
18 | return get(`${regionUrl}`)
19 | }
20 |
21 | export function listDatacenter (data) {
22 | return post(`${regionUrl}/datacenter`, data)
23 | }
24 |
25 | export function createRegion (data) {
26 | return post(`${regionUrl}`, data)
27 | }
28 |
29 | export function getRegionBy (name) {
30 | return get(`${regionUrl}/${name}`)
31 | }
32 |
33 | export function updateRegion (name, data) {
34 | return patch(`${regionUrl}/${name}`, data)
35 | }
36 |
--------------------------------------------------------------------------------
/src/api/system-log.js:
--------------------------------------------------------------------------------
1 | import {post} from "@/plugins/request"
2 |
3 | export function systemQuery(page, size, conditions) {
4 | return post(`/api/v1/logs?pageNum=${page}&pageSize=${size}`, conditions)
5 | }
6 |
--------------------------------------------------------------------------------
/src/api/system-setting.js:
--------------------------------------------------------------------------------
1 | import {get, patch, post, del} from "@/plugins/request"
2 |
3 | const settingUrl = "/api/v1/settings"
4 | const ntpUrl = "/api/v1/ntp"
5 | const messageUrl = "/api/v1/message/setting"
6 | const msgUrl = "/api/v1/msg"
7 |
8 | //msg
9 | export function getMsgAccount (name) {
10 | return get(`${msgUrl}/accounts/${name}`)
11 | }
12 |
13 | export function createMsgAccount (data) {
14 | return post(`${msgUrl}/accounts`, data)
15 | }
16 | export function verifyMsgAccount (data) {
17 | return post(`${msgUrl}/accounts/verify`, data)
18 | }
19 |
20 | // Settings
21 | export function getSetting (tabName) {
22 | return get(`${settingUrl}/${tabName}`)
23 | }
24 |
25 | export function check (tabName, data) {
26 | return post(`${settingUrl}/check/${tabName}`, data)
27 | }
28 |
29 | export function createSetting (data) {
30 | return post(settingUrl, data)
31 | }
32 |
33 | // Registry
34 | export function listRegistry (currentPage, pageSize) {
35 | return get(`${settingUrl}/registry?pageNum=${currentPage}&pageSize=${pageSize}`)
36 | }
37 |
38 | export function listRegistryAll () {
39 | return get(`${settingUrl}/registry`)
40 | }
41 |
42 | export function createRegistry (data) {
43 | return post(`${settingUrl}/registry`, data)
44 | }
45 |
46 | export function changePassword (data) {
47 | return post(`${settingUrl}/registry/change/password`, data)
48 | }
49 |
50 | export function updateRegistry (arch, data) {
51 | return patch(`${settingUrl}/registry/${arch}`, data)
52 | }
53 |
54 | export function testConnection (data) {
55 | return post(`${settingUrl}/registry/check/conn`, data)
56 | }
57 |
58 | export function searchRegistry (currentPage, pageSize, conditions) {
59 | return post(`${settingUrl}/registry/search?pageNum=${currentPage}&pageSize=${pageSize}`, conditions)
60 | }
61 |
62 | export function getRegistry (id) {
63 | return get(`${settingUrl}/registry/${id}`)
64 | }
65 |
66 | export function deleteRegistry (id) {
67 | return del(`${settingUrl}/registry/${id}`)
68 | }
69 |
70 | // ntp
71 | export function searchNtp (currentPage, pageSize) {
72 | return get(`${ntpUrl}/?pageNum=${currentPage}&pageSize=${pageSize}`)
73 | }
74 |
75 | export function deleteNtp (name) {
76 | return del(`${ntpUrl}/${name}`)
77 | }
78 |
79 | export function createNtp (data) {
80 | return post(`${ntpUrl}`, data)
81 | }
82 |
83 | export function updateNtp (name, data) {
84 | return patch(`${ntpUrl}/${name}`, data)
85 | }
86 |
87 | // Message
88 | export function getMessageSetting (tabName) {
89 | return get(`${messageUrl}/${tabName}`)
90 | }
91 |
92 | export function checkMessage (tabName, data) {
93 | return post(`${messageUrl}/check/${tabName}`, data)
94 | }
95 |
96 | export function createMessageSetting (tabName, data) {
97 | return post(`${messageUrl}/${tabName}`, data)
98 | }
99 |
100 | // LDAP
101 | export function sync () {
102 | return get(`/api/v1/ldap/sync`)
103 | }
104 |
105 | export function createLDAP (data) {
106 | return post(`/api/v1/ldap/`, data)
107 | }
108 |
109 | export function testConnect (data) {
110 | return post(`/api/v1/ldap/test/connect`, data)
111 | }
112 |
113 | export function testLogin (data) {
114 | return post(`/api/v1/ldap/test/login`, data)
115 | }
116 |
117 | export function importUsers (data) {
118 | return post(`/api/v1/ldap/import/users`, data)
119 | }
120 |
121 | // kubepi
122 | export function bindUser (data) {
123 | return post(`/api/v1/dashboard/bind`, data)
124 | }
125 |
126 | export function getUser (data) {
127 | return get(`/api/v1/dashboard/user`, data)
128 | }
129 |
130 | export function getBindInfo (data) {
131 | return post(`/api/v1/dashboard/search`, data)
132 | }
133 |
134 | export function testKubepiConn (data) {
135 | return post(`/api/v1/dashboard/check/conn`, data)
136 | }
137 |
138 | export function jumpTo (project, cluster) {
139 | return get(`/api/v1/dashboard/jump/${project}/${cluster}`)
140 | }
141 |
--------------------------------------------------------------------------------
/src/api/template-config.js:
--------------------------------------------------------------------------------
1 | import {del, get, patch, post} from "@/plugins/request"
2 |
3 | const templateUrl = "/api/v1/templates"
4 |
5 | export function searchTemplates (page, size, condition) {
6 | return post(`${templateUrl}/search?pageNum=${page}&pageSize=${size}`, condition)
7 | }
8 |
9 | export function createTemplate (data) {
10 | return post(`${templateUrl}/create`, data)
11 | }
12 |
13 | export function getTemplate(name) {
14 | return get(`${templateUrl}/${name}`)
15 | }
16 |
17 | export function delTemplate(name) {
18 | return del(`${templateUrl}/${name}`)
19 | }
20 |
21 | export function updateTemplate(name,data) {
22 | return patch(`${templateUrl}/${name}`, data)
23 | }
24 |
25 | export function listTemplateConfigs() {
26 | return get(`${templateUrl}`)
27 | }
28 |
--------------------------------------------------------------------------------
/src/api/theme.js:
--------------------------------------------------------------------------------
1 | import {get,post} from "@/plugins/request"
2 |
3 | const userUrl = "/api/v1/theme"
4 |
5 | export function getTheme() {
6 | return get(userUrl)
7 | }
8 |
9 | export function importTheme(data) {
10 | return post(userUrl,data)
11 | }
12 |
--------------------------------------------------------------------------------
/src/api/user-management.js:
--------------------------------------------------------------------------------
1 | import {get} from "@/plugins/request";
2 |
3 | export function listUsers(page, size) {
4 | return get(`/api/v1/samples/user-management/list/${page}/${size}`)
5 | }
6 |
--------------------------------------------------------------------------------
/src/api/user-message.js:
--------------------------------------------------------------------------------
1 | import {get, post} from "@/plugins/request"
2 |
3 | export function listUserMessages (currentPage, pageSize) {
4 | return get(`/api/v1/user/messages?pageNum=${currentPage}&pageSize=${pageSize}`)
5 | }
6 |
7 | export function readUserMessage (id) {
8 | return post(`/api/v1/user/messages/read/${id}`, {})
9 | }
10 |
11 | export function markAllRead() {
12 | return post(`/api/v1/user/messages/read/all`, {})
13 | }
14 |
--------------------------------------------------------------------------------
/src/api/user-token.js:
--------------------------------------------------------------------------------
1 | /* 前后端分离的登录方式 */
2 | import {get, post, put} from "@/plugins/request"
3 |
4 | export function login(data) {
5 | return post("/api/v1/samples/user-token/login", data)
6 | }
7 |
8 | export function logout() {
9 | return post("/samples/user-token/logout")
10 | }
11 |
12 | export function getCurrentUser() {
13 | return get("/samples/user-token/current")
14 | }
15 |
16 | export function updateInfo(data) {
17 | return put("/samples/user-token/update", data)
18 | }
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/api/user.js:
--------------------------------------------------------------------------------
1 | import {get, patch, post, del} from "@/plugins/request"
2 |
3 | const userUrl = "/api/v1/users"
4 | const userSettingUrl = "/api/v1/user/settings"
5 |
6 |
7 | export function updateUser (name, data) {
8 | return patch(`${userUrl}/${name}`, data)
9 | }
10 |
11 | export function listUsers (currentPage, pageSize) {
12 | return get(`${userUrl}?pageNum=${currentPage}&pageSize=${pageSize}`)
13 | }
14 |
15 | export function createUser (data) {
16 | return post(userUrl, data)
17 | }
18 |
19 | export function searchUsers (currentPage, pageSize, conditions) {
20 | return post(`${userUrl}/search?pageNum=${currentPage}&pageSize=${pageSize}`, conditions)
21 | }
22 |
23 | export function getUser (name) {
24 | return get(`${userUrl}/${name}`)
25 | }
26 |
27 | export function deleteUser (name) {
28 | return del(`${userUrl}/${name}`)
29 | }
30 |
31 | export function getUserSetting (name) {
32 | return get(`${userSettingUrl}/${name}`)
33 | }
34 |
35 | export function updateUserSetting (data) {
36 | return post(`${userSettingUrl}/update`, data)
37 | }
38 |
39 | export function searchUsersByName (name) {
40 | return post(`${userUrl}/search?`, {quick: {field: "quick",value: name} })
41 | }
42 |
--------------------------------------------------------------------------------
/src/api/vm-config.js:
--------------------------------------------------------------------------------
1 | import {get, del, post, patch} from "@/plugins/request"
2 |
3 | const vmConfigUrl = "/api/v1/vmconfigs"
4 |
5 | export function listVmConfigs (page, size) {
6 | return get(`${vmConfigUrl}/search?pageNum=${page}&pageSize=${size}`)
7 | }
8 |
9 | export function deleteVmConfigBy (name) {
10 | return del(vmConfigUrl + "/" + name)
11 | }
12 |
13 | export function createVmConfig (data) {
14 | return post(vmConfigUrl, data)
15 | }
16 |
17 | export function getVmConfig (name) {
18 | return get(`${vmConfigUrl}/${name}`)
19 | }
20 |
21 |
22 | export function updateVmConfig (name, data) {
23 | return patch(`${vmConfigUrl}/${name}`, data)
24 | }
25 |
26 | export function searchVmConfigs (page, size, conditions) {
27 | return post(`${vmConfigUrl}/search?pageNum=${page}&pageSize=${size}`, conditions)
28 | }
29 |
--------------------------------------------------------------------------------
/src/api/xpack/multi-cluster.js:
--------------------------------------------------------------------------------
1 | import {get, post, del, patch} from "@/plugins/request"
2 |
3 | const baseUrl = "/api/v1/multicluster"
4 |
5 | export function listMultiClusterRepositories(currentPage, pageSize) {
6 | return get(`${baseUrl}/repositories?pageNum=${currentPage}&pageSize=${pageSize}`,)
7 | }
8 |
9 |
10 | export function getMultiClusterRepository(name) {
11 | return get(`${baseUrl}/repositories/${name}`,)
12 | }
13 |
14 | export function createMultiClusterRepository(data) {
15 | return post(`${baseUrl}/repositories`, data)
16 | }
17 |
18 | export function deleteMultiClusterRepository(name) {
19 | return del(`${baseUrl}/repositories/${name}`)
20 | }
21 |
22 | export function updateMultiClusterRepository(name, data) {
23 | return patch(`${baseUrl}/repositories/${name}`, data)
24 | }
25 |
26 |
27 | export function listMultiClusterRepositoryRelations(name) {
28 | return get(`${baseUrl}/repositories/relations/${name}`,)
29 | }
30 |
31 | export function updateMultiClusterRepositoryRelations(name, data) {
32 | return post(`${baseUrl}/repositories/relations/${name}`, data)
33 | }
34 |
35 | export function getMultiClusterSyncLogs(name, currentPage, pageSize) {
36 | return get(`${baseUrl}/repositories/logs/${name}?pageNum=${currentPage}&pageSize=${pageSize}`,)
37 | }
38 |
39 | export function getMultiClusterSyncLogsDetail(name, logId) {
40 | return get(`${baseUrl}/repositories/logs/detail/${name}/${logId}`,)
41 | }
42 |
--------------------------------------------------------------------------------
/src/api/zone.js:
--------------------------------------------------------------------------------
1 | import {get, del, post, patch} from "@/plugins/request"
2 |
3 | const zoneUrl = "/api/v1/zones"
4 |
5 | export function listZones (page, size) {
6 | return get(`${zoneUrl}?pageNum=${page}&pageSize=${size}`)
7 | }
8 |
9 | export function deleteZoneBy (name) {
10 | return del(zoneUrl + "/" + name)
11 | }
12 |
13 | export function searchZone (page, size, condition) {
14 | return post(`${zoneUrl}/search?pageNum=${page}&pageSize=${size}`, condition)
15 | }
16 |
17 | export function listCloudZones (data) {
18 | return post(`${zoneUrl}/clusters`, data)
19 | }
20 |
21 | export function listDatastores (data) {
22 | return post(`${zoneUrl}/datastores`, data)
23 | }
24 |
25 | export function listFolders (data) {
26 | return post(`${zoneUrl}/folders`, data)
27 | }
28 |
29 | export function listTemplates (data) {
30 | return post(`${zoneUrl}/templates`, data)
31 | }
32 |
33 | export function createZone (data) {
34 | return post(`${zoneUrl}`, data)
35 | }
36 |
37 | export function listAllZones () {
38 | return get(`${zoneUrl}`)
39 | }
40 |
41 | export function listByRegion(regionName) {
42 | return get(`${zoneUrl}/list/${regionName}`)
43 | }
44 |
45 | export function getZone(name) {
46 | return get(`${zoneUrl}/${name}`)
47 | }
48 |
49 | export function updateZone(name,data) {
50 | return patch(`${zoneUrl}/${name}`, data)
51 | }
52 |
53 | export function uploadImage(data){
54 | return post(`${zoneUrl}/upload/image`, data)
55 | }
56 |
--------------------------------------------------------------------------------
/src/assets/KobeOperator-login.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/KobeOperator-login.jpg
--------------------------------------------------------------------------------
/src/assets/KubeOperator-about-background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/KubeOperator-about-background.png
--------------------------------------------------------------------------------
/src/assets/KubeOperator-assist-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/KubeOperator-assist-white.png
--------------------------------------------------------------------------------
/src/assets/KubeOperator-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/KubeOperator-black.png
--------------------------------------------------------------------------------
/src/assets/KubeOperator-red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/KubeOperator-red.png
--------------------------------------------------------------------------------
/src/assets/KubeOperator-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/KubeOperator-white.png
--------------------------------------------------------------------------------
/src/assets/font/Roboto/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/font/Roboto/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/src/assets/font/Roboto/index.css:
--------------------------------------------------------------------------------
1 | /* cyrillic-ext */
2 | @font-face {
3 | font-family: 'Roboto';
4 | font-style: normal;
5 | font-display: swap;
6 | src: url(Roboto-Regular.ttf) format('truetype');
7 | unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
8 | }
9 | /* cyrillic */
10 | @font-face {
11 | font-family: 'Roboto';
12 | font-style: normal;
13 | font-display: swap;
14 | src: url(Roboto-Regular.ttf) format('truetype');
15 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
16 | }
17 | /* greek-ext */
18 | @font-face {
19 | font-family: 'Roboto';
20 | font-style: normal;
21 | font-display: swap;
22 | src: url(Roboto-Regular.ttf) format('truetype');
23 | unicode-range: U+1F00-1FFF;
24 | }
25 | /* greek */
26 | @font-face {
27 | font-family: 'Roboto';
28 | font-style: normal;
29 | font-display: swap;
30 | src: url(Roboto-Regular.ttf) format('truetype');
31 | unicode-range: U+0370-03FF;
32 | }
33 | /* vietnamese */
34 | @font-face {
35 | font-family: 'Roboto';
36 | font-style: normal;
37 | font-display: swap;
38 | src: url(Roboto-Regular.ttf) format('truetype');
39 | unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
40 | }
41 | /* latin-ext */
42 | @font-face {
43 | font-family: 'Roboto';
44 | font-style: normal;
45 | font-display: swap;
46 | src: url(Roboto-Regular.ttf) format('truetype');
47 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
48 | }
49 | /* latin */
50 | @font-face {
51 | font-family: 'Roboto';
52 | font-style: normal;
53 | font-display: swap;
54 | src: url(Roboto-Regular.ttf) format('truetype');
55 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/src/assets/iconfont/alicdn/font_985780_km7mi63cihi.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/iconfont/alicdn/font_985780_km7mi63cihi.eot
--------------------------------------------------------------------------------
/src/assets/iconfont/alicdn/font_985780_km7mi63cihi.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
30 |
--------------------------------------------------------------------------------
/src/assets/iconfont/alicdn/font_985780_km7mi63cihi.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/iconfont/alicdn/font_985780_km7mi63cihi.ttf
--------------------------------------------------------------------------------
/src/assets/iconfont/alicdn/font_985780_km7mi63cihi.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/iconfont/alicdn/font_985780_km7mi63cihi.woff
--------------------------------------------------------------------------------
/src/assets/iconfont/alicdn/font_985780_km7mi63cihi_iefix.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/iconfont/alicdn/font_985780_km7mi63cihi_iefix.eot
--------------------------------------------------------------------------------
/src/assets/iconfont/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/iconfont/iconfont.ttf
--------------------------------------------------------------------------------
/src/assets/iconfont/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/iconfont/iconfont.woff
--------------------------------------------------------------------------------
/src/assets/iconfont/iconfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/iconfont/iconfont.woff2
--------------------------------------------------------------------------------
/src/assets/images/tools/chartmuseum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/images/tools/chartmuseum.png
--------------------------------------------------------------------------------
/src/assets/images/tools/docker-registry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/images/tools/docker-registry.png
--------------------------------------------------------------------------------
/src/assets/images/tools/elasticsearch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/images/tools/elasticsearch.png
--------------------------------------------------------------------------------
/src/assets/images/tools/gatekeeper.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/images/tools/gatekeeper.jpg
--------------------------------------------------------------------------------
/src/assets/images/tools/grafana.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/images/tools/grafana.png
--------------------------------------------------------------------------------
/src/assets/images/tools/kubeapps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/images/tools/kubeapps.png
--------------------------------------------------------------------------------
/src/assets/images/tools/kubepi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/images/tools/kubepi.png
--------------------------------------------------------------------------------
/src/assets/images/tools/kubernetes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/images/tools/kubernetes.png
--------------------------------------------------------------------------------
/src/assets/images/tools/loki.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/images/tools/loki.png
--------------------------------------------------------------------------------
/src/assets/images/tools/prometheus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/images/tools/prometheus.png
--------------------------------------------------------------------------------
/src/assets/images/tools/registry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/images/tools/registry.png
--------------------------------------------------------------------------------
/src/assets/login-desc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KubeOperator/neeko/028abed4e888dbef472d83c6a33aaea4bb6050ed/src/assets/login-desc.png
--------------------------------------------------------------------------------
/src/business/app-layout/header-components/Help.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ $t('commons.help.help') }}
6 |
7 |
8 |
9 | {{ $t('commons.help.ko_docs') }}
10 | {{ $t('commons.help.business_support') }}
11 | {{ $t('commons.help.api_docs') }}
12 |
13 |
14 |
15 |
16 |
36 |
37 |
42 |
--------------------------------------------------------------------------------
/src/business/app-layout/header-components/LanguageSwitch.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 | {{ languageMap[language] }}
7 |
8 |
9 |
10 |
11 | {{ value }}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
59 |
60 |
80 |
--------------------------------------------------------------------------------
/src/business/app-layout/header-components/ProjectSwitch.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{currentProject}}
6 |
7 |
8 |
9 |
10 | {{ p.name }}
11 |
12 |
13 |
14 |
15 |
16 |
48 |
49 |
54 |
--------------------------------------------------------------------------------
/src/business/app-layout/horizontal-layout/HorizontalHeader.vue:
--------------------------------------------------------------------------------
1 |
2 |
24 |
25 |
26 |
39 |
40 |
72 |
--------------------------------------------------------------------------------
/src/business/app-layout/horizontal-layout/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
19 |
--------------------------------------------------------------------------------
/src/business/authorization/projects/create/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{$t('commons.validate.name_help')}}
12 |
13 |
14 |
15 |
16 |
17 |
18 | {{ $t("commons.button.cancel") }}
19 | {{ $t("commons.button.submit") }}
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
83 |
84 |
87 |
--------------------------------------------------------------------------------
/src/business/authorization/projects/edit/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {{ $t("commons.button.cancel") }}
17 | {{ $t("commons.button.submit") }}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
73 |
74 |
77 |
--------------------------------------------------------------------------------
/src/business/automatic/vm-configs/create/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | {{$t('commons.validate.name_help')}}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | {{ $t("commons.button.cancel") }}
21 | {{ $t("commons.button.submit") }}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
95 |
96 |
99 |
--------------------------------------------------------------------------------
/src/business/automatic/vm-configs/edit/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | {{ $t("commons.button.cancel") }}
19 | {{ $t("commons.button.submit") }}
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
91 |
92 |
95 |
--------------------------------------------------------------------------------
/src/business/clusters/detail/backup/logs/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ $t("cluster.detail.backup." + row.type) }}
7 |
8 |
9 |
10 |
11 | {{ row.startTime | timeStampFormat }}
12 |
13 |
14 |
15 |
16 | -
17 | {{ row.endTime | timeStampFormat }}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | {{ $t("commons.status.failed") }}
27 |
28 |
29 |
30 |
31 |
32 | {{ $t("commons.status.waiting") }}
33 |
34 |
35 |
36 | {{ $t("commons.status.running") }}
37 |
38 |
39 |
40 | {{ $t("commons.status.success") }}
41 |
42 |
43 |
44 |
45 |
46 | {{ row.createdAt | datetimeFormat }}
47 |
48 |
49 |
50 |
51 |
52 |
53 |
88 |
89 |
--------------------------------------------------------------------------------
/src/business/clusters/detail/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{$t('cluster.detail.tag.overview')}}
6 | {{$t('cluster.detail.tag.node')}}
7 | {{$t('cluster.detail.tag.storage')}}
8 | {{$t('cluster.detail.backup.backup_recover')}}
9 | {{$t('cluster.detail.tag.component')}}
10 | {{$t('cluster.detail.tag.tool')}}
11 | {{$t('cluster.detail.tag.monitor')}}
12 | {{$t('cluster.detail.tag.log')}}
13 | {{$t('cluster.detail.tag.security')}}
14 | {{$t('cluster.detail.tag.grade')}}
15 | {{$t('cluster.detail.tag.task')}}
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
67 |
68 |
70 |
--------------------------------------------------------------------------------
/src/business/clusters/detail/log/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ $t("cluster.detail.log.log_help") }}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
61 |
62 |
--------------------------------------------------------------------------------
/src/business/clusters/detail/node/detail/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
{{$t ('cluster.detail.node.base_infomation')}}
6 |
7 |
8 |
9 |
10 | Name |
11 | {{DetaiInfo.metadata.name}} |
12 |
13 |
14 | Kernel Version |
15 | {{DetaiInfo.status.nodeInfo.kernelVersion}} |
16 |
17 |
18 | OS Image |
19 | {{DetaiInfo.status.nodeInfo.osImage}} |
20 |
21 |
22 | Container Runtime Version |
23 | {{DetaiInfo.status.nodeInfo.containerRuntimeVersion}} |
24 |
25 |
26 | Kubelet Version |
27 | {{DetaiInfo.status.nodeInfo.kubeletVersion}} |
28 |
29 |
30 | KubeProxy Version |
31 | {{DetaiInfo.status.nodeInfo.kubeProxyVersion}} |
32 |
33 |
34 | Operating System |
35 | {{DetaiInfo.status.nodeInfo.operatingSystem}} |
36 |
37 |
38 | Architecture |
39 | {{DetaiInfo.status.nodeInfo.architecture}} |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
{{$t ('cluster.detail.node.label')}}
47 |
48 |
49 |
50 |
51 | {{name}} |
52 | {{value}} |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
{{$t('cluster.detail.node.status')}}
60 |
61 |
62 |
63 |
64 |
65 |
66 | {{ row.lastTransitionTime | datetimeFormat }}
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
77 |
78 |
79 |
80 |
81 |
82 |
90 |
91 |
--------------------------------------------------------------------------------
/src/business/dashboard/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ $t('commons.message_box.prompt') }}
4 |
5 |
6 |
7 |
12 |
13 |
16 |
--------------------------------------------------------------------------------
/src/business/directive/ClickOutsideDemo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Element UI的指令,但是文档上没写,但是挺好用的,这里写个例子。
4 |
5 | 点击1,触发2,3的外部事件
6 |
7 | 点击空白处,触发1,2,3的外部事件
8 |
9 | 控制台查看触发事件
10 |
11 | 1
12 | 2
13 | 3
14 |
15 |
16 |
17 |
31 |
32 |
35 |
--------------------------------------------------------------------------------
/src/business/directive/PermissionDemo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 切换admin、editor、readonly用户看到不同的内容
4 |
5 |
6 |
7 | 需要admin角色才能看到, 指令设置:v-permission="['admin']"
8 |
9 |
10 |
11 | 需要editor角色才能看到, 指令设置:v-permission="['editor']"
12 |
13 |
14 |
15 | 需要admin或者editor角色才能看到, 指令设置:v-permission="['admin', 'editor']"
16 |
17 |
18 |
19 | 任何人都能看到
20 |
21 |
22 |
23 |
24 |
32 |
33 |
53 |
--------------------------------------------------------------------------------
/src/business/system-log/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 | {{ row.createdAt | datetimeFormat }}
13 |
14 |
15 |
16 |
17 |
18 |
19 |
77 |
78 |
--------------------------------------------------------------------------------
/src/business/system-setting/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{$t('setting.registry')}}
5 | {{$t('setting.credential')}}
6 | {{$t('setting.ntp')}}
7 | Dashboard
8 | LDAP
9 | {{$t('setting.message')}}
10 | {{$t('setting.license')}}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
39 |
40 |
42 |
--------------------------------------------------------------------------------
/src/business/system-setting/kubepi/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | admin
11 |
12 |
13 |
14 |
15 |
16 |
17 | {{ $t("commons.button.test_connection") }}
18 | {{$t('commons.button.submit')}}
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
95 |
96 |
98 |
--------------------------------------------------------------------------------
/src/business/xpack/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
13 |
--------------------------------------------------------------------------------
/src/business/xpack/multi-cluster/dialog/RelationsManagement.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
9 |
10 |
14 |
15 |
16 |
17 |
18 |
85 |
--------------------------------------------------------------------------------
/src/business/xpack/multi-cluster/dialog/RepositoryErrorMessage.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 | {{message}}
8 |
9 |
12 |
13 |
14 |
15 |
16 |
45 |
--------------------------------------------------------------------------------
/src/business/xpack/multi-cluster/dialog/SyncLogDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
{{log.clusterName}}
10 |
11 |
12 |
13 | {{item.resourceName}} |
14 | {{item.sourceFile}} |
15 | {{item.status}} |
16 | {{item.message}} |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
30 |
31 |
71 |
--------------------------------------------------------------------------------
/src/business/xpack/multi-cluster/edit/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | {{$t('commons.button.submit')}}
20 | {{$t('commons.button.cancel')}}
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
72 |
73 |
75 |
--------------------------------------------------------------------------------
/src/business/xterm/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/components/back-button/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
29 |
30 |
44 |
--------------------------------------------------------------------------------
/src/components/batch-delete/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ $t('commons.confirm_message.operator') }}
5 | {{ delInfo }}
6 |
7 |
{{ $t('cluster.delete.is_force') }}
8 |
{{ $t('cluster.delete.force_delete') }}
9 |
10 | {{ $t('commons.confirm_message.delete_help') }}
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/components/cloud-providers/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
9 |
12 | {{provider}}
13 |
14 |
15 |
16 |
25 |
--------------------------------------------------------------------------------
/src/components/complex-table/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
21 |
22 |
23 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
40 |
41 |
42 |
43 |
81 |
82 |
108 |
--------------------------------------------------------------------------------
/src/components/detail-card/ItemValue.vue:
--------------------------------------------------------------------------------
1 |
37 |
38 |
41 |
--------------------------------------------------------------------------------
/src/components/detail-card/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | {{ $t('setting.table.license.valid') }}
10 |
11 |
12 | {{ $t('setting.table.license.invalid') }}
13 |
14 |
15 | {{ $t('setting.table.license.expired') }}
16 |
17 |
18 | {{ item.value }}
19 |
20 |
21 |
22 |
23 |
24 |
25 |
48 |
49 |
55 |
--------------------------------------------------------------------------------
/src/components/k8s-page/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ko_currentPage}}
5 |
6 |
7 |
8 |
9 |
57 |
58 |
--------------------------------------------------------------------------------
/src/components/ko-status/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ $t("commons.status.running") }}
7 |
8 |
9 |
10 | {{ $t("commons.status.failed") }}
11 |
12 |
13 |
14 | {{ $t("commons.status.initializing") }}
15 | {{ $t("commons.status.initializing") }}
16 |
17 |
18 |
19 | {{ $t("commons.status.upgrading") }}
20 |
21 |
22 |
23 | {{ $t("commons.status.terminating") }}
24 |
25 |
26 |
27 | {{ $t("commons.status.terminating") }}
28 |
29 |
30 |
31 | {{ $t("commons.status.terminating") }}
32 |
33 |
34 |
35 | {{ $t("commons.status.synchronizing") }}
36 |
37 |
38 | {{ $t("commons.status.creating") }}
39 |
40 |
41 |
42 | {{ $t("commons.status.active") }}
43 |
44 |
45 |
46 | {{ $t("commons.status.passive") }}
47 |
48 |
49 |
50 |
51 |
62 |
63 |
65 |
--------------------------------------------------------------------------------
/src/components/layout/LayoutContent.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
40 |
41 |
67 |
--------------------------------------------------------------------------------
/src/components/layout/LayoutHeader.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
12 |
13 |
15 |
--------------------------------------------------------------------------------
/src/components/layout/LayoutMain.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
14 |
17 |
--------------------------------------------------------------------------------
/src/components/layout/LayoutSidebar.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
26 |
--------------------------------------------------------------------------------
/src/components/layout/LayoutView.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
33 |
--------------------------------------------------------------------------------
/src/components/layout/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
26 |
27 |
67 |
--------------------------------------------------------------------------------
/src/components/layout/sidebar/FixiOSBug.js:
--------------------------------------------------------------------------------
1 | export default {
2 | computed: {
3 | device() {
4 | return this.$store.state.app.device
5 | }
6 | },
7 | mounted() {
8 | // In order to fix the click on menu on the ios device will trigger the mouseleave bug
9 | // https://github.com/PanJiaChen/vue-element-admin/issues/1135
10 | this.fixBugIniOS()
11 | },
12 | methods: {
13 | fixBugIniOS() {
14 | const $subMenu = this.$refs.subMenu
15 | if ($subMenu) {
16 | const handleMouseleave = $subMenu.handleMouseleave
17 | $subMenu.handleMouseleave = (e) => {
18 | if (this.device === 'mobile') {
19 | return
20 | }
21 | handleMouseleave(e)
22 | }
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/layout/sidebar/Item.vue:
--------------------------------------------------------------------------------
1 |
30 |
31 |
38 |
--------------------------------------------------------------------------------
/src/components/layout/sidebar/Link.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
44 |
--------------------------------------------------------------------------------
/src/components/layout/sidebar/Logo.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
46 |
47 |
104 |
--------------------------------------------------------------------------------
/src/components/layout/sidebar/SidebarItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
14 |
15 |
16 |
17 |
25 |
26 |
27 |
28 |
29 |
98 |
--------------------------------------------------------------------------------
/src/components/layout/sidebar/SidebarToggleButton.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
25 |
26 |
34 |
--------------------------------------------------------------------------------
/src/components/redirect/index.vue:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/directive/click-outside/index.js:
--------------------------------------------------------------------------------
1 | import ClickOutside from "element-ui/src/utils/clickoutside";
2 |
3 | const install = function (Vue) {
4 | Vue.directive("click-outside", ClickOutside)
5 | }
6 |
7 | ClickOutside.install = install
8 | export default ClickOutside
9 |
--------------------------------------------------------------------------------
/src/directive/index.js:
--------------------------------------------------------------------------------
1 | import ClickOutside from "element-ui/src/utils/clickoutside";
2 | import permission from "./permission";
3 |
4 | export default {
5 | install(Vue) {
6 | Vue.directive('click-outside', ClickOutside);
7 | Vue.directive('permission', permission);
8 | }
9 | }
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/directive/permission/index.js:
--------------------------------------------------------------------------------
1 | import store from '@/store'
2 |
3 | function checkPermission(el, binding) {
4 | const {value} = binding
5 | const roles = store.getters && store.getters.roles
6 |
7 | if (value && value instanceof Array) {
8 | if (value.length > 0) {
9 | const permissionRoles = value
10 |
11 | const hasPermission = roles.some(role => {
12 | return permissionRoles.includes(role)
13 | })
14 |
15 | if (!hasPermission) {
16 | el.parentNode && el.parentNode.removeChild(el)
17 | }
18 | }
19 | }
20 | }
21 |
22 | export default {
23 | inserted(el, binding) {
24 | checkPermission(el, binding)
25 | },
26 | update(el, binding) {
27 | checkPermission(el, binding)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/filters/index.js:
--------------------------------------------------------------------------------
1 | import {dateFormat, datetimeFormat} from "fit2cloud-ui/src/filters/time";
2 |
3 | export function errorFormat(value) {
4 | if (value !== null) {
5 | let errItem = value;
6 | errItem = errItem.replace(/\\n/gi,'\n');
7 | errItem = errItem.replace(/\\u/gi,'%u');
8 | errItem = errItem.replace(/\\/gi,'');
9 | errItem = unescape(errItem)
10 | return errItem
11 | }
12 | return value
13 | }
14 |
15 | export function emailFormat(value) {
16 | let result = '';
17 | if (value.indexOf('@') === -1 || value.indexOf('.') === -1) {
18 | return value
19 | }
20 | const aiteIndex = value.indexOf('@')
21 | const pointIndex = value.lastIndexOf('.')
22 | const mail = value.substring(0, aiteIndex)
23 | if (mail.length <= 3) {
24 | result += '***'
25 | } else {
26 | result += value.substring(0, 3) + '***'
27 | }
28 | result += value.substring(pointIndex+1, value.length)
29 | return result;
30 | }
31 |
32 | export function timeStampFormat(value) {
33 | return datetimeFormat(new Date(value * 1000))
34 | }
35 |
36 | const filters = {
37 | "dateFormat": dateFormat,
38 | "datetimeFormat": datetimeFormat,
39 | "timeStampFormat": timeStampFormat,
40 | "errorFormat": errorFormat,
41 | "emailFormat": emailFormat,
42 | };
43 |
44 | export default {
45 | install(Vue) {
46 | Object.keys(filters).forEach(key => {
47 | Vue.filter(key, filters[key])
48 | });
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/i18n/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import VueI18n from "vue-i18n";
3 |
4 | Vue.use(VueI18n);
5 |
6 | // 直接加载翻译的语言文件
7 | const LOADED_LANGUAGES = ['zh-CN', 'en-US'];
8 | const LANG_FILES = require.context('./lang', true, /\.js$/)
9 | // 自动加载lang目录下语言文件,默认只加载LOADED_LANGUAGES中规定的语言文件,其他的语言动态加载
10 | const messages = LANG_FILES.keys().reduce((messages, path) => {
11 | const value = LANG_FILES(path)
12 | const lang = path.replace(/^\.\/(.*)\.\w+$/, '$1');
13 | if (LOADED_LANGUAGES.includes(lang)) {
14 | messages[lang] = value.default
15 | }
16 | return messages;
17 | }, {})
18 |
19 | export const getLanguage = () => {
20 | let language = localStorage.getItem('language')
21 | if (!language) {
22 | language = "zh-CN"
23 | }
24 | return language;
25 | }
26 |
27 | const i18n = new VueI18n({
28 | locale: getLanguage(),
29 | messages,
30 | });
31 |
32 | const importLanguage = lang => {
33 | if (!LOADED_LANGUAGES.includes(lang)) {
34 | return import(`./lang/${lang}`).then(response => {
35 | i18n.mergeLocaleMessage(lang, response.default);
36 | LOADED_LANGUAGES.push(lang);
37 | return Promise.resolve(lang)
38 | })
39 | }
40 | return Promise.resolve(lang)
41 | }
42 |
43 | const setLang = lang => {
44 | localStorage.setItem('language', lang)
45 | i18n.locale = lang;
46 | }
47 |
48 | export const setLanguage = lang => {
49 | if (i18n.locale !== lang) {
50 | importLanguage(lang).then(setLang)
51 | }
52 | }
53 |
54 | // 组合翻译,例如key为'请输入{0}',keys为login.username,则自动将keys翻译并替换到{0} {1}...
55 | Vue.prototype.$tm = function (key, ...keys) {
56 | let values = [];
57 | for (const k of keys) {
58 | values.push(i18n.t(k))
59 | }
60 | return i18n.t(key, values);
61 | };
62 |
63 | // 忽略警告,即:不存在Key直接返回Key
64 | Vue.prototype.$tk = function (key) {
65 | const hasKey = i18n.te(key)
66 | if (hasKey) {
67 | return i18n.t(key)
68 | }
69 | return key
70 | };
71 |
72 | // 设置当前语言,LOADED_LANGUAGES以外的翻译文件会自动从lang目录获取(如果有的话), 如果不需要动态加载语言文件,直接用setLang
73 | Vue.prototype.$setLang = setLanguage;
74 |
75 | export default i18n;
76 |
--------------------------------------------------------------------------------
/src/i18n/lang/zh-TW.js:
--------------------------------------------------------------------------------
1 | import el from "element-ui/lib/locale/lang/zh-TW";
2 |
3 | const message = {
4 | // TODO
5 | }
6 |
7 | export default {
8 | ...el,
9 | ...message
10 | };
11 |
--------------------------------------------------------------------------------
/src/i18n/国际化规范.md:
--------------------------------------------------------------------------------
1 | # 国际化文件书写规范
2 |
3 | ### 文件内容
4 |
5 | 每个语言文件由element-ui的国际化内容和自定义国际化内容组成,以zh_CN.js为例:
6 |
7 | ```js
8 | import el from "element-ui/lib/locale/lang/zh-CN";
9 |
10 | const message = {
11 | ...
12 | }
13 |
14 | export default {
15 | ...el, // element-ui的国际化内容
16 | ...message // 自定义内容
17 | };
18 | ```
19 |
20 | ### 自定义内容
21 |
22 | 自定义部分按照业务模块划分,通用的写在commons内,例如
23 |
24 | ```js
25 | const message = {
26 | commons: { // 通用
27 | ...
28 | },
29 | login: { // 登录
30 | ...
31 | },
32 | ... // 其他模块
33 | }
34 |
35 | ```
36 |
37 | ### 层级结构
38 |
39 | 按照业务模块划分后,仍然可以按照子业务或功能再进行划分,但每个业务模块下不要超过3层,例如:
40 |
41 | ```js
42 | const message = {
43 | user_manager: {
44 | user_list: { // 用户列表
45 | name: "姓名",
46 | search: {
47 | ... // 用户列表查询
48 | },
49 | ... // 用户列表
50 | },
51 | user_edit: {
52 | ... // 编辑用户
53 | }
54 | },
55 | ... // 其他模块
56 | }
57 |
58 | ```
59 |
60 | ### Key命名
61 |
62 | 所有Key的命名必须采用英文单词的方式命名,多个单词之间用下划线( _ )连接,尽量让人一看就知道这个key代表的意思, 例如:user_list
63 |
64 | ```js
65 | const message = {
66 | user_manager: {
67 | user_list: {
68 | ...
69 | },
70 | user_edit: {}
71 | },
72 | }
73 |
74 | ```
75 |
--------------------------------------------------------------------------------
/src/icons/index.js:
--------------------------------------------------------------------------------
1 | import {library} from '@fortawesome/fontawesome-svg-core'
2 | import {fas} from '@fortawesome/free-solid-svg-icons'
3 | import {far} from '@fortawesome/free-regular-svg-icons'
4 | import {fab} from '@fortawesome/free-brands-svg-icons'
5 | import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome'
6 |
7 | export default {
8 | install(Vue) {
9 | library.add(fas, far, fab);
10 | Vue.component('font-awesome-icon', FontAwesomeIcon);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import "@/styles/index.scss"
3 | import "@/assets/iconfont/iconfont"
4 | import '@/assets/iconfont/iconfont.css'
5 | import Fit2CloudUI from 'fit2cloud-ui'
6 | // import Fit2CloudUI from './external/fit2cloud-ui.common';
7 | import {library} from '@fortawesome/fontawesome-svg-core'
8 | import {fas} from '@fortawesome/free-solid-svg-icons'
9 | import {far} from '@fortawesome/free-regular-svg-icons'
10 | import {fab} from '@fortawesome/free-brands-svg-icons'
11 | import {FontAwesomeIcon, FontAwesomeLayers, FontAwesomeLayersText} from '@fortawesome/vue-fontawesome'
12 |
13 |
14 | import ElementUI from 'element-ui';
15 | import App from './App.vue'
16 | import i18n from "./i18n";
17 | import router from './router'
18 | import store from './store'
19 | import icons from './icons'
20 | import plugins from "./plugins";
21 | import directives from "./directive";
22 | import filters from "./filters";
23 | import "./permission"
24 | import VueCodemirror from 'vue-codemirror';
25 | import 'codemirror/lib/codemirror.css';
26 | Vue.config.productionTip = false
27 |
28 | import echarts from "echarts";
29 | Vue.prototype.$echarts = echarts;
30 |
31 | Vue.use(ElementUI, {
32 | size: 'small',
33 | i18n: (key, value) => i18n.t(key, value)
34 | });
35 | Vue.use(Fit2CloudUI, {
36 | i18n: (key, value) => i18n.t(key, value)
37 | });
38 | library.add(fas, far, fab)
39 |
40 | Vue.component('font-awesome-icon', FontAwesomeIcon)
41 | Vue.component('font-awesome-layers', FontAwesomeLayers)
42 | Vue.component('font-awesome-layers-text', FontAwesomeLayersText)
43 | Vue.use(icons);
44 | Vue.use(plugins);
45 | Vue.use(directives);
46 | Vue.use(filters);
47 | Vue.use(VueCodemirror)
48 |
49 | Vue.directive("preventReClick", {
50 | inserted(el, binding) {
51 | el.addEventListener("click", () => {
52 | el.style.pointerEvents = "none"
53 | if (!el.disabled) {
54 | setTimeout(() => {
55 | el.style.pointerEvents = "auto"
56 | }, binding.value || 1000)
57 | }
58 | })
59 | }
60 | })
61 |
62 | new Vue({
63 | el: '#app',
64 | i18n,
65 | router,
66 | store,
67 | render: h => h(App),
68 | })
69 |
--------------------------------------------------------------------------------
/src/permission.js:
--------------------------------------------------------------------------------
1 | import router from './router'
2 | import store from './store'
3 | import NProgress from 'nprogress'
4 | import 'nprogress/nprogress.css'
5 |
6 | NProgress.configure({showSpinner: false}) // NProgress Configuration
7 |
8 | const whiteList = ['/login'] // no redirect whitelist
9 |
10 | const generateRoutes = async (to, from, next) => {
11 | const hasRoles = store.getters.roles && store.getters.roles.length > 0
12 | if (hasRoles) {
13 | next()
14 | } else {
15 | try {
16 | const {roles} = await store.dispatch('user/getCurrentUser')
17 | const license = await store.dispatch('license/getLicense')
18 | const accessRoutes = await store.dispatch('permission/generateRoutes', {license, roles})
19 | router.addRoutes(accessRoutes)
20 | next({...to, replace: true})
21 | } catch (error) {
22 | await store.dispatch('user/logout')
23 | next(`/login?redirect=${to.path}`)
24 | NProgress.done()
25 | }
26 | }
27 | }
28 |
29 | // 路由前置钩子,根据实际需求修改
30 | router.beforeEach(async (to, from, next) => {
31 | NProgress.start()
32 |
33 | const isLogin = await store.dispatch('user/isLogin')
34 |
35 | if (isLogin) {
36 | if (to.path === '/login') {
37 | next({path: '/'})
38 | NProgress.done()
39 | } else {
40 | await generateRoutes(to, from, next)
41 | }
42 | } else {
43 | /* has not login*/
44 | if (whiteList.indexOf(to.path) !== -1) {
45 | // in the free login whitelist, go directly
46 | next()
47 | } else {
48 | // other pages that do not have permission to access are redirected to the login page.
49 | next(`/login?redirect=${to.path}`)
50 | NProgress.done()
51 | }
52 | }
53 | })
54 |
55 | router.afterEach(() => {
56 | // finish progress bar
57 | NProgress.done()
58 | })
59 |
--------------------------------------------------------------------------------
/src/plugins/index.js:
--------------------------------------------------------------------------------
1 | import message from "@/plugins/message";
2 | import request from "@/plugins/request";
3 |
4 | export default {
5 | install(Vue) {
6 | Vue.use(message);
7 | Vue.use(request);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/plugins/message.js:
--------------------------------------------------------------------------------
1 | import {MessageBox, Message} from 'element-ui';
2 | import i18n from "@/i18n";
3 |
4 | export const $alert = (message, callback, options) => {
5 | let title = i18n.t("commons.message_box.alert");
6 | MessageBox.alert(message, title, options).then(() => {
7 | callback();
8 | });
9 | }
10 |
11 | export const $confirm = (message, callback, options = {}) => {
12 | let defaultOptions = {
13 | confirmButtonText: i18n.t("commons.button.ok"),
14 | cancelButtonText: i18n.t("commons.button.cancel"),
15 | type: 'warning',
16 | ...options
17 | }
18 | let title = i18n.t("commons.message_box.confirm");
19 | MessageBox.confirm(message, title, defaultOptions).then(() => {
20 | callback();
21 | });
22 | }
23 |
24 | export const $success = (message, duration) => {
25 | Message.success({
26 | message: message,
27 | type: "success",
28 | showClose: true,
29 | duration: duration || 1500
30 | })
31 | }
32 |
33 | export const $info = (message, duration) => {
34 | Message.info({
35 | message: message,
36 | type: "info",
37 | showClose: true,
38 | duration: duration || 3000
39 | })
40 | }
41 |
42 | export const $warning = (message, duration) => {
43 | Message.warning({
44 | message: message,
45 | type: "warning",
46 | showClose: true,
47 | duration: duration || 5000
48 | })
49 | }
50 |
51 | export const $error = (message, duration) => {
52 | Message.error({
53 | message: message,
54 | type: "error",
55 | showClose: true,
56 | duration: duration || 10000
57 | })
58 | }
59 |
60 | export default {
61 | install(Vue) {
62 | // 使用$$前缀,避免与Element UI的冲突
63 | Vue.prototype.$$confirm = $confirm;
64 | Vue.prototype.$$alert = $alert;
65 |
66 | Vue.prototype.$success = $success;
67 | Vue.prototype.$info = $info;
68 | Vue.prototype.$warning = $warning;
69 | Vue.prototype.$error = $error;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/plugins/request.js:
--------------------------------------------------------------------------------
1 | import axios from "axios"
2 | import {$alert, $error} from "./message"
3 | import store from "@/store"
4 | import i18n, {getLanguage} from "@/i18n"
5 |
6 | const instance = axios.create({
7 | baseURL: "", // url = base url + request url
8 | withCredentials: true,
9 | timeout: 60000 // request timeout, default 1 min
10 | })
11 |
12 | let whiteList = [
13 | "/api/v1/kubernetes/search/metric/",
14 | "/api/v1/kubernetes/evict",
15 | ]
16 |
17 | instance.interceptors.request.use(
18 | config => {
19 | config.headers["lang"] = getLanguage()
20 | return config
21 | },
22 | error => {
23 | return Promise.reject(error)
24 | }
25 | )
26 |
27 | const checkAuth = response => {
28 | // 请根据实际需求修改
29 | if (response.headers["authentication-status"] === "invalid" || response.status === 401) {
30 | let message = i18n.t("login.expires")
31 | $alert(message, () => {
32 | store.dispatch("user/logout").then(() => {
33 | location.reload()
34 | })
35 | })
36 | }
37 | }
38 |
39 | const checkPermission = response => {
40 | // 请根据实际需求修改
41 | if (response.status === 403) {
42 | location.href = "/403"
43 | }
44 | }
45 |
46 | // 请根据实际需求修改
47 | instance.interceptors.response.use(response => {
48 | checkAuth(response)
49 | return response
50 | }, error => {
51 | let msg
52 | if (error.response) {
53 | checkAuth(error.response)
54 | checkPermission(error.response)
55 | msg = error.response.data.msg || error.response.data
56 | } else {
57 | msg = error.message
58 | }
59 |
60 | let isWhite = false
61 | for (const whiteUrl of whiteList) {
62 | if (error.response.config.url.indexOf(whiteUrl) !== -1) {
63 | isWhite = true
64 | break
65 | }
66 | }
67 | if (!isWhite) {
68 | $error(msg)
69 | }
70 | return Promise.reject(error)
71 | })
72 |
73 | export const request = instance
74 |
75 | /* 简化请求方法,统一处理返回结果,并增加loading处理,这里以{success,data,message}格式的返回值为例,具体项目根据实际需求修改 */
76 | const promise = (request, loading = {}) => {
77 | return new Promise((resolve, reject) => {
78 | loading.status = true
79 | request.then(response => {
80 | // if (response.data.success) {
81 | resolve(response.data)
82 | // }
83 | // else {
84 | // reject(response.data)
85 | // }
86 | loading.status = false
87 | }).catch(error => {
88 | reject(error)
89 | loading.status = false
90 | })
91 | })
92 | }
93 |
94 | export const get = (url, data, loading) => {
95 | return promise(request({ url: url, method: "get", params: data }), loading)
96 | }
97 |
98 | export const post = (url, data, headers, loading) => {
99 | if (headers) {
100 | return promise(request({ url: url, headers: headers, method: "post", data }), loading)
101 | }
102 | return promise(request({ url: url, method: "post", data }), loading)
103 | }
104 |
105 | export const put = (url, data, loading) => {
106 | return promise(request({ url: url, method: "put", data }), loading)
107 | }
108 |
109 | export const del = (url, loading) => {
110 | return promise(request({ url: url, method: "delete" }), loading)
111 | }
112 |
113 | export const patch = (url, data, headers, loading) => {
114 | if (headers) {
115 | return promise(request({ url: url, headers: headers, method: "patch", data }), loading)
116 | }
117 | return promise(request({ url: url, method: "patch", data }), loading)
118 | }
119 |
120 | export default {
121 | install (Vue) {
122 | Vue.prototype.$get = get
123 | Vue.prototype.$post = post
124 | Vue.prototype.$put = put
125 | Vue.prototype.$delete = del
126 | Vue.prototype.$request = request
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue"
2 | import Router from "vue-router"
3 |
4 | // 加载modules中的路由
5 | const modules = require.context("./modules", true, /\.js$/)
6 |
7 | // 修复路由变更后报错的问题
8 | const routerPush = Router.prototype.push;
9 | Router.prototype.push = function push(location) {
10 | return routerPush.call(this, location).catch(error => error)
11 | }
12 |
13 | Vue.use(Router)
14 |
15 | import Layout from "@/business/app-layout/horizontal-layout"
16 |
17 | export const constantRoutes = [
18 | {
19 | path: "/redirect",
20 | component: Layout,
21 | hidden: true,
22 | children: [
23 | {
24 | path: "/redirect/:path(.*)",
25 | component: () => import("@/components/redirect")
26 | }
27 | ]
28 | },
29 | {
30 | path: "/login",
31 | component: () => import("@/business/login"),
32 | hidden: true
33 | },
34 | {
35 | path: "/logger",
36 | component: () => import("@/business/xterm"),
37 | hidden: true
38 | },
39 | {
40 | path: "/",
41 | component: Layout,
42 | redirect: "/clusters",
43 | }
44 | ]
45 |
46 | /**
47 | * 用户登录后根据角色加载的路由
48 | */
49 | export const rolesRoutes = [
50 | // 先按sort排序
51 | ...modules.keys().map(key => modules(key).default).sort((r1, r2) => {
52 | r1.sort ??= Number.MAX_VALUE
53 | r2.sort ??= Number.MAX_VALUE
54 | return r1.sort - r2.sort
55 | }),
56 | {path: "*", redirect: "/", hidden: true}
57 | ]
58 |
59 | const createRouter = () => new Router({
60 | scrollBehavior: () => ({y: 0}),
61 | routes: constantRoutes
62 | })
63 |
64 | const router = createRouter()
65 |
66 | export function resetRouter() {
67 | const newRouter = createRouter()
68 | router.matcher = newRouter.matcher // reset router
69 | }
70 |
71 | export default router
72 |
--------------------------------------------------------------------------------
/src/router/modules/authorization.js:
--------------------------------------------------------------------------------
1 | import Layout from "@/business/app-layout/horizontal-layout"
2 | import AuthorizationComponent from "@/business/authorization"
3 |
4 |
5 | const Authorization = {
6 | sort: 7,
7 | path: "/authorization",
8 | component: Layout,
9 | name: "Authorization",
10 | children: [
11 | {
12 | path: "list",
13 | component: () => import("@/business/authorization"),
14 | name: "ProjectAuthorizationList",
15 | props: true,
16 | meta: {
17 | title: "route.project_management",
18 | icon: "iconfont iconproject",
19 | roles: ["ADMIN", "PROJECT_MANAGER"]
20 | }
21 | },
22 | {
23 | path: "resource",
24 | component: AuthorizationComponent,
25 | name: "Resource",
26 | hidden: true,
27 | meta: {
28 | activeMenu: "/authorization/list",
29 | roles: ["ADMIN", "PROJECT_MANAGER"]
30 | },
31 | },
32 | {
33 | path: "project/create",
34 | component: () => import("@/business/authorization/projects/create"),
35 | name: "ProjectCreate",
36 | hidden: true,
37 | meta: {
38 | activeMenu: "/authorization/list",
39 | roles: ["ADMIN", "PROJECT_MANAGER"]
40 | }
41 | },
42 | {
43 | path: "project/edit/:name",
44 | props: true,
45 | component: () => import("@/business/authorization/projects/edit"),
46 | name: "ProjectEdit",
47 | hidden: true,
48 | meta: {
49 | activeMenu: "/authorization/list",
50 | roles: ["ADMIN", "PROJECT_MANAGER"]
51 | }
52 | }
53 | ]
54 | }
55 |
56 | export default Authorization
57 |
--------------------------------------------------------------------------------
/src/router/modules/backup-account.js:
--------------------------------------------------------------------------------
1 | import Layout from "@/business/app-layout/horizontal-layout"
2 |
3 | const BackupAccount = {
4 | sort: 5,
5 | path: "/backup_account",
6 | component: Layout,
7 | name: "BackupAccount",
8 | props: true,
9 | meta: {
10 | title: "route.backup_account",
11 | icon: "iconfont iconbackup",
12 | roles: ["ADMIN","PROJECT_MANAGER"]
13 | },
14 | redirect: to => {
15 | return {
16 | name: 'BackupAccountList',
17 | params: to.params,
18 | }
19 | },
20 | children: [
21 | {
22 | path: "/backup_account",
23 | component: () => import("@/business/backup-account/index"),
24 | name: "BackupAccountList",
25 | props: true,
26 | hidden: true,
27 | meta: {
28 | activeMenu: "/backup_account",
29 | title: "route.backup_account",
30 | roles: ["ADMIN","PROJECT_MANAGER"]
31 | }
32 | },
33 | {
34 | path: "create",
35 | component: () => import("@/business/backup-account/create"),
36 | name: "BackupAccountCreate",
37 | hidden: true,
38 | props: true,
39 | meta: {
40 | activeMenu: "/backup_account",
41 | title: "route.backup_account",
42 | roles: ["ADMIN","PROJECT_MANAGER"]
43 | }
44 | },
45 | {
46 | path: "edit/:name",
47 | component: () => import("@/business/backup-account/edit"),
48 | name: "BackupAccountEdit",
49 | props: true,
50 | hidden: true,
51 | meta: {
52 | activeMenu: "/backup_account",
53 | title: "route.backup_account",
54 | roles: ["ADMIN","PROJECT_MANAGER"]
55 | }
56 | }
57 | ]
58 | }
59 |
60 | export default BackupAccount
61 |
--------------------------------------------------------------------------------
/src/router/modules/hosts.js:
--------------------------------------------------------------------------------
1 | import Layout from "@/business/app-layout/horizontal-layout";
2 |
3 | const Host = {
4 | sort: 2,
5 | path: '/hosts',
6 | component: Layout,
7 | name: 'Host',
8 | children: [
9 | {
10 | path: 'list',
11 | component: () => import('@/business/hosts'),
12 | name: "HostList",
13 | meta: {
14 | title: "route.host",
15 | icon: 'iconfont iconhost',
16 | roles: ['ADMIN', "PROJECT_MANAGER"]
17 | },
18 | },
19 | {
20 | path: "create",
21 | hidden: true,
22 | name: "HostCreate",
23 | component: () => import('@/business/hosts/create'),
24 | meta: {
25 | activeMenu: "/hosts/list",
26 | roles: ['ADMIN']
27 | },
28 | },
29 | {
30 | path: "edit/:name",
31 | props: true,
32 | hidden: true,
33 | name: "HostEdit",
34 | component: () => import('@/business/hosts/edit'),
35 | meta: {
36 | activeMenu: "/hosts/list",
37 | roles: ['ADMIN']
38 | },
39 | }
40 | ]
41 | }
42 | export default Host
43 |
--------------------------------------------------------------------------------
/src/router/modules/manifest.js:
--------------------------------------------------------------------------------
1 | import Layout from "@/business/app-layout/horizontal-layout"
2 |
3 | const Manifest = {
4 | path: "/manifest",
5 | sort: 6,
6 | component: Layout,
7 | name: "Manifest",
8 | meta: {
9 | title: "route.manifest",
10 | icon: "iconfont iconmanifest",
11 | roles: ["ADMIN","PROJECT_MANAGER"]
12 | },
13 | children: [
14 | {
15 | path: "manifests",
16 | component: () => import("@/business/manifest/index"),
17 | name: "Manifests",
18 | meta: {
19 | title: "route.manifest",
20 | roles: ["ADMIN","PROJECT_MANAGER"]
21 | }
22 | }
23 | ]
24 | }
25 | export default Manifest
26 |
--------------------------------------------------------------------------------
/src/router/modules/msg-subscribe.js:
--------------------------------------------------------------------------------
1 | import Layout from "@/business/app-layout/horizontal-layout"
2 |
3 | const MsgSubscribe = {
4 | sort: 7,
5 | path: "/msg_subscribe",
6 | component: Layout,
7 | name: "MsgSubscribe",
8 | props: true,
9 | meta: {
10 | icon: "iconfont iconweidu1",
11 | roles: ["ADMIN", "PROJECT_MANAGER"]
12 | },
13 | children: [
14 | {
15 | path: "msgSubscribe",
16 | component: () => import("@/business/msg-subscribe/index"),
17 | name: "MsgSubscribeList",
18 | meta: {
19 | title: "message.message_subscribe",
20 | roles: ["ADMIN","PROJECT_MANAGER"]
21 | }
22 | },
23 | ]
24 | }
25 |
26 | export default MsgSubscribe
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/router/modules/system-log.js:
--------------------------------------------------------------------------------
1 | import Layout from "@/business/app-layout/horizontal-layout";
2 |
3 | const SystemLog = {
4 | sort: 10,
5 | path: '/system-log',
6 | component: Layout,
7 | name: 'SystemLog',
8 | meta: {
9 | title: "route.system_log",
10 | icon: 'iconfont iconxitongrizhi',
11 | roles: ['ADMIN', "PROJECT_MANAGER","CLUSTER_MANAGER"]
12 | },
13 | children: [
14 | {
15 | path: 'logs',
16 | component: () => import('@/business/system-log/index'),
17 | name: "Logs",
18 | meta: {
19 | title: "route.system_log",
20 | roles: ['ADMIN', "PROJECT_MANAGER","CLUSTER_MANAGER"]
21 | }
22 | }
23 | ]
24 | }
25 | export default SystemLog
26 |
--------------------------------------------------------------------------------
/src/router/modules/users.js:
--------------------------------------------------------------------------------
1 | import Layout from "@/business/app-layout/horizontal-layout"
2 |
3 | const Users = {
4 | sort: 8,
5 | path: "/users",
6 | component: Layout,
7 | name: "User",
8 | meta: {
9 | roles: ["ADMIN"]
10 | },
11 | children: [
12 | {
13 | path: "list",
14 | component: () => import("@/business/users"),
15 | name: "UserList",
16 | meta: {
17 | title: "route.user",
18 | icon: "iconfont iconyonghuguanli",
19 | roles: ["ADMIN"]
20 | }
21 | },
22 | {
23 | path: "create",
24 | hidden: true,
25 | name: "UserCreate",
26 | component: () => import("@/business/users/create"),
27 | meta: {
28 | activeMenu: "/users/list",
29 | roles: ["ADMIN"]
30 | },
31 | }, {
32 | props: true,
33 | path: "edit/:name",
34 | hidden: true,
35 | name: "UserEdit",
36 | component: () => import("@/business/users/edit"),
37 | meta: {
38 | activeMenu: "/users/list",
39 | roles: ["ADMIN"]
40 | },
41 | }
42 | ]
43 | }
44 | export default Users
45 |
--------------------------------------------------------------------------------
/src/router/modules/x-pack.js:
--------------------------------------------------------------------------------
1 | import Layout from "@/business/app-layout/horizontal-layout"
2 |
3 | const XPack = {
4 | path: "/xpack",
5 | sort: 9,
6 | name: "XPack",
7 | component: Layout,
8 | meta: {
9 | title: "X-Pack",
10 | icon: "iconfont iconx-pack",
11 | requireLicense: true
12 | },
13 | children: [
14 | {
15 | path: "multi-cluster",
16 | component: () => import("@/business/xpack"),
17 | name: "MultiCluster",
18 | meta: {
19 | title: "route.multi_cluster",
20 | roles: ["ADMIN", "PROJECT_MANAGER"]
21 | },
22 | redirect: () => {
23 | return {
24 | name: 'MultiClusterRepositoriesList',
25 | }
26 | },
27 | children: [
28 | {
29 | path: "list",
30 | hidden: true,
31 | component: () => import("@/business/xpack/multi-cluster"),
32 | name: "MultiClusterRepositoriesList",
33 | meta: {
34 | title: "route.multi_cluster",
35 | activeMenu: "/xpack/multi-cluster",
36 | roles: ["ADMIN", "PROJECT_MANAGER"]
37 | },
38 | },
39 | {
40 | path: "create",
41 | hidden: true,
42 | component: () => import("@/business/xpack/multi-cluster/create"),
43 | name: "MultiClusterRepositoryCreate",
44 | meta: {
45 | activeMenu: "/xpack/multi-cluster",
46 | roles: ["ADMIN", "PROJECT_MANAGER"]
47 | },
48 | },
49 | {
50 | path: "edit/:name",
51 | props: true,
52 | hidden: true,
53 | component: () => import("@/business/xpack/multi-cluster/edit"),
54 | name: "MultiClusterRepositoryEdit",
55 | meta: {
56 | activeMenu: "/xpack/multi-cluster",
57 | roles: ["ADMIN", "PROJECT_MANAGER"]
58 | }
59 | },
60 | {
61 | path: "log/:name",
62 | props: true,
63 | hidden: true,
64 | component: () => import("@/business/xpack/multi-cluster/log"),
65 | name: "MultiClusterRepositoryLog",
66 | meta: {
67 | activeMenu: "/xpack/multi-cluster",
68 | roles: ["ADMIN", "PROJECT_MANAGER"]
69 | }
70 | },
71 | ],
72 | },
73 | {
74 | path: "theme",
75 | name: "Theme",
76 | props: true,
77 | component: () => import('@/business/xpack/theme'),
78 | meta: {
79 | requireLicense: true,
80 | title: "route.theme",
81 | activeMenu: "/xpack/theme",
82 | roles: ['ADMIN']
83 | }
84 | },
85 | ]
86 | }
87 | export default XPack
88 |
--------------------------------------------------------------------------------
/src/store/getters.js:
--------------------------------------------------------------------------------
1 | // 根据实际需要修改
2 | const getters = {
3 | sidebar: state => state.app.sidebar,
4 | name: state => state.user.name,
5 | currentProject: state => state.user.currentProject,
6 | language: state => state.user.language,
7 | roles: state => state.user.roles,
8 | permission_routes: state => state.permission.routes,
9 | license: state => state.license,
10 | theme: state => state.theme.theme,
11 | }
12 | export default getters
13 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import getters from './getters'
4 |
5 | Vue.use(Vuex)
6 |
7 | // 自动从modules目录下获取模块
8 | const MODULES_FILES = require.context('./modules', true, /\.js$/)
9 |
10 | // 模块名为js文件名,例如user.js 则模块名为user
11 | const modules = MODULES_FILES.keys().reduce((modules, modulePath) => {
12 | const value = MODULES_FILES(modulePath)
13 | const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
14 | modules[moduleName] = value.default
15 | return modules
16 | }, {})
17 |
18 | const store = new Vuex.Store({
19 | modules,
20 | getters
21 | })
22 |
23 | export default store
24 |
--------------------------------------------------------------------------------
/src/store/modules/app.js:
--------------------------------------------------------------------------------
1 | const get = () => {
2 | return localStorage.getItem('sidebarStatus')
3 | }
4 | const set = value => {
5 | localStorage.setItem('sidebarStatus', value)
6 | }
7 | const state = {
8 | sidebar: {
9 | opened: get() ? !!+get() : true
10 | },
11 | device: 'desktop'
12 | }
13 |
14 | const mutations = {
15 | TOGGLE_SIDEBAR: state => {
16 | state.sidebar.opened = !state.sidebar.opened
17 | if (state.sidebar.opened) {
18 | set(1)
19 | } else {
20 | set(0)
21 | }
22 | },
23 | OPEN_SIDEBAR: (state) => {
24 | set('sidebarStatus', 1)
25 | state.sidebar.opened = true
26 | },
27 | CLOSE_SIDEBAR: (state) => {
28 | set('sidebarStatus', 0)
29 | state.sidebar.opened = false
30 | }
31 | }
32 |
33 | const actions = {
34 | toggleSideBar({commit}) {
35 | commit('TOGGLE_SIDEBAR')
36 | },
37 | openSideBar({commit}) {
38 | commit('OPEN_SIDEBAR')
39 | },
40 | closeSideBar({commit}) {
41 | commit('CLOSE_SIDEBAR')
42 | }
43 | }
44 |
45 | export default {
46 | namespaced: true,
47 | state,
48 | mutations,
49 | actions
50 | }
51 |
--------------------------------------------------------------------------------
/src/store/modules/license.js:
--------------------------------------------------------------------------------
1 | import {getLicense} from "@/api/license"
2 |
3 | const LicenseKey = "X-License";
4 |
5 | const Status = {
6 | valid: "valid",
7 | invalid: "invalid",
8 | expired: "expired",
9 | }
10 |
11 | const get = () => {
12 | return localStorage.getItem(LicenseKey)
13 | }
14 | const set = value => {
15 | localStorage.setItem(LicenseKey, value)
16 | }
17 | const state = {
18 | status: get(),
19 | license: {},
20 | message: ""
21 | }
22 |
23 | const mutations = {
24 | SET_STATUS: (state, status) => {
25 | set(LicenseKey, status)
26 | state.status = status;
27 | },
28 | SET_LICENSE: (state, license) => {
29 | state.license = license;
30 | },
31 | SET_MESSAGE: (state, message) => {
32 | state.message = message;
33 | }
34 | }
35 |
36 | const actions = {
37 | getLicense({commit}) {
38 | return new Promise((resolve, reject) => {
39 | getLicense().then(data => {
40 | const {status, license, message} = data;
41 | commit('SET_STATUS', status)
42 | commit('SET_LICENSE', license)
43 | commit('SET_MESSAGE', message)
44 | resolve(data)
45 | }).catch(error => {
46 | commit('SET_STATUS', Status.invalid)
47 | reject(error)
48 | })
49 | })
50 | },
51 | isValid({state}) {
52 | return state.status === Status.valid
53 | },
54 | isExpired({state}) {
55 | return state.status === Status.expired
56 | }
57 | }
58 |
59 | export default {
60 | namespaced: true,
61 | state,
62 | mutations,
63 | actions
64 | }
65 |
--------------------------------------------------------------------------------
/src/store/modules/permission.js:
--------------------------------------------------------------------------------
1 | import {rolesRoutes, constantRoutes} from '@/router'
2 |
3 | function hasPermission(roles, license, route) {
4 | if (route.meta && route.meta.requireLicense) {
5 | if (license.status !== 'valid') {
6 | return false
7 | }
8 | }
9 | if (route.meta && route.meta.roles) {
10 | return roles.some(role => route.meta.roles.includes(role))
11 | } else {
12 | return true
13 | }
14 | }
15 |
16 |
17 | export function filterRolesRoutes(routes, license, roles) {
18 | const res = []
19 | routes.forEach(route => {
20 | const tmp = {...route}
21 | if (hasPermission(roles, license, tmp)) {
22 | if (tmp.children) {
23 | tmp.children = filterRolesRoutes(tmp.children, license, roles)
24 | }
25 | res.push(tmp)
26 | }
27 | })
28 |
29 | return res
30 | }
31 |
32 | const state = {
33 | routes: [],
34 | addRoutes: []
35 | }
36 |
37 | const mutations = {
38 | SET_ROUTES: (state, routes) => {
39 | state.addRoutes = routes
40 | state.routes = constantRoutes.concat(routes)
41 | }
42 | }
43 |
44 | const actions = {
45 | generateRoutes({commit}, p) {
46 | return new Promise(resolve => {
47 | const {license, roles} = p
48 | let accessedRoutes
49 | accessedRoutes = filterRolesRoutes(rolesRoutes, license, roles)
50 | commit('SET_ROUTES', accessedRoutes)
51 | resolve(accessedRoutes)
52 | })
53 | }
54 | }
55 |
56 | export default {
57 | namespaced: true,
58 | state,
59 | mutations,
60 | actions
61 | }
62 |
--------------------------------------------------------------------------------
/src/store/modules/theme.js:
--------------------------------------------------------------------------------
1 | import { getTheme } from "@/api/theme";
2 |
3 | const state = {
4 | theme: null
5 | };
6 |
7 | const mutations = {
8 | SET_THEME: (state, data) => {
9 | state.theme = data;
10 | state.theme.systemName = state.theme.systemName === "" ? "KubeOperator" : state.theme.systemName;
11 | let link = document.querySelector("link[rel*='icon']");
12 | if (!link) {
13 | link = document.createElement('link');
14 | link.type = 'image/x-icon';
15 | link.rel = 'shortcut icon';
16 | document.getElementsByTagName('head')[0].appendChild(link);
17 | }
18 | if (data.icon !== '') {
19 | link.href = data.icon;
20 | } else {
21 | link.href = "ui/favicon.ico"
22 | }
23 | document.title = state.theme.systemName;
24 | }
25 | };
26 |
27 | const actions = {
28 | getThemeInfo({ commit }) {
29 | return new Promise((resolve, reject) => {
30 | getTheme()
31 | .then(data => {
32 | commit("SET_THEME", data);
33 | resolve(data);
34 | })
35 | .catch(error => {
36 | commit("SET_THEME", {
37 | systemName: "KubeOperator",
38 | logo: "",
39 | logoWithText: "",
40 | loginImage: "",
41 | icon: "",
42 | logoAbout: ""
43 | });
44 | reject(error);
45 | });
46 | });
47 | }
48 | };
49 |
50 | export default {
51 | namespaced: true,
52 | state,
53 | mutations,
54 | actions
55 | };
56 |
--------------------------------------------------------------------------------
/src/store/modules/user-token.js:
--------------------------------------------------------------------------------
1 | import {login, getCurrentUser, updateInfo, logout} from "@/api/user-token"
2 | import {resetRouter} from "@/router"
3 | import {getToken, setToken, removeToken} from "@/utils/token"
4 | import {getLanguage, setLanguage} from "@/i18n"
5 |
6 | /* 前后端不分离的登录办法*/
7 | const state = {
8 | token: getToken(),
9 | name: "",
10 | language: getLanguage(),
11 | roles: []
12 | }
13 |
14 | const mutations = {
15 | SET_TOKEN: (state, token) => {
16 | state.token = token
17 | },
18 | SET_NAME: (state, name) => {
19 | state.name = name
20 | },
21 | SET_LANGUAGE: (state, language) => {
22 | state.language = language
23 | setLanguage(language)
24 | },
25 | SET_ROLES: (state, roles) => {
26 | state.roles = roles
27 | }
28 | }
29 |
30 | const actions = {
31 | login ({ commit }, userInfo) {
32 | const { username, password, captchaId, code } = userInfo
33 | return new Promise((resolve, reject) => {
34 | login({ username: username.trim(), password: password, captchaId: captchaId, code: code }).then(response => {
35 | let token = response.data
36 | commit("SET_TOKEN", token)
37 | setToken(token)
38 | resolve(response)
39 | }).catch(error => {
40 | reject(error)
41 | })
42 | })
43 | },
44 |
45 | isLogin ({ commit }) {
46 | return new Promise((resolve, reject) => {
47 | let token = getToken()
48 | if (token) {
49 | commit("SET_TOKEN", token)
50 | resolve(true)
51 | } else {
52 | reject(false)
53 | }
54 | })
55 | },
56 |
57 | getCurrentUser ({ commit }) {
58 | return new Promise((resolve, reject) => {
59 | getCurrentUser().then(response => {
60 | const { name, roles, language } = response.data
61 | commit("SET_NAME", name)
62 | commit("SET_ROLES", roles)
63 | commit("SET_LANGUAGE", language)
64 | resolve(response.data)
65 | }).catch(error => {
66 | reject(error)
67 | })
68 | })
69 | },
70 |
71 | setLanguage ({ commit, state }, language) {
72 | commit("SET_LANGUAGE", language)
73 | return new Promise((resolve, reject) => {
74 | updateInfo(state.id, { language: language }).then(response => {
75 | resolve(response)
76 | }).catch(error => {
77 | reject(error)
78 | })
79 | })
80 | },
81 |
82 | logout ({ commit }) {
83 | logout().then(() => {
84 | commit("SET_TOKEN", "")
85 | commit("SET_ROLES", [])
86 | removeToken()
87 | resetRouter()
88 | })
89 | },
90 | }
91 |
92 | export default {
93 | namespaced: true,
94 | state,
95 | mutations,
96 | actions
97 | }
98 |
--------------------------------------------------------------------------------
/src/store/modules/user.js:
--------------------------------------------------------------------------------
1 | /* 前后端不分离的登录方式*/
2 | import {updateUser} from "@/api/user"
3 | import {login, logout, isLogin, getSession} from "@/api/auth"
4 | import {resetRouter} from "@/router"
5 | import {getLanguage, setLanguage} from "@/i18n"
6 |
7 | const state = {
8 | login: false,
9 | name: "",
10 | currentProject: "",
11 | language: getLanguage(),
12 | roles: []
13 | }
14 |
15 | const mutations = {
16 | LOGIN: (state) => {
17 | state.login = true
18 | },
19 | LOGOUT: (state) => {
20 | state.login = false
21 | },
22 | SET_NAME: (state, name) => {
23 | state.name = name
24 | },
25 | SET_LANGUAGE: (state, language) => {
26 | state.language = language
27 | setLanguage(language)
28 | },
29 | SET_ROLES: (state, roles) => {
30 | state.roles = roles
31 | },
32 | SET_CURRENT_PROJECT: (state, project) => {
33 | state.currentProject = project
34 | }
35 | }
36 |
37 | const actions = {
38 | login ({ commit }, userInfo) {
39 | const { username, password, captchaId, code } = userInfo
40 | return new Promise((resolve, reject) => {
41 | login({ username: username.trim(), password: password, captchaId: captchaId, code: code }).then(response => {
42 | commit("LOGIN")
43 | resolve(response)
44 | }).catch(error => {
45 | reject(error)
46 | })
47 | })
48 | },
49 |
50 | isLogin ({ commit }) {
51 | return new Promise((resolve) => {
52 | if (state.isLogin) {
53 | resolve(true)
54 | return
55 | }
56 | isLogin().then((data) => {
57 | if (data.isLogin) {
58 | commit("LOGIN")
59 | resolve(true)
60 | } else {
61 | resolve(false)
62 | }
63 | }).catch(() => {
64 | resolve(false)
65 | })
66 | })
67 | },
68 |
69 | getCurrentUser ({ commit }) {
70 | return new Promise((resolve, reject) => {
71 | getSession().then(data => {
72 | const user = data.user
73 | const { name, roles, language, currentProject } = user
74 | commit("SET_NAME", name)
75 | commit("SET_ROLES", roles)
76 | commit("SET_LANGUAGE", language)
77 | commit("SET_CURRENT_PROJECT", currentProject)
78 | resolve(user)
79 | }).catch(error => {
80 | reject(error)
81 | })
82 | })
83 | },
84 |
85 | setLanguage ({ commit, state }, language) {
86 | commit("SET_LANGUAGE", language)
87 | return new Promise((resolve, reject) => {
88 | updateUser(state.name, { language: language }).then(response => {
89 | resolve(response)
90 | }).catch(error => {
91 | reject(error)
92 | })
93 | })
94 | },
95 | setCurrentProject ({ commit, state }, project) {
96 | commit("SET_CURRENT_PROJECT", project)
97 | return new Promise((resolve, reject) => {
98 | updateUser(state.name, { currentProject: project }).then(response => {
99 | resolve(response)
100 | }).catch(error => {
101 | reject(error)
102 | })
103 | })
104 | },
105 |
106 | logout ({ commit }) {
107 | logout().then(() => {
108 | commit("LOGOUT")
109 | commit("SET_ROLES", [])
110 | resetRouter()
111 | })
112 | },
113 | }
114 |
115 | export default {
116 | namespaced: true,
117 | state,
118 | mutations,
119 | actions
120 | }
121 |
--------------------------------------------------------------------------------
/src/styles/business/header-menu.scss:
--------------------------------------------------------------------------------
1 | @import "~@/styles/common/variables.scss";
2 |
3 | .header-menu {
4 | min-width: 100px;
5 | color: #3E3E3D;
6 |
7 | &.el-menu {
8 | background-color: transparent;
9 |
10 | &.el-menu--horizontal {
11 | border: none;
12 |
13 | .el-submenu__title {
14 | border: none;
15 | min-width: 120px;
16 | height: 40px;
17 | line-height: 40px;
18 | padding: 0 3px;
19 | }
20 | }
21 | }
22 | }
23 |
24 | .header-menu-popper {
25 | color: #3E3E3D;
26 |
27 | .el-menu--popup {
28 | min-width: 100px;
29 | }
30 |
31 | .el-menu-item {
32 | &.is-active {
33 | color: $--color-primary;
34 | }
35 |
36 | &:hover {
37 | background-color: #D5D5D5;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/styles/common/mixins.scss:
--------------------------------------------------------------------------------
1 | @mixin flex-row($justify: flex-start, $align: stretch) {
2 | display: flex;
3 | @if $justify != flex-start {
4 | justify-content: $justify;
5 | }
6 | @if $align != stretch {
7 | align-items: $align;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/styles/common/variables.scss:
--------------------------------------------------------------------------------
1 | /* Element 变量 */
2 | $--color-primary: #FA5D50;
3 | $--color-success: #87CB16;
4 | $--color-warning: #FFA534;
5 | $--color-danger: #FB404B;
6 | $--color-info: #0033FF;
7 | $--color-ko: #FA5D50;
8 |
9 | $--box-shadow-light: 0 1px 4px 0 rgba(0, 0, 0, .14);
10 |
11 | $--color-text-primary: #3c4858;
12 |
13 | /* layout */
14 | $layout-bg-color: #F2F2F2;
15 |
16 | /* sidebar */
17 | $sidebar-open-width: 260px;
18 | $sidebar-close-width: 60px;
19 | $sidebar-bg-color: #30373d;
20 | $sidebar-bg-gradient: linear-gradient(to bottom right, #30373D, #3E3E3D);
21 |
22 | /* menu */
23 | $menu-height: 50px; // 菜单项高度
24 | $menu-bg-color: transparent; // 菜单项背景
25 | $menu-bg-color-hover: mix($sidebar-bg-color, #000, 90%); // 菜单项hover背景
26 | $menu-color: #B6C0CD; // 菜单项字体颜色
27 | $menu-open-bg-color: #252B2F; // 菜单项展开背景
28 | $menu-active-color: #FFF; // 菜单项激活时颜色
29 | $menu-active-bg-color: transparent; // 菜单项激活时背景
30 |
31 | $submenu-height: 40px; // 子菜单项高度
32 | $submenu-bg-color-hover: mix($menu-open-bg-color, #000, 80%); // 子菜单项hover背景
33 | $submenu-active-color: $menu-active-color; // 子菜单项激活时颜色
34 | $submenu-active-bg-color: transparent; // 子菜单项激活时背景
35 |
36 | $menu-active-prefix-color: $--color-ko; // 菜单激活前缀颜色
37 | $menu-active-prefix-width: 4px; // 菜单激活前缀宽度
38 |
39 | /* logo */
40 | $logo-height: 40px;
41 | $logo-bg-color: #4E5051;
42 |
43 | /* header */
44 | $header-height: 60px;
45 | $header-padding: 30px;
46 |
47 | /* main */
48 | $view-padding: 15px;
49 |
50 | /* fit2cloud-ui的variables加载了element-ui的变量 */
51 | @import "~fit2cloud-ui/src/styles/common/variables";
52 |
53 | :export {
54 | theme: $--color-primary;
55 | }
56 |
57 | #nprogress .bar {
58 | background: $--color-ko !important; //自定义颜色
59 | }
60 |
61 | //.statusFailed {
62 | // color: #0033FF;
63 | // text-decoration: underline;
64 | //}
65 |
66 | .koLink {
67 | color: #0033FF;
68 | text-decoration: underline;
69 | }
70 |
71 | .linkStyle {
72 | color: #0033FF;
73 | }
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/src/styles/index.scss:
--------------------------------------------------------------------------------
1 | @import '~normalize.css/normalize.css';
2 | @import "./common/variables";
3 | @import "~fit2cloud-ui/src/styles";
4 | @import "./business/app";
5 |
--------------------------------------------------------------------------------
/src/utils/format_ansible_err.js:
--------------------------------------------------------------------------------
1 | export function ansibleErrFormat(str) {
2 | let formatMsgs = [];
3 | if (!isJson(str)) {
4 | return [
5 | { name: "Error Message", info: str, failed: false, type: "unFormat" }
6 | ];
7 | }
8 | var json1 = JSON.parse(str);
9 | for (const key in json1) {
10 | var itemMsg = { name: "", info: {}, failed: false };
11 | itemMsg.name = key;
12 | if (isJson(json1[key])) {
13 | var json2 = JSON.parse(json1[key]);
14 | itemMsg.info = json2;
15 | if (itemMsg.info.msg) {
16 | itemMsg.info.msg = itemMsg.info.msg.replace(/\t/g, "").trim();
17 | }
18 | if (itemMsg.info.stdout) {
19 | itemMsg.info.stdout = itemMsg.info.stdout.replace(/\t/g, "").trim();
20 | }
21 | if (itemMsg.info.stderr) {
22 | itemMsg.info.stderr = itemMsg.info.stderr.replace(/\t/g, "").trim();
23 | }
24 | if (itemMsg.info.unreachable) {
25 | itemMsg.failed = true;
26 | } else {
27 | itemMsg.failed = json2.failed;
28 | }
29 | } else {
30 | itemMsg.type = "unFormat";
31 | itemMsg.info = json1[key];
32 | }
33 | if (itemMsg.info.length !== 0) {
34 | formatMsgs.push(itemMsg);
35 | }
36 | }
37 | return formatMsgs;
38 | }
39 |
40 | function isJson(str) {
41 | try {
42 | if (typeof JSON.parse(str) === "object") {
43 | return true;
44 | }
45 | } catch {
46 | return false;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/utils/format_conversion.js:
--------------------------------------------------------------------------------
1 | export function changeUnderLineToPoint(obj) {
2 | for (var item in obj) {
3 | if (item.indexOf("_") !== -1) {
4 | var newParam = item.replace(new RegExp("__", 'g'), "-").replace(new RegExp("_", 'g'), ".");
5 | obj[newParam] = obj[item];
6 | delete obj[item];
7 | }
8 | }
9 | return obj;
10 | }
11 |
12 | export function changePointToUnderLine(obj) {
13 | for (var item in obj) {
14 | if (item.indexOf("-") !== -1 || item.indexOf(".") !== -1) {
15 | var newParam = item.replace(new RegExp("-", 'g'), "__").replace(/\./g, "_");
16 | obj[newParam] = obj[item];
17 | delete obj[item];
18 | }
19 | }
20 | return obj;
21 | }
22 |
--------------------------------------------------------------------------------
/src/utils/format_date.js:
--------------------------------------------------------------------------------
1 | export function formatDate(date, fmt) {
2 | if (/(y+)/.test(fmt)) {
3 | fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
4 | }
5 | let o = {
6 | 'M+': date.getMonth() + 1,
7 | 'd+': date.getDate(),
8 | 'h+': date.getHours(),
9 | 'm+': date.getMinutes(),
10 | 's+': date.getSeconds()
11 | };
12 | for (let k in o) {
13 | if (new RegExp(`(${k})`).test(fmt)) {
14 | let str = o[k] + '';
15 | fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str));
16 | }
17 | }
18 | return fmt;
19 | }
20 |
21 | function padLeftZero(str) {
22 | return ('00' + str).substr(str.length);
23 | }
--------------------------------------------------------------------------------
/src/utils/global_variable.js:
--------------------------------------------------------------------------------
1 | const IpEeg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/
2 | const PasswordPattern = /^(?=.*\d)(?=.*[a-zA-Z])[\da-zA-Z~!@#$%^&*]{8,30}$/
3 | const NamePattern = /^[a-zA-Z0-9\u4e00-\u9fa5]{1}[a-zA-Z0-9_.\u4e00-\u9fa5-]{0,30}$/
4 |
5 | // 支持小写英文、数字和- 不能以数字开头
6 | const ClusterNamePattern = /^[a-z]([-a-z0-9]{0,48})[a-z0-9]$/
7 | // 支持小写英文、数字和-
8 | const StorageNamePattern = /^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$/
9 |
10 | const EsIndexPattern = /^[a-zA-Z]{1}[a-zA-Z0-9]{0,30}$/
11 | const VmConfigPattern = /[a-zA-Z0-9]{1}[a-zA-Z0-9]{0,30}$/
12 |
13 |
14 | export default {
15 | IpEeg, PasswordPattern, NamePattern, EsIndexPattern, VmConfigPattern, ClusterNamePattern, StorageNamePattern
16 | }
17 |
--------------------------------------------------------------------------------
/src/utils/permisstion.js:
--------------------------------------------------------------------------------
1 | import store from "@/store";
2 |
3 | export const checkPermission = function (permissionRoles) {
4 | const roles = store.getters && store.getters.roles
5 |
6 | return roles.some(role => {
7 | return permissionRoles.includes(role)
8 | })
9 | }
10 |
--------------------------------------------------------------------------------
/src/utils/rules.js:
--------------------------------------------------------------------------------
1 | import Global from "@/utils/global_variable"
2 | import i18n from "@/i18n"
3 |
4 | var ipaddr = require("ipaddr.js")
5 |
6 | var checkName = (rule, value, callback) => {
7 | if (!value) {
8 | return callback(new Error(i18n.t("commons.validate.required_msg")))
9 | }
10 | if (!Global.NamePattern.test(value)) {
11 | return callback(new Error(i18n.t("commons.validate.name_not_compliant")))
12 | }
13 | callback()
14 | }
15 |
16 | var checkIp = (rule, value, callback) => {
17 | if (!value) {
18 | return callback(new Error(i18n.t("commons.validate.required_msg")))
19 | }
20 | if (!ipaddr.isValid(value)) {
21 | return callback(new Error(i18n.t("commons.validate.ip_error")))
22 | }
23 | callback()
24 | }
25 |
26 |
27 | const RequiredRule = { required: true, trigger: "blur", message: i18n.t("commons.validate.required_msg") }
28 | const SelectRequiredRule = { required: true, trigger: "change", message: i18n.t("commons.validate.cannot_be_empty") }
29 | const NameRule = { validator: checkName, required: true, trigger: "blur" }
30 | const IpRule = { validator: checkIp, required: true, trigger: "blur" }
31 | const EmailRule = { type: "email", message: i18n.t("commons.validate.email") }
32 |
33 | // 非零正整数
34 | const NumberRule = {
35 | required: true,
36 | trigger: "blur",
37 | min: 1,
38 | type: "number",
39 | message: i18n.t("commons.validate.number_limit")
40 | }
41 |
42 | // 含零正整数
43 | const NumberWithZeroRule = {
44 | required: true,
45 | trigger: "blur",
46 | min: 0,
47 | type: "number",
48 | message: i18n.t("commons.validate.number_limit")
49 | }
50 |
51 | // 支持小写英文、数字和- 不能以数字开头
52 | const ClusterNameRule = {
53 | required: true,
54 | pattern: Global.ClusterNamePattern,
55 | message: i18n.t("commons.validate.name_not_compliant"),
56 | trigger: "blur"
57 | }
58 | // 支持小写英文、数字和-
59 | const CommonNameRule = {
60 | required: true,
61 | pattern: Global.StorageNamePattern,
62 | message: i18n.t("commons.validate.name_not_compliant"),
63 | trigger: "blur"
64 | }
65 | // 密码规范
66 | const PasswordRule = {
67 | required: true,
68 | pattern: Global.PasswordPattern,
69 | message: i18n.t("commons.validate.password_help"),
70 | trigger: "blur"
71 | }
72 |
73 | const LengthRule = {
74 | min: 1,
75 | max: 30,
76 | message: i18n.t("commons.validate.limit", [1, 30]),
77 | trigger: "blur"
78 | }
79 | export default {
80 | NameRule, RequiredRule, SelectRequiredRule, EmailRule, IpRule, NumberWithZeroRule, NumberRule, ClusterNameRule, CommonNameRule, PasswordRule, LengthRule
81 | }
--------------------------------------------------------------------------------
/src/utils/sort.js:
--------------------------------------------------------------------------------
1 | export const sortCommon = function (str1, str2) {
2 | return str1 - str2
3 | }
--------------------------------------------------------------------------------
/src/utils/token.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 |
3 | export const TokenKey = 'App-Token' // 自行修改
4 |
5 | export function getToken() {
6 | return Cookies.get(TokenKey)
7 | }
8 |
9 | export function setToken(token) {
10 | return Cookies.set(TokenKey, token)
11 | }
12 |
13 | export function removeToken() {
14 | return Cookies.remove(TokenKey)
15 | }
16 |
--------------------------------------------------------------------------------
/src/utils/validate.js:
--------------------------------------------------------------------------------
1 | export function isExternal(path) {
2 | return /^(https?:|mailto:|tel:)/.test(path)
3 | }
4 |
5 | export function isJson(str) {
6 | try {
7 | if (typeof JSON.parse(str) === "object") {
8 | return true
9 | }
10 | } catch {
11 | return false
12 | }
13 | }
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | function resolve(dir) {
4 | return path.join(__dirname, dir)
5 | }
6 |
7 | module.exports = {
8 | productionSourceMap: true,
9 | devServer: {
10 | port: 4200,
11 | open: true,
12 | overlay: {
13 | warnings: false,
14 | errors: true
15 | },
16 | proxy: {
17 | '/kubepi': {
18 | target: 'http://0.0.0.0:80',
19 | ws: true,
20 | secure: false
21 | },
22 | '/api': {
23 | target: 'http://127.0.0.1:8080',
24 | ws: true,
25 | secure: false,
26 | },
27 | '/proxy': {
28 | target: 'http://127.0.0.1:8080',
29 | ws: true,
30 | secure: false,
31 | },
32 | }
33 | },
34 | configureWebpack: {
35 | devtool: 'source-map',
36 | resolve: {
37 | alias: {
38 | '@': resolve('src')
39 | }
40 | }
41 | },
42 | publicPath: '/ui/',
43 | };
44 |
--------------------------------------------------------------------------------