mirror of
https://github.com/jumpserver/lina.git
synced 2026-01-14 11:55:34 +00:00
Compare commits
407 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
607eec6c44 | ||
|
|
28daf41fb5 | ||
|
|
e45720af1b | ||
|
|
2c69b36291 | ||
|
|
d267cd1f5e | ||
|
|
807e3a407a | ||
|
|
1ba790e680 | ||
|
|
44b701edbc | ||
|
|
8619ab8bca | ||
|
|
79e92fa46b | ||
|
|
f19c863440 | ||
|
|
fff8b79a45 | ||
|
|
cf810b3d3e | ||
|
|
f58e37a76a | ||
|
|
5889e20aae | ||
|
|
7caa2c8264 | ||
|
|
865388dedc | ||
|
|
35c1077eed | ||
|
|
487e199995 | ||
|
|
f584e96675 | ||
|
|
1f4f1d3712 | ||
|
|
08facb1eda | ||
|
|
34cb9424d4 | ||
|
|
36767cd265 | ||
|
|
86b9fc8f5a | ||
|
|
49054e5dc0 | ||
|
|
bac7cef23c | ||
|
|
4013ea6212 | ||
|
|
37153ebe1d | ||
|
|
da35d9be25 | ||
|
|
c3c24b0ad1 | ||
|
|
98da517724 | ||
|
|
f002c7f917 | ||
|
|
0d4e4324ce | ||
|
|
fdeab46970 | ||
|
|
5acbdd5679 | ||
|
|
3a64120241 | ||
|
|
81d1cbf3a1 | ||
|
|
cec17bbef8 | ||
|
|
fbc3373e1b | ||
|
|
b4a935ab15 | ||
|
|
7fbff42067 | ||
|
|
5077fec5a8 | ||
|
|
c4619af96f | ||
|
|
025d0abeae | ||
|
|
5735a591ba | ||
|
|
3b664ee1dc | ||
|
|
a3f6de330e | ||
|
|
cbc67a5a4c | ||
|
|
dec0593907 | ||
|
|
1ed432b1e2 | ||
|
|
b65664f9c4 | ||
|
|
f64def0bec | ||
|
|
06f6202bc4 | ||
|
|
6fa7800d6b | ||
|
|
54aa252c20 | ||
|
|
c083f6c4a4 | ||
|
|
73bb854ebb | ||
|
|
d6f9df277e | ||
|
|
ba78e33f89 | ||
|
|
09ef15cff0 | ||
|
|
62d520e625 | ||
|
|
f07a857813 | ||
|
|
2699d5e8eb | ||
|
|
fb398ca3e4 | ||
|
|
3230c37318 | ||
|
|
bc258a7ff8 | ||
|
|
64d610e282 | ||
|
|
4d95461b5c | ||
|
|
f364c8fdf9 | ||
|
|
88dc2d9271 | ||
|
|
3aced25da4 | ||
|
|
fcf142b696 | ||
|
|
2123037897 | ||
|
|
f5bc2842ec | ||
|
|
2c95e5f10b | ||
|
|
b3ff9c5bcb | ||
|
|
905e5e00b1 | ||
|
|
81db3d86fa | ||
|
|
ea15515264 | ||
|
|
4048a000c7 | ||
|
|
a60693c41c | ||
|
|
06d6c54db8 | ||
|
|
57d5c893d3 | ||
|
|
435ce24c75 | ||
|
|
4a757bb6bc | ||
|
|
32fa4f0b11 | ||
|
|
9f12e1aa18 | ||
|
|
6165709747 | ||
|
|
0ad1eef196 | ||
|
|
d2d07555b5 | ||
|
|
7f60224c6d | ||
|
|
bbf502c85d | ||
|
|
e6aaa52506 | ||
|
|
70affacfde | ||
|
|
40a8da5e58 | ||
|
|
24266bb929 | ||
|
|
14286b961e | ||
|
|
0498db9a8f | ||
|
|
266d107ffd | ||
|
|
4f2a9c0c6c | ||
|
|
affb0ec2bb | ||
|
|
3075d50357 | ||
|
|
e49da02c4d | ||
|
|
7df5736354 | ||
|
|
98886149f9 | ||
|
|
abb98d55b9 | ||
|
|
f9c979af88 | ||
|
|
89018a2258 | ||
|
|
a0c29563ca | ||
|
|
21223fddea | ||
|
|
254a2b58cc | ||
|
|
777c371070 | ||
|
|
0cba2b3116 | ||
|
|
c27dd0baef | ||
|
|
990aebefdd | ||
|
|
6f84312dbe | ||
|
|
d4c12fb38f | ||
|
|
1bb94824df | ||
|
|
5772430761 | ||
|
|
790941f361 | ||
|
|
a9ce01ac0e | ||
|
|
1cdc406e70 | ||
|
|
cb60660272 | ||
|
|
8625e21077 | ||
|
|
2251a1653e | ||
|
|
ff1debcbce | ||
|
|
17e5564cd7 | ||
|
|
615576b3fd | ||
|
|
c0d3fbb47a | ||
|
|
09075b13b7 | ||
|
|
4e92c1a77c | ||
|
|
7cc49bc907 | ||
|
|
2e2b5bf873 | ||
|
|
66b1d17dd2 | ||
|
|
ee26e47c4d | ||
|
|
aedf6d2158 | ||
|
|
6e848e65b4 | ||
|
|
5c0108906c | ||
|
|
6c1f8ec8f7 | ||
|
|
dda36d2b40 | ||
|
|
1abf30c347 | ||
|
|
697b5a3d13 | ||
|
|
74e4c3397e | ||
|
|
c227bf59a6 | ||
|
|
0092f6d6d7 | ||
|
|
747477b27c | ||
|
|
4943dab50c | ||
|
|
5cac3ee1f7 | ||
|
|
fa5a227aff | ||
|
|
792e8595b8 | ||
|
|
9d62614ff4 | ||
|
|
48c0f6e8c6 | ||
|
|
31b17b384d | ||
|
|
858d7a9d6f | ||
|
|
48b6c48581 | ||
|
|
38be9dd367 | ||
|
|
7e5570ad72 | ||
|
|
16476caa1e | ||
|
|
6a5c28ac26 | ||
|
|
5335faa789 | ||
|
|
fd1ee6ef7d | ||
|
|
52d8c34bbf | ||
|
|
9eac41c0c3 | ||
|
|
6881316203 | ||
|
|
d4ee8379e8 | ||
|
|
f64e877491 | ||
|
|
f46a63cfcf | ||
|
|
65a71df10e | ||
|
|
fd6b0532ba | ||
|
|
e02d05a327 | ||
|
|
23740cdce0 | ||
|
|
a50f224227 | ||
|
|
f8ec327f11 | ||
|
|
1d76e037a4 | ||
|
|
98f5f38694 | ||
|
|
b78b95e67a | ||
|
|
5f60130952 | ||
|
|
5a82931fc2 | ||
|
|
ad49e3250b | ||
|
|
7ef95f4567 | ||
|
|
25a9d21fd7 | ||
|
|
b849df1dc1 | ||
|
|
1519ccb8e2 | ||
|
|
47e88e7bb4 | ||
|
|
c86aef999c | ||
|
|
2f9d7ab826 | ||
|
|
b4311b8a59 | ||
|
|
04a97a9923 | ||
|
|
c7624f9092 | ||
|
|
fc29fc6c6d | ||
|
|
7afc501db5 | ||
|
|
8ed5672e95 | ||
|
|
951c9f56c5 | ||
|
|
2c0e079aa2 | ||
|
|
a8e7ea9c80 | ||
|
|
30143f833a | ||
|
|
ad88daef9a | ||
|
|
9eb80eb6ca | ||
|
|
112de6e81c | ||
|
|
d01f903a9e | ||
|
|
af6d0aff7c | ||
|
|
edf8621e8f | ||
|
|
eeb15c624a | ||
|
|
79e2d49a3d | ||
|
|
628395e447 | ||
|
|
6cb6e6444b | ||
|
|
1b9aa23761 | ||
|
|
537c385ecf | ||
|
|
c0f7d6e7ff | ||
|
|
78df96f888 | ||
|
|
829957090d | ||
|
|
026c8f37ea | ||
|
|
97340c6aac | ||
|
|
bbe54eae48 | ||
|
|
9137207055 | ||
|
|
0ef30ef651 | ||
|
|
5ae8a6c9e4 | ||
|
|
ace1dcd0b8 | ||
|
|
5df487d6bd | ||
|
|
6e548749e1 | ||
|
|
99885d9f28 | ||
|
|
83163e11e3 | ||
|
|
8c191fee67 | ||
|
|
ff9862fa06 | ||
|
|
db0cea7051 | ||
|
|
305c713a57 | ||
|
|
8a5f93e268 | ||
|
|
c4d262150b | ||
|
|
94f161f7e6 | ||
|
|
2c5bfb3f4c | ||
|
|
8e12837a77 | ||
|
|
4385d84f01 | ||
|
|
214bb28c4c | ||
|
|
14c2285ac8 | ||
|
|
18cbe578f0 | ||
|
|
e19ded8365 | ||
|
|
0150008075 | ||
|
|
b0bca65cab | ||
|
|
cb95b9ba4f | ||
|
|
4a840288c5 | ||
|
|
11b1d6638d | ||
|
|
2225807a36 | ||
|
|
a8baca81d5 | ||
|
|
30161c7178 | ||
|
|
e222d147f6 | ||
|
|
3ddc41707c | ||
|
|
a245055150 | ||
|
|
ba5fdf2027 | ||
|
|
e1999e5ce8 | ||
|
|
be4e0b5e35 | ||
|
|
82c381b80d | ||
|
|
7d71aa96b9 | ||
|
|
93408e52c1 | ||
|
|
cea03df4eb | ||
|
|
72ee5f60b9 | ||
|
|
f6a8e5634b | ||
|
|
868e77c983 | ||
|
|
2a3fd42ca1 | ||
|
|
596a26bfb6 | ||
|
|
2fc8cea9ef | ||
|
|
6f8a5c2bfc | ||
|
|
260901351f | ||
|
|
66845e58db | ||
|
|
0e9e549bea | ||
|
|
785611414e | ||
|
|
19267ee001 | ||
|
|
65326916ca | ||
|
|
0b925ccf33 | ||
|
|
58505d2b50 | ||
|
|
ecae504a80 | ||
|
|
844bc5b44f | ||
|
|
c1dcf82fbd | ||
|
|
336406ddff | ||
|
|
81e8e650bf | ||
|
|
af6308e1b3 | ||
|
|
aae552f374 | ||
|
|
b4c1ee786a | ||
|
|
61da88114d | ||
|
|
279859ce81 | ||
|
|
820bb075a3 | ||
|
|
d96bd76ca9 | ||
|
|
7c56c889f2 | ||
|
|
3547fb26ad | ||
|
|
ac1363b377 | ||
|
|
6b5c90ee86 | ||
|
|
8164fa57ef | ||
|
|
96c9f229e2 | ||
|
|
58313f5fe0 | ||
|
|
738a9c3da1 | ||
|
|
0f10ed9ffc | ||
|
|
294e05cb06 | ||
|
|
1598dcbfbc | ||
|
|
cf2d6a47c2 | ||
|
|
c8fb334dae | ||
|
|
93dba0bbee | ||
|
|
2832d876fd | ||
|
|
5cd89cee6a | ||
|
|
2f69861361 | ||
|
|
8f51d9b0ea | ||
|
|
3a2b6d79fb | ||
|
|
67ede69685 | ||
|
|
17c4c9b2ef | ||
|
|
0319d43942 | ||
|
|
dcd088fd58 | ||
|
|
9875ded710 | ||
|
|
e26cd95ef9 | ||
|
|
1bb8e8c709 | ||
|
|
09617fa606 | ||
|
|
62a6d11332 | ||
|
|
8f00dbf23e | ||
|
|
8fd624e0b7 | ||
|
|
cef6521a2b | ||
|
|
da1217972a | ||
|
|
9efacb68b6 | ||
|
|
b3c22f96d8 | ||
|
|
6bf15655b7 | ||
|
|
ee3dc30985 | ||
|
|
21da017f8e | ||
|
|
38b4810d9e | ||
|
|
d49aae69ab | ||
|
|
012fefa3ea | ||
|
|
1f91b9a72f | ||
|
|
e061d9eb75 | ||
|
|
00cd04e103 | ||
|
|
4b3b1a723f | ||
|
|
2d3a43c202 | ||
|
|
e8e751668d | ||
|
|
c6e0a17aaa | ||
|
|
066d81446c | ||
|
|
a63b07cf2e | ||
|
|
0ab96fa413 | ||
|
|
e064c1cfc4 | ||
|
|
2913699597 | ||
|
|
c413623a22 | ||
|
|
92f08605df | ||
|
|
3fb32ad81c | ||
|
|
760dbad5ac | ||
|
|
878933bc07 | ||
|
|
603ebff771 | ||
|
|
c23ed70df4 | ||
|
|
d21598cf1c | ||
|
|
34f1b5d662 | ||
|
|
c493aca11b | ||
|
|
cc937d600b | ||
|
|
fcbe61cb92 | ||
|
|
b39f01a023 | ||
|
|
794ad35f84 | ||
|
|
729b07798e | ||
|
|
f2514f68b8 | ||
|
|
30d4044d20 | ||
|
|
e7cd6e49e8 | ||
|
|
75276d37e4 | ||
|
|
5a92c4f3ee | ||
|
|
ae6fb22fae | ||
|
|
ccd98606a1 | ||
|
|
7f2ed5d038 | ||
|
|
d24741ab4b | ||
|
|
9ac5eabff2 | ||
|
|
18b5fafa41 | ||
|
|
8a76bb05ac | ||
|
|
ad5b5c7c20 | ||
|
|
fe7d43f669 | ||
|
|
aad23f3de5 | ||
|
|
9c33093b01 | ||
|
|
c94a5dfa1f | ||
|
|
143973531c | ||
|
|
7db590950c | ||
|
|
7e65a52062 | ||
|
|
226d118d28 | ||
|
|
0e3bd186fe | ||
|
|
50e8dfc86d | ||
|
|
a023e03074 | ||
|
|
a0a592f064 | ||
|
|
4d86edd65e | ||
|
|
c597bc1dca | ||
|
|
a3d45fd4b9 | ||
|
|
e16d3c2e3f | ||
|
|
e251127f6e | ||
|
|
58b8917739 | ||
|
|
ad423e921a | ||
|
|
b82231f3ea | ||
|
|
f976800cde | ||
|
|
4973c62618 | ||
|
|
786528f9b2 | ||
|
|
661409b99d | ||
|
|
702bb3acfa | ||
|
|
8c6d2a1150 | ||
|
|
1295fb7fd2 | ||
|
|
d3fbb9a391 | ||
|
|
2b14cf0225 | ||
|
|
a78f8a3633 | ||
|
|
c4868dabac | ||
|
|
faf848dca5 | ||
|
|
05edffe173 | ||
|
|
4b3862443a | ||
|
|
536ebd7513 | ||
|
|
7dce39d79c | ||
|
|
a8389304d6 | ||
|
|
649d4ac848 | ||
|
|
86b5cb81fc | ||
|
|
1ffcf9e7b4 | ||
|
|
a665d6ed20 | ||
|
|
47c05922ae | ||
|
|
7db080b418 | ||
|
|
57e4b65059 | ||
|
|
5aa28903dd |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "src/views/xpack"]
|
||||
path = src/views/xpack
|
||||
url = git@github.com:jumpserver/lina-xpack.git
|
||||
|
||||
@@ -46,7 +46,7 @@ server {
|
||||
|
||||
|
||||
## License & Copyright
|
||||
Copyright (c) 2014-2020 飞致云 FIT2CLOUD, All rights reserved.
|
||||
Copyright (c) 2014-2021 飞致云 FIT2CLOUD, All rights reserved.
|
||||
|
||||
Licensed under The GNU General Public License version 2 (GPLv2) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ server {
|
||||
listen 80;
|
||||
|
||||
location /ui/ {
|
||||
try_files $uri / /ui/index.html;
|
||||
alias /opt/lina/;
|
||||
try_files $uri / /ui/index.html;
|
||||
alias /opt/lina/;
|
||||
}
|
||||
|
||||
location / {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"dependencies": {
|
||||
"@ztree/ztree_v3": "3.5.44",
|
||||
"axios": "0.18.1",
|
||||
"axios-retry": "^3.1.9",
|
||||
"deepmerge": "^4.2.2",
|
||||
"echarts": "^4.7.0",
|
||||
"element-ui": "2.13.2",
|
||||
@@ -82,8 +83,8 @@
|
||||
"less-loader": "^5.0.0",
|
||||
"lint-staged": "^10.1.2",
|
||||
"mockjs": "1.0.1-beta3",
|
||||
"node-sass": "^4.9.0",
|
||||
"runjs": "^4.3.2",
|
||||
"sass": "^1.26.10",
|
||||
"sass-loader": "^7.1.0",
|
||||
"script-ext-html-webpack-plugin": "2.1.3",
|
||||
"script-loader": "0.7.2",
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta http-equiv="Expires" content="0">
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
<meta http-equiv="Cache-control" content="no-cache">
|
||||
<meta http-equiv="Cache" content="no-cache">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= webpackConfig.name %></title>
|
||||
|
||||
8
src/api/ticket.js
Normal file
8
src/api/ticket.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getTicketOpenCount(assign) {
|
||||
return request({
|
||||
url: `/api/v1/tickets/tickets/?assignees__id=${assign}&status=open&offset=0&limit=15&display=1&draw=1/`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -65,3 +65,7 @@ export function logout() {
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
export function refreshSessionIdAge() {
|
||||
return getProfile()
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<div :class="grouped ? 'el-button-group' : ''">
|
||||
<el-button v-for="item in iActions" :key="item.name" :size="size" v-bind="item" @click="handleClick(item.name)">
|
||||
<el-tooltip v-if="['actionExport', 'actionImport', 'actionRefresh'].indexOf(item.name) !== -1" effect="dark" :content="item.tip" placement="top">
|
||||
<el-tooltip v-if="item.tip" effect="dark" :content="item.tip" placement="top">
|
||||
<i v-if="item.fa" :class="'fa ' + item.fa" />{{ item.title }}
|
||||
</el-tooltip>
|
||||
<span v-else>
|
||||
<i v-if="item.fa" :class="'fa ' + item.fa" />{{ item.title }}
|
||||
</span>
|
||||
</el-button>
|
||||
<el-dropdown v-if="iMoreActions.length > 0" trigger="click" @command="handleClick">
|
||||
<el-dropdown v-if="iMoreActions.length > 0" trigger="click" :placement="moreActionsPlacement" @command="handleClick">
|
||||
<el-button :size="size" :type="moreActionsType" class="btn-more-actions">
|
||||
{{ iMoreActionsTitle }}<i class="el-icon-arrow-down el-icon--right" />
|
||||
</el-button>
|
||||
@@ -52,6 +52,11 @@ export default {
|
||||
moreActionsType: {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
moreActionsPlacement: {
|
||||
type: String,
|
||||
default: 'bottom'
|
||||
// 居中对齐
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -114,6 +119,11 @@ export default {
|
||||
if (!has) {
|
||||
continue
|
||||
}
|
||||
// 是否有分割线
|
||||
const divided = this.checkItem(action, 'divided', false)
|
||||
delete action['divided']
|
||||
action.divided = divided
|
||||
|
||||
// 是否是disabled
|
||||
const can = this.checkItem(action, 'can')
|
||||
delete action['can']
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<AssetSelect ref="assetSelect" />
|
||||
<AssetSelect ref="assetSelect" :can-select="canSelect" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -49,6 +49,12 @@ export default {
|
||||
onAddSuccess: {
|
||||
type: Function,
|
||||
default: (objects, that) => {}
|
||||
},
|
||||
canSelect: {
|
||||
type: Function,
|
||||
default(row, index) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
||||
@@ -34,6 +34,12 @@ export default {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
canSelect: {
|
||||
type: Function,
|
||||
default(row, index) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -68,6 +74,7 @@ export default {
|
||||
tableConfig: {
|
||||
url: '/api/v1/assets/assets/',
|
||||
hasTree: true,
|
||||
canSelect: this.canSelect,
|
||||
columns: [
|
||||
{
|
||||
prop: 'hostname',
|
||||
@@ -81,7 +88,7 @@ export default {
|
||||
},
|
||||
{
|
||||
prop: 'ip',
|
||||
label: this.$t('assets.ip'),
|
||||
label: this.$t('assets.ipDomain'),
|
||||
sortable: 'custom'
|
||||
}
|
||||
],
|
||||
@@ -156,20 +163,20 @@ export default {
|
||||
.el-select{
|
||||
width: 100%;
|
||||
}
|
||||
.page /deep/ .page-heading{
|
||||
.page ::v-deep .page-heading{
|
||||
display: none;
|
||||
}
|
||||
.el-dialog__wrapper /deep/.el-dialog__body{
|
||||
.el-dialog__wrapper ::v-deep .el-dialog__body{
|
||||
padding: 5px 10px;
|
||||
}
|
||||
.page /deep/ .treebox{
|
||||
.page ::v-deep .treebox{
|
||||
height: inherit !important;
|
||||
}
|
||||
.asset-select-dialog >>> .transition-box:first-child {
|
||||
background-color: #f3f3f3 ;
|
||||
}
|
||||
|
||||
.el-dialog__wrapper /deep/.el-dialog__body .wrapper-content {
|
||||
.el-dialog__wrapper ::v-deep .el-dialog__body .wrapper-content {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ export default {
|
||||
{
|
||||
prop: 'ip',
|
||||
label: this.$t('assets.ip'),
|
||||
width: 140
|
||||
width: '120px'
|
||||
},
|
||||
{
|
||||
prop: 'username',
|
||||
@@ -130,7 +130,7 @@ export default {
|
||||
{
|
||||
prop: 'version',
|
||||
label: this.$t('assets.Version'),
|
||||
width: '50px'
|
||||
width: '70px'
|
||||
},
|
||||
{
|
||||
prop: 'date_created',
|
||||
@@ -154,7 +154,7 @@ export default {
|
||||
type: 'primary',
|
||||
callback: function(val) {
|
||||
this.MFAInfo.asset = val.cellValue
|
||||
if (this.MFAVerifyAt + this.MFA_TTl * 1000 > (new Date()).valueOf()) {
|
||||
if (!this.needMFAVerify) {
|
||||
this.showMFADialog = true
|
||||
this.MFAConfirmed = true
|
||||
this.$axios.get(`/api/v1/assets/asset-user-auth-infos/${this.MFAInfo.asset}/`).then(res => {
|
||||
@@ -176,7 +176,7 @@ export default {
|
||||
this.$axios.delete(`/api/v1/assets/asset-users/${val.cellValue}/`).then(() => {
|
||||
this.$message.success(this.$t('common.deleteSuccessMsg'))
|
||||
this.$refs.ListTable.reloadTable()
|
||||
}).catch(() => this.$message.error(this.$t('common.deleteFailedMsg')))
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -239,7 +239,8 @@ export default {
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'MFA_TTl',
|
||||
'MFAVerifyAt'
|
||||
'MFAVerifyAt',
|
||||
'publicSettings'
|
||||
]),
|
||||
needMFAVerify() {
|
||||
if (!this.publicSettings.SECURITY_VIEW_AUTH_NEED_MFA) {
|
||||
@@ -312,6 +313,7 @@ export default {
|
||||
key: ''
|
||||
}
|
||||
this.showDialog = false
|
||||
this.$refs.ListTable.reloadTable()
|
||||
},
|
||||
Onchange(e) {
|
||||
const vm = this
|
||||
@@ -351,6 +353,7 @@ export default {
|
||||
key: ''
|
||||
}
|
||||
this.showDialog = false
|
||||
this.$refs.ListTable.reloadTable()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ export default {
|
||||
groups: []
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.optionUrlMeta()
|
||||
},
|
||||
@@ -54,7 +53,7 @@ export default {
|
||||
this.meta = data.actions[this.method.toUpperCase()] || {}
|
||||
this.generateColumns()
|
||||
}).catch(err => {
|
||||
console.error(err)
|
||||
this.$log.error(err)
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
@@ -63,9 +62,11 @@ export default {
|
||||
switch (type) {
|
||||
case 'choice':
|
||||
type = 'radio-group'
|
||||
field.options = fieldMeta.choices.map(v => {
|
||||
return { label: v.display_name, value: v.value }
|
||||
})
|
||||
if (!fieldMeta.read_only) {
|
||||
field.options = fieldMeta.choices.map(v => {
|
||||
return { label: v.display_name, value: v.value }
|
||||
})
|
||||
}
|
||||
break
|
||||
case 'datetime':
|
||||
type = 'date-picker'
|
||||
@@ -76,6 +77,9 @@ export default {
|
||||
case 'field':
|
||||
type = ''
|
||||
field.component = Select2
|
||||
if (fieldMeta.required) {
|
||||
field.el.clearable = false
|
||||
}
|
||||
break
|
||||
case 'string':
|
||||
type = 'input'
|
||||
@@ -89,12 +93,14 @@ export default {
|
||||
break
|
||||
}
|
||||
if (type === 'radio-group') {
|
||||
const options = fieldMeta.choices.map(v => {
|
||||
return { label: v.display_name, value: v.value }
|
||||
})
|
||||
if (options.length > 4) {
|
||||
type = 'select'
|
||||
field.el.filterable = true
|
||||
if (!fieldMeta.read_only) {
|
||||
const options = fieldMeta.choices.map(v => {
|
||||
return { label: v.display_name, value: v.value }
|
||||
})
|
||||
if (options.length > 4) {
|
||||
type = 'select'
|
||||
field.el.filterable = true
|
||||
}
|
||||
}
|
||||
}
|
||||
field.type = type
|
||||
@@ -128,7 +134,8 @@ export default {
|
||||
},
|
||||
generateField(name) {
|
||||
let field = { id: name, prop: name, el: {}, attrs: {}}
|
||||
const fieldMeta = this.meta[name] || {}
|
||||
// const fieldMeta = this.meta[name] || this.meta['attrs']['children'][name] || {}
|
||||
const fieldMeta = this.meta[name] || ((this.meta['attrs']) ? (this.meta['attrs']['children'][name]) : {})
|
||||
field.label = fieldMeta.label
|
||||
field = this.generateFieldByType(fieldMeta.type, field, fieldMeta)
|
||||
field = this.generateFieldByName(name, field)
|
||||
@@ -146,12 +153,25 @@ export default {
|
||||
})
|
||||
return this.generateFields(fields)
|
||||
},
|
||||
generateFieldAttrs(name) {
|
||||
const fields = []
|
||||
Object.keys(this.meta[name]['children']).forEach((key, i) => {
|
||||
const filed = this.generateField(key)
|
||||
fields.push(filed)
|
||||
})
|
||||
return fields
|
||||
},
|
||||
generateFields(data) {
|
||||
let fields = []
|
||||
for (let field of data) {
|
||||
if (field instanceof Array) {
|
||||
const items = this.generateFieldGroup(field)
|
||||
fields = [...fields, ...items]
|
||||
} else if (field === 'attrs') {
|
||||
const items = this.generateFieldAttrs(field)
|
||||
fields = [...fields, ...items]
|
||||
// 修改title插入ID
|
||||
this.groups[this.groups.length - 1].name = items[0].id
|
||||
} else if (typeof field === 'string') {
|
||||
field = this.generateField(field)
|
||||
fields.push(field)
|
||||
@@ -165,15 +185,23 @@ export default {
|
||||
},
|
||||
generateColumns() {
|
||||
this.totalFields = this.generateFields(this.fields)
|
||||
this.$log.debug('Total fields: ', this.totalFields)
|
||||
},
|
||||
setFieldError(name, error) {
|
||||
const field = this.totalFields.find((v) => v.prop === name)
|
||||
if (!field) {
|
||||
return
|
||||
}
|
||||
if (field.attrs.error === error) {
|
||||
error += '.'
|
||||
if (typeof error === 'object') {
|
||||
const str = error
|
||||
error = ''
|
||||
Object.keys(str).forEach(key => {
|
||||
error += `${parseInt(key) + 1}.${str[key][0]} `
|
||||
})
|
||||
}
|
||||
// if (field.attrs.error === error) {
|
||||
// error += '.'
|
||||
// }
|
||||
field.attrs.error = error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,9 @@ export default {
|
||||
}
|
||||
const option = {
|
||||
label: field.label,
|
||||
type: field.type,
|
||||
value: name
|
||||
|
||||
}
|
||||
if (field.type === 'choice' && field.choices) {
|
||||
option.children = field.choices.map(item => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<DataTable v-if="!loading" ref="dataTable" v-loading="loading" :config="iConfig" v-bind="$attrs" v-on="$listeners" />
|
||||
<DataTable v-if="!loading" ref="dataTable" v-loading="loading" :config="iConfig" v-bind="$attrs" v-on="$listeners" @filter-change="filterChange" />
|
||||
</template>
|
||||
|
||||
<script type="text/jsx">
|
||||
@@ -15,6 +15,10 @@ export default {
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
filterTable: {
|
||||
type: Function,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -118,6 +122,37 @@ export default {
|
||||
}
|
||||
return col
|
||||
},
|
||||
addFilterIfNeed(col) {
|
||||
if (col.prop) {
|
||||
const column = this.meta[col.prop] || {}
|
||||
if (!column.filter) {
|
||||
return col
|
||||
}
|
||||
if (column.type === 'boolean') {
|
||||
col.filters = [
|
||||
{ text: this.$t('common.Yes'), value: true },
|
||||
{ text: this.$t('common.No'), value: false }
|
||||
]
|
||||
col.sortable = false
|
||||
col['column-key'] = col.prop
|
||||
}
|
||||
if (column.type === 'choice' && column.choices) {
|
||||
col.filters = column.choices.map(item => {
|
||||
if (typeof (item.value) === 'boolean') {
|
||||
if (item.value) {
|
||||
return { text: item.display_name, value: 'True' }
|
||||
} else {
|
||||
return { text: item.display_name, value: 'False' }
|
||||
}
|
||||
}
|
||||
return { text: item.display_name, value: item.value }
|
||||
})
|
||||
col.sortable = false
|
||||
col['column-key'] = col.prop
|
||||
}
|
||||
}
|
||||
return col
|
||||
},
|
||||
generateColumn(name) {
|
||||
const colMeta = this.meta[name] || {}
|
||||
const customMeta = this.config.columnsMeta ? this.config.columnsMeta[name] : {}
|
||||
@@ -127,6 +162,7 @@ export default {
|
||||
col = this.generateColumnByType(colMeta.type, col)
|
||||
col = Object.assign(col, customMeta)
|
||||
col = this.addHelpTipsIfNeed(col)
|
||||
col = this.addFilterIfNeed(col)
|
||||
return col
|
||||
},
|
||||
generateColumns() {
|
||||
@@ -142,6 +178,12 @@ export default {
|
||||
}
|
||||
config.columns = columns
|
||||
this.iConfig = config
|
||||
},
|
||||
filterChange(filters) {
|
||||
const key = Object.keys(filters)[0]
|
||||
const attr = {}
|
||||
attr[key] = filters[key][0]
|
||||
this.filterTable(attr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,8 +139,6 @@ export default {
|
||||
treeNode.name = treeNode.name + ' (' + assetsAmount + ')'
|
||||
this.zTree.updateNode(treeNode)
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
}).catch(error => {
|
||||
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + error))
|
||||
})
|
||||
},
|
||||
onBodyMouseDown: function(event) {
|
||||
@@ -159,6 +157,11 @@ export default {
|
||||
y -= (offset.top + scrollTop) / 3 - 10
|
||||
x += document.body.scrollLeft
|
||||
y += document.body.scrollTop + document.documentElement.scrollTop
|
||||
|
||||
if (y + $(`#${rMenuID} ul`).height() >= window.innerHeight) {
|
||||
y -= $(`#${rMenuID} ul`).height()
|
||||
}
|
||||
|
||||
this.rMenu.css({ 'top': y + 'px', 'left': x + 'px', 'visibility': 'visible' })
|
||||
$(`#${rMenuID} ul`).show()
|
||||
$('body').bind('mousedown', this.onBodyMouseDown)
|
||||
@@ -237,10 +240,7 @@ export default {
|
||||
})
|
||||
},
|
||||
refresh: function() {
|
||||
this.$axios.post(
|
||||
'/api/v1/assets/nodes/00000000-0000-0000-0000-000000000000/tasks/',
|
||||
{ action: 'refresh_cache' }
|
||||
)
|
||||
|
||||
},
|
||||
getSelectedNodes: function() {
|
||||
return this.zTree.getSelectedNodes()
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<el-form-item>
|
||||
<el-button v-for="button in moreButtons" :key="button.title" size="small" v-bind="button" @click="handleClick(button)">{{ button.title }}</el-button>
|
||||
<el-button v-if="defaultButton && hasReset" size="small" @click="resetForm('form')">{{ $t('common.Reset') }}</el-button>
|
||||
<el-button v-if="defaultButton && hasSaveContinue" size="small" @click="submitForm('form', true)">{{ $t('common.SaveAndAddAnother') }}</el-button>
|
||||
<el-button v-if="defaultButton" size="small" :loading="isSubmitting" type="primary" @click="submitForm('form')">{{ $t('common.Submit') }}</el-button>
|
||||
</el-form-item>
|
||||
</ElFormRender>
|
||||
@@ -35,6 +36,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hasSaveContinue: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
fields: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
@@ -60,11 +65,11 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
// 获取表单数据
|
||||
submitForm(formName) {
|
||||
submitForm(formName, addContinue) {
|
||||
const form = this.$refs[formName]
|
||||
form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$emit('submit', form.getFormValue(), form)
|
||||
this.$emit('submit', form.getFormValue(), form, addContinue)
|
||||
} else {
|
||||
this.$emit('invalid', valid)
|
||||
return false
|
||||
@@ -77,7 +82,7 @@ export default {
|
||||
},
|
||||
handleClick(button) {
|
||||
const callback = button.callback || function(values, form) {
|
||||
console.log('Click ', button.title, ': ', values)
|
||||
// console.log('Click ', button.title, ': ', values)
|
||||
}
|
||||
const form = this.$refs['form']
|
||||
const values = form.getFormValue()
|
||||
@@ -88,27 +93,27 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.el-form /deep/ .el-form-item {
|
||||
.el-form ::v-deep .el-form-item {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.el-form /deep/ .el-form-item__content {
|
||||
.el-form ::v-deep .el-form-item__content {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.el-form /deep/ .el-form-item__label {
|
||||
.el-form ::v-deep .el-form-item__label {
|
||||
padding: 0 30px 0 0;
|
||||
}
|
||||
|
||||
.el-form /deep/ .el-form-item__error {
|
||||
.el-form ::v-deep .el-form-item__error {
|
||||
position: inherit;
|
||||
}
|
||||
|
||||
.el-form /deep/ .form-group-header {
|
||||
.el-form ::v-deep .form-group-header {
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
.el-form /deep/ .help-block {
|
||||
.el-form ::v-deep .help-block {
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
@@ -116,7 +121,7 @@ export default {
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.el-form /deep/ .help-block a {
|
||||
.el-form ::v-deep .help-block a {
|
||||
color: #1c84c6;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
v-bind="tableAttrs"
|
||||
:data="data"
|
||||
:row-class-name="rowClassName"
|
||||
v-on="$listeners"
|
||||
@selection-change="selectStrategy.onSelectionChange"
|
||||
@select="selectStrategy.onSelect"
|
||||
@select-all="selectStrategy.onSelectAll($event, selectable)"
|
||||
@select-all="selectStrategy.onSelectAll($event, canSelect)"
|
||||
@sort-change="onSortChange"
|
||||
>
|
||||
<!--TODO 不用jsx写, 感觉template逻辑有点不清晰了-->
|
||||
@@ -90,11 +91,14 @@
|
||||
|
||||
<!--非树-->
|
||||
<template v-else>
|
||||
<el-data-table-column v-if="hasSelection" type="selection" :align="selectionAlign" />
|
||||
<el-data-table-column v-if="hasSelection" type="selection" :align="selectionAlign" :selectable="canSelect" />
|
||||
<el-data-table-column
|
||||
v-for="col in columns"
|
||||
:key="col.prop"
|
||||
:formatter="typeof col.formatter === 'function' ? col.formatter : null"
|
||||
:filters="col.filters || null"
|
||||
:filter-multiple="false"
|
||||
:filter-method="typeof col.filterMethod === 'function' ? col.filterMethod : null"
|
||||
v-bind="{align: columnsAlign, ...col}"
|
||||
>
|
||||
<template v-if="col.formatter && typeof col.formatter !== 'function'" v-slot:default="{row, column, index}">
|
||||
@@ -422,7 +426,7 @@ export default {
|
||||
onEdit: {
|
||||
type: Function,
|
||||
default(row) {
|
||||
console.log('On delete row')
|
||||
// console.log('On delete row')
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -713,6 +717,12 @@ export default {
|
||||
hasDetail: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
canSelect: {
|
||||
type: Function,
|
||||
default(row, index) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -953,6 +963,8 @@ export default {
|
||||
})
|
||||
},
|
||||
search(attrs, reset) {
|
||||
// 重置搜索结果到第一页
|
||||
this.page = defaultFirstPage
|
||||
// Orange 重置查询对象
|
||||
if (reset) {
|
||||
this.innerQuery = merge({}, attrs)
|
||||
@@ -962,6 +974,8 @@ export default {
|
||||
return this.getList()
|
||||
},
|
||||
searchDate(attrs) {
|
||||
// 重置搜索结果到第一页
|
||||
this.page = defaultFirstPage
|
||||
this.innerQuery = merge(this.innerQuery, attrs)
|
||||
return this.getList()
|
||||
},
|
||||
@@ -996,7 +1010,7 @@ export default {
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
if (this.size === val) return
|
||||
|
||||
this.$emit('sizeChange', val)
|
||||
this.page = defaultFirstPage
|
||||
this.size = val
|
||||
this.getList()
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
.el-data-table /deep/ .el-pagination{
|
||||
.el-data-table ::v-deep .el-pagination{
|
||||
text-align: center !important;
|
||||
}
|
||||
.el-data-table /deep/ .el-table td{
|
||||
.el-data-table ::v-deep .el-table td{
|
||||
padding: 4px 0;
|
||||
}
|
||||
.el-data-table /deep/ .el-table th{
|
||||
.el-data-table ::v-deep .el-table th{
|
||||
padding: 4px 0;
|
||||
}
|
||||
.el-data-table/deep/ .el-form-item{
|
||||
.el-data-table ::v-deep .el-form-item{
|
||||
margin-bottom:10px !important ;
|
||||
margin-top:10px;
|
||||
}
|
||||
.el-data-table/deep/ .el-pagination{
|
||||
.el-data-table ::v-deep .el-pagination{
|
||||
padding:15px 0 !important ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
<template>
|
||||
<ElDatableTable ref="table" class="el-table" v-bind="tableConfig" @update="onUpdate" v-on="iListeners" />
|
||||
<ElDatableTable
|
||||
ref="table"
|
||||
class="el-table"
|
||||
v-bind="tableConfig"
|
||||
@update="onUpdate"
|
||||
v-on="iListeners"
|
||||
@sizeChange="handleSizeChange"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { default as ElDatableTable } from './compenents/el-data-table'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'DataTable',
|
||||
@@ -58,7 +66,6 @@ export default {
|
||||
pageCount: 5,
|
||||
paginationLayout: 'total, sizes, prev, pager, next',
|
||||
paginationSizes: [15, 30, 50, 100],
|
||||
paginationSize: 15,
|
||||
paginationBackground: true,
|
||||
transformQuery: query => {
|
||||
if (query.page && query.size) {
|
||||
@@ -85,12 +92,17 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
tableConfig() {
|
||||
const config = Object.assign(this.defaultConfig, this.config)
|
||||
const tableDefaultConfig = this.defaultConfig
|
||||
tableDefaultConfig.paginationSize = _.get(this.globalTableConfig, 'paginationSize', 15)
|
||||
const config = Object.assign(tableDefaultConfig, this.config)
|
||||
return config
|
||||
},
|
||||
iListeners() {
|
||||
return Object.assign({}, this.$listeners, this.tableConfig.listeners)
|
||||
}
|
||||
},
|
||||
...mapGetters({
|
||||
'globalTableConfig': 'tableConfig'
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
config: {
|
||||
@@ -131,6 +143,14 @@ export default {
|
||||
this.toggleRowSelection(row, true)
|
||||
}
|
||||
}
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.$store.commit('table/SET_TABLE_CONFIG',
|
||||
{
|
||||
key: 'paginationSize',
|
||||
value: val
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,16 +158,16 @@ export default {
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
.el-table /deep/ .el-table__row > td {
|
||||
.el-table ::v-deep .el-table__row > td {
|
||||
line-height: 1.5;
|
||||
padding: 8px 0;
|
||||
}
|
||||
.el-table /deep/ .el-table__row > td> div > span {
|
||||
.el-table ::v-deep .el-table__row > td> div > span {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.el-table /deep/ .el-table__header > thead > tr >th {
|
||||
.el-table ::v-deep .el-table__header > thead > tr >th {
|
||||
padding: 8px 0;
|
||||
background-color: #F5F5F6;
|
||||
font-size: 13px;
|
||||
@@ -158,11 +178,11 @@ export default {
|
||||
}
|
||||
|
||||
//分页
|
||||
.el-pagination /deep/ .el-pagination__total{
|
||||
.el-pagination ::v-deep .el-pagination__total{
|
||||
float: left;
|
||||
}
|
||||
|
||||
.el-pagination /deep/ .el-pagination__sizes{
|
||||
.el-pagination ::v-deep .el-pagination__sizes{
|
||||
float: left;
|
||||
}
|
||||
//修改颜色
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="treebox">
|
||||
<ul v-show="loading" class="ztree">
|
||||
{{ this.$t('common.tree.Loading') }}...
|
||||
</ul>
|
||||
<div v-show="!loading" class="treebox">
|
||||
<ul :id="iZTreeID" class="ztree">
|
||||
{{ this.$t('common.tree.Loading') }}...
|
||||
</ul>
|
||||
@@ -22,6 +25,7 @@
|
||||
import $ from '@/utils/jquery-vendor.js'
|
||||
import '@ztree/ztree_v3/js/jquery.ztree.all.min.js'
|
||||
import '@/styles/ztree.css'
|
||||
import axiosRetry from 'axios-retry'
|
||||
|
||||
const defaultObject = {
|
||||
type: Object,
|
||||
@@ -39,7 +43,9 @@ export default {
|
||||
iZTreeID: `zTree_${this._uid}`,
|
||||
iRMenuID: `rMenu_${this._uid}`,
|
||||
zTree: '',
|
||||
rMenu: ''
|
||||
rMenu: '',
|
||||
init: false,
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -52,11 +58,30 @@ export default {
|
||||
// $('.treebox').css('height', window.innerHeight - 60)
|
||||
},
|
||||
beforeDestroy() {
|
||||
$.fn.zTree.destroy()
|
||||
$.fn.zTree.destroy(this.iZTreeID)
|
||||
},
|
||||
methods: {
|
||||
initTree: function() {
|
||||
this.$axios.get(this.treeSetting.treeUrl).then(res => {
|
||||
const vm = this
|
||||
let treeUrl
|
||||
if (this.init) {
|
||||
this.loading = true
|
||||
}
|
||||
if (this.init && this.treeSetting.treeUrl.indexOf('/perms/') !== -1 && this.treeSetting.treeUrl.indexOf('rebuild_tree') === -1) {
|
||||
treeUrl = (this.treeSetting.treeUrl.indexOf('?') === -1) ? `${this.treeSetting.treeUrl}?rebuild_tree=1` : `${this.treeSetting.treeUrl}&rebuild_tree=1`
|
||||
} else {
|
||||
treeUrl = this.treeSetting.treeUrl
|
||||
}
|
||||
this.$axios.get(treeUrl, {
|
||||
'axios-retry': {
|
||||
retries: 20,
|
||||
retryCondition: e => {
|
||||
return axiosRetry.isNetworkOrIdempotentRequestError(e) || e.response.status === 409
|
||||
},
|
||||
shouldResetTimeout: true,
|
||||
retryDelay: () => { return 5000 }
|
||||
}
|
||||
}).then(res => {
|
||||
if (!res) {
|
||||
res = []
|
||||
}
|
||||
@@ -65,6 +90,10 @@ export default {
|
||||
name: this.$t('common.tree.Empty')
|
||||
})
|
||||
}
|
||||
this.treeSetting.treeUrl = treeUrl
|
||||
if (this.init) {
|
||||
vm.zTree.destroy()
|
||||
}
|
||||
this.zTree = $.fn.zTree.init($(`#${this.iZTreeID}`), this.treeSetting, res)
|
||||
if (this.treeSetting.showRefresh) {
|
||||
this.rootNodeAddDom(
|
||||
@@ -79,6 +108,9 @@ export default {
|
||||
if (this.treeSetting.otherMenu) {
|
||||
$('.menu-actions').append(this.otherMenu)
|
||||
}
|
||||
}).finally(_ => {
|
||||
vm.loading = false
|
||||
vm.init = true
|
||||
})
|
||||
},
|
||||
rootNodeAddDom: function(ztree, callback) {
|
||||
@@ -95,7 +127,6 @@ export default {
|
||||
}
|
||||
const refreshIconRef = $('#tree-refresh')
|
||||
refreshIconRef.bind('click', function() {
|
||||
ztree.destroy()
|
||||
const result = callback()
|
||||
if (result && result.then) {
|
||||
result.finally(() => {
|
||||
@@ -158,7 +189,7 @@ export default {
|
||||
top: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
.ztree /deep/ .fa-refresh {
|
||||
.ztree ::v-deep .fa-refresh {
|
||||
font: normal normal normal 14px/1 FontAwesome !important;
|
||||
}
|
||||
.dropdown a:hover {
|
||||
|
||||
@@ -37,8 +37,8 @@ export default {
|
||||
showRemoveBtn: false,
|
||||
showRenameBtn: false,
|
||||
drag: {
|
||||
isCopy: true,
|
||||
isMove: true
|
||||
isCopy: false,
|
||||
isMove: false
|
||||
}
|
||||
},
|
||||
callback: {
|
||||
@@ -72,7 +72,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
defaultCallback: function(action) {
|
||||
console.log(action)
|
||||
// console.log(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,17 +93,17 @@ export default {
|
||||
|
||||
<style lang='less' scoped>
|
||||
.datepicker{
|
||||
width: 240px;
|
||||
width: 233px;
|
||||
}
|
||||
.el-input__inner{
|
||||
border: 1px solid #dcdee2;
|
||||
border-radius: 3px;
|
||||
height: 36px;
|
||||
}
|
||||
/*.el-date-editor /deep/ .el-input__icon{*/
|
||||
/*.el-date-editor ::v-deep .el-input__icon{*/
|
||||
/* line-height: 28px;*/
|
||||
/*}*/
|
||||
.el-date-editor /deep/ .el-range-separator{
|
||||
.el-date-editor ::v-deep .el-range-separator{
|
||||
line-height: 28px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,7 +3,7 @@ export default {
|
||||
name: 'ItemValue',
|
||||
props: {
|
||||
value: {
|
||||
type: [String, Number, Function, Array, Object],
|
||||
type: [String, Number, Function, Array, Object, Boolean],
|
||||
default: ''
|
||||
},
|
||||
item: {
|
||||
@@ -15,10 +15,21 @@ export default {
|
||||
default: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toChoicesDisplay(value) {
|
||||
if (!value) {
|
||||
return this.$t('common.No')
|
||||
}
|
||||
return this.$t('common.Yes')
|
||||
}
|
||||
},
|
||||
render(h) {
|
||||
if (typeof this.formatter === 'function') {
|
||||
return this.formatter(this.item, this.value)
|
||||
}
|
||||
if (typeof this.value === 'boolean') {
|
||||
return <span>{this.toChoicesDisplay(this.value)}</span>
|
||||
}
|
||||
return <span>{this.value}</span>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
<template>
|
||||
<IBox :title="title" fa="fa-info-circle">
|
||||
<div class="content">
|
||||
<el-row v-if="this.$route.params.id" :gutter="10" class="item">
|
||||
<el-col :span="6"><div :style="{ 'text-align': align }" class="item-label"><label>ID: </label></div></el-col>
|
||||
<el-col :span="18"><div class="item-text">{{ this.$route.params.id }}</div></el-col>
|
||||
</el-row>
|
||||
<el-row v-for="item in items" :key="'card-' + item.key" :gutter="10" class="item">
|
||||
<el-col :span="6"><div :style="{ 'text-align': align }" class="item-label"><label>{{ item.key }}: </label></div></el-col>
|
||||
<el-col :span="18"><div class="item-text">
|
||||
<ItemValue :value="item.value" v-bind="item" />
|
||||
</div></el-col>
|
||||
<el-col :span="6">
|
||||
<div :style="{ 'text-align': align }" class="item-label"><label>{{ item.key }}: </label></div>
|
||||
</el-col>
|
||||
<el-col :span="18">
|
||||
<div class="item-text">
|
||||
<ItemValue :value="item.value" v-bind="item" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<slot name="footer">
|
||||
<el-button v-if="showCancel" size="small" @click="onCancel">{{ cancelTitle }}</el-button>
|
||||
<el-button v-if="showConfirm" type="primary" size="small" @click="onConfirm">{{ confirmTitle }}</el-button>
|
||||
<el-button v-if="showConfirm" type="primary" size="small" :loading="loadingStatus" @click="onConfirm">{{ confirmTitle }}</el-button>
|
||||
</slot>
|
||||
</div>
|
||||
</el-dialog>
|
||||
@@ -42,6 +42,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
loadingStatus: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
confirmTitle: {
|
||||
type: String,
|
||||
default() {
|
||||
|
||||
@@ -65,22 +65,24 @@ export default {
|
||||
sortable: true,
|
||||
formatterArgs: {
|
||||
route: 'AssetDetail'
|
||||
}
|
||||
},
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
{
|
||||
prop: 'ip',
|
||||
label: this.$t('assets.IP'),
|
||||
width: '140px',
|
||||
sortable: 'custom'
|
||||
},
|
||||
{
|
||||
prop: 'systemUsers',
|
||||
label: this.$t('assets.SystemUsers'),
|
||||
align: 'center',
|
||||
width: '200px',
|
||||
formatter: SystemUserFormatter,
|
||||
formatterArgs: {
|
||||
getUrl: this.getShowUrl.bind(this)
|
||||
}
|
||||
},
|
||||
showOverflowTooltip: true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
<template>
|
||||
<Dialog v-if="showExportDialog" :title="$t('common.Export')" :visible.sync="showExportDialog" :destroy-on-close="true" @confirm="handleExportConfirm()" @cancel="handleExportCancel()">
|
||||
<el-form label-position="left" style="padding-left: 50px">
|
||||
<el-form-item :label="$t('common.fileType' )" :label-width="'100px'">
|
||||
<el-radio-group v-model="exportTypeOption">
|
||||
<el-radio v-for="option of exportTypeOptions" :key="option.value" style="padding: 10px 20px;" :label="option.value" :disabled="!option.can">{{ option.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item class="export-form" :label="this.$t('common.imExport.ExportRange')" :label-width="'100px'">
|
||||
<el-radio-group v-model="exportOption">
|
||||
<el-radio v-for="option of exportOptions" :key="option.value" class="export-item" :label="option.value" :disabled="!option.can">{{ option.label }}</el-radio>
|
||||
@@ -51,7 +56,8 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
showExportDialog: false,
|
||||
exportOption: '',
|
||||
exportOption: 'all',
|
||||
exportTypeOption: 'csv',
|
||||
meta: {}
|
||||
}
|
||||
},
|
||||
@@ -67,6 +73,8 @@ export default {
|
||||
const query = listTableRef.dataTable.getQuery()
|
||||
delete query['limit']
|
||||
delete query['offset']
|
||||
delete query['date_from']
|
||||
delete query['date_to']
|
||||
return query
|
||||
},
|
||||
tableHasQuery() {
|
||||
@@ -77,7 +85,7 @@ export default {
|
||||
{
|
||||
label: this.$t('common.imExport.ExportAll'),
|
||||
value: 'all',
|
||||
can: this.canExportAll
|
||||
can: this.canExportAll && !this.tableHasQuery
|
||||
},
|
||||
{
|
||||
label: this.$t('common.imExport.ExportOnlySelectedItems'),
|
||||
@@ -90,6 +98,20 @@ export default {
|
||||
can: this.tableHasQuery && this.canExportFiltered
|
||||
}
|
||||
]
|
||||
},
|
||||
exportTypeOptions() {
|
||||
return [
|
||||
{
|
||||
label: 'CSV',
|
||||
value: 'csv',
|
||||
can: true
|
||||
},
|
||||
{
|
||||
label: 'Excel',
|
||||
value: 'xlsx',
|
||||
can: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -121,7 +143,7 @@ export default {
|
||||
// delete query['limit']
|
||||
// delete query['offset']
|
||||
}
|
||||
query['format'] = 'csv'
|
||||
query['format'] = this.exportTypeOption
|
||||
const queryStr =
|
||||
(url.indexOf('?') > -1 ? '&' : '?') +
|
||||
queryUtil.stringify(query, '=', '&')
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
<template>
|
||||
<Dialog :title="$t('common.Import')" :visible.sync="showImportDialog" :destroy-on-close="true" @confirm="handleImportConfirm" @cancel="handleImportCancel()">
|
||||
<Dialog
|
||||
:title="$t('common.Import')"
|
||||
:visible.sync="showImportDialog"
|
||||
:destroy-on-close="true"
|
||||
:loading-status="loadStatus"
|
||||
@confirm="handleImportConfirm"
|
||||
@cancel="handleImportCancel()"
|
||||
>
|
||||
<el-form label-position="left" style="padding-left: 50px">
|
||||
<el-form-item :label="$t('common.fileType' )" :label-width="'100px'">
|
||||
<el-radio-group v-model="importTypeOption">
|
||||
<el-radio v-for="option of importTypeOptions" :key="option.value" class="export-item" :label="option.value" :disabled="!option.can">{{ option.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('common.Import' )" :label-width="'100px'">
|
||||
<el-radio v-model="importOption" class="export-item" label="1">{{ this.$t('common.Create') }}</el-radio>
|
||||
<el-radio v-model="importOption" class="export-item" label="2">{{ this.$t('common.Update') }}</el-radio>
|
||||
@@ -26,7 +38,7 @@
|
||||
:before-upload="beforeUpload"
|
||||
>
|
||||
<el-button size="mini" type="default">{{ this.$t('common.SelectFile') }}</el-button>
|
||||
<div slot="tip" :class="uploadHelpTextClass" style="line-height: 1.5">{{ this.$t('common.imExport.onlyCSVFilesTips') }}</div>
|
||||
<!-- <div slot="tip" :class="uploadHelpTextClass" style="line-height: 1.5">{{ this.$t('common.imExport.onlyCSVFilesTips') }}</div>-->
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -63,19 +75,36 @@ export default {
|
||||
showImportDialog: false,
|
||||
importOption: '1',
|
||||
isCsv: true,
|
||||
errorMsg: ''
|
||||
errorMsg: '',
|
||||
loadStatus: false,
|
||||
importTypeOption: 'csv'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasSelected() {
|
||||
return this.selectedRows.length > 0
|
||||
},
|
||||
importTypeOptions() {
|
||||
return [
|
||||
{
|
||||
label: 'CSV',
|
||||
value: 'csv',
|
||||
can: true
|
||||
},
|
||||
{
|
||||
label: 'Excel',
|
||||
value: 'xlsx',
|
||||
can: true
|
||||
}
|
||||
]
|
||||
},
|
||||
upLoadUrl() {
|
||||
return this.url
|
||||
},
|
||||
downloadImportTempUrl() {
|
||||
const baseUrl = (process.env.VUE_APP_ENV === 'production') ? (`${this.url}`) : (`${process.env.VUE_APP_BASE_API}${this.url}`)
|
||||
return baseUrl + '?format=csv&template=import&limit=1'
|
||||
const format = this.importTypeOption === 'csv' ? 'format=csv&template=import&limit=1' : 'format=xlsx&template=import&limit=1'
|
||||
const url = (this.url.indexOf('?') === -1) ? `${this.url}?${format}` : `${this.url}&${format}`
|
||||
return url
|
||||
},
|
||||
uploadHelpTextClass() {
|
||||
const cls = ['el-upload__tip']
|
||||
@@ -95,24 +124,28 @@ export default {
|
||||
this.$axios.put(
|
||||
this.upLoadUrl,
|
||||
item.file,
|
||||
{ headers: { 'Content-Type': 'text/csv' }, disableFlashErrorMsg: true }
|
||||
{ headers: { 'Content-Type': this.importTypeOption === 'csv' ? 'text/csv' : 'text/xlsx' }, disableFlashErrorMsg: true }
|
||||
).then((data) => {
|
||||
const msg = this.$t('common.imExport.updateSuccessMsg', { count: data.length })
|
||||
this.onSuccess(msg)
|
||||
}).catch(error => {
|
||||
this.catchError(error)
|
||||
}).finally(() => {
|
||||
this.loadStatus = false
|
||||
})
|
||||
},
|
||||
performCreate(item) {
|
||||
this.$axios.post(
|
||||
this.upLoadUrl,
|
||||
item.file,
|
||||
{ headers: { 'Content-Type': 'text/csv' }, disableFlashErrorMsg: true }
|
||||
{ headers: { 'Content-Type': this.importTypeOption === 'csv' ? 'text/csv' : 'text/xlsx' }, disableFlashErrorMsg: true }
|
||||
).then((data) => {
|
||||
const msg = this.$t('common.imExport.createSuccessMsg', { count: data.length })
|
||||
this.onSuccess(msg)
|
||||
}).catch(error => {
|
||||
this.catchError(error)
|
||||
}).finally(() => {
|
||||
this.loadStatus = false
|
||||
})
|
||||
},
|
||||
catchError(error) {
|
||||
@@ -149,6 +182,7 @@ export default {
|
||||
window.URL.revokeObjectURL(url)
|
||||
},
|
||||
handleImport(item) {
|
||||
this.loadStatus = true
|
||||
if (this.importOption === '1') {
|
||||
this.performCreate(item)
|
||||
} else {
|
||||
@@ -163,7 +197,8 @@ export default {
|
||||
}
|
||||
const spm = await createSourceIdCache(resources)
|
||||
const baseUrl = (process.env.VUE_APP_ENV === 'production') ? (`${this.url}`) : (`${process.env.VUE_APP_BASE_API}${this.url}`)
|
||||
const url = `${baseUrl}?format=csv&template=update&spm=` + spm.spm
|
||||
const format = this.importTypeOption === 'csv' ? '?format=csv&template=update&spm=' : '?format=xlsx&template=update&spm='
|
||||
const url = `${baseUrl}${format}` + spm.spm
|
||||
return this.downloadCsv(url)
|
||||
},
|
||||
async handleImportConfirm() {
|
||||
@@ -173,7 +208,12 @@ export default {
|
||||
this.showImportDialog = false
|
||||
},
|
||||
beforeUpload(file) {
|
||||
this.isCsv = _.endsWith(file.name, 'csv')
|
||||
this.isCsv = this.importTypeOption === 'csv' ? _.endsWith(file.name, 'csv') : _.endsWith(file.name, 'xlsx')
|
||||
if (!this.isCsv) {
|
||||
this.$message.error(
|
||||
this.$t('common.NeedSpecifiedFile')
|
||||
)
|
||||
}
|
||||
return this.isCsv
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<ActionsGroup :is-fa="true" :actions="rightSideActions" class="right-side-actions right-side-item" />
|
||||
<ImExportDialog :selected-rows="selectedRows" :url="tableUrl" />
|
||||
<ImExportDialog :selected-rows="selectedRows" :url="tableUrl" v-bind="$attrs" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -119,7 +119,7 @@ export default {
|
||||
}
|
||||
|
||||
.right-side-actions >>> .el-button:hover {
|
||||
background-color: rgb(0, 0, 0, 0.05);
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.action-search >>> .el-input__suffix i {
|
||||
|
||||
@@ -24,6 +24,19 @@ const defaultUpdateCallback = function({ row, col }) {
|
||||
this.$router.push(route)
|
||||
}
|
||||
|
||||
const defaultCloneCallback = function({ row, col }) {
|
||||
const id = row.id
|
||||
let route = { query: { clone_from: id }}
|
||||
const cloneRoute = this.colActions.cloneRoute
|
||||
|
||||
if (typeof cloneRoute === 'object') {
|
||||
route = Object.assign(route, cloneRoute)
|
||||
} else {
|
||||
route.name = cloneRoute
|
||||
}
|
||||
this.$router.push(route)
|
||||
}
|
||||
|
||||
const defaultDeleteCallback = function({ row, col, cellValue, reload }) {
|
||||
let msg = this.$t('common.deleteWarningMsg')
|
||||
const name = row.name || row.hostname
|
||||
@@ -71,10 +84,14 @@ export default {
|
||||
canUpdate: true, // can set function(row, value)
|
||||
hasDelete: true, // can set function(row, value)
|
||||
canDelete: true,
|
||||
hasClone: false,
|
||||
canClone: true,
|
||||
updateRoute: this.$route.name.replace('List', 'Update'),
|
||||
cloneRoute: this.$route.name.replace('List', 'Create'),
|
||||
performDelete: defaultPerformDelete,
|
||||
onUpdate: defaultUpdateCallback,
|
||||
onDelete: defaultDeleteCallback,
|
||||
onClone: defaultCloneCallback,
|
||||
extraActions: [] // format see defaultActions
|
||||
}
|
||||
}
|
||||
@@ -89,7 +106,8 @@ export default {
|
||||
type: 'primary',
|
||||
has: colActions.hasUpdate,
|
||||
can: colActions.canUpdate,
|
||||
callback: colActions.onUpdate
|
||||
callback: colActions.onUpdate,
|
||||
order: 10
|
||||
},
|
||||
{
|
||||
name: 'delete',
|
||||
@@ -97,7 +115,17 @@ export default {
|
||||
type: 'danger',
|
||||
has: colActions.hasDelete,
|
||||
can: colActions.canDelete,
|
||||
callback: colActions.onDelete
|
||||
callback: colActions.onDelete,
|
||||
order: 20
|
||||
},
|
||||
{
|
||||
name: 'clone',
|
||||
title: this.$t('common.Clone'),
|
||||
type: 'info',
|
||||
has: colActions.hasClone,
|
||||
can: colActions.canClone,
|
||||
callback: colActions.onClone,
|
||||
order: 30
|
||||
}
|
||||
]
|
||||
return {
|
||||
@@ -115,9 +143,11 @@ export default {
|
||||
v.has = this.cleanBoolean(v, 'has')
|
||||
v.can = this.cleanBoolean(v, 'can')
|
||||
v.callback = this.cleanCallback(v)
|
||||
v.order = v.order || 100
|
||||
return v
|
||||
})
|
||||
actions = actions.filter((v) => v.has)
|
||||
actions.sort((a, b) => a.order - b.order)
|
||||
return actions
|
||||
},
|
||||
actions() {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
<script>
|
||||
import BaseFormatter from './base'
|
||||
import { toSafeLocalDateStr } from '@/utils/common'
|
||||
export default {
|
||||
name: 'ChoicesFormatter',
|
||||
extends: BaseFormatter,
|
||||
@@ -54,7 +55,7 @@ export default {
|
||||
return this.formatterArgs.tipStatus(this.cellValue, vm)
|
||||
},
|
||||
tipTime() {
|
||||
return this.cellValue.datetime
|
||||
return toSafeLocalDateStr(this.cellValue.datetime)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
console.log(this.col)
|
||||
// console.log(this.col)
|
||||
},
|
||||
methods: {
|
||||
checkBool(item, attr, defaults) {
|
||||
|
||||
@@ -33,6 +33,9 @@ export default {
|
||||
}
|
||||
},
|
||||
iCanDelete() {
|
||||
if (this.col.objects === 'all') {
|
||||
return false
|
||||
}
|
||||
return this.col.objects.indexOf(this.cellValue) === -1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div>
|
||||
<TableAction :table-url="iTableConfig.url" :search-table="search" :date-pick="handleDateChange" v-bind="headerActions" :selected-rows="selectedRows" :reload-table="reloadTable" />
|
||||
<IBox class="table-content">
|
||||
<AutoDataTable ref="dataTable" :config="iTableConfig" @selection-change="handleSelectionChange" v-on="$listeners" />
|
||||
<AutoDataTable ref="dataTable" :filter-table="filter" :config="iTableConfig" @selection-change="handleSelectionChange" v-on="$listeners" />
|
||||
</IBox>
|
||||
</div>
|
||||
</template>
|
||||
@@ -13,6 +13,7 @@ import IBox from '../IBox'
|
||||
import TableAction from './TableAction'
|
||||
import Emitter from '@/mixins/emitter'
|
||||
import deepmerge from 'deepmerge'
|
||||
|
||||
export default {
|
||||
name: 'ListTable',
|
||||
components: {
|
||||
@@ -41,11 +42,24 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
dataTable() {
|
||||
return this.$refs.dataTable.$refs.dataTable
|
||||
},
|
||||
hasCreateAction() {
|
||||
const hasLeftAction = this.headerActions.hasLeftActions
|
||||
if (hasLeftAction === false) {
|
||||
return false
|
||||
}
|
||||
const hasCreate = this.headerActions.hasCreate
|
||||
if (hasCreate === false) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
iTableConfig() {
|
||||
const config = deepmerge(this.tableConfig, { extraQuery: this.extraQuery })
|
||||
this.$log.debug('Header actions', this.headerActions)
|
||||
this.$log.debug('ListTable: iTableConfig change', config)
|
||||
return config
|
||||
}
|
||||
@@ -56,10 +70,14 @@ export default {
|
||||
this.$log.debug('ListTable: found extraQuery change')
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
tableColConfig: {
|
||||
handler() {
|
||||
this.$log.debug('ListTable: found colConfig change')
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
handleSelectionChange(val) {
|
||||
this.selectedRows = val
|
||||
@@ -70,6 +88,9 @@ export default {
|
||||
search(attrs) {
|
||||
return this.dataTable.search(attrs, true)
|
||||
},
|
||||
filter(attrs) {
|
||||
this.$refs.dataTable.$refs.dataTable.search(attrs, true)
|
||||
},
|
||||
handleDateChange(attrs) {
|
||||
this.$set(this.extraQuery, 'date_from', attrs[0].toISOString())
|
||||
this.$set(this.extraQuery, 'date_to', attrs[1].toISOString())
|
||||
@@ -92,28 +113,28 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.table-content {
|
||||
margin-top: 10px;
|
||||
.table-content {
|
||||
margin-top: 10px;
|
||||
|
||||
& >>> .el-card__body {
|
||||
padding: 0;
|
||||
}
|
||||
& >>> .el-table__header thead > tr > th {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
/*& >>> .el-table--striped .el-table__body tr.el-table__row--striped td {*/
|
||||
/*background: white;*/
|
||||
/*}*/
|
||||
|
||||
/*& >>> .el-table th, .el-table tr {*/
|
||||
/*background-color: red;*/
|
||||
/*!*background-color: #FAFAFA;*!*/
|
||||
/*}*/
|
||||
& >>> .el-card__body {
|
||||
padding: 0;
|
||||
}
|
||||
& >>> .el-table__header thead > tr > th {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
//修改颜色
|
||||
// .el-button--text{
|
||||
// color: #409EFF;
|
||||
// }
|
||||
/*& >>> .el-table--striped .el-table__body tr.el-table__row--striped td {*/
|
||||
/*background: white;*/
|
||||
/*}*/
|
||||
|
||||
/*& >>> .el-table th, .el-table tr {*/
|
||||
/*background-color: red;*/
|
||||
/*!*background-color: #FAFAFA;*!*/
|
||||
/*}*/
|
||||
}
|
||||
|
||||
//修改颜色
|
||||
// .el-button--text{
|
||||
// color: #409EFF;
|
||||
// }
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<IBox fa="fa-edit" :title="title" v-bind="$attrs">
|
||||
<div class="quick-actions">
|
||||
<div v-for="action of actions" :key="action.title" class="quick-actions">
|
||||
<table>
|
||||
<ActionItem v-for="action of actions" :key="action.title" :action="action" />
|
||||
<ActionItem v-if="action.has === undefined || action.has" :action="action" />
|
||||
</table>
|
||||
</div>
|
||||
</IBox>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<Select2 ref="select2" v-model="select2.value" v-bind="select2" />
|
||||
</td>
|
||||
</tr>
|
||||
<slot />
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<el-button :type="type" size="small" :loading="submitLoading" @click="addObjects">{{ $t('common.Add') }}</el-button>
|
||||
@@ -21,7 +22,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
<tr v-if="params.hasMore" class="item">
|
||||
<tr v-if="params.hasMore && showHasMore" class="item">
|
||||
<td colspan="2">
|
||||
<el-button :type="type" size="small" style="width: 100%" @click="loadMore">
|
||||
<i class="fa fa-arrow-down" />
|
||||
@@ -37,7 +38,6 @@
|
||||
import Select2 from '../Select2'
|
||||
import IBox from '../IBox'
|
||||
import { createSourceIdCache } from '@/api/common'
|
||||
|
||||
export default {
|
||||
name: 'RelationCard',
|
||||
components: {
|
||||
@@ -83,6 +83,10 @@ export default {
|
||||
type: [Array, Number, String],
|
||||
default: () => []
|
||||
},
|
||||
showHasMore: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
performDelete: {
|
||||
type: Function,
|
||||
default: (obj, that) => {}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
:remote-method="filterOptions"
|
||||
:multiple="multiple"
|
||||
filterable
|
||||
:clearable="clearable"
|
||||
popper-append-to-body
|
||||
class="select2"
|
||||
v-bind="$attrs"
|
||||
@@ -69,6 +70,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
clearable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 初始化值,也就是选中的值
|
||||
value: {
|
||||
type: [Array, String, Number, Boolean],
|
||||
@@ -172,6 +177,9 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async loadMore(load) {
|
||||
if (!this.iAjax.url) {
|
||||
return
|
||||
}
|
||||
if (!this.params.hasMore) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,14 +1,35 @@
|
||||
<template>
|
||||
|
||||
<div class="filter-field">
|
||||
<el-cascader ref="Cascade" :options="options" :props="config" @change="handleMenuItemChange" />
|
||||
<el-tag v-for="(v, k) in filterTags" :key="k" :name="k" closable size="small" class="filter-tag" type="info" @close="handleTagClose(k)">
|
||||
<el-tag
|
||||
v-for="(v, k) in filterTags"
|
||||
:key="k"
|
||||
:name="k"
|
||||
closable
|
||||
size="small"
|
||||
class="filter-tag"
|
||||
type="info"
|
||||
:disable-transitions="true"
|
||||
@close="handleTagClose(k)"
|
||||
@click="handleTagClick(v,k)"
|
||||
>
|
||||
<strong v-if="v.label">{{ v.label + ':' }}</strong>
|
||||
<span v-if="v.valueLabel">{{ v.valueLabel }}</span>
|
||||
<span v-else>{{ v.value }}</span>
|
||||
</el-tag>
|
||||
<span v-if="keyLabel" slot="prefix" class="filterTitle">{{ keyLabel + ':' }}</span>
|
||||
<el-input ref="SearchInput" v-model="filterValue" :placeholder="placeholder" class="search-input" @blur="focus = false" @focus="focus = true" @change="handleConfirm" />
|
||||
<el-input
|
||||
ref="SearchInput"
|
||||
v-model="filterValue"
|
||||
:placeholder="placeholder"
|
||||
class="search-input"
|
||||
@blur="focus = false"
|
||||
@focus="focus = true"
|
||||
@change="handleConfirm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -65,13 +86,13 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
filterTags: {
|
||||
handler(val) {
|
||||
this.$nextTick(() => this.$emit('tagSearch', this.filterMaps))
|
||||
// this.$emit('tagSearch', this.filterMaps)
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
// filterTags: {
|
||||
// handler(val) {
|
||||
// this.$nextTick(() => this.$emit('tagSearch', this.filterMaps))
|
||||
// // this.$emit('tagSearch', this.filterMaps)
|
||||
// },
|
||||
// deep: true
|
||||
// }
|
||||
},
|
||||
mounted() {
|
||||
setTimeout(() => {
|
||||
@@ -116,6 +137,7 @@ export default {
|
||||
},
|
||||
handleTagClose(evt) {
|
||||
this.$delete(this.filterTags, evt)
|
||||
this.$emit('tagSearch', this.filterMaps)
|
||||
return true
|
||||
},
|
||||
handleConfirm() {
|
||||
@@ -124,9 +146,33 @@ export default {
|
||||
}
|
||||
const tag = { key: this.filterKey, label: this.keyLabel, value: this.filterValue, valueLabel: this.valueLabel }
|
||||
this.$set(this.filterTags, this.filterKey, tag)
|
||||
this.$emit('tagSearch', this.filterMaps)
|
||||
this.filterKey = ''
|
||||
this.filterValue = ''
|
||||
this.valueLabel = ''
|
||||
},
|
||||
handleTagClick(v, k) {
|
||||
let unableChange = false
|
||||
for (const field of this.options) {
|
||||
if (field.value === v.key) {
|
||||
if (field.type === 'choice') {
|
||||
unableChange = true
|
||||
}
|
||||
if (field.type === 'boolean') {
|
||||
unableChange = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unableChange) {
|
||||
return
|
||||
}
|
||||
if (this.filterValue.length !== 0) {
|
||||
this.handleConfirm()
|
||||
}
|
||||
this.$delete(this.filterTags, k)
|
||||
this.filterKey = v.key
|
||||
this.filterValue = v.value
|
||||
this.$refs.SearchInput.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ export default {
|
||||
color: #FFFFFF;
|
||||
border-radius: 3px;
|
||||
line-height: 1.428;
|
||||
cursor:pointer;
|
||||
}
|
||||
.el-tree{
|
||||
background-color: inherit !important;
|
||||
|
||||
@@ -2,8 +2,25 @@
|
||||
"": "",
|
||||
"applications": {
|
||||
"": "",
|
||||
"applicationsType": {
|
||||
"chrome": "Chrome",
|
||||
"mysql_workbench": "MySQL Workbench",
|
||||
"vmware_client":"Vmware Client",
|
||||
"custom":"Custom",
|
||||
"mysql": "MySQL",
|
||||
"oracle": "Oracle",
|
||||
"postgresql": "PostgreSQL",
|
||||
"mariadb": "MariaDB",
|
||||
"k8s": "Kubernetes"
|
||||
},
|
||||
"applicationsCategory": {
|
||||
"remote_app": "远程应用",
|
||||
"db": "数据库应用",
|
||||
"cloud": "云应用"
|
||||
},
|
||||
"appPath": "应用路径",
|
||||
"appType": "应用类型",
|
||||
"appName": "应用名称",
|
||||
"asset": "资产",
|
||||
"database": "数据库",
|
||||
"host": "主机",
|
||||
@@ -16,6 +33,7 @@
|
||||
"chrome_password": "登录密码",
|
||||
"mysql_workbench": "MySQL Workbench",
|
||||
"mysql_workbench_ip": "数据库IP",
|
||||
"mysql_workbench_port": "数据库端口",
|
||||
"mysql_workbench_name": "数据库名",
|
||||
"mysql_workbench_username": "数据库账号",
|
||||
"mysql_workbench_password": "数据库密码",
|
||||
@@ -28,7 +46,11 @@
|
||||
"custom_target": "目标地址",
|
||||
"custom_username": "登录账号",
|
||||
"custom_password": "登录密码",
|
||||
"Custom": "自定义"
|
||||
"Custom": "自定义",
|
||||
"cluster": "集群",
|
||||
"kubernetes":"Kubernetes",
|
||||
"clusterHelpTextMessage": "例如:https://172.16.8.8:8443",
|
||||
"DBInfo": "数据库信息"
|
||||
},
|
||||
"assets": {
|
||||
"Action": "动作",
|
||||
@@ -37,13 +59,19 @@
|
||||
"AdminUserDetail": "管理用户详情",
|
||||
"AdminUserListHelpMessage": "管理用户是资产(被控服务器)上的 root,或拥有 NOPASSWD: ALL sudo 权限的用户, JumpServer 使用该用户来 `推送系统用户`、`获取资产硬件信息` 等。\n",
|
||||
"Asset": "资产",
|
||||
"HardwareInfo": "硬件信息",
|
||||
"AssetDetail": "资产详情",
|
||||
"AssetList": "资产列表",
|
||||
"ReplaceNodeAssetsAdminUser":"替换节点资产的管理员",
|
||||
"AssetListHelpMessage": "左侧是资产树,右击可以新建、删除、更改树节点,授权资产也是以节点方式组织的,右侧是属于该节点下的资产\n",
|
||||
"TestGatewayTestConnection":"测试连接网关",
|
||||
"TestGatewayHelpMessage": "如果使用了nat端口映射,请设置为ssh真实监听的端口",
|
||||
"SshPort": "SSH 端口",
|
||||
"AssetNumber": "资产编号",
|
||||
"AssetUserList": "资产用户列表",
|
||||
"Assets": "资产",
|
||||
"Auth": "认证",
|
||||
"AccountList": "账号列表",
|
||||
"AutoGenerateKey": "自动生成密钥",
|
||||
"AutoPush": "自动推送",
|
||||
"BasePlatform": "基础平台",
|
||||
@@ -63,6 +91,8 @@
|
||||
"DateUpdated": "更新日期",
|
||||
"DeactiveSelected": "禁用所选",
|
||||
"Disk": "硬盘",
|
||||
"AdDomain": "AD域名",
|
||||
"AdDomainHelpText": "提供给域用户登录的AD域名",
|
||||
"Domain": "网域",
|
||||
"DomainDetail": "网域详情",
|
||||
"DomainHelpMessage": "网域功能是为了解决部分环境(如:混合云)无法直接连接而新增的功能,原理是通过网关服务器进行跳转登录。JMS => 网域网关 => 目标资产",
|
||||
@@ -87,6 +117,7 @@
|
||||
"OnlyLatestVersion": "仅最新版本",
|
||||
"Os": "操作系统",
|
||||
"Other": "其它",
|
||||
"Hardware": "硬件信息",
|
||||
"Password": "密码",
|
||||
"PasswordWithoutSpecialCharHelpText": "不能包含特殊字符",
|
||||
"Pending": "等待",
|
||||
@@ -106,6 +137,7 @@
|
||||
"RefreshHardware": "更新硬件信息",
|
||||
"RemoteAppListHelpMessage": "使用此功能前,请确保已将应用加载器上传到应用服务器并成功发布为一个 RemoteApp 应用 <b><a href='https://github.com/jumpserver/Jmservisor/releases'>下载应用加载器</a></b>",
|
||||
"RemoteApps": "远程应用",
|
||||
"Applications": "应用",
|
||||
"RemoteType": "应用类型",
|
||||
"RemoveFromCurrentNode": "从节点移除",
|
||||
"ReplaceNodeAssetsAdminUserWithThis": "替换资产的管理员",
|
||||
@@ -133,7 +165,12 @@
|
||||
"command_filter_list": "命令过滤器列表",
|
||||
"date_joined": "创建日期",
|
||||
"ip": "IP",
|
||||
"sshkey": "sshkey"
|
||||
"sshkey": "sshkey",
|
||||
"GroupsHelpMessage": "请输入用户组,多个用户组使用逗号分隔(需填写已存在的用户组)",
|
||||
"HomeHelpMessage": "默认家目录 /home/系统用户名: /home/username",
|
||||
"Home": "家目录",
|
||||
"LinuxUserAffiliateGroup": "用户附属组",
|
||||
"ipDomain": "IP(域名)"
|
||||
|
||||
},
|
||||
"audits": {
|
||||
@@ -148,15 +185,27 @@
|
||||
},
|
||||
"common": {
|
||||
"Action": "动作",
|
||||
"RequestTickets": "申请工单",
|
||||
"Actions": "操作",
|
||||
"CustomCol":"自定义列表字段",
|
||||
"Activate": "激活",
|
||||
"NeedSpecifiedFile": "需上传指定格式文件",
|
||||
"TestPortErrorMsg":"端口错误,请重新输入",
|
||||
"Active": "激活中",
|
||||
"actionsTips":"剪切板权限控制目前仅支持 RDP/VNC 协议的连接",
|
||||
"TableColSettingInfo": "请选择您想显示的列表详细信息。",
|
||||
"Add": "添加",
|
||||
"UpdateAssetDetail": "配置更多信息",
|
||||
"AddSuccessMsg": "添加成功",
|
||||
"Auth": "认证",
|
||||
"PushSelected":"推送所选",
|
||||
"BadRequestErrorMsg": "请求错误,请检查填写内容",
|
||||
"BadRoleErrorMsg": "请求错误,无该操作权限",
|
||||
"BadConflictErrorMsg": "正在刷新中,请稍后再试",
|
||||
"Basic": "基本",
|
||||
"PleaseAgreeToTheTerms": "请同意条款",
|
||||
"BasicInfo": "基本信息",
|
||||
"ApplyInfo": "申请信息",
|
||||
"Cancel": "取消",
|
||||
"Close": "关闭",
|
||||
"Command filter": "命令过滤器",
|
||||
@@ -166,6 +215,7 @@
|
||||
"CreatedBy": "创建者",
|
||||
"CrontabHelpTips": "eg:每周日 03:05 执行 <5 3 * * 0> <br> 提示: 使用5位 Linux crontab 表达式 <分 时 日 月 星期> (<a href='https://tool.lu/crontab/' target='_blank'>在线工具</a>) <br>注意: 如果同时设置了定期执行和周期执行,优先使用定期执行",
|
||||
"DateEnd": "结束日期",
|
||||
"Resource": "资源",
|
||||
"DateLast24Hours": "最近一天",
|
||||
"DateLast3Months": "最近三月",
|
||||
"DateLastMonth": "最近一月",
|
||||
@@ -185,6 +235,7 @@
|
||||
"MFARequireForSecurity": "为了安全请输入MFA",
|
||||
"Members": "成员",
|
||||
"More": "更多",
|
||||
"Message": "消息",
|
||||
"MoreActions": "更多操作",
|
||||
"Name": "名称",
|
||||
"No": "否",
|
||||
@@ -202,11 +253,13 @@
|
||||
"SelectFile": "选择文件",
|
||||
"Show": "显示",
|
||||
"Submit": "提交",
|
||||
"SaveAndAddAnother": "保存并继续添加",
|
||||
"Test": "测试",
|
||||
"TestSuccessMsg": "测试成功",
|
||||
"To": "至",
|
||||
"Update": "更新",
|
||||
"Upload": "上传",
|
||||
"Clone": "克隆",
|
||||
"Username": "用户名",
|
||||
"Validity": "有效",
|
||||
"Invalidity": "无效",
|
||||
@@ -217,13 +270,17 @@
|
||||
"bulkDeleteErrorMsg": "批量删除失败: ",
|
||||
"bulkDeleteSuccessMsg": "批量删除成功",
|
||||
"bulkRemoveErrorMsg": "批量移除失败: ",
|
||||
"NeedAssetsAndSystemUserErrMsg": "请先选择授权的系统用户和资产",
|
||||
"bulkRemoveSuccessMsg": "批量移除成功",
|
||||
"createBy": "创建者",
|
||||
"cloneFrom": "克隆自",
|
||||
"createErrorMsg": "创建失败",
|
||||
"createSuccessMsg": "创建成功",
|
||||
"saveSuccessContinueMsg": "创建成功,更新内容后可以继续添加",
|
||||
"createdBy": "创建人",
|
||||
"dateCreated": "创建日期",
|
||||
"dateExpired": "失效日期",
|
||||
"dateFinished": "完成日期",
|
||||
"dateStart": "开始日期",
|
||||
"deleteErrorMsg": "删除失败",
|
||||
"deleteFailedMsg": "删除失败",
|
||||
@@ -245,6 +302,7 @@
|
||||
"onlyCSVFilesTips": "仅支持csv文件导入",
|
||||
"updateSuccessMsg": "导入更新成功,总共:{count}"
|
||||
},
|
||||
"fileType": "文件类型",
|
||||
"isValid": "有效",
|
||||
"nav": {
|
||||
"APIKey": "API Key",
|
||||
@@ -279,7 +337,8 @@
|
||||
"NUMBER_REQUIRED": "须包含数字",
|
||||
"SPECIAL_CHAR_REQUIRED": "须包含特殊字符",
|
||||
"MIN_LENGTH_ERROR": "密码最小长度 {0} 位"
|
||||
}
|
||||
},
|
||||
"lastCannotBeDeleteMsg": "最后一项,不能被删除"
|
||||
},
|
||||
"dashboard": {
|
||||
"ActiveAsset": "近期被登录过",
|
||||
@@ -359,7 +418,7 @@
|
||||
},
|
||||
"perms": {
|
||||
"": "",
|
||||
"Actions": "动作",
|
||||
"Actions": "权限",
|
||||
"Asset": "资产",
|
||||
"Basic": "基本",
|
||||
"Exclude": "不包含",
|
||||
@@ -370,10 +429,16 @@
|
||||
"SystemUser": "系统用户",
|
||||
"User": "用户",
|
||||
"UserGroups": "用户组",
|
||||
"PermName":"授权名称",
|
||||
"DatabaseAppPermission": "数据库授权",
|
||||
"RemoteAppPermission": "远程应用授权",
|
||||
"addApplicationToThisPermission": "添加应用",
|
||||
"KubernetesAppPermission": "Kubernetes授权",
|
||||
"addAssetToThisPermission": "添加资产",
|
||||
"addDatabaseAppToThisPermission": "添加数据库应用",
|
||||
"addNodeToThisPermission": "添加节点",
|
||||
"addRemoteAppToThisPermission": "添加远程应用",
|
||||
"addK8sAppToThisPermission": "添加Kubernetes应用",
|
||||
"addSystemUserToThisPermission": "添加系统用户",
|
||||
"addUserGroupToThisPermission": "添加用户组",
|
||||
"addUserToThisPermission": "添加用户",
|
||||
@@ -382,6 +447,7 @@
|
||||
"assetCount": "资产数量",
|
||||
"connect": "连接",
|
||||
"databaseApp": "数据库应用",
|
||||
"KubernetesApp": "Kubernetes",
|
||||
"dateStart": "开始日期",
|
||||
"downloadFile": "下载文件",
|
||||
"hostName": "主机名",
|
||||
@@ -392,15 +458,23 @@
|
||||
"refreshSuccess": "刷新成功",
|
||||
"remoteApp": "远程应用",
|
||||
"remoteAppCount": "远程应用数量",
|
||||
"appsCount": "应用数量",
|
||||
"appsList":"应用列表",
|
||||
"DatabaseAppCount": "数据库应用数量",
|
||||
"KubernetesAppCount": "Kubernetes应用数量",
|
||||
"systemUserCount": "系统用户数量",
|
||||
"upDownload": "上传下载",
|
||||
"uploadFile": "上传文件",
|
||||
"clipboardCopyPaste":"复制粘贴",
|
||||
"clipboardCopy":"剪切板复制",
|
||||
"clipboardPaste":"剪切板粘贴",
|
||||
"userCount": "用户数量",
|
||||
"userGroupCount": "用户组数量",
|
||||
"usersAndUserGroups": "用户或用户组"
|
||||
},
|
||||
"route": {
|
||||
"": "",
|
||||
"Ticket":"工单",
|
||||
"AdminUserCreate": "创建管理用户",
|
||||
"AdminUserDetail": "管理用户详情",
|
||||
"AdminUserList": "管理用户",
|
||||
@@ -431,7 +505,7 @@
|
||||
"CreateCommandStorage": "创建命令存储",
|
||||
"CreateReplayStorage": "创建录像存储",
|
||||
"Dashboard": "仪表盘",
|
||||
"DatabaseApp": "数据库应用",
|
||||
"DatabaseApp": "数据库",
|
||||
"DatabaseAppCreate": "创建数据库应用",
|
||||
"DatabaseAppDetail": "数据库详情",
|
||||
"DatabaseAppPermission": "数据库授权",
|
||||
@@ -439,6 +513,15 @@
|
||||
"DatabaseAppPermissionDetail": "数据库授权详情",
|
||||
"DatabaseAppPermissionUpdate": "更新数据库授权规则",
|
||||
"DatabaseAppUpdate": "数据库应用更新",
|
||||
"KubernetesApp": "Kubernetes",
|
||||
"KubernetesAppCreate": "创建Kubernetes",
|
||||
"KubernetesAppDetail": "Kubernetes详情",
|
||||
"KubernetesAppPermission": "Kubernetes授权",
|
||||
"KubernetesAppPermissionCreate": "创建Kubernetes授权规则",
|
||||
"KubernetesAppPermissionDetail": "Kubernetes授权详情",
|
||||
"KubernetesAppPermissionUpdate": "更新Kubernetes授权规则",
|
||||
"KubernetesAppUpdate": "更新Kubernetes",
|
||||
|
||||
"DomainCreate": "创建网域",
|
||||
"DomainDetail": "网域详情",
|
||||
"DomainList": "网域列表",
|
||||
@@ -468,6 +551,11 @@
|
||||
"RemoteAppPermissionCreate": "创建远程应用授权规则",
|
||||
"RemoteAppPermissionDetail": "远程应用授权详情",
|
||||
"RemoteAppPermissionUpdate": "更新远程应用授权规则",
|
||||
"ApplicationDetail": "应用详情",
|
||||
"ApplicationPermission": "应用授权",
|
||||
"ApplicationPermissionCreate": "创建应用授权规则",
|
||||
"ApplicationPermissionDetail": "应用授权详情",
|
||||
"ApplicationPermissionUpdate": "更新应用授权规则",
|
||||
"RemoteAppUpdate": "更新远程应用",
|
||||
"ReplayStorageUpdate": "更新录像存储",
|
||||
"SessionDetail": "会话详情",
|
||||
@@ -484,6 +572,7 @@
|
||||
"TaskMonitor": "任务监控",
|
||||
"Terminal": "终端管理",
|
||||
"TicketDetail": "工单详情",
|
||||
"TicketCreate": "创建工单",
|
||||
"Tickets": "工单管理",
|
||||
"UserCreate": "创建用户",
|
||||
"UserDetail": "用户详情",
|
||||
@@ -507,6 +596,7 @@
|
||||
"active": "激活中",
|
||||
"alive": "在线",
|
||||
"asset": "资产",
|
||||
"target": "目标",
|
||||
"bucket": "桶名称",
|
||||
"command": "命令",
|
||||
"commandStorage": "命令存储",
|
||||
@@ -534,6 +624,10 @@
|
||||
"name": "名称",
|
||||
"protocol": "协议",
|
||||
"region": "地域",
|
||||
"sessionActiveCount": "在线会话数量",
|
||||
"systemCpuLoad": "CPU负载",
|
||||
"systemDiskUsedPercent": "硬盘使用率",
|
||||
"systemMemoryUsedPercent": "内存使用率",
|
||||
"remoteAddr": "远端地址",
|
||||
"replay": "回放",
|
||||
"replaySession": "回放会话",
|
||||
@@ -545,7 +639,9 @@
|
||||
"systemUser": "系统用户",
|
||||
"terminalDetail": "终端详情",
|
||||
"terminalUpdate": "更新终端",
|
||||
"terminalUpdateStorage": "更新终端存储",
|
||||
"terminate": "终断",
|
||||
"sessionTerminate": "会话终断",
|
||||
"test": "测试",
|
||||
"type": "类型",
|
||||
"user": "用户",
|
||||
@@ -553,7 +649,15 @@
|
||||
"common": "普通"
|
||||
},
|
||||
"Monitor": "监控",
|
||||
"TerminateTaskSendSuccessMsg": "终断任务已下发,请稍后刷新表格查看"
|
||||
"sessionMonitor": "监控",
|
||||
"TerminateTaskSendSuccessMsg": "终断任务已下发,请稍后刷新查看",
|
||||
"helpText": {
|
||||
"esUrl": "提示:如果有多台主机,请使用逗号 ( , ) 进行分割。(eg: http://www.jumpserver.a.com,http://www.jumpserver.b.com)",
|
||||
"esIndex": "es提供默认index:jumpserver",
|
||||
"esDocType": "es默认文档类型:command",
|
||||
"s3Endpoint": "S3 格式: http://s3.{REGION_NAME}.amazonaws.com<br>S3(China) 格式: http://s3.{REGION_NAME}.amazonaws.com.cn<br>如: http://s3.cn-north-1.amazonaws.com.cn",
|
||||
"ossEndpoint": "OSS 格式: http://{REGION_NAME}.aliyuncs.com<br>如: http://oss-cn-hangzhou.aliyuncs.com"
|
||||
}
|
||||
},
|
||||
"setting": {
|
||||
"ApiKeyList": "API Key 列表",
|
||||
@@ -584,6 +688,7 @@
|
||||
"authLdapSearchOu": "用户OU",
|
||||
"authLdapServerUri": "LDAP地址",
|
||||
"authLdapUserAttrMap": "LDAP属性映射",
|
||||
"unselectedUser": "没有选择用户",
|
||||
"auto": "自动",
|
||||
"basicSetting": "基本设置",
|
||||
"communityEdition": "社区版",
|
||||
@@ -603,6 +708,9 @@
|
||||
"emailTest": "测试连接",
|
||||
"emailUserSSL": "使用SSL",
|
||||
"emailUserTLS": "使用TLS",
|
||||
"SecurityInsecureCommand": "危险命令告警",
|
||||
"Insecure_Command_Alert": "危险命令告警",
|
||||
"SecurityInsecureCommandEmailReceiver": "告警接收邮件",
|
||||
"helpText": {
|
||||
"ApiKeyList": "使用api key签名请求头,每个请求的头部是不一样的, 请查阅使用文档",
|
||||
"authLdapSearchFilter": "可能的选项是(cn或uid或sAMAccountName=%(user)s)",
|
||||
@@ -623,7 +731,8 @@
|
||||
"terminalHeartbeatInterval": "单位: 秒",
|
||||
"terminalSessionKeepDuration": "单位:天。 会话、录像、命令记录超过该时长将会被删除(仅影响数据库存储, oss等不受影响)",
|
||||
"terminalTelnetRegex": "登录telnet服务器成功后的提示正则表达式,如: Last\\s*login|success|成功",
|
||||
"userGuideUrl": "用户第一次登录,修改profile后重定向到地址"
|
||||
"userGuideUrl": "用户第一次登录,修改profile后重定向到地址",
|
||||
"SecurityInsecureCommandEmailReceiver": "多个邮箱时,以半角逗号','分隔"
|
||||
},
|
||||
"helpTip": {
|
||||
"emailUserSSL": "如果SMTP端口是465,通常需要启用SSL",
|
||||
@@ -634,7 +743,8 @@
|
||||
"securityPasswordNumber": "开启后,用户密码修改、重置必须包含数字字符",
|
||||
"securityPasswordSpecialChar": "开启后,用户密码修改、重置必须包含特殊字符",
|
||||
"securityPasswordUpperCase": "开启后,用户密码修改、重置必须包含大写字母",
|
||||
"securityServiceAccountRegistration": "允许使用bootstrap token注册终端, 当终端注册成功后可以禁止"
|
||||
"securityServiceAccountRegistration": "允许使用bootstrap token注册终端, 当终端注册成功后可以禁止",
|
||||
"SecurityInsecureCommand": "开启后,当资产上有危险命令执行时,会发送邮件告警通知"
|
||||
},
|
||||
"validatorMessage": {
|
||||
"EnsureThisValueIsGreaterThanOrEqualTo3": "请确保该值大于或者等于 3",
|
||||
@@ -676,28 +786,57 @@
|
||||
"userGuideUrl": "用户向导URL",
|
||||
"username": "用户名",
|
||||
"usernamePlaceholder": "请输入用户名",
|
||||
"refreshLdapCache":"刷新Ldap缓存,请稍后"
|
||||
"refreshLdapCache":"刷新Ldap缓存,请稍后",
|
||||
"LicenseExpired": "许可证已经过期",
|
||||
"LicenseWillBe": "许可证即将在 ",
|
||||
"Expire": " 过期"
|
||||
},
|
||||
"settings": {
|
||||
"setting": "设置"
|
||||
},
|
||||
"tickets": {
|
||||
"Accept": "接受",
|
||||
"AssignedMe": "待处理",
|
||||
"Accept": "同意",
|
||||
"AssignedMe": "待我审批",
|
||||
"Assignee": "处理人",
|
||||
"Assignees": "待处理人",
|
||||
"Close": "关闭",
|
||||
"OpenStatus":"开启",
|
||||
"CloseStatus":"关闭",
|
||||
"Comment": "备注",
|
||||
"MyTickets": "我的工单",
|
||||
"MyTickets": "我发起的",
|
||||
"RequestPerm":"授权申请",
|
||||
"Reject": "拒绝",
|
||||
"date": "日期",
|
||||
"reply": "回复",
|
||||
"status": "状态",
|
||||
"title": "标题",
|
||||
"action": "动作",
|
||||
"IPGroup": "IP 组",
|
||||
"type": "类型",
|
||||
"user": "用户",
|
||||
"Status": "状态",
|
||||
"Open": "打开"
|
||||
"Open": "待处理",
|
||||
"OrgName":"组织名称",
|
||||
"AssignedInfo":"审批信息",
|
||||
"OpenTicket": "创建工单",
|
||||
"HandleTicket": "处理工单",
|
||||
"FinishedTicket": "完成工单",
|
||||
"IP": "IP",
|
||||
"Hostname": "主机名",
|
||||
"Asset": "资产",
|
||||
"SystemUser": "系统用户",
|
||||
"RequestAssetPerm": "申请资产授权",
|
||||
"RequestApplicationPerm": "申请应用授权",
|
||||
"Applicant": "申请人",
|
||||
"Pending": "待处理",
|
||||
"Approved": "已同意",
|
||||
"Rejected": "已拒绝",
|
||||
"Closed": "已完成",
|
||||
"helpText": {
|
||||
"ips": "请输入逗号分割的IP地址组",
|
||||
"fuzzySearch": "支持模糊搜索",
|
||||
"application": "请输入逗号分割的应用名称组"
|
||||
}
|
||||
},
|
||||
"tree": {
|
||||
"AddAssetToNode": "添加资产到节点",
|
||||
@@ -707,6 +846,7 @@
|
||||
"RenameNode": "重命名节点",
|
||||
"ShowAssetAllChildrenNode": "显示所有子节点资产",
|
||||
"ShowAssetOnlyCurrentNode": "仅显示当前节点资产",
|
||||
"CheckAssetsAmount": "校对资产数量",
|
||||
"ShowNodeInfo": "显示节点详情",
|
||||
"TestNodeAssetConnectivity": "测试资产节点可连接性",
|
||||
"UpdateNodeAssetHardwareInfo": "更新节点资产硬件信息"
|
||||
@@ -725,11 +865,18 @@
|
||||
"Email": "邮件",
|
||||
"FingerPrint": "指纹",
|
||||
"FirstLogin": "首次登录",
|
||||
"OrgUser": "组织用户",
|
||||
"OrgAdmin": "组织管理员",
|
||||
"OrgAuditor": "组织审计员",
|
||||
"InviteUser": "邀请用户",
|
||||
"Invite": "邀请",
|
||||
"InviteUserInOrg": "邀请用户加入此组织",
|
||||
"Guide": "向导",
|
||||
"HelpText": {
|
||||
"MFAOfUserFirstLoginPersonalInformationImprovementPage": "启用多因子认证,使账号更加安全。<br/> 启用之后您将会在下次登录时进入多因子认证绑定流程;您也可以在(个人信息->快速修改->更改多因子设置)中直接绑定!",
|
||||
"MFAOfUserFirstLoginUserGuidePage": "为了保护您和公司的安全,请妥善保管您的账户、密码和密钥等重要敏感信息;(如:设置复杂密码,并启用多因子认证)",
|
||||
"SSHKeyOfProfileSSHUpdatePage": "复制你的公钥到这里"
|
||||
"SSHKeyOfProfileSSHUpdatePage": "复制你的公钥到这里",
|
||||
"OrgRoleHelpText": "组织角色是用户在当前组织中的角色"
|
||||
},
|
||||
"IAgree": "我同意",
|
||||
"ImprovePersonalInformation": "完善个人信息",
|
||||
@@ -737,6 +884,7 @@
|
||||
"LoginConfirm": "登录复核",
|
||||
"LoginPasswordSetting": "登录密码设置",
|
||||
"MFA": "MFA",
|
||||
"Existing":"已存在",
|
||||
"MfaLevel": "多因子认证",
|
||||
"Name": "姓名",
|
||||
"NewPassword": "新密码",
|
||||
@@ -748,6 +896,8 @@
|
||||
"ResetAndDownloadSSHKey": "重置并下载密钥",
|
||||
"ResetPublicKeyAndDownload": "重置并下载SSH密钥",
|
||||
"Role": "角色",
|
||||
"SuperRole": "系统角色",
|
||||
"OrgRole": "组织角色",
|
||||
"SSHKey": "SSH公钥",
|
||||
"SSHKeySetting": "SSH公钥设置",
|
||||
"Secure": "安全",
|
||||
@@ -778,14 +928,21 @@
|
||||
"tabs": {
|
||||
"assetPermissionRules": "资产授权规则",
|
||||
"databasePermissionRules": "数据库授权规则",
|
||||
"k8sPermissionRules": "Kubernetes授权规则",
|
||||
"grantedAssets": "授权的资产",
|
||||
"grantedK8Ss": "授权的Kubernetes",
|
||||
"grantedDatabases": "授权的数据库",
|
||||
"grantedRemoteApps": "授权的远程应用",
|
||||
"grantedApplications": "授权的应用",
|
||||
"ApplicationPermissionRules": "应用授权规则",
|
||||
"remoteAppPermissionRules": "远程应用授权规则"
|
||||
},
|
||||
"dateLastLogin": "最后登录日期",
|
||||
"UpdatePassword": "更新密码",
|
||||
"SetPublicKey": "设置SSH公钥"
|
||||
"SetPublicKey": "设置SSH公钥",
|
||||
"passwordExpired": "密码过期了",
|
||||
"passwordWillExpiredPrefixMsg": "密码即将在 ",
|
||||
"passwordWillExpiredSuffixMsg": "天 后过期,请尽快修改您的密码。"
|
||||
},
|
||||
"xpack": {
|
||||
"Admin": "管理员",
|
||||
@@ -810,6 +967,9 @@
|
||||
"ExecutionDetail": "执行详情",
|
||||
"ExecutionList": "执行列表",
|
||||
"ExecutionTimes": "执行次数",
|
||||
"validatorMessage": {
|
||||
"EnsureThisValueIsGreaterThanOrEqualTo1": "请确保该值大于或者等于 1"
|
||||
},
|
||||
"HelpText": {
|
||||
"CrontabOfCreateUpdatePage": "例如:每周日 03:05 执行 <5 3 * * 0> <br/> 使用5位 Linux crontab 表达式 <分 时 日 月 星期> (<a href=\"https://tool.lu/crontab/\" target=\"_blank\">在线工具</a>) <br/> 如果同时设置了定期执行和周期执行,优先使用定期执行",
|
||||
"IntervalOfCreateUpdatePage": "单位:时",
|
||||
@@ -831,12 +991,22 @@
|
||||
"Username": "用户名"
|
||||
},
|
||||
"Cloud": {
|
||||
"Aliyun": "阿里云",
|
||||
"Qcloud": "腾讯云",
|
||||
"AWS_China": "AWS(中国)",
|
||||
"AWS_Int": "AWS(国际)",
|
||||
"HuaweiCloud": "华为云",
|
||||
"Azure":"Azure(中国)",
|
||||
"HostnameStrategy": "用于生成资产主机名。例如:1. 实例名称 (instanceDemo);2. 实例名称和部分IP(后两位) (instanceDemo-250.1)",
|
||||
"IsAlwaysUpdate": "资产信息保持最新",
|
||||
"AccountCreate": "创建账户",
|
||||
"AccountList": "账户列表",
|
||||
"AccountUpdate": "更新账户",
|
||||
"AccountDetail": "账户详情",
|
||||
"Cloud": "云管中心",
|
||||
"CloudCenter": "云管中心",
|
||||
"Provider": "云服务商",
|
||||
"Validity": "有效",
|
||||
"IsAlwaysUpdateHelpTips": "每次执行同步任务时,是否同步更新资产的信息,包括主机名、IP、系统平台、管理用户",
|
||||
"SyncInstanceTaskCreate": "创建同步实例任务",
|
||||
"SyncInstanceTaskList": "同步实例任务列表",
|
||||
@@ -886,6 +1056,13 @@
|
||||
"ImportLicenseTip": "请导入许可证",
|
||||
"InterfaceSettings": "界面设置",
|
||||
"License": "许可证",
|
||||
"SystemMonitor": "系统监控",
|
||||
"ServiceRatio": "组件负载统计",
|
||||
"LoadStatus":"组件状态",
|
||||
"NormalLoad":"正常",
|
||||
"HighLoad":"较高",
|
||||
"CriticalLoad":"严重",
|
||||
"Offline": "离线",
|
||||
"LicenseDetail": "许可证详情",
|
||||
"LicenseFile": "许可证文件",
|
||||
"NoLicense": "暂无许可证",
|
||||
@@ -895,8 +1072,20 @@
|
||||
"OrganizationDetail": "组织详情",
|
||||
"OrganizationList": "组织管理",
|
||||
"OrganizationUpdate": "更新组织",
|
||||
"OrganizationMembership": "组织成员",
|
||||
"DeleteOrgTitle": "请确保组织内的以下信息已删除",
|
||||
"DeleteOrgMsg": "用户列表、用户组、资产列表、网域列表、管理用户、系统用户、标签管理、资产授权规则"
|
||||
"DeleteOrgMsg": "用户列表、用户组、资产列表、网域列表、管理用户、系统用户、标签管理、资产授权规则",
|
||||
"OrgRole": "组织角色",
|
||||
"users_amount": "用户数量",
|
||||
"groups_amount": "用户组数量",
|
||||
"assets_amount": "资产数量",
|
||||
"admin_users_amount": "管理用户数量",
|
||||
"system_users_amount": "系统用户数量",
|
||||
"applications_amount": "应用数量",
|
||||
"asset_perms_amount": "资产授权数量",
|
||||
"app_perms_amount": "应用授权数量",
|
||||
"CreateOrgMsg": "请去组织详情内添加用户",
|
||||
"AddOrgMembers": "添加组织成员"
|
||||
},
|
||||
"RestoreButton": "恢复默认",
|
||||
"SubscriptionID": "订阅授权ID",
|
||||
@@ -913,9 +1102,9 @@
|
||||
"loginImageTip": "提示:将会显示在企业版用户登录页面(建议图片大小为: 492*472px)",
|
||||
"loginTitle": "登录页面标题",
|
||||
"loginTitleTip": "提示:将会显示在企业版用户登录页面(eg: 欢迎使用JumpServer开源堡垒机)",
|
||||
"logoIndex": "管理页面logo",
|
||||
"logoIndex": "Logo (带文字)",
|
||||
"logoIndexTip": "提示:将会显示在管理页面左上方(建议图片大小为: 185px*55px)",
|
||||
"logoLogout": "退出页面logo",
|
||||
"logoLogout": "Logo (不带文字)",
|
||||
"logoLogoutTip": "提示:将会显示在企业版用户退出页面(建议图片大小为:82px*82px)",
|
||||
"restoreDialogMessage": "您确定要恢复默认初始化吗?",
|
||||
"restoreDialogTitle": "你确认吗",
|
||||
|
||||
@@ -2,8 +2,25 @@
|
||||
"": "",
|
||||
"applications": {
|
||||
"": "",
|
||||
"applicationsType": {
|
||||
"chrome": "Chrome",
|
||||
"mysql_workbench": "MySQL Workbench",
|
||||
"vmware_client":"Vmware Client",
|
||||
"custom":"Custom",
|
||||
"mysql": "MySQL",
|
||||
"oracle": "Oracle",
|
||||
"postgresql": "PostgreSQL",
|
||||
"mariadb": "MariaDB",
|
||||
"k8s": "kubernetes"
|
||||
},
|
||||
"applicationsCategory": {
|
||||
"remote_app": "Remote app",
|
||||
"db": "Database app",
|
||||
"cloud": "Cloud app"
|
||||
},
|
||||
"appPath": "App path",
|
||||
"appType": "App type",
|
||||
"appName": "App name",
|
||||
"asset": "Asset",
|
||||
"database": "Database",
|
||||
"host": "Host",
|
||||
@@ -17,6 +34,7 @@
|
||||
"mysql_workbench": "MySQL Workbench",
|
||||
"mysql_workbench_ip": "DB IP",
|
||||
"mysql_workbench_name": "DB Name",
|
||||
"mysql_workbench_port": "DB Port",
|
||||
"mysql_workbench_username": "DB Account",
|
||||
"mysql_workbench_password": "DB Password",
|
||||
"vmware_client": "vSphere Client",
|
||||
@@ -28,20 +46,31 @@
|
||||
"custom_target": "target URL",
|
||||
"custom_username": "Account",
|
||||
"custom_password": "Password",
|
||||
"Custom": "Custom"
|
||||
"Custom": "Custom",
|
||||
"cluster": "Cluster",
|
||||
"kubernetes":"Kubernetes",
|
||||
"clusterHelpTextMessage": "Tips: https://172.16.8.8:8443",
|
||||
"DBInfo": "Database Info"
|
||||
},
|
||||
"assets": {
|
||||
"Action": "Action",
|
||||
"ActiveSelected": "Active selected",
|
||||
"AdminUser": "Admin user",
|
||||
"ReplaceNodeAssetsAdminUser":"Replace node assets admin user with this",
|
||||
"AdminUserDetail": "Admin user detail",
|
||||
"AdminUserListHelpMessage": "Admin users are asset (charged server) on the root, or have NOPASSWD: ALL sudo permissions users, JumpServer users of the system using the user to `push system user`, `get assets hardware information`, etc.\n",
|
||||
"Asset": "Asset",
|
||||
"HardwareInfo": "Hardware info",
|
||||
"Hardware": "Hardware",
|
||||
"AccountList": "Account list",
|
||||
"AssetDetail": "Asset detail",
|
||||
"AssetList": "Asset list",
|
||||
"AssetListHelpMessage": "The left side is the asset tree, right click to create, delete, and change the tree node, authorization asset is also organized as a node, and the right side is the asset under that node\n",
|
||||
"AssetNumber": "Asset number",
|
||||
"AssetUserList": "Asset user list",
|
||||
"TestGatewayTestConnection":"Test gateway test connection",
|
||||
"TestGatewayHelpMessage": "If use nat, set the ssh real port",
|
||||
"SshPort": "SSH Port",
|
||||
"Assets": "Assets",
|
||||
"Auth": "Auth",
|
||||
"AutoGenerateKey": "Auto generate ssh key",
|
||||
@@ -63,6 +92,8 @@
|
||||
"DateUpdated": "Date updated",
|
||||
"DeactiveSelected": "Deactive selected",
|
||||
"Disk": "Disk",
|
||||
"AdDomain": "AD Domain",
|
||||
"AdDomainHelpText": "AD domain provided to domain users for login",
|
||||
"Domain": "Domain",
|
||||
"DomainDetail": "Domain detail",
|
||||
"DomainHelpMessage": "The domain function is added to address the fact that some environments (such as the hybrid cloud) cannot be connected directly by jumping on the gateway server.\nJMS => Domain gateway => Target assets",
|
||||
@@ -106,6 +137,7 @@
|
||||
"RefreshHardware": "Refresh hardware",
|
||||
"RemoteAppListHelpMessage": "Before using this feature, make sure that the application loader has been uploaded to the application server and successfully published as a RemoteApp application <b><a href='https://github.com/jumpserver/Jmservisor/releases'> Download application loader</a></b>",
|
||||
"RemoteApps": "Remote apps",
|
||||
"Applications": "Applications",
|
||||
"RemoteType": "Remote type",
|
||||
"RemoveFromCurrentNode": "Remove from node",
|
||||
"ReplaceNodeAssetsAdminUserWithThis": "Replace node assets admin user with this",
|
||||
@@ -133,7 +165,12 @@
|
||||
"command_filter_list": "Command filter list",
|
||||
"date_joined": "Date joined",
|
||||
"ip": "IP",
|
||||
"sshkey": "sshkey"
|
||||
"sshkey": "sshkey",
|
||||
"GroupsHelpMessage": "Please fill in user groups, separated by commas if there are multiple user groups(Please fill in the existing user groups)",
|
||||
"HomeHelpMessage": "Default home directory: /home/system username",
|
||||
"Home": "Home",
|
||||
"LinuxUserAffiliateGroup": "Linux user affiliate group",
|
||||
"ipDomain": "IP(Domain)"
|
||||
},
|
||||
"audits": {
|
||||
"Hosts": "Host",
|
||||
@@ -148,15 +185,27 @@
|
||||
"common": {
|
||||
"Nothing": "Nothing",
|
||||
"Action": "Action",
|
||||
"CustomCol":"Custom table col",
|
||||
"RequestTickets": "Request tickets",
|
||||
"Actions": "Actions",
|
||||
"NeedSpecifiedFile": "Required to upload the specified format file",
|
||||
"TestPortErrorMsg":"Port Error, please check",
|
||||
"Activate": "Activate",
|
||||
"actionsTips":"Clipboard's copy and paste control only support RDP/VNC protocol.",
|
||||
"Active": "Active",
|
||||
"TableColSettingInfo": "Please select the list details you want to display",
|
||||
"Add": "Add",
|
||||
"PleaseAgreeToTheTerms": "Please agree to the terms",
|
||||
"PushSelected":"Push selected",
|
||||
"UpdateAssetDetail": "Update more detail",
|
||||
"AddSuccessMsg": "Add success",
|
||||
"Auth": "Authorization",
|
||||
"BadRequestErrorMsg": "Bad request, please check again",
|
||||
"BadRoleErrorMsg": "Bad request, no permission for this operation",
|
||||
"BadConflictErrorMsg": "Refreshing, please try again later",
|
||||
"Basic": "Basic",
|
||||
"BasicInfo": "Basic info",
|
||||
"ApplyInfo": "Apply info",
|
||||
"Cancel": "Cancel",
|
||||
"Close": "Close",
|
||||
"Command filter": "Command filter",
|
||||
@@ -166,6 +215,7 @@
|
||||
"CreatedBy": "Created by",
|
||||
"CrontabHelpTips": "eg: Every Sunday 03:05 run <5 3 * * 0> <br>Tips:Using 5 digits linux crontab expressions<min hour day month week> (<a href='https://tool.lu/crontab/' target='_blank'>Online tools</a>) <br>Note:If both Regularly perform and Cycle perform are set,give priority to Regularly perform",
|
||||
"DateEnd": "End date",
|
||||
"Resource": "Resource",
|
||||
"DateLast24Hours": "Last 24 hours",
|
||||
"DateLast3Months": "Last 3 months",
|
||||
"DateLastMonth": "Last month",
|
||||
@@ -185,6 +235,7 @@
|
||||
"MFARequireForSecurity": "MFA required for security",
|
||||
"Members": "Members",
|
||||
"More": "More",
|
||||
"Message": "Message",
|
||||
"MoreActions": "Actions",
|
||||
"Name": "Name",
|
||||
"No": "No",
|
||||
@@ -207,6 +258,7 @@
|
||||
"To": "To",
|
||||
"Update": "Update",
|
||||
"Upload": "Upload",
|
||||
"Clone": "Clone",
|
||||
"Username": "Username",
|
||||
"Validity": "Validity",
|
||||
"Invalidity": "Invalidity",
|
||||
@@ -218,11 +270,15 @@
|
||||
"bulkDeleteSuccessMsg": "Bulk delete success",
|
||||
"bulkRemoveErrorMsg": "Bulk remove failed: ",
|
||||
"bulkRemoveSuccessMsg": "Bulk remove success",
|
||||
"NeedAssetsAndSystemUserErrMsg": "Need assets and systemuser",
|
||||
"createBy": "Create by",
|
||||
"cloneFrom": "Clone from",
|
||||
"createErrorMsg": "Create error",
|
||||
"createSuccessMsg": "Create success",
|
||||
"saveSuccessContinueMsg": "Create success, you may add another",
|
||||
"createdBy": "Created by",
|
||||
"dateCreated": "Date created",
|
||||
"dateFinished": "Date finished",
|
||||
"dateExpired": "Date expired",
|
||||
"dateStart": "Date start",
|
||||
"deleteErrorMsg": "Delete failed",
|
||||
@@ -233,6 +289,7 @@
|
||||
"disableSelected": "Disable selected",
|
||||
"fieldRequiredError": "This field is required",
|
||||
"getErrorMsg": "Get failed",
|
||||
"fileType": "File type",
|
||||
"imExport": {
|
||||
"ExportAll": "Export all",
|
||||
"ExportOnlyFiltered": "Export only filtered",
|
||||
@@ -278,7 +335,8 @@
|
||||
"NUMBER_REQUIRED": "Number required",
|
||||
"SPECIAL_CHAR_REQUIRED": "Special char required",
|
||||
"MIN_LENGTH_ERROR": "Password minimum length {}"
|
||||
}
|
||||
},
|
||||
"lastCannotBeDeleteMsg": "The last one can't be delete"
|
||||
},
|
||||
"dashboard": {
|
||||
"ActiveAsset": "Asset active",
|
||||
@@ -358,7 +416,7 @@
|
||||
},
|
||||
"perms": {
|
||||
"": "",
|
||||
"Actions": "Actions",
|
||||
"Actions": "Permission",
|
||||
"Asset": "Asset",
|
||||
"Basic": "Basic",
|
||||
"Exclude": "Exclude",
|
||||
@@ -369,18 +427,25 @@
|
||||
"SystemUser": "System user",
|
||||
"User": "User",
|
||||
"UserGroups": "UserGroups",
|
||||
"DatabaseAppPermission": "Databases permissions",
|
||||
"RemoteAppPermission": "Remote apps permissions",
|
||||
"KubernetesAppPermission": "Kubernetes permissions",
|
||||
"addAssetToThisPermission": "Add asset to this permission",
|
||||
"addDatabaseAppToThisPermission": "Add DatabaseApp to this permission",
|
||||
"addK8sAppToThisPermission": "Add KubernetesApp to this permission",
|
||||
"addApplicationToThisPermission": "Add Application to this permission",
|
||||
"addNodeToThisPermission": "Add node to this permission",
|
||||
"addRemoteAppToThisPermission": "Add RemoteApp to this permission",
|
||||
"addSystemUserToThisPermission": "System user",
|
||||
"addUserGroupToThisPermission": "Add user group to this permission",
|
||||
"addUserToThisPermission": "Add user to this permission",
|
||||
"all": "All",
|
||||
"PermName":"Perm name",
|
||||
"assetAndNode": "Assets and node",
|
||||
"assetCount": "Asset count",
|
||||
"connect": "Connect",
|
||||
"databaseApp": "DatabaseApp",
|
||||
"KubernetesApp": "KubernetesApp",
|
||||
"dateStart": "Date start",
|
||||
"downloadFile": "Download file",
|
||||
"hostName": "Hostname",
|
||||
@@ -391,15 +456,23 @@
|
||||
"refreshSuccess": "Refresh success",
|
||||
"remoteApp": "RemoteApp",
|
||||
"remoteAppCount": "RemoteApp count",
|
||||
"appsCount": "App count",
|
||||
"appsList":"App list",
|
||||
"DatabaseAppCount": "DatabaseApp count",
|
||||
"KubernetesAppCount": "KubernetesApp count",
|
||||
"systemUserCount": "System user count",
|
||||
"upDownload": "Upload download",
|
||||
"uploadFile": "Upload file",
|
||||
"clipboardCopyPaste":"Copy Paste",
|
||||
"clipboardCopy":"Clipboard copy",
|
||||
"clipboardPaste":"Clipboard paste",
|
||||
"userCount": "User count",
|
||||
"userGroupCount": "User group count",
|
||||
"usersAndUserGroups": "Users and user groups"
|
||||
},
|
||||
"route": {
|
||||
"": "",
|
||||
"Ticket": "Tickets",
|
||||
"AdminUserCreate": "Admin user create",
|
||||
"AdminUserDetail": "Admin user detail",
|
||||
"AdminUserList": "Admin users",
|
||||
@@ -438,6 +511,14 @@
|
||||
"DatabaseAppPermissionDetail": "Databases permissions detail",
|
||||
"DatabaseAppPermissionUpdate": "Databases permissions update",
|
||||
"DatabaseAppUpdate": "Database app update",
|
||||
"KubernetesApp": "Kubernetes apps",
|
||||
"KubernetesAppCreate": "Kubernetes app create",
|
||||
"KubernetesAppDetail": "Kubernetes app detail",
|
||||
"KubernetesAppPermission": "Kubernetes permissions",
|
||||
"KubernetesAppPermissionCreate": "Kubernetes permissions create",
|
||||
"KubernetesAppPermissionDetail": "Kubernetes permissions detail",
|
||||
"KubernetesAppPermissionUpdate": "Kubernetes permissions update",
|
||||
"KubernetesAppUpdate": "Kubernetes app update",
|
||||
"DomainCreate": "Domain create",
|
||||
"DomainDetail": "Domain detail",
|
||||
"DomainList": "Domains",
|
||||
@@ -464,6 +545,7 @@
|
||||
"RemoteApp": "Remote apps",
|
||||
"RemoteAppDetail": "Remote app detail",
|
||||
"RemoteAppPermission": "Remote apps permissions",
|
||||
"ApplicationPermission": "Application permissions",
|
||||
"RemoteAppPermissionCreate": "Remote apps permission create",
|
||||
"RemoteAppPermissionDetail": "Remote apps permissions detail",
|
||||
"RemoteAppPermissionUpdate": "Remote app permission update",
|
||||
@@ -483,6 +565,7 @@
|
||||
"TaskMonitor": "Task monitor",
|
||||
"Terminal": "Terminal",
|
||||
"TicketDetail": "Ticket detail",
|
||||
"TicketCreate": "Ticket create",
|
||||
"Tickets": "Tickets",
|
||||
"UserCreate": "User create",
|
||||
"UserDetail": "User detail",
|
||||
@@ -506,6 +589,7 @@
|
||||
"active": "active",
|
||||
"alive": "alive",
|
||||
"asset": "Asset",
|
||||
"target": "Target",
|
||||
"bucket": "Bucket",
|
||||
"command": "Command",
|
||||
"commandStorage": "Command storage",
|
||||
@@ -521,6 +605,10 @@
|
||||
"duration": "Duration",
|
||||
"endPoint": "Endpoint",
|
||||
"endpointSuffix": "Endpoint suffix",
|
||||
"sessionActiveCount": "session active count",
|
||||
"systemCpuLoad": "cpu load",
|
||||
"systemDiskUsedPercent": "disk used percent",
|
||||
"systemMemoryUsedPercent": "memory used percent",
|
||||
"go": "Go",
|
||||
"goto": "Goto",
|
||||
"hosts": "Hosts",
|
||||
@@ -544,7 +632,9 @@
|
||||
"systemUser": "System user",
|
||||
"terminalDetail": "Terminal detail",
|
||||
"terminalUpdate": "Update terminal",
|
||||
"terminalUpdateStorage": "Update terminal storage",
|
||||
"terminate": "Terminate",
|
||||
"sessionTerminate": "Session Terminate",
|
||||
"test": "Test",
|
||||
"type": "Type",
|
||||
"user": "Use",
|
||||
@@ -552,7 +642,15 @@
|
||||
"common": "common"
|
||||
},
|
||||
"Monitor": "Monitor",
|
||||
"TerminateTaskSendSuccessMsg": "Terminate task has been send, Please check later"
|
||||
"sessionMonitor": "Session Monitor",
|
||||
"TerminateTaskSendSuccessMsg": "Terminate task has been send, Please check later",
|
||||
"helpText": {
|
||||
"esUrl": "Tip: If you have multiple hosts, use comma (,) to split (eg: http://www.jumpserver.a.com,http://www.jumpserver.b.com)",
|
||||
"esIndex":"Es provides the default index: jumpserver",
|
||||
"esDocType": "Es provides the default document type: command",
|
||||
"s3Endpoint": "S3: http://s3.{REGION_NAME}.amazonaws.com<br>S3(China): http://s3.{REGION_NAME}.amazonaws.com.cn<br>Example: http://s3.cn-north-1.amazonaws.com.cn",
|
||||
"ossEndpoint": "OSS: http://{REGION_NAME}.aliyuncs.com<br>Example: http://oss-cn-hangzhou.aliyuncs.com"
|
||||
}
|
||||
},
|
||||
"setting": {
|
||||
"ApiKeyList": "Api key list",
|
||||
@@ -583,6 +681,7 @@
|
||||
"authLdapSearchOu": "User OU",
|
||||
"authLdapServerUri": "LDAP server",
|
||||
"authLdapUserAttrMap": "User attr map",
|
||||
"unselectedUser": "Unselected user",
|
||||
"auto": "Auto",
|
||||
"basicSetting": "Basic setting",
|
||||
"communityEdition": "Community edition",
|
||||
@@ -675,7 +774,10 @@
|
||||
"userGuideUrl": "User Guide URL",
|
||||
"username": "Username",
|
||||
"usernamePlaceholder": "Please input username",
|
||||
"refreshLdapCache":"Refreshing Ldap cache "
|
||||
"refreshLdapCache":"Refreshing Ldap cache ",
|
||||
"LicenseExpired": "License expired",
|
||||
"LicenseWillBe": "License will expire at ",
|
||||
"Expire": ""
|
||||
},
|
||||
"settings": {
|
||||
"setting": "Setting"
|
||||
@@ -684,10 +786,19 @@
|
||||
"Accept": "Accept",
|
||||
"AssignedMe": "Assigned me",
|
||||
"Assignee": "Assignee",
|
||||
"RequestPerm":"Request Perm",
|
||||
"AssignedInfo":"Assigned Info",
|
||||
"OpenTicket": "Open Ticket",
|
||||
"HandleTicket": "Handle Ticket",
|
||||
"FinishedTicket": "Finished Ticket",
|
||||
"Assignees": "Assignees",
|
||||
"Close": "Close",
|
||||
"OpenStatus":"Open",
|
||||
"CloseStatus":"Close",
|
||||
"Comment": "Comment",
|
||||
"MyTickets": "My tickets",
|
||||
"action": "Action",
|
||||
"IPGroup": "IP 组",
|
||||
"Reject": "Reject",
|
||||
"date": "Date",
|
||||
"reply": "Reply",
|
||||
@@ -696,7 +807,24 @@
|
||||
"type": "Type",
|
||||
"user": "User",
|
||||
"Status": "Status",
|
||||
"Open": "Open"
|
||||
"Open": "Open",
|
||||
"OrgName":"Org name",
|
||||
"IP": "IP",
|
||||
"Hostname": "Hostname",
|
||||
"Asset": "Asset",
|
||||
"SystemUser": "System user",
|
||||
"Applicant": "Applicant",
|
||||
"RequestAssetPerm": "Request asset perm",
|
||||
"RequestApplicationPerm": "Request application perm",
|
||||
"Pending": "Open",
|
||||
"Approved": "Approved",
|
||||
"Rejected": "Rejected",
|
||||
"Closed": "Closed",
|
||||
"helpText": {
|
||||
"ips": "Enter the IP address group, separated by commas",
|
||||
"fuzzySearch": "Support for fuzzy search",
|
||||
"application": "Enter the application group, separated by commas"
|
||||
}
|
||||
},
|
||||
"tree": {
|
||||
"AddAssetToNode": "Add asset to node",
|
||||
@@ -706,12 +834,14 @@
|
||||
"RenameNode": "Rename node",
|
||||
"ShowAssetAllChildrenNode": "Show asset all children node",
|
||||
"ShowAssetOnlyCurrentNode": "Show asset only current node",
|
||||
"CheckAssetsAmount": "Check assets amount",
|
||||
"ShowNodeInfo": "Show node information",
|
||||
"TestNodeAssetConnectivity": "Test node asset connectivity",
|
||||
"UpdateNodeAssetHardwareInfo": "Update node asset hardware information"
|
||||
},
|
||||
"users": {
|
||||
"Account": "Account",
|
||||
"Existing":"Existing",
|
||||
"Authentication": "Account",
|
||||
"Comment": "Comment",
|
||||
"ConfirmPassword": "Confirm password",
|
||||
@@ -724,11 +854,19 @@
|
||||
"Email": "Email",
|
||||
"FingerPrint": "Fingerprint",
|
||||
"FirstLogin": "First login",
|
||||
"InviteUser": "Invite user",
|
||||
"InviteUserInOrg": "Invite user in this org",
|
||||
"Invite": "Invite",
|
||||
"Guide": "Guide",
|
||||
"OrgUser": "Org User",
|
||||
"OrgAdmin": "Org Admin",
|
||||
"OrgAuditor": "Org Auditor",
|
||||
|
||||
"HelpText": {
|
||||
"MFAOfUserFirstLoginPersonalInformationImprovementPage": "Enable multi-factor authentication to make the account more secure <br/> After is enabled, you will enter the multi-factor authentication binding process on your next login <br/> You can also bind directly in (personal information -> fast modifier -> modifier multiple factor Settings)",
|
||||
"MFAOfUserFirstLoginUserGuidePage": "To protect the security of you and the company <br/> please properly keep your account, password, key and other important and sensitive information <br/> (e.g., set a complex password and enable multi-factor authentication)",
|
||||
"SSHKeyOfProfileSSHUpdatePage": "Copy your public key here"
|
||||
"SSHKeyOfProfileSSHUpdatePage": "Copy your public key here",
|
||||
"OrgRoleHelpText": "Organizational roles are the user's role in the current organization"
|
||||
},
|
||||
"IAgree": "I agree",
|
||||
"ImprovePersonalInformation": "Improve personal information",
|
||||
@@ -747,6 +885,8 @@
|
||||
"ResetAndDownloadSSHKey": "Reset and download SSH Key",
|
||||
"ResetPublicKeyAndDownload": "Reset public key and download",
|
||||
"Role": "Role",
|
||||
"SuperRole": "Super role",
|
||||
"OrgRole": "Org role",
|
||||
"SSHKey": "SSH Key",
|
||||
"SSHKeySetting": "SSH Key setting",
|
||||
"Secure": "Secure",
|
||||
@@ -777,13 +917,20 @@
|
||||
"tabs": {
|
||||
"assetPermissionRules": "Asset permission rules",
|
||||
"databasePermissionRules": "Database Permission rules",
|
||||
"k8sPermissionRules": "Kubernetes Permission rules",
|
||||
"grantedAssets": "Granted assets",
|
||||
"grantedK8Ss":"Granted K8Ss",
|
||||
"grantedDatabases": "Granted databases",
|
||||
"grantedRemoteApps": "Granted remote apps",
|
||||
"grantedApplications": "Granted applications",
|
||||
"ApplicationPermissionRules": "Application permission rules",
|
||||
"remoteAppPermissionRules": "Remote app permission rules"
|
||||
},
|
||||
"UpdatePassword": "",
|
||||
"UpdatePublicKey": ""
|
||||
"UpdatePublicKey": "",
|
||||
"passwordExpired": "Password expired",
|
||||
"passwordWillExpiredPrefixMsg": "The password will expire in ",
|
||||
"passwordWillExpiredSuffixMsg": " days.Please change your password as soon as possible."
|
||||
},
|
||||
"xpack": {
|
||||
"Admin": "Admin",
|
||||
@@ -808,6 +955,9 @@
|
||||
"ExecutionDetail": "Execution detail",
|
||||
"ExecutionList": "Execution list",
|
||||
"ExecutionTimes": "Execution times",
|
||||
"validatorMessage": {
|
||||
"EnsureThisValueIsGreaterThanOrEqualTo1": "Ensure this value is greater than or equal to 1"
|
||||
},
|
||||
"HelpText": {
|
||||
"CrontabOfCreateUpdatePage": "For example: every Sunday at 03:05 execute <5 3 * * 0> <br/> Using the 5-bit Linux crontab expression <minute hour day month week> (<a href=\"https://tool.lu/crontab/\" target=\"_blank\"> Online tool </a>) <br/> If both regularly perform and cycle perform execution are set, use regularly perform first",
|
||||
"IntervalOfCreateUpdatePage": "Unit: hour",
|
||||
@@ -829,12 +979,22 @@
|
||||
"Username": "Username"
|
||||
},
|
||||
"Cloud": {
|
||||
"Aliyun": "Ali Cloud",
|
||||
"Qcloud": "Tencent Cloud",
|
||||
"AWS_China": "AWS(China)",
|
||||
"AWS_Int": "AWS(International)",
|
||||
"HuaweiCloud": "Huawei Cloud",
|
||||
"Azure":"Azure(China)",
|
||||
"HostnameStrategy": "Used to produce the asset hostname. For example, 1. Instance name (instanceDemo);2. Instance name and Partial IP (instanceDemo-250.1)",
|
||||
"IsAlwaysUpdate": "Asset info is kept up-to-date",
|
||||
"AccountCreate": "Create account",
|
||||
"AccountList": "Account list",
|
||||
"AccountUpdate": "Update account",
|
||||
"AccountDetail": "Account detail",
|
||||
"Cloud": "Cloud center",
|
||||
"CloudCenter": "Cloud center",
|
||||
"Provider": "Provider",
|
||||
"Validity": "Validity",
|
||||
"IsAlwaysUpdateHelpTips": "Whether the asset information, including Hostname, IP, Platform, and AdminUser, is updated synchronously each time a synchronization task is performed",
|
||||
"SyncInstanceTaskCreate": "Create sync instance task",
|
||||
"SyncInstanceTaskList": "Sync instance task list",
|
||||
@@ -885,6 +1045,13 @@
|
||||
"InterfaceSettings": "Interface setting",
|
||||
"License": "License",
|
||||
"LicenseDetail": "License detail",
|
||||
"SystemMonitor": "System Monitor",
|
||||
"ServiceRatio": "Service ratio",
|
||||
"LoadStatus":"Status",
|
||||
"NormalLoad":"Normal",
|
||||
"HighLoad":"High",
|
||||
"Offline": "Offline",
|
||||
"CriticalLoad":"Critical",
|
||||
"LicenseFile": "License file",
|
||||
"NoLicense": "No License",
|
||||
"Node": "Node",
|
||||
@@ -893,8 +1060,20 @@
|
||||
"OrganizationDetail": "Org detail",
|
||||
"OrganizationList": "Organlizations",
|
||||
"OrganizationUpdate": "Update org",
|
||||
"OrganizationMembership": "Organization membership",
|
||||
"DeleteOrgTitle":"Please ensure that the following information in the organization has been deleted",
|
||||
"DeleteOrgMsg":"User list、User group、Asset list、Domain list、Admin user、System user、Labels、Asset permission"
|
||||
"DeleteOrgMsg":"User list、User group、Asset list、Domain list、Admin user、System user、Labels、Asset permission",
|
||||
"OrgRole": "Org role",
|
||||
"CreateOrgMsg": "Please go to Organization Details to add users",
|
||||
"AddOrgMembers": "Add organization members",
|
||||
"users_amount": "Users amount",
|
||||
"groups_amount": "Groups amount",
|
||||
"assets_amount": "Assets amount",
|
||||
"admin_users_amount": "Admin users amount",
|
||||
"system_users_amount": "System users amount",
|
||||
"applications_amount": "Applications amount",
|
||||
"asset_perms_amount": "Asset perms amount",
|
||||
"app_perms_amount": "App perms amount"
|
||||
},
|
||||
"RestoreButton": "Restore Default",
|
||||
"SubscriptionID": "Subscription ID",
|
||||
@@ -911,9 +1090,9 @@
|
||||
"loginImageTip": "Tips: This will be displayed on the enterprise user login page. (suggest image size: 492px*472px)",
|
||||
"loginTitle": "Title of login page",
|
||||
"loginTitleTip": "Tips: This will be displayed on the enterprise user login page. (eg: Welcome to the JumpServer open source fortress)",
|
||||
"logoIndex": "Logo of management page",
|
||||
"logoIndex": "Logo (It contains text)",
|
||||
"logoIndexTip": "Tips: This will appear at the top left of the administration page. (suggest image size: 185px*55px)",
|
||||
"logoLogout": "Logo of logout page",
|
||||
"logoLogout": "Logo (It contains no text)",
|
||||
"logoLogoutTip": "Tips: This will be displayed on the enterprise user logout page. (suggest image size: 82px*82px)",
|
||||
"restoreDialogMessage": "This will restore default Settings of the interface !!!",
|
||||
"restoreDialogTitle": "Are you sure?",
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="footer" :style="style">
|
||||
<div class="pull-right">
|
||||
Version <strong>2.0.2</strong> <span v-if="!publicSettings.XPACK_LICENSE_IS_VALID"> GPLv2. </span>
|
||||
Version <strong> dev </strong> <span v-if="!publicSettings.XPACK_LICENSE_IS_VALID"> GPLv2. </span>
|
||||
</div>
|
||||
<div v-if="!publicSettings.XPACK_LICENSE_IS_VALID" style="padding-left:20px;">
|
||||
<strong>Copyright</strong> FIT2CLOUD 飞致云 © 2014-2020
|
||||
<strong>Copyright</strong> FIT2CLOUD 飞致云 © 2014-2021
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
:method="method"
|
||||
:form="form"
|
||||
:url="iUrl"
|
||||
:has-save-continue="iHasSaveContinue"
|
||||
:has-reset="iHasReset"
|
||||
:is-submitting="isSubmitting"
|
||||
v-bind="$attrs"
|
||||
v-on="$listeners"
|
||||
@@ -13,50 +15,66 @@
|
||||
</template>
|
||||
<script>
|
||||
import AutoDataForm from '@/components/AutoDataForm'
|
||||
import deepmerge from 'deepmerge'
|
||||
export default {
|
||||
name: 'GenericCreateUpdateForm',
|
||||
components: {
|
||||
AutoDataForm
|
||||
},
|
||||
props: {
|
||||
// 创建对象的地址
|
||||
url: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 更新的对象
|
||||
object: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
// form的默认值
|
||||
initial: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
// 提交前,清理form的值
|
||||
cleanFormValue: {
|
||||
type: Function,
|
||||
default: (value) => value
|
||||
},
|
||||
// 当提交的时候,怎么处理
|
||||
onSubmit: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
// 如何提交数据
|
||||
performSubmit: {
|
||||
type: Function,
|
||||
default(validValues) {
|
||||
return this.$axios[this.method](this.iUrl, validValues)
|
||||
}
|
||||
},
|
||||
// 创建成功的msg
|
||||
createSuccessMsg: {
|
||||
type: String,
|
||||
default: function() {
|
||||
return this.$t('common.createSuccessMsg')
|
||||
}
|
||||
},
|
||||
// 更新成功的msg
|
||||
saveSuccessContinueMsg: {
|
||||
type: String,
|
||||
default: function() {
|
||||
return this.$t('common.saveSuccessContinueMsg')
|
||||
}
|
||||
},
|
||||
updateSuccessMsg: {
|
||||
type: String,
|
||||
default: function() {
|
||||
return this.$t('common.updateSuccessMsg')
|
||||
}
|
||||
},
|
||||
// 创建成功的跳转路由
|
||||
createSuccessNextRoute: {
|
||||
type: Object,
|
||||
default: function() {
|
||||
@@ -64,6 +82,7 @@ export default {
|
||||
return { name: routeName }
|
||||
}
|
||||
},
|
||||
// 更新成功的跳转路由
|
||||
updateSuccessNextRoute: {
|
||||
type: Object,
|
||||
default: function() {
|
||||
@@ -71,12 +90,21 @@ export default {
|
||||
return { name: routeName }
|
||||
}
|
||||
},
|
||||
objectDetailRoute: {
|
||||
type: Object,
|
||||
default: function() {
|
||||
const routeName = this.$route.name.replace('Update', 'Detail').replace('Create', 'Detail')
|
||||
return { name: routeName }
|
||||
}
|
||||
},
|
||||
// 获取下一个路由
|
||||
getNextRoute: {
|
||||
type: Function,
|
||||
default(res, method) {
|
||||
return method === 'post' ? this.createSuccessNextRoute : this.updateSuccessNextRoute
|
||||
}
|
||||
},
|
||||
// 获取提交的方法
|
||||
getMethod: {
|
||||
type: Function,
|
||||
default: function() {
|
||||
@@ -88,6 +116,7 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
// 获取创建和更新的url function
|
||||
getUrl: {
|
||||
type: Function,
|
||||
default: function() {
|
||||
@@ -101,12 +130,47 @@ export default {
|
||||
},
|
||||
onPerformSuccess: {
|
||||
type: Function,
|
||||
default(res, method, vm) {
|
||||
const msg = method === 'post' ? this.createSuccessMsg : this.updateSuccessMsg
|
||||
default(res, method, vm, addContinue) {
|
||||
let msg = method === 'post' ? this.createSuccessMsg : this.updateSuccessMsg
|
||||
if (addContinue) {
|
||||
msg = this.saveSuccessContinueMsg
|
||||
}
|
||||
let msgLinkName = this.$t('common.Resource')
|
||||
if (res.name) {
|
||||
msgLinkName = res.name
|
||||
} else if (res.hostname) {
|
||||
msgLinkName = res.hostname
|
||||
}
|
||||
const detailRoute = this.objectDetailRoute
|
||||
detailRoute['params'] = { 'id': res.id }
|
||||
const route = this.getNextRoute(res, method)
|
||||
this.$emit('submitSuccess', res)
|
||||
this.$message.success(msg)
|
||||
setTimeout(() => this.$router.push(route), 100)
|
||||
const h = this.$createElement
|
||||
this.$log.debug('router is: ', detailRoute)
|
||||
if (this.hasDetailInMsg) {
|
||||
this.$message({
|
||||
message: h('p', null, [
|
||||
h('el-link', {
|
||||
on: {
|
||||
click: () => this.$router.push(detailRoute)
|
||||
},
|
||||
style: { 'vertical-align': 'top' }
|
||||
}, msgLinkName),
|
||||
h('span', { style: {
|
||||
'padding-left': '5px',
|
||||
'height': '18px',
|
||||
'line-height': '18px',
|
||||
'font-size': '13.5px',
|
||||
'font-weight': ' 400' }}, msg)
|
||||
]),
|
||||
type: 'success'
|
||||
})
|
||||
} else {
|
||||
this.$message.success(msg)
|
||||
}
|
||||
if (!addContinue) {
|
||||
setTimeout(() => this.$router.push(route), 100)
|
||||
}
|
||||
}
|
||||
},
|
||||
onPerformError: {
|
||||
@@ -125,13 +189,22 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
hasSaveContinue: {
|
||||
type: Boolean,
|
||||
default: null
|
||||
},
|
||||
hasDetailInMsg: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
loading: true,
|
||||
isSubmitting: false
|
||||
isSubmitting: false,
|
||||
clone: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -140,44 +213,77 @@ export default {
|
||||
},
|
||||
iUrl() {
|
||||
return this.getUrl()
|
||||
},
|
||||
iHasSaveContinue() {
|
||||
if (this.hasSaveContinue != null) {
|
||||
return this.hasSaveContinue
|
||||
}
|
||||
return this.method === 'post'
|
||||
},
|
||||
iHasReset() {
|
||||
if (this.hasReset != null) {
|
||||
return this.hasReset
|
||||
}
|
||||
return this.method === 'put'
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
this.$log.debug('Object init is: ', this.object)
|
||||
this.loading = true
|
||||
try {
|
||||
const values = await this.getFormValue()
|
||||
this.$log.debug('Final object is: ', values)
|
||||
this.form = Object.assign(this.form, values)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSubmit(values) {
|
||||
handleSubmit(values, formName, addContinue) {
|
||||
let handler = this.onSubmit || this.defaultOnSubmit
|
||||
handler = handler.bind(this)
|
||||
values = this.cleanFormValue(values)
|
||||
return handler(values)
|
||||
return handler(values, formName, addContinue)
|
||||
},
|
||||
defaultOnSubmit(validValues) {
|
||||
defaultOnSubmit(validValues, formName, addContinue) {
|
||||
this.isSubmitting = true
|
||||
this.performSubmit(validValues)
|
||||
.then((res) => this.onPerformSuccess.bind(this)(res, this.method, this))
|
||||
.then((res) => this.onPerformSuccess.bind(this)(res, this.method, this, addContinue))
|
||||
.catch((error) => this.onPerformError(error, this.method, this))
|
||||
.finally(() => { this.isSubmitting = false })
|
||||
},
|
||||
async getFormValue() {
|
||||
if (this.method !== 'put') {
|
||||
const cloneFrom = this.$route.query['clone_from']
|
||||
if (this.method !== 'put' && !cloneFrom) {
|
||||
return Object.assign(this.form, this.initial)
|
||||
}
|
||||
let object = this.object
|
||||
if (object === null) {
|
||||
object = await this.getObjectDetail()
|
||||
if (!object) {
|
||||
if (cloneFrom) {
|
||||
this.$log.debug('Clone from: ', cloneFrom)
|
||||
const url = `${this.url}${cloneFrom}/`
|
||||
object = await this.getObjectDetail(url)
|
||||
if (object['name']) {
|
||||
object.name = this.$t('common.cloneFrom') + ' ' + object.name
|
||||
} else if (object['hostname']) {
|
||||
object.hostname = this.$t('common.cloneFrom') + ' ' + object.hostname
|
||||
}
|
||||
} else {
|
||||
object = await this.getObjectDetail(this.iUrl)
|
||||
}
|
||||
}
|
||||
if (object) {
|
||||
if (object['attrs']) {
|
||||
object = deepmerge(object, object['attrs'])
|
||||
}
|
||||
this.$log.debug('Object is: ', object)
|
||||
this.$emit('update:object', object)
|
||||
}
|
||||
return object
|
||||
},
|
||||
async getObjectDetail() {
|
||||
return this.$axios.get(this.iUrl)
|
||||
async getObjectDetail(url) {
|
||||
this.$log.debug('Get object detail: ', url)
|
||||
return this.$axios.get(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Page>
|
||||
<Page v-bind="$attrs">
|
||||
<IBox>
|
||||
<GenericCreateUpdateForm ref="createUpdateForm" v-bind="$attrs" v-on="$listeners" />
|
||||
</IBox>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<Page v-bind="$attrs">
|
||||
<ListTable v-bind="$attrs" />
|
||||
<ListTable ref="ListTable" v-bind="$attrs" />
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<template>
|
||||
<Dialog
|
||||
v-if="dialogSetting.dialogVisible"
|
||||
:title="this.$t('common.updateSelected')"
|
||||
:visible.sync="dialogSetting.dialogVisible"
|
||||
width="70%"
|
||||
@@ -99,6 +98,7 @@ export default {
|
||||
const url = this.url
|
||||
const msg = this.updateSuccessMsg
|
||||
this.$axios.patch(url, validValues).then((res) => {
|
||||
vm.$emit('update')
|
||||
this.$message.success(msg)
|
||||
vm.dialogSetting.dialogVisible = false
|
||||
}).catch(error => {
|
||||
|
||||
@@ -82,7 +82,7 @@ export default {
|
||||
case 'userPage':
|
||||
if (this.currentOrgUsePagePerm) {
|
||||
this.$store.dispatch('users/setCurrentRole', rolec.USER)
|
||||
console.log('Switch to: ', rolec.USER)
|
||||
// console.log('Switch to: ', rolec.USER)
|
||||
window.location.href = `/ui/`
|
||||
}
|
||||
break
|
||||
@@ -97,7 +97,7 @@ export default {
|
||||
},
|
||||
logout() {
|
||||
// Clean Status
|
||||
const statusList = ['currentOrg', 'currentRole', 'jms_current_org', 'jms_current_role', 'sidebarStatus', 'django_language', 'X-JMS-ORG', 'activeTab']
|
||||
const statusList = ['currentOrg', 'currentRole', 'jms_current_org', 'jms_current_role', 'sidebarStatus', 'X-JMS-ORG', 'activeTab']
|
||||
for (const i in statusList) {
|
||||
this.$cookie.delete(statusList[i])
|
||||
}
|
||||
|
||||
@@ -31,25 +31,46 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
supportedLangMapper() {
|
||||
return this.supportLanguages.reduce((map, obj) => {
|
||||
map[obj.code] = obj
|
||||
return map
|
||||
})
|
||||
},
|
||||
currentLang() {
|
||||
const cookieCode = this.$cookie.get(this.LANG_COOKIE_NAME)
|
||||
let lang = this.supportLanguages.find((v) => v.cookieCode === cookieCode)
|
||||
const langCode = this.getLangCode()
|
||||
let lang = this.supportedLangMapper[langCode]
|
||||
if (!lang) {
|
||||
lang = this.supportLanguages[0]
|
||||
this.changeLangTo(lang)
|
||||
}
|
||||
if (lang.code !== this.$i18n.locale) {
|
||||
this.changeLangTo(lang)
|
||||
}
|
||||
return lang
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.currentLang.code !== this.$i18n.locale) {
|
||||
this.changeLangTo(this.currentLang)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeLangTo(item) {
|
||||
this.$i18n.locale = item.code
|
||||
localStorage.setItem('lang', item.code)
|
||||
this.$cookie.set(this.LANG_COOKIE_NAME, item.cookieCode)
|
||||
window.location.reload()
|
||||
},
|
||||
getLangCode() {
|
||||
let langCode = localStorage.lang
|
||||
if (!langCode) {
|
||||
langCode = this.$cookie.get(this.LANG_COOKIE_NAME)
|
||||
}
|
||||
if (!langCode) {
|
||||
langCode = navigator.language || navigator.userLanguage
|
||||
}
|
||||
langCode = langCode.substr(0, 2)
|
||||
langCode = langCode.replace('zh', 'cn')
|
||||
if (langCode) {
|
||||
return langCode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
51
src/layout/components/NavHeader/Tickets.vue
Normal file
51
src/layout/components/NavHeader/Tickets.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- <el-link class="el-link" target="_blank" @click="goToTickets">{{ $t('route.Ticket') }}</el-link>-->
|
||||
<el-badge :value="assignedTicketCount" :hidden="assignedTicketCount===0" size="mini" type="primary">
|
||||
<el-link class="el-link" target="_blank" @click="goToTickets">{{ $t('route.Ticket') }}</el-link>
|
||||
</el-badge>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getTicketOpenCount } from '@/api/ticket'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'WebTerminal',
|
||||
data() {
|
||||
return {
|
||||
assignedTicketCount: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'currentUser'
|
||||
])
|
||||
},
|
||||
created() {
|
||||
this.ticketsOpenedCount()
|
||||
},
|
||||
methods: {
|
||||
ticketsOpenedCount() {
|
||||
getTicketOpenCount(this.currentUser.id).then(data => {
|
||||
this.assignedTicketCount = data.count
|
||||
})
|
||||
},
|
||||
goToTickets() {
|
||||
this.$router.push({ name: 'TicketList' })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-link {
|
||||
color: #606266 !important;
|
||||
font-size: 13px;
|
||||
font-weight: 400
|
||||
}
|
||||
.el-badge ::v-deep .el-badge__content.is-fixed{
|
||||
top:10px;
|
||||
}
|
||||
</style>
|
||||
24
src/layout/components/NavHeader/WebTerminal.vue
Normal file
24
src/layout/components/NavHeader/WebTerminal.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<el-link class="el-link" :href="webTerminalUrl" target="_blank">{{ $t('route.WebTerminal') }}</el-link>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BASE_URL } from '@/utils/common'
|
||||
|
||||
export default {
|
||||
name: 'WebTerminal',
|
||||
computed: {
|
||||
webTerminalUrl() {
|
||||
return `${BASE_URL}/luna/?_=${Date.now()}`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-link {
|
||||
color: #606266 !important;
|
||||
font-size: 13px;
|
||||
font-weight: 400
|
||||
}
|
||||
</style>
|
||||
@@ -10,6 +10,19 @@
|
||||
<div class="header-item">
|
||||
<Language />
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
publicSettings.TICKETS_ENABLED
|
||||
&& publicSettings.XPACK_LICENSE_IS_VALID
|
||||
&& !isOrgAuditor
|
||||
"
|
||||
class="header-item"
|
||||
>
|
||||
<Tickets />
|
||||
</div>
|
||||
<div class="header-item">
|
||||
<WebTerminal />
|
||||
</div>
|
||||
<div class="header-item header-profile">
|
||||
<AccountDropdown />
|
||||
</div>
|
||||
@@ -23,6 +36,9 @@ import Hamburger from '@/components/Hamburger'
|
||||
import AccountDropdown from './AccountDropdown'
|
||||
import Help from './Help'
|
||||
import Language from './Language'
|
||||
import WebTerminal from './WebTerminal'
|
||||
import Tickets from './Tickets'
|
||||
import rolc from '@/utils/role'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -30,7 +46,9 @@ export default {
|
||||
Hamburger,
|
||||
AccountDropdown,
|
||||
Language,
|
||||
Help
|
||||
Help,
|
||||
Tickets,
|
||||
WebTerminal
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -38,8 +56,11 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'sidebar'
|
||||
])
|
||||
'sidebar', 'publicSettings', 'currentOrgRoles'
|
||||
]),
|
||||
isOrgAuditor() {
|
||||
return rolc.getRolesDisplay(this.currentOrgRoles).includes('OrgAuditor') || rolc.getRolesDisplay(this.currentOrgRoles).includes('Auditor')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleSideBar() {
|
||||
|
||||
64
src/layout/components/Page/LicenseExpireTip.vue
Normal file
64
src/layout/components/Page/LicenseExpireTip.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div v-if="!loading">
|
||||
<el-alert v-if="isExpire" type="error">
|
||||
{{ isExpire }}
|
||||
</el-alert>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { toSafeLocalDateStr } from '@/utils/common'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'LicenseExpireTip',
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
licenseData: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'publicSettings',
|
||||
'currentUser'
|
||||
]),
|
||||
isExpire() {
|
||||
if (!this.publicSettings.XPACK_ENABLED || this.currentUser.role !== 'Admin') {
|
||||
return false
|
||||
}
|
||||
const intervalDays = this.getIntervalDays(this.licenseData.date_expired)
|
||||
if (intervalDays < 0) {
|
||||
return this.$t('setting.LicenseExpired')
|
||||
}
|
||||
if (intervalDays < 7) {
|
||||
return this.$t('setting.LicenseWillBe') + this.licenseData.date_expired + this.$t('setting.Expire')
|
||||
}
|
||||
return false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.publicSettings.XPACK_ENABLED && this.currentUser.role === 'Admin') {
|
||||
this.$axios.get('/api/v1/xpack/license/detail').then(res => {
|
||||
this.licenseData = res
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
} else {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getIntervalDays(date) {
|
||||
const dateExpired = new Date(toSafeLocalDateStr(date))
|
||||
const dateNow = new Date()
|
||||
const intervalTime = dateExpired.getTime() - dateNow.getTime()
|
||||
return Math.floor(intervalTime / (24 * 3600 * 1000))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,22 +1,34 @@
|
||||
<template>
|
||||
<div class="page-heading">
|
||||
<el-row :gutter="0">
|
||||
<el-col :span="16" class="page-heading-left">
|
||||
<slot><h2>{{ title }}</h2></slot>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="page-heading-right">
|
||||
<slot name="rightSide" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div>
|
||||
<slot name="globalNotification">
|
||||
<LicenseExpireTip />
|
||||
<PasswordExpireTip />
|
||||
</slot>
|
||||
<div class="page-heading">
|
||||
<el-row :gutter="0">
|
||||
<el-col :span="16" class="page-heading-left">
|
||||
<slot><h2>{{ title }}</h2></slot>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="page-heading-right">
|
||||
<slot name="rightSide" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <Breadcrumb />-->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LicenseExpireTip from '@/layout/components/Page/LicenseExpireTip'
|
||||
import PasswordExpireTip from '@/layout/components/Page/PasswordExpireTip'
|
||||
export default {
|
||||
name: 'PageHeading',
|
||||
components: {
|
||||
LicenseExpireTip,
|
||||
PasswordExpireTip
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
|
||||
55
src/layout/components/Page/PasswordExpireTip.vue
Normal file
55
src/layout/components/Page/PasswordExpireTip.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert v-if="isExpire" type="error">
|
||||
{{ isExpire }}
|
||||
</el-alert>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { toSafeLocalDateStr } from '@/utils/common'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'PasswordExpireTip',
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
securityData: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'publicSettings',
|
||||
'currentUser'
|
||||
]),
|
||||
isExpire() {
|
||||
// 用户来源不是Local时不显示密码过期提示
|
||||
if (this.currentUser.source !== 'local') {
|
||||
return false
|
||||
}
|
||||
const intervalTime = this.getIntervalDays(this.currentUser.date_password_last_updated)
|
||||
const securityPasswordExpirationTime = this.publicSettings.SECURITY_PASSWORD_EXPIRATION_TIME
|
||||
if (intervalTime >= securityPasswordExpirationTime) {
|
||||
return this.$t('users.passwordExpired')
|
||||
}
|
||||
if (securityPasswordExpirationTime - intervalTime <= 5) {
|
||||
return this.$t('users.passwordWillExpiredPrefixMsg') + (securityPasswordExpirationTime - intervalTime) + this.$t('users.passwordWillExpiredSuffixMsg')
|
||||
}
|
||||
return false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getIntervalDays(date) {
|
||||
const dateExpired = new Date(toSafeLocalDateStr(date))
|
||||
const dateNow = new Date()
|
||||
const intervalTime = dateNow.getTime() - dateExpired.getTime()
|
||||
return Math.floor(intervalTime / (24 * 3600 * 1000))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -9,7 +9,14 @@
|
||||
|
||||
<div>
|
||||
<el-tabs v-if="submenu.length > 0" slot="submenu" v-model="iActiveMenu" class="page-submenu" @tab-click="handleTabClick">
|
||||
<el-tab-pane v-for="item in submenu" :key="item.name" :label="item.title" :label-content="item.labelContent" :name="item.name" />
|
||||
<template v-for="item in submenu">
|
||||
<el-tab-pane :key="item.name" :label-content="item.labelContent" :name="item.name">
|
||||
<span slot="label">
|
||||
{{ item.title }}
|
||||
<slot name="badge" :tab="item.name" />
|
||||
</span>
|
||||
</el-tab-pane>
|
||||
</template>
|
||||
</el-tabs>
|
||||
<transition name="fade-transform" mode="out-in">
|
||||
<slot />
|
||||
|
||||
@@ -77,7 +77,7 @@ export default {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
/deep/ {
|
||||
::v-deep {
|
||||
.el-scrollbar__bar {
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export default [
|
||||
{
|
||||
path: '',
|
||||
name: 'RemoteAppList',
|
||||
meta: { title: i18n.t('route.RemoteApp') },
|
||||
meta: { title: i18n.t('route.RemoteApp'), activeMenu: '/applications/remote-apps' },
|
||||
component: () => import('@/views/applications/RemoteApp/RemoteAppList')
|
||||
},
|
||||
{
|
||||
@@ -63,5 +63,32 @@ export default [
|
||||
component: () => import('@/views/applications/DatabaseApp/DatabaseAppDetail/index'),
|
||||
meta: { title: i18n.t('route.DatabaseAppDetail'), activeMenu: '/applications/database-apps' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'kubernetes-apps',
|
||||
name: 'KubernetesAppList',
|
||||
component: () => import('@/views/applications/KubernetesApp/KubernetesAppList'),
|
||||
meta: { title: i18n.t('route.KubernetesApp') }
|
||||
},
|
||||
{
|
||||
path: 'kubernetes-apps/create',
|
||||
name: 'KubernetesAppCreate',
|
||||
component: () => import('@/views/applications/KubernetesApp/KubernetesAppCreateUpdate'),
|
||||
meta: { title: i18n.t('route.KubernetesAppCreate'), activeMenu: '/applications/kubernetes-apps', action: 'create' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'kubernetes-apps/:id/update',
|
||||
name: 'KubernetesAppUpdate',
|
||||
component: () => import('@/views/applications/KubernetesApp/KubernetesAppCreateUpdate'),
|
||||
meta: { title: i18n.t('route.KubernetesAppUpdate'), activeMenu: '/applications/kubernetes-apps', action: 'update' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'kubernetes-apps/:id',
|
||||
name: 'KubernetesAppDetail',
|
||||
component: () => import('@/views/applications/KubernetesApp/KubernetesAppDetail/index'),
|
||||
meta: { title: i18n.t('route.KubernetesAppDetail'), activeMenu: '/applications/kubernetes-apps' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -12,7 +12,7 @@ export default [
|
||||
path: '',
|
||||
name: 'AssetList',
|
||||
component: () => import('@/views/assets/Asset/AssetList.vue'),
|
||||
meta: { title: i18n.t('route.AssetList') }
|
||||
meta: { title: i18n.t('route.AssetList'), activeMenu: '/assets/assets' }
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
@@ -34,6 +34,13 @@ export default [
|
||||
component: () => import('@/views/assets/Asset/AssetCreateUpdate.vue'),
|
||||
meta: { title: i18n.t('route.AssetUpdate'), activeMenu: '/assets/assets' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'detail/:id/update',
|
||||
name: 'AssetMoreInformationEdit',
|
||||
component: () => import('@/views/assets/Asset/AssetMoreInformationEdit.vue'),
|
||||
meta: { title: i18n.t('common.UpdateAssetDetail'), activeMenu: '/assets/assets' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -47,7 +54,7 @@ export default [
|
||||
path: '',
|
||||
name: 'DomainList',
|
||||
component: () => import('@/views/assets/Domain/DomainList.vue'),
|
||||
meta: { title: i18n.t('route.DomainList') }
|
||||
meta: { title: i18n.t('route.DomainList'), activeMenu: '/assets/domains' }
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
@@ -104,7 +111,7 @@ export default [
|
||||
path: '',
|
||||
name: 'AdminUserList',
|
||||
component: () => import('@/views/assets/AdminUser/AdminUserList'),
|
||||
meta: { title: i18n.t('route.AdminUserList') }
|
||||
meta: { title: i18n.t('route.AdminUserList'), activeMenu: '/assets/admin-users' }
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
@@ -174,7 +181,7 @@ export default [
|
||||
path: '',
|
||||
name: 'CommandFilterList',
|
||||
component: () => import('@/views/assets/CommandFilter/CommandFilterList.vue'),
|
||||
meta: { title: i18n.t('route.CommandFilterList') }
|
||||
meta: { title: i18n.t('route.CommandFilterList'), activeMenu: '/assets/cmd-filters' }
|
||||
},
|
||||
{
|
||||
path: ':id/update',
|
||||
@@ -265,7 +272,7 @@ export default [
|
||||
path: '',
|
||||
name: 'LabelList',
|
||||
component: () => import('@/views/assets/Label/LabelList.vue'),
|
||||
meta: { title: i18n.t('route.LabelList') }
|
||||
meta: { title: i18n.t('route.LabelList'), activeMenu: '/assets/labels' }
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
|
||||
@@ -45,5 +45,12 @@ export default [
|
||||
name: 'CeleryTaskLog',
|
||||
hidden: true,
|
||||
meta: { title: i18n.t('route.CeleryTaskLog'), roles: ['SuperAdmin', 'Admin', 'Auditor', 'User'] }
|
||||
},
|
||||
{
|
||||
path: '/ops/task/task/:id/log/',
|
||||
component: () => import('@/views/ops/CeleryTaskLog'),
|
||||
name: 'TaskLog',
|
||||
hidden: true,
|
||||
meta: { title: i18n.t('route.CeleryTaskLog'), roles: ['SuperAdmin', 'Admin', 'Auditor', 'User'] }
|
||||
}
|
||||
]
|
||||
|
||||
@@ -140,8 +140,12 @@ export const allRoleRoutes = [
|
||||
component: Layout,
|
||||
redirect: '/tickets/tickets/',
|
||||
children: TicketsRoutes,
|
||||
hidden: true,
|
||||
meta: {
|
||||
licenseRequired: true
|
||||
// hidden: ({ settings }) => {
|
||||
// return !settings.TICKETS_ENABLED
|
||||
// }
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import i18n from '@/i18n/i18n'
|
||||
import rolec from '@/utils/role'
|
||||
import { BASE_URL } from '@/utils/common'
|
||||
|
||||
export default [
|
||||
{
|
||||
path: 'tasks',
|
||||
@@ -32,7 +34,7 @@ export default [
|
||||
path: 'command-executions/create',
|
||||
name: 'BatchCommand',
|
||||
component: () => import('@/views/ops/CommandExecution'),
|
||||
meta: { title: i18n.t('route.BatchCommand'), commandExecutionRequired: true }
|
||||
meta: { title: i18n.t('route.BatchCommand'), hidden: ({ settings }) => !settings.SECURITY_COMMAND_EXECUTION }
|
||||
},
|
||||
// {
|
||||
// path: 'celery/task/:id',
|
||||
@@ -42,9 +44,9 @@ export default [
|
||||
// meta: { title: i18n.t('route.CeleryTaskLog') }
|
||||
// },
|
||||
{
|
||||
path: 'task/monitor',
|
||||
path: `${BASE_URL}/core/flower?_=${Date.now()}`,
|
||||
name: 'TaskMonitor',
|
||||
component: () => window.open(`/core/flower?_=${Date.now()}`),
|
||||
// component: () => window.open(`/core/flower?_=${Date.now()}`),
|
||||
meta: { title: i18n.t('route.TaskMonitor'), permissions: [rolec.PERM_SUPER] }
|
||||
}
|
||||
]
|
||||
|
||||
@@ -31,77 +31,45 @@ const assetPermissionRoutes = [
|
||||
}
|
||||
]
|
||||
|
||||
const remoteAppPermissionRoutes = [
|
||||
const ApplicationPermissionRoutes = [
|
||||
{
|
||||
path: 'remote-app-permissions',
|
||||
path: 'app-permissions',
|
||||
component: empty,
|
||||
meta: { title: i18n.t('route.RemoteAppPermission'), licenseRequired: true },
|
||||
meta: { title: i18n.t('route.ApplicationPermission') },
|
||||
redirect: '',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'RemoteAppPermissionList',
|
||||
component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionList'),
|
||||
meta: { title: i18n.t('route.RemoteAppPermission') }
|
||||
|
||||
name: 'ApplicationPermissionList',
|
||||
component: () => import('@/views/perms/ApplicationPermission/ApplicationPermissionList'),
|
||||
meta: { title: i18n.t('route.ApplicationPermission'), activeMenu: '/perms/app-permissions' }
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionCreateUpdate'),
|
||||
name: 'RemoteAppPermissionCreate',
|
||||
component: () => import('@/views/perms/ApplicationPermission/ApplicationPermissionCreateUpdate'),
|
||||
name: 'ApplicationPermissionCreate',
|
||||
hidden: true,
|
||||
meta: { title: i18n.t('route.RemoteAppPermissionCreate'), activeMenu: '/perms/remote-app-permissions', action: 'create' }
|
||||
},
|
||||
{
|
||||
path: 'update',
|
||||
component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionCreateUpdate'),
|
||||
name: 'RemoteAppPermissionUpdate',
|
||||
hidden: true,
|
||||
meta: { title: i18n.t('route.RemoteAppPermissionUpdate'), activeMenu: '/perms/remote-app-permissions', action: 'update' }
|
||||
meta: { title: i18n.t('route.ApplicationPermissionCreate'), activeMenu: '/perms/app-permissions', action: 'create' }
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionDetail/index'),
|
||||
name: 'RemoteAppPermissionDetail',
|
||||
component: () => import('@/views/perms/ApplicationPermission/ApplicationPermissionDetail/index'),
|
||||
name: 'ApplicationPermissionDetail',
|
||||
hidden: true,
|
||||
meta: { title: i18n.t('route.RemoteAppPermissionDetail'), activeMenu: '/perms/remote-app-permissions' }
|
||||
meta: { title: i18n.t('route.ApplicationPermissionDetail'), activeMenu: '/perms/app-permissions' }
|
||||
},
|
||||
{
|
||||
path: ':id/update',
|
||||
component: () => import('@/views/perms/ApplicationPermission/ApplicationPermissionCreateUpdate'),
|
||||
name: 'ApplicationPermissionUpdate',
|
||||
hidden: true,
|
||||
meta: { title: i18n.t('route.ApplicationPermissionUpdate'), activeMenu: '/perms/app-permissions', action: 'update' }
|
||||
}]
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
const databasePermissionRoutes = [
|
||||
{
|
||||
path: 'database-app-permissions',
|
||||
name: 'DatabaseAppPermissionList',
|
||||
component: () => import('@/views/perms/DatabaseAppPermission/DatabaseAppPermissionList'),
|
||||
meta: { title: i18n.t('route.DatabaseAppPermission') }
|
||||
},
|
||||
{
|
||||
path: 'database-app-permissions/create',
|
||||
component: () => import('@/views/perms/DatabaseAppPermission/DatabaseAppPermissionCreateUpdate'), // Parent router-view
|
||||
name: 'DatabaseAppPermissionCreate',
|
||||
hidden: true,
|
||||
meta: { title: i18n.t('route.DatabaseAppPermissionCreate'), activeMenu: '/perms/database-app-permissions' }
|
||||
},
|
||||
{
|
||||
path: 'database-app-permissions/update',
|
||||
component: () => import('@/views/perms/DatabaseAppPermission/DatabaseAppPermissionCreateUpdate'), // Parent router-view
|
||||
name: 'DatabaseAppPermissionUpdate',
|
||||
hidden: true,
|
||||
meta: { title: i18n.t('route.DatabaseAppPermissionUpdate'), activeMenu: '/perms/database-app-permissions', action: 'update' }
|
||||
},
|
||||
{
|
||||
path: 'database-app-permissions/:id',
|
||||
component: () => import('@/views/perms/DatabaseAppPermission/DatabaseAppPermissionDetail/index'),
|
||||
name: 'DatabaseAppPermissionDetail',
|
||||
hidden: true,
|
||||
meta: { title: i18n.t('route.DatabaseAppPermissionDetail'), activeMenu: '/perms/database-app-permissions' }
|
||||
}
|
||||
]
|
||||
|
||||
export default [
|
||||
... assetPermissionRoutes,
|
||||
... remoteAppPermissionRoutes,
|
||||
... databasePermissionRoutes
|
||||
... ApplicationPermissionRoutes
|
||||
]
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import i18n from '@/i18n/i18n'
|
||||
import rolec from '@/utils/role'
|
||||
import empty from '@/layout/empty'
|
||||
import { BASE_URL } from '@/utils/common'
|
||||
|
||||
export default [
|
||||
{
|
||||
path: 'session',
|
||||
@@ -22,15 +24,16 @@ export default [
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'luna',
|
||||
path: `${BASE_URL}/luna/?_=${Date.now()}`,
|
||||
name: 'WebTerminal',
|
||||
component: () => window.open(`/luna/?_=${Date.now()}`),
|
||||
// component: () => window.open(`/luna/?_=${Date.now()}`),
|
||||
meta: { title: i18n.t('route.WebTerminal') }
|
||||
// hidden: true
|
||||
},
|
||||
{
|
||||
path: 'sftp',
|
||||
path: `${BASE_URL}/koko/elfinder/sftp/?`,
|
||||
name: 'FileManager',
|
||||
component: () => window.open(`/koko/elfinder/sftp/?`),
|
||||
// component: () => window.open(`/koko/elfinder/sftp/?`),
|
||||
meta: { title: i18n.t('route.FileManager') }
|
||||
},
|
||||
{
|
||||
|
||||
@@ -4,7 +4,8 @@ export default [
|
||||
path: 'tickets',
|
||||
name: 'TicketList',
|
||||
component: () => import('@/views/tickets/TicketList'),
|
||||
meta: { title: i18n.t('route.Tickets'), icon: 'check-square-o' }
|
||||
meta: { title: i18n.t('route.Tickets'), icon: 'check-square-o', activeMenu: '/tickets/tickets' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'tickets/:id',
|
||||
@@ -12,5 +13,33 @@ export default [
|
||||
component: () => import('@/views/tickets/TicketDetail/index'),
|
||||
meta: { title: i18n.t('route.TicketDetail'), activeMenu: '/tickets/tickets' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'tickets/request-asset-perm/create',
|
||||
name: 'RequestAssetPermTicketCreateUpdate',
|
||||
component: () => import('@/views/tickets/RequestAssetPerm/RequestAssetPermTicketCreateUpdate'),
|
||||
meta: { title: i18n.t('route.TicketCreate'), activeMenu: '/tickets/tickets' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'tickets/request-asset-perm/:id',
|
||||
name: 'AssetsTicketDetail',
|
||||
component: () => import('@/views/tickets/RequestAssetPerm/Detail/index'),
|
||||
meta: { title: i18n.t('route.TicketDetail'), activeMenu: '/tickets/tickets' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'tickets/request-application-perm/create',
|
||||
name: 'RequestApplicationPermTicketCreateUpdate',
|
||||
component: () => import('@/views/tickets/RequestApplicationPerm/RequestApplicationPermTicketCreateUpdate'),
|
||||
meta: { title: i18n.t('route.TicketCreate'), activeMenu: '/tickets/tickets' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'tickets/request-application-perm/:id',
|
||||
name: 'AppsTicketDetail',
|
||||
component: () => import('@/views/tickets/RequestApplicationPerm/Detail/index'),
|
||||
meta: { title: i18n.t('route.TicketDetail'), activeMenu: '/tickets/tickets' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import Layout from '@/layout/index'
|
||||
import i18n from '@/i18n/i18n'
|
||||
import rolec from '@/utils/role'
|
||||
|
||||
const scheme = document.location.protocol
|
||||
const port = document.location.port ? ':' + document.location.port : ''
|
||||
const URL = scheme + '//' + document.location.hostname + port
|
||||
import { BASE_URL } from '@/utils/common'
|
||||
|
||||
export default [
|
||||
// 404 page must be placed at the end !!!
|
||||
@@ -47,6 +44,12 @@ export default [
|
||||
name: 'MyDatebases',
|
||||
component: () => import('@/userviews/apps/DatabaseApp'),
|
||||
meta: { title: i18n.t('route.DatabaseApp'), permissions: [rolec.PERM_USE] }
|
||||
},
|
||||
{
|
||||
path: '/apps/kubernetes',
|
||||
name: 'MyKubernetes',
|
||||
component: () => import('@/userviews/apps/KubernetesApp'),
|
||||
meta: { title: i18n.t('route.KubernetesApp'), permissions: [rolec.PERM_USE] }
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -55,7 +58,7 @@ export default [
|
||||
component: Layout,
|
||||
meta: {
|
||||
permissions: [rolec.PERM_USE],
|
||||
commandExecutionRequired: true
|
||||
hidden: ({ settings }) => !settings.SECURITY_COMMAND_EXECUTION
|
||||
},
|
||||
children: [
|
||||
{
|
||||
@@ -66,6 +69,63 @@ export default [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/tickets',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
meta: {
|
||||
title: i18n.t('route.Tickets'),
|
||||
icon: 'history',
|
||||
permissions: [rolec.PERM_USE],
|
||||
licenseRequired: true,
|
||||
hidden: ({ settings }) => {
|
||||
return !settings.TICKETS_ENABLED
|
||||
}
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'TicketList',
|
||||
component: () => import('@/views/tickets/TicketList'),
|
||||
meta: { title: i18n.t('route.Tickets'), icon: 'check-square-o', activeMenu: '/tickets', permissions: [rolec.PERM_USE] }
|
||||
},
|
||||
{
|
||||
path: 'tickets/request-asset-perm/create',
|
||||
name: 'RequestAssetPermTicketCreateUpdate',
|
||||
component: () => import('@/views/tickets/RequestAssetPerm/RequestAssetPermTicketCreateUpdate'),
|
||||
meta: { title: i18n.t('route.TicketDetail'), activeMenu: '/tickets', permissions: [rolec.PERM_USE] },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'tickets/request-asset-perm/:id',
|
||||
name: 'AssetsTicketDetail',
|
||||
component: () => import('@/views/tickets/RequestAssetPerm/Detail/index'),
|
||||
meta: { title: i18n.t('route.TicketDetail'), activeMenu: '/tickets', permissions: [rolec.PERM_USE] },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'tickets/request-application-perm/create',
|
||||
name: 'RequestApplicationPermTicketCreateUpdate',
|
||||
component: () => import('@/views/tickets/RequestApplicationPerm/RequestApplicationPermTicketCreateUpdate'),
|
||||
meta: { title: i18n.t('route.TicketCreate'), activeMenu: '/tickets/tickets', permissions: [rolec.PERM_USE] },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'tickets/request-application-perm/:id',
|
||||
name: 'AppsTicketDetail',
|
||||
component: () => import('@/views/tickets/RequestApplicationPerm/Detail/index'),
|
||||
meta: { title: i18n.t('route.TicketDetail'), activeMenu: '/tickets/tickets', permissions: [rolec.PERM_USE] },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'tickets/:id',
|
||||
name: 'TicketDetail',
|
||||
component: () => import('@/views/tickets/TicketDetail/index'),
|
||||
meta: { title: i18n.t('route.TicketDetail'), activeMenu: '/tickets', permissions: [rolec.PERM_USE] },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: `external-luna`,
|
||||
component: Layout,
|
||||
@@ -74,7 +134,7 @@ export default [
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: `${URL}/luna/`,
|
||||
path: `${BASE_URL}/luna/`,
|
||||
meta: { title: i18n.t('route.WebTerminal'), icon: 'window-maximize', activeMenu: '/assets', permissions: [rolec.PERM_USE] }
|
||||
}
|
||||
]
|
||||
@@ -87,7 +147,7 @@ export default [
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: `${URL}/koko/elfinder/sftp/`,
|
||||
path: `${BASE_URL}/koko/elfinder/sftp/`,
|
||||
meta: { title: i18n.t('route.WebFTP'), icon: 'file', activeMenu: '/assets', permissions: [rolec.PERM_USE] }
|
||||
}
|
||||
]
|
||||
|
||||
@@ -13,6 +13,7 @@ const getters = {
|
||||
currentOrgRoles: state => state.users.roles,
|
||||
currentOrgPerms: state => state.users.perms,
|
||||
MFAVerifyAt: state => state.users.MFAVerifyAt,
|
||||
MFA_TTl: state => state.settings.publicSettings.SECURITY_MFA_VERIFY_TTL
|
||||
MFA_TTl: state => state.settings.publicSettings.SECURITY_MFA_VERIFY_TTL,
|
||||
tableConfig: state => state.table.tableConfig
|
||||
}
|
||||
export default getters
|
||||
|
||||
@@ -17,39 +17,26 @@ function hasPermission(roles, route) {
|
||||
// console.log('Has route permission: ', route.path, requirePermsSum, userRolesSum, ' => ', has, roles)
|
||||
return has
|
||||
}
|
||||
function hasLicense(licState, route) {
|
||||
if (licState) {
|
||||
return licState
|
||||
}
|
||||
let requireLic = route.meta ? route.meta.licenseRequired : null
|
||||
if (!requireLic) {
|
||||
requireLic = false
|
||||
}
|
||||
return licState === requireLic
|
||||
}
|
||||
|
||||
function hasCommand(cmdBulkExecutionEnable, route) {
|
||||
const routeRequireCmd = route.meta ? route.meta.commandExecutionRequired : false
|
||||
if (!routeRequireCmd) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (!cmdBulkExecutionEnable) {
|
||||
function hasLicense(route, rootState) {
|
||||
const licenseIsValid = rootState.settings.publicSettings.XPACK_LICENSE_IS_VALID
|
||||
const licenseRequired = route.meta ? route.meta.licenseRequired : false
|
||||
if (!licenseIsValid && licenseRequired) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export function filterLicRoutes(routes, roles) {
|
||||
export function filterLicenseRequiredRoutes(routes, rootState) {
|
||||
const res = []
|
||||
|
||||
routes.forEach(route => {
|
||||
const tmp = {
|
||||
...route
|
||||
}
|
||||
if (hasLicense(roles, tmp)) {
|
||||
if (hasLicense(route, rootState)) {
|
||||
if (tmp.children) {
|
||||
tmp.children = filterLicRoutes(tmp.children, roles)
|
||||
tmp.children = filterLicenseRequiredRoutes(tmp.children, rootState)
|
||||
}
|
||||
res.push(tmp)
|
||||
}
|
||||
@@ -58,16 +45,24 @@ export function filterLicRoutes(routes, roles) {
|
||||
return res
|
||||
}
|
||||
|
||||
export function filterCmdRoutes(routes, roles) {
|
||||
function isNeedHidden(route, rootState) {
|
||||
let hidden = route.meta ? route.meta.hidden : false
|
||||
if (typeof hidden === 'function') {
|
||||
hidden = hidden({ route: route, settings: rootState.settings.publicSettings })
|
||||
}
|
||||
return hidden
|
||||
}
|
||||
|
||||
export function filterHiddenRoutes(routes, rootState) {
|
||||
const res = []
|
||||
|
||||
routes.forEach(route => {
|
||||
const tmp = {
|
||||
...route
|
||||
}
|
||||
if (hasCommand(roles, tmp)) {
|
||||
if (!isNeedHidden(route, rootState)) {
|
||||
if (tmp.children) {
|
||||
tmp.children = filterCmdRoutes(tmp.children, roles)
|
||||
tmp.children = filterHiddenRoutes(tmp.children, rootState)
|
||||
}
|
||||
res.push(tmp)
|
||||
}
|
||||
@@ -84,18 +79,18 @@ export function filterCmdRoutes(routes, roles) {
|
||||
export function filterAsyncRoutes(routes, roles) {
|
||||
const res = []
|
||||
|
||||
routes.forEach(route => {
|
||||
for (const route of routes) {
|
||||
const tmp = {
|
||||
...route
|
||||
}
|
||||
|
||||
if (hasPermission(roles, tmp)) {
|
||||
if (tmp.children) {
|
||||
tmp.children = filterAsyncRoutes(tmp.children, roles)
|
||||
}
|
||||
res.push(tmp)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -115,10 +110,10 @@ const actions = {
|
||||
generateRoutes({ commit, rootState }, roles) {
|
||||
return new Promise(resolve => {
|
||||
let accessedRoutes = filterAsyncRoutes(allRoleRoutes, roles)
|
||||
accessedRoutes = filterCmdRoutes(accessedRoutes, rootState.settings.publicSettings.SECURITY_COMMAND_EXECUTION)
|
||||
accessedRoutes = filterLicRoutes(accessedRoutes, rootState.settings.publicSettings.XPACK_LICENSE_IS_VALID)
|
||||
accessedRoutes = filterHiddenRoutes(accessedRoutes, rootState)
|
||||
accessedRoutes = filterLicenseRequiredRoutes(accessedRoutes, rootState)
|
||||
if (accessedRoutes.length === 0) {
|
||||
console.log('No route find')
|
||||
// console.log('No route find')
|
||||
}
|
||||
commit('SET_ROUTES', accessedRoutes)
|
||||
resolve(accessedRoutes)
|
||||
|
||||
@@ -35,6 +35,10 @@ const actions = {
|
||||
link.rel = 'shortcut icon'
|
||||
link.href = response.data.LOGO_URLS.favicon
|
||||
document.getElementsByTagName('head')[0].appendChild(link)
|
||||
|
||||
// 动态修改Title
|
||||
if (response.data.LOGIN_TITLE) { document.title = response.data.LOGIN_TITLE }
|
||||
|
||||
commit('SET_PUBLIC_SETTINGS', response.data)
|
||||
resolve(response)
|
||||
}).catch(error => {
|
||||
|
||||
28
src/store/modules/table.js
Normal file
28
src/store/modules/table.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import VueCookie from 'vue-cookie'
|
||||
import Vue from 'vue'
|
||||
|
||||
function getTableConfigfromCookie() {
|
||||
return VueCookie.get('tableConfig') ? JSON.parse(VueCookie.get('tableConfig')) : {}
|
||||
}
|
||||
|
||||
const state = {
|
||||
tableConfig: getTableConfigfromCookie()
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
SET_TABLE_CONFIG: (state, tableConfig) => {
|
||||
Vue.set(state.tableConfig, tableConfig.key, tableConfig.value)
|
||||
VueCookie.set('tableConfig', JSON.stringify(state.tableConfig), 14)
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
|
||||
}
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
}
|
||||
@@ -37,6 +37,15 @@ const mutations = {
|
||||
SET_ORGS: (state, orgs) => {
|
||||
state.orgs = orgs
|
||||
},
|
||||
MODIFY_ORG: (state, org) => {
|
||||
state.orgs = state.orgs.map(oldOrg => {
|
||||
if (oldOrg.id === org.id) {
|
||||
oldOrg.name = org.name
|
||||
}
|
||||
return oldOrg
|
||||
}
|
||||
)
|
||||
},
|
||||
ADD_ORG: (state, org) => {
|
||||
state.orgs.push(org)
|
||||
},
|
||||
@@ -89,7 +98,7 @@ const actions = {
|
||||
commit('SET_PROFILE', response)
|
||||
resolve(response)
|
||||
}).catch(error => {
|
||||
console.log(error)
|
||||
// console.log(error)
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
@@ -125,6 +134,9 @@ const actions = {
|
||||
addAdminOrg({ commit, state }, org) {
|
||||
commit('ADD_ORG', org)
|
||||
},
|
||||
modifyOrg({ commit, state }, org) {
|
||||
commit('MODIFY_ORG', org)
|
||||
},
|
||||
// user logout
|
||||
logout({ commit, state }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
@@ -96,7 +96,7 @@ td .el-button.el-button--mini {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.el-button.el-button--default:focus:not(.is-disabled), .el-button.el-button--default:hover:not(.is-disabled) {
|
||||
.el-button.el-button--default:hover:not(.is-disabled) {
|
||||
color: #606266;
|
||||
border-color: #d2d2d2;
|
||||
background-color: #e6e6e6;
|
||||
@@ -214,6 +214,10 @@ td .el-button.el-button--mini {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.el-select-dropdown__item.is-disabled:hover{
|
||||
color:#c0c4cc;
|
||||
}
|
||||
|
||||
.el-select-dropdown.is-multiple .el-select-dropdown__item.selected::after {
|
||||
color: $--color-primary;
|
||||
}
|
||||
@@ -431,7 +435,7 @@ a {
|
||||
|
||||
.el-button--danger.is-plain {
|
||||
color: $--color-danger;
|
||||
background: white;
|
||||
background: #ffffff;
|
||||
border-color: $--color-danger;
|
||||
}
|
||||
|
||||
|
||||
@@ -148,3 +148,12 @@ input[type=file] {
|
||||
font-size: 12px;
|
||||
opacity: 80;
|
||||
}
|
||||
|
||||
.el-table__body {
|
||||
width: 100%;
|
||||
table-layout: fixed !important;
|
||||
}
|
||||
|
||||
.el-table__column-filter-trigger i {
|
||||
color: #888888 !important;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ li.is-active {
|
||||
// line-height: 30px !important;
|
||||
//}
|
||||
////重置字体大小 菜单宽度
|
||||
//.el-submenu /deep/ .el-submenu__title, .submenu-title-noDropdown{
|
||||
//.el-submenu ::v-deep .el-submenu__title, .submenu-title-noDropdown{
|
||||
// height: 46px !important;
|
||||
// line-height: 46px !important;
|
||||
//}
|
||||
|
||||
@@ -21,7 +21,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
tableConfig: {
|
||||
url: `/api/v1/perms/users/database-apps/`,
|
||||
url: `/api/v1/perms/users/applications/?category=db`,
|
||||
columns: [
|
||||
{
|
||||
prop: 'name',
|
||||
@@ -30,18 +30,19 @@ export default {
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
prop: 'get_type_display',
|
||||
prop: 'type_display',
|
||||
align: 'center',
|
||||
label: this.$t('assets.Type')
|
||||
},
|
||||
{
|
||||
prop: 'database',
|
||||
prop: 'attrs.database',
|
||||
align: 'center',
|
||||
label: this.$t('assets.Database')
|
||||
},
|
||||
{
|
||||
prop: 'comment',
|
||||
align: 'center',
|
||||
showOverflowTooltip: true,
|
||||
label: this.$t('assets.Comment')
|
||||
},
|
||||
{
|
||||
@@ -52,6 +53,7 @@ export default {
|
||||
formatterArgs: {
|
||||
hasDelete: false,
|
||||
hasUpdate: false,
|
||||
hasClone: false,
|
||||
extraActions: [
|
||||
{
|
||||
name: 'connect',
|
||||
@@ -69,13 +71,13 @@ export default {
|
||||
headerActions: {
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasRefresh: false,
|
||||
hasRefresh: true,
|
||||
hasCreate: false,
|
||||
hasBulkDelete: false,
|
||||
hasBulkUpdate: false,
|
||||
hasLeftActions: false,
|
||||
hasSearch: true,
|
||||
hasRightActions: false
|
||||
hasRightActions: true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
96
src/userviews/apps/KubernetesApp.vue
Normal file
96
src/userviews/apps/KubernetesApp.vue
Normal file
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<Page>
|
||||
<ListTable ref="ListTable" :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</Page>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ListTable from '@/components/ListTable/index'
|
||||
import Page from '@/layout/components/Page/index'
|
||||
import { ActionsFormatter } from '@/components/ListTable/formatters'
|
||||
|
||||
export default {
|
||||
name: 'KubernetesApp',
|
||||
components: {
|
||||
ListTable,
|
||||
Page
|
||||
},
|
||||
props: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableConfig: {
|
||||
url: `/api/v1/perms/users/applications/?category=cloud`,
|
||||
columns: [
|
||||
{
|
||||
prop: 'name',
|
||||
align: 'center',
|
||||
label: this.$t('assets.Name'),
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
prop: 'type_display',
|
||||
align: 'center',
|
||||
label: this.$t('assets.Type')
|
||||
},
|
||||
{
|
||||
prop: 'attrs.cluster',
|
||||
align: 'center',
|
||||
label: this.$t('applications.cluster')
|
||||
},
|
||||
{
|
||||
prop: 'comment',
|
||||
align: 'center',
|
||||
showOverflowTooltip: true,
|
||||
label: this.$t('assets.Comment')
|
||||
},
|
||||
{
|
||||
prop: 'id',
|
||||
align: 'center',
|
||||
label: this.$t('assets.Action'),
|
||||
formatter: ActionsFormatter,
|
||||
formatterArgs: {
|
||||
hasDelete: false,
|
||||
hasUpdate: false,
|
||||
hasClone: false,
|
||||
extraActions: [
|
||||
{
|
||||
name: 'connect',
|
||||
fa: 'fa-terminal',
|
||||
type: 'primary',
|
||||
callback: function({ row, col, cellValue, reload }) {
|
||||
window.open(`/luna/?type=k8s_app&login_to=${cellValue}`, '_blank')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
headerActions: {
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasRefresh: true,
|
||||
hasCreate: false,
|
||||
hasBulkDelete: false,
|
||||
hasBulkUpdate: false,
|
||||
hasLeftActions: false,
|
||||
hasSearch: true,
|
||||
hasRightActions: true
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='less' scoped>
|
||||
|
||||
</style>
|
||||
@@ -20,7 +20,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
tableConfig: {
|
||||
url: `/api/v1/perms/users/remote-apps/`,
|
||||
url: `/api/v1/perms/users/applications/?category=remote_app`,
|
||||
columns: [
|
||||
{
|
||||
prop: 'name',
|
||||
@@ -29,18 +29,19 @@ export default {
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
prop: 'get_type_display',
|
||||
prop: 'type_display',
|
||||
align: 'center',
|
||||
label: this.$t('assets.RemoteType')
|
||||
label: this.$t('assets.Type')
|
||||
},
|
||||
{
|
||||
prop: 'asset_info.hostname',
|
||||
prop: 'attrs.asset_info.hostname',
|
||||
align: 'center',
|
||||
label: this.$t('assets.Asset')
|
||||
},
|
||||
{
|
||||
prop: 'comment',
|
||||
align: 'center',
|
||||
showOverflowTooltip: true,
|
||||
label: this.$t('assets.Comment')
|
||||
},
|
||||
{
|
||||
@@ -51,6 +52,7 @@ export default {
|
||||
formatterArgs: {
|
||||
hasDelete: false,
|
||||
hasUpdate: false,
|
||||
hasClone: false,
|
||||
extraActions: [
|
||||
{
|
||||
name: 'connect',
|
||||
@@ -68,13 +70,13 @@ export default {
|
||||
headerActions: {
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasRefresh: false,
|
||||
hasRefresh: true,
|
||||
hasCreate: false,
|
||||
hasBulkDelete: false,
|
||||
hasBulkUpdate: false,
|
||||
hasLeftActions: false,
|
||||
hasSearch: true,
|
||||
hasRightActions: false
|
||||
hasRightActions: true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -59,6 +59,10 @@ export default {
|
||||
key: this.$t('assets.Platform'),
|
||||
value: row.platform
|
||||
},
|
||||
{
|
||||
key: this.$t('common.Activate'),
|
||||
value: row.is_active
|
||||
},
|
||||
{
|
||||
key: this.$t('assets.Comment'),
|
||||
value: row.comment
|
||||
@@ -86,6 +90,17 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'platform',
|
||||
label: this.$t('assets.Platform'),
|
||||
width: '120px'
|
||||
},
|
||||
{
|
||||
prop: 'comment',
|
||||
label: this.$t('assets.Comment'),
|
||||
showOverflowTooltip: true,
|
||||
width: '180px'
|
||||
},
|
||||
{
|
||||
prop: 'id',
|
||||
align: 'center',
|
||||
@@ -95,12 +110,16 @@ export default {
|
||||
formatterArgs: {
|
||||
hasDelete: false,
|
||||
loading: true,
|
||||
hasClone: false,
|
||||
hasUpdate: false,
|
||||
extraActions: [
|
||||
{
|
||||
name: 'connect',
|
||||
fa: 'fa-terminal',
|
||||
type: 'primary',
|
||||
can: (row, cellValue) => {
|
||||
return row.is_active
|
||||
},
|
||||
callback: function({ row, col, cellValue, reload }) {
|
||||
window.open(`/luna/?login_to=${cellValue}`, '_blank')
|
||||
}
|
||||
@@ -121,7 +140,12 @@ export default {
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
tableAttrs: {
|
||||
rowClassName({ row }) {
|
||||
return !row.is_active ? 'row_disabled' : ''
|
||||
}
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasExport: false,
|
||||
@@ -136,10 +160,10 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
refreshAllFavorites() {
|
||||
this.tableConfig.columns[3].formatterArgs.loading = true
|
||||
this.tableConfig.columns[this.tableConfig.columns.length - 1].formatterArgs.loading = true
|
||||
this.$axios.get('/api/v1/assets/favorite-assets/').then(resp => {
|
||||
this.allFavorites = resp
|
||||
this.tableConfig.columns[3].formatterArgs.loading = false
|
||||
this.tableConfig.columns[this.tableConfig.columns.length - 1].formatterArgs.loading = false
|
||||
})
|
||||
},
|
||||
addOrDeleteFavorite(assetId) {
|
||||
@@ -175,4 +199,8 @@ export default {
|
||||
.el-card {
|
||||
border: 0 !important;
|
||||
}
|
||||
.row_disabled,.row_disabled:hover,.row_disabled:hover > td{
|
||||
cursor: not-allowed;
|
||||
background-color:rgba(192,196,204,0.28) !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
:update-success-next-route="updateSuccessNextRoute"
|
||||
:clean-form-value="cleanFormValue"
|
||||
:get-method="getMethod"
|
||||
:on-perform-success="onPerformSuccess"
|
||||
:perform-submit="performSubmit"
|
||||
/>
|
||||
</IBox>
|
||||
</template>
|
||||
@@ -15,6 +17,7 @@
|
||||
<script>
|
||||
import GenericCreateUpdateForm from '@/layout/components/GenericCreateUpdateForm/index'
|
||||
import { IBox } from '@/components'
|
||||
import { Required } from '@/components/DataForm/rules'
|
||||
|
||||
export default {
|
||||
name: 'ProfileUpdate',
|
||||
@@ -68,9 +71,7 @@ export default {
|
||||
label: this.$t('users.IAgree'),
|
||||
type: 'checkbox',
|
||||
checked: false,
|
||||
rules: [
|
||||
{ required: true }
|
||||
],
|
||||
rules: [Required],
|
||||
helpText: this.$t('users.HelpText.MFAOfUserFirstLoginUserGuidePage')
|
||||
}
|
||||
},
|
||||
@@ -87,6 +88,17 @@ export default {
|
||||
methods: {
|
||||
getMethod() {
|
||||
return 'put'
|
||||
},
|
||||
performSubmit(validValues) {
|
||||
if (!validValues.terms) {
|
||||
this.$message.error(this.$t('common.PleaseAgreeToTheTerms'))
|
||||
return Promise.reject()
|
||||
}
|
||||
return this.$axios['put'](this.url, validValues)
|
||||
},
|
||||
onPerformSuccess() {
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
setTimeout(() => this.$router.push({ name: 'UserGuide' }), 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
:url="url"
|
||||
:get-method="getMethod"
|
||||
class="password-update"
|
||||
:update-success-next-route="updateSuccessNextRoute"
|
||||
/>
|
||||
</IBox>
|
||||
</template>
|
||||
@@ -50,6 +51,9 @@ export default {
|
||||
type: 'password'
|
||||
}
|
||||
}
|
||||
},
|
||||
updateSuccessNextRoute: {
|
||||
path: '/'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -54,12 +54,39 @@ export default {
|
||||
type: 'primary',
|
||||
label: this.$t('common.Update')
|
||||
},
|
||||
has: this.object.mfa_enabled,
|
||||
callbacks: {
|
||||
click: function() {
|
||||
window.location.href = `/core/auth/profile/otp/update/?next=${this.$route.fullPath}`
|
||||
}.bind(this)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('users.UpdatePassword'),
|
||||
attrs: {
|
||||
type: 'primary',
|
||||
label: this.$t('common.Update'),
|
||||
disabled: this.$store.state.users.profile.source !== 'local'
|
||||
},
|
||||
callbacks: {
|
||||
click: function() {
|
||||
this.$emit('update:activeMenu', 'PasswordUpdate')
|
||||
}.bind(this)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('users.UpdateSSHKey'),
|
||||
attrs: {
|
||||
type: 'primary',
|
||||
label: this.$t('common.Update'),
|
||||
disabled: this.$store.state.users.profile.source !== 'local'
|
||||
},
|
||||
callbacks: {
|
||||
click: function() {
|
||||
this.$emit('update:activeMenu', 'SSHUpdate')
|
||||
}.bind(this)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: this.$t('users.ResetPublicKeyAndDownload'),
|
||||
attrs: {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<template>
|
||||
<IBox>
|
||||
<GenericCreateUpdateForm
|
||||
ref="GenericCreateUpdateForm"
|
||||
:fields="fields"
|
||||
:fields-meta="fieldsMeta"
|
||||
:initial="object"
|
||||
:url="url"
|
||||
:get-method="getMethod"
|
||||
:more-buttons="moreButtons"
|
||||
:on-perform-success="onPerformSuccess"
|
||||
/>
|
||||
</IBox>
|
||||
</template>
|
||||
@@ -46,7 +48,8 @@ export default {
|
||||
public_key: {
|
||||
el: {
|
||||
type: 'textarea',
|
||||
placeholder: 'ssh-rsa AAAA...'
|
||||
placeholder: 'ssh-rsa AAAA...',
|
||||
autosize: { minRows: 3 }
|
||||
},
|
||||
helpText: this.$t('users.HelpText.SSHKeyOfProfileSSHUpdatePage')
|
||||
}
|
||||
@@ -64,6 +67,10 @@ export default {
|
||||
methods: {
|
||||
getMethod() {
|
||||
return 'put'
|
||||
},
|
||||
onPerformSuccess() {
|
||||
this.$refs.GenericCreateUpdateForm.$refs.form.$refs.dataForm.resetForm('form')
|
||||
this.$message.success(this.$t('common.updateSuccessMsg'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<GenericDetailPage :object.sync="user" :active-menu.sync="config.activeMenu" v-bind="config" v-on="$listeners">
|
||||
<keep-alive>
|
||||
<component :is="config.activeMenu" :object="user" />
|
||||
<component :is="config.activeMenu" :object="user" @update:activeMenu="handleUpdate" />
|
||||
</keep-alive>
|
||||
</GenericDetailPage>
|
||||
</template>
|
||||
@@ -60,6 +60,9 @@ export default {
|
||||
])
|
||||
}
|
||||
return submenu
|
||||
},
|
||||
handleUpdate(value) {
|
||||
this.config.activeMenu = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ export function getCurrentRoleFromCookie() {
|
||||
}
|
||||
|
||||
export function saveCurrentRoleToCookie(role) {
|
||||
console.log('Save current role to cookie: ', role)
|
||||
// console.log('Save current role to cookie: ', role)
|
||||
return VueCookie.set(CURRENT_ROLE_KEY, role, 14)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ export function getCurrentOrgFromCookie() {
|
||||
try {
|
||||
org = JSON.parse(VueCookie.get(CURRENT_ORG_KEY))
|
||||
} catch (e) {
|
||||
console.log('Current org in cookie: ', org)
|
||||
// console.log('Current org in cookie: ', org)
|
||||
}
|
||||
return org
|
||||
}
|
||||
|
||||
@@ -65,15 +65,23 @@ function cleanDateStr(d) {
|
||||
case 1:
|
||||
d = d.split('+')[0].trimRight()
|
||||
break
|
||||
case 2:
|
||||
d = d.replace(/-/g, '/')
|
||||
}
|
||||
}
|
||||
return null
|
||||
return d
|
||||
}
|
||||
|
||||
export function toSafeLocalDateStr(d) {
|
||||
if (d === '') {
|
||||
return ''
|
||||
}
|
||||
const date = safeDate(d)
|
||||
// let date_s = date.toLocaleString(getUserLang(), {hour12: false});
|
||||
const date_s = date.toLocaleString(getUserLang(), { hourCycle: 'h23' })
|
||||
// const date_s = date.toLocaleString(getUserLang(), { hourCycle: 'h23' })
|
||||
const date_s =
|
||||
date.toLocaleDateString(getUserLang(), { hourCycle: 'h23' }) +
|
||||
' ' +
|
||||
date.toLocaleTimeString(getUserLang(), { hourCycle: 'h23' })
|
||||
return date_s
|
||||
}
|
||||
|
||||
@@ -136,6 +144,20 @@ export function getDaysAgo(days, now) {
|
||||
return new Date(now.getTime() - 3600 * 1000 * 24 * days)
|
||||
}
|
||||
|
||||
export function getDaysFuture(days, now) {
|
||||
if (!now) {
|
||||
now = new Date()
|
||||
}
|
||||
return new Date(now.getTime() + 3600 * 1000 * 24 * days)
|
||||
}
|
||||
|
||||
export function getDayEnd(now) {
|
||||
if (!now) {
|
||||
now = new Date()
|
||||
}
|
||||
return new Date(new Date(now.toLocaleDateString()).getTime() + 24 * 60 * 60 * 1000 - 1)
|
||||
}
|
||||
|
||||
export function setUrlParam(url, name, value) {
|
||||
const urlArray = url.split('?')
|
||||
if (urlArray.length === 1) {
|
||||
@@ -164,3 +186,9 @@ export function getDayFuture(days, now) {
|
||||
}
|
||||
return new Date(now.getTime() + 3600 * 1000 * 24 * days)
|
||||
}
|
||||
|
||||
const scheme = document.location.protocol
|
||||
const port = document.location.port ? ':' + document.location.port : ''
|
||||
const BASE_URL = scheme + '//' + document.location.hostname + port
|
||||
|
||||
export { BASE_URL }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { hasUUID } from '@/utils/common'
|
||||
import { hasUUID, BASE_URL } from '@/utils/common'
|
||||
import store from '@/store'
|
||||
|
||||
function getPropOrg() {
|
||||
@@ -36,17 +36,20 @@ function hasCurrentOrgPermission() {
|
||||
return orgInList
|
||||
}
|
||||
|
||||
function changeOrg(orgId) {
|
||||
async function changeOrg(orgId) {
|
||||
const org = getOrgIdMapper()[orgId]
|
||||
if (!org) {
|
||||
console.debug('Error: org not found')
|
||||
} else {
|
||||
console.debug('Change to org: ', org)
|
||||
}
|
||||
// 重置Role为空
|
||||
await store.dispatch('users/setCurrentRole', null)
|
||||
|
||||
store.dispatch('users/setCurrentOrg', org).then(() => {
|
||||
console.log('Set current org to: ', org)
|
||||
// console.log('Set current org to: ', org)
|
||||
if (hasUUID(location.href)) {
|
||||
location.href = process.env.VUE_APP_PUBLIC_PATH
|
||||
location.href = BASE_URL
|
||||
} else {
|
||||
window.location.reload(true)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import axios from 'axios'
|
||||
import i18n from '@/i18n/i18n'
|
||||
import NProgress from 'nprogress' // progress bar
|
||||
|
||||
import { getTokenFromCookie } from '@/utils/auth'
|
||||
import { refreshSessionIdAge } from '@/api/users'
|
||||
import { Message, MessageBox } from 'element-ui'
|
||||
import store from '@/store'
|
||||
import axiosRetry from 'axios-retry'
|
||||
|
||||
// create an axios instance
|
||||
const service = axios.create({
|
||||
@@ -13,11 +14,12 @@ const service = axios.create({
|
||||
})
|
||||
|
||||
function beforeRequestAddToken(config) {
|
||||
if (store.getters.token) {
|
||||
const csrfToken = getTokenFromCookie()
|
||||
if (csrfToken) {
|
||||
// let each request carry token
|
||||
// ['X-Token'] is a custom headers key
|
||||
// please modify it according to the actual situation
|
||||
config.headers['X-CSRFToken'] = store.getters.token
|
||||
config.headers['X-CSRFToken'] = csrfToken
|
||||
}
|
||||
if (store.getters.currentOrg) {
|
||||
config.headers['X-JMS-ORG'] = store.getters.currentOrg.id
|
||||
@@ -36,7 +38,7 @@ function beforeRequestAddTimezone(config) {
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
// do something before request is sent
|
||||
NProgress.start()
|
||||
// NProgress.start()
|
||||
beforeRequestAddToken(config)
|
||||
beforeRequestAddTimezone(config)
|
||||
return config
|
||||
@@ -71,6 +73,13 @@ function ifBadRequest({ response, error }) {
|
||||
if (response.status === 400) {
|
||||
error.message = i18n.t('common.BadRequestErrorMsg')
|
||||
}
|
||||
if (response.status === 403) {
|
||||
error.message = i18n.t('common.BadRoleErrorMsg')
|
||||
}
|
||||
if (response.status === 409) {
|
||||
error.response.status = 409
|
||||
error.message = i18n.t('common.BadConflictErrorMsg')
|
||||
}
|
||||
}
|
||||
|
||||
export function flashErrorMsg({ response, error }) {
|
||||
@@ -88,6 +97,19 @@ export function flashErrorMsg({ response, error }) {
|
||||
}
|
||||
}
|
||||
|
||||
let timer = null
|
||||
function refreshSessionAgeDelay(response) {
|
||||
if (response.request.responseURL.indexOf('/users/profile/') !== -1) {
|
||||
return
|
||||
}
|
||||
if (timer) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
timer = setTimeout(function() {
|
||||
refreshSessionIdAge()
|
||||
}, 30 * 1000)
|
||||
}
|
||||
|
||||
// response interceptor
|
||||
service.interceptors.response.use(
|
||||
/**
|
||||
@@ -101,7 +123,8 @@ service.interceptors.response.use(
|
||||
* You can also judge the status by HTTP Status Code
|
||||
*/
|
||||
response => {
|
||||
NProgress.done()
|
||||
// NProgress.done()
|
||||
refreshSessionAgeDelay(response)
|
||||
const res = response.data
|
||||
|
||||
if (response.config.raw === 1) {
|
||||
@@ -110,7 +133,7 @@ service.interceptors.response.use(
|
||||
return res
|
||||
},
|
||||
error => {
|
||||
NProgress.done()
|
||||
// NProgress.done()
|
||||
if (!error.response) {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
@@ -123,4 +146,9 @@ service.interceptors.response.use(
|
||||
}
|
||||
)
|
||||
|
||||
axiosRetry(service, {
|
||||
// 默认不开启请求重试
|
||||
retries: 0
|
||||
})
|
||||
|
||||
export default service
|
||||
|
||||
@@ -57,7 +57,7 @@ async function changeCurrentOrgIfNeed({ to, from, next }) {
|
||||
}
|
||||
const currentOrg = store.getters.currentOrg
|
||||
if (!currentOrg || typeof currentOrg !== 'object') {
|
||||
console.log('Not has current org')
|
||||
// console.log('Not has current org')
|
||||
orgUtil.change2PropOrg()
|
||||
return reject('change prop org')
|
||||
}
|
||||
|
||||
@@ -10,9 +10,10 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
fields: [
|
||||
[this.$t('common.Basic'), ['name', 'type']],
|
||||
[this.$t('applications.mysql'), ['host', 'port', 'database']],
|
||||
[this.$t('common.Basic'), ['name', 'type', 'domain']],
|
||||
[this.$t('applications.DBInfo'), ['attrs']],
|
||||
[this.$t('common.Other'), ['comment']]
|
||||
],
|
||||
fieldsMeta: {
|
||||
@@ -23,14 +24,56 @@ export default {
|
||||
value: 'mysql'
|
||||
}],
|
||||
disabled: true
|
||||
},
|
||||
host: {
|
||||
type: 'input'
|
||||
},
|
||||
domain: {
|
||||
el: {
|
||||
multiple: false,
|
||||
clearable: true,
|
||||
ajax: {
|
||||
url: '/api/v1/assets/domains/'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
url: '/api/v1/applications/database-apps/'
|
||||
url: '/api/v1/applications/applications/',
|
||||
getUrl() {
|
||||
const params = this.$route.params
|
||||
let url = `/api/v1/applications/applications/`
|
||||
const method = this.getMethod()
|
||||
if (params.id) {
|
||||
url = `${url}${params.id}/`
|
||||
}
|
||||
return method === 'post' ? `${url}?type=${this.$route.query.type}` : `${url}?category=db`
|
||||
},
|
||||
performSubmit(validValues) {
|
||||
const params = this.$route.params
|
||||
const baseUrl = `/api/v1/applications/applications/`
|
||||
const url = (params.id) ? `${baseUrl}${params.id}/` : baseUrl
|
||||
const method = this.getMethod()
|
||||
validValues.attrs = {
|
||||
host: validValues.host,
|
||||
port: validValues.port,
|
||||
database: validValues.database
|
||||
}
|
||||
validValues.category = 'db'
|
||||
return this.$axios[method](`${url}?type=${validValues.type}`, validValues)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
initial() {
|
||||
return this.$route.query
|
||||
},
|
||||
getMethod() {
|
||||
const params = this.$route.params
|
||||
if (params.id) {
|
||||
return 'put'
|
||||
} else {
|
||||
return 'post'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,19 +33,19 @@ export default {
|
||||
},
|
||||
{
|
||||
key: this.$t('applications.type'),
|
||||
value: this.object.get_type_display
|
||||
value: this.object.type_display
|
||||
},
|
||||
{
|
||||
key: this.$t('applications.host'),
|
||||
value: this.object.host
|
||||
value: this.object.attrs.host
|
||||
},
|
||||
{
|
||||
key: this.$t('applications.port'),
|
||||
value: JSON.stringify(this.object.port)
|
||||
value: JSON.stringify(this.object.attrs.port)
|
||||
},
|
||||
{
|
||||
key: this.$t('applications.database'),
|
||||
value: this.object.database
|
||||
value: this.object.attrs.database
|
||||
},
|
||||
{
|
||||
key: this.$t('common.dateCreated'),
|
||||
|
||||
@@ -19,7 +19,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
DatabaseApp: {
|
||||
name: '', get_type_display: '', host: '', port: '', database: '', date_created: '', created_by: '', comment: ''
|
||||
name: '', get_type_display: '', host: '', port: '', database: '', date_created: '', created_by: '', comment: '', attrs: ''
|
||||
},
|
||||
config: {
|
||||
activeMenu: 'DatabaseAppDetail',
|
||||
@@ -28,7 +28,11 @@ export default {
|
||||
title: this.$t('route.DatabaseAppDetail'),
|
||||
name: 'DatabaseAppDetail'
|
||||
}
|
||||
]
|
||||
],
|
||||
actions: {
|
||||
detailApiUrl: `/api/v1/applications/applications/${this.$route.params.id}/`,
|
||||
deleteApiUrl: `/api/v1/applications/applications/${this.$route.params.id}/`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<template>
|
||||
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" />
|
||||
<GenericListPage ref="GenericListTable" :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GenericListPage } from '@/layout/components'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -12,21 +13,49 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
tableConfig: {
|
||||
url: '/api/v1/applications/database-apps/',
|
||||
url: '/api/v1/applications/applications/?category=db',
|
||||
columns: [
|
||||
'name', 'get_type_display', 'host', 'port', 'database', 'comment', 'actions'
|
||||
'name', 'type_display', 'attrs.host', 'attrs.port', 'attrs.database', 'comment', 'actions'
|
||||
],
|
||||
columnsMeta: {
|
||||
get_type_display: {
|
||||
label: this.$t('applications.type')
|
||||
type_display: {
|
||||
label: this.$t('applications.type'),
|
||||
width: '120px'
|
||||
},
|
||||
database: {
|
||||
'attrs.host': {
|
||||
label: this.$t('applications.host'),
|
||||
width: '140px'
|
||||
},
|
||||
'attrs.port': {
|
||||
label: this.$t('applications.port'),
|
||||
width: '80px'
|
||||
},
|
||||
'attrs.database': {
|
||||
label: this.$t('applications.database'),
|
||||
showOverflowTooltip: true
|
||||
},
|
||||
actions: {
|
||||
prop: '',
|
||||
formatterArgs: {
|
||||
hasClone: false,
|
||||
performDelete: function({ row, col, cellValue, reload }) {
|
||||
this.$axios.delete(
|
||||
`/api/v1/applications/applications/${row.id}/`
|
||||
).then(res => {
|
||||
this.$refs.GenericListTable.$refs.ListTable.reloadTable()
|
||||
// this.$message.success(this.$t('common.deleteSuccessMsg'))
|
||||
}).catch(error => {
|
||||
this.$message.error(this.$t('common.deleteErrorMsg' + ' ' + error))
|
||||
})
|
||||
}.bind(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasCreate: false,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasBulkDelete: false,
|
||||
createRoute: 'DatabaseAppCreate',
|
||||
moreActionsTitle: this.$t('common.Create'),
|
||||
@@ -36,16 +65,55 @@ export default {
|
||||
name: 'MySQL',
|
||||
title: 'MySQL',
|
||||
type: 'primary',
|
||||
can: true,
|
||||
has: true,
|
||||
callback: this.createMysql.bind(this)
|
||||
},
|
||||
{
|
||||
name: 'PostgreSQL',
|
||||
title: 'PostgreSQL',
|
||||
type: 'primary',
|
||||
has: this.isValidateLicense,
|
||||
callback: this.createPostgreSQL.bind(this)
|
||||
},
|
||||
{
|
||||
name: 'MariaDB',
|
||||
title: 'MariaDB',
|
||||
type: 'primary',
|
||||
has: this.isValidateLicense,
|
||||
callback: this.createMariaDB.bind(this)
|
||||
},
|
||||
{
|
||||
name: 'Oracle',
|
||||
title: 'Oracle',
|
||||
type: 'primary',
|
||||
has: this.isValidateLicense,
|
||||
callback: this.createOracle.bind(this)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['publicSettings', 'currentOrg'])
|
||||
},
|
||||
methods: {
|
||||
createMysql() {
|
||||
this.$router.push({ name: 'DatabaseAppCreate', query: { type: 'mysql' }})
|
||||
},
|
||||
createPostgreSQL() {
|
||||
this.$router.push({ name: 'DatabaseAppCreate', query: { type: 'postgresql' }})
|
||||
},
|
||||
createMariaDB() {
|
||||
this.$router.push({ name: 'DatabaseAppCreate', query: { type: 'mariadb' }})
|
||||
},
|
||||
createOracle() {
|
||||
this.$router.push({ name: 'DatabaseAppCreate', query: { type: 'oracle' }})
|
||||
},
|
||||
isValidateLicense() {
|
||||
if (this.publicSettings.XPACK_ENABLED) {
|
||||
return this.publicSettings.XPACK_LICENSE_IS_VALID
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<GenericCreateUpdatePage v-bind="$data" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GenericCreateUpdatePage } from '@/layout/components'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GenericCreateUpdatePage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
initial: {
|
||||
type: 'k8s'
|
||||
},
|
||||
fields: [
|
||||
[this.$t('common.Basic'), ['name', 'type', 'domain']],
|
||||
[this.$t('applications.kubernetes'), ['attrs']],
|
||||
[this.$t('common.Other'), ['comment']]
|
||||
],
|
||||
fieldsMeta: {
|
||||
type: {
|
||||
disabled: true
|
||||
},
|
||||
cluster: {
|
||||
helpText: this.$t('applications.clusterHelpTextMessage')
|
||||
},
|
||||
domain: {
|
||||
el: {
|
||||
multiple: false,
|
||||
clearable: true,
|
||||
ajax: {
|
||||
url: '/api/v1/assets/domains/'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
url: '/api/v1/applications/applications/',
|
||||
getUrl() {
|
||||
const params = this.$route.params
|
||||
let url = `/api/v1/applications/applications/`
|
||||
if (params.id) {
|
||||
url = `${url}${params.id}/`
|
||||
}
|
||||
return `${url}?type=k8s`
|
||||
},
|
||||
performSubmit(validValues) {
|
||||
const params = this.$route.params
|
||||
const baseUrl = `/api/v1/applications/applications/`
|
||||
const url = (params.id) ? `${baseUrl}${params.id}/` : baseUrl
|
||||
const method = this.getMethod()
|
||||
validValues.attrs = {
|
||||
cluster: validValues.cluster
|
||||
}
|
||||
validValues.category = 'cloud'
|
||||
return this.$axios[method](`${url}?type=${validValues.type}`, validValues)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getMethod() {
|
||||
const params = this.$route.params
|
||||
if (params.id) {
|
||||
return 'put'
|
||||
} else {
|
||||
return 'post'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :md="14" :sm="24">
|
||||
<DetailCard :title="cardTitle" :items="detailItems" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DetailCard from '@/components/DetailCard'
|
||||
import { toSafeLocalDateStr } from '@/utils/common'
|
||||
|
||||
export default {
|
||||
name: 'DatabaseAppDetail',
|
||||
components: {
|
||||
DetailCard
|
||||
},
|
||||
props: {
|
||||
object: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
cardTitle() {
|
||||
return this.object.name
|
||||
},
|
||||
detailItems() {
|
||||
return [
|
||||
{
|
||||
key: this.$t('common.Name'),
|
||||
value: this.object.name
|
||||
},
|
||||
{
|
||||
key: this.$t('applications.type'),
|
||||
value: this.object.type_display
|
||||
},
|
||||
{
|
||||
key: this.$t('applications.cluster'),
|
||||
value: this.object.attrs.cluster
|
||||
},
|
||||
{
|
||||
key: this.$t('common.dateCreated'),
|
||||
value: toSafeLocalDateStr(this.object.date_created)
|
||||
},
|
||||
{
|
||||
key: this.$t('common.createdBy'),
|
||||
value: this.object.created_by
|
||||
},
|
||||
{
|
||||
key: this.$t('common.Comment'),
|
||||
value: this.object.comment
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<GenericDetailPage :object.sync="KubernetesApp" :active-menu.sync="config.activeMenu" v-bind="config" v-on="$listeners">
|
||||
<keep-alive>
|
||||
<component :is="config.activeMenu" :object="KubernetesApp" />
|
||||
</keep-alive>
|
||||
</GenericDetailPage>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GenericDetailPage, TabPage } from '@/layout/components'
|
||||
import KubernetesAppDetail from './KubernetesAppDetail'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GenericDetailPage,
|
||||
KubernetesAppDetail,
|
||||
TabPage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
KubernetesApp: {
|
||||
name: '', type_display: '', cluster: '', date_created: '', created_by: '', comment: '', attrs: ''
|
||||
},
|
||||
config: {
|
||||
activeMenu: 'KubernetesAppDetail',
|
||||
submenu: [
|
||||
{
|
||||
title: this.$t('route.KubernetesAppDetail'),
|
||||
name: 'KubernetesAppDetail'
|
||||
}
|
||||
],
|
||||
actions: {
|
||||
detailApiUrl: `/api/v1/applications/applications/${this.$route.params.id}/`,
|
||||
deleteApiUrl: `/api/v1/applications/applications/${this.$route.params.id}/`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
|
||||
</style>
|
||||
60
src/views/applications/KubernetesApp/KubernetesAppList.vue
Normal file
60
src/views/applications/KubernetesApp/KubernetesAppList.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<GenericListPage ref="GenericListTable" :table-config="tableConfig" :header-actions="headerActions" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GenericListPage } from '@/layout/components'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GenericListPage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableConfig: {
|
||||
url: '/api/v1/applications/applications/?category=cloud',
|
||||
columns: [
|
||||
'name', 'type', 'attrs.cluster', 'comment', 'actions'
|
||||
],
|
||||
columnsMeta: {
|
||||
'attrs.cluster': {
|
||||
label: this.$t('applications.cluster')
|
||||
},
|
||||
comment: {
|
||||
width: '340px'
|
||||
},
|
||||
type: {
|
||||
width: '140px'
|
||||
},
|
||||
actions: {
|
||||
prop: '',
|
||||
formatterArgs: {
|
||||
hasClone: false,
|
||||
performDelete: function({ row, col, cellValue, reload }) {
|
||||
this.$axios.delete(
|
||||
`/api/v1/applications/applications/${row.id}/`
|
||||
).then(res => {
|
||||
this.$refs.GenericListTable.$refs.ListTable.reloadTable()
|
||||
// this.$message.success(this.$t('common.deleteSuccessMsg'))
|
||||
}).catch(error => {
|
||||
this.$message.error(this.$t('common.deleteErrorMsg' + ' ' + error))
|
||||
})
|
||||
}.bind(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasBulkDelete: false,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
createRoute: 'KubernetesAppCreate'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -22,14 +22,76 @@ export default {
|
||||
path: pathInitial
|
||||
},
|
||||
fields: [
|
||||
[this.$t('common.Basic'), ['name', 'asset', 'type', 'path']],
|
||||
[appTypeMeta.title, ['params']],
|
||||
[this.$t('common.Basic'), ['name', 'type', 'domain']],
|
||||
[appTypeMeta.title, ['attrs']],
|
||||
[this.$t('common.Other'), ['comment']]
|
||||
],
|
||||
url: '/api/v1/applications/remote-apps/',
|
||||
url: '/api/v1/applications/applications/',
|
||||
getUrl() {
|
||||
const params = this.$route.params
|
||||
let url = `/api/v1/applications/applications/`
|
||||
if (params.id) {
|
||||
url = `${url}${params.id}/`
|
||||
}
|
||||
return `${url}?type=${this.$route.query.type}`
|
||||
},
|
||||
performSubmit(validValues) {
|
||||
const params = this.$route.params
|
||||
const baseUrl = `/api/v1/applications/applications/`
|
||||
const url = (params.id) ? `${baseUrl}${params.id}/` : baseUrl
|
||||
const method = this.getMethod()
|
||||
switch (validValues.type) {
|
||||
case 'chrome': {
|
||||
validValues.attrs = {
|
||||
chrome_target: validValues.chrome_target,
|
||||
chrome_username: validValues.chrome_username,
|
||||
chrome_password: validValues.chrome_password,
|
||||
asset: validValues.asset,
|
||||
path: validValues.path
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'mysql_workbench': {
|
||||
validValues.attrs = {
|
||||
mysql_workbench_ip: validValues.mysql_workbench_ip,
|
||||
mysql_workbench_port: validValues.mysql_workbench_port,
|
||||
mysql_workbench_name: validValues.mysql_workbench_name,
|
||||
mysql_workbench_username: validValues.mysql_workbench_username,
|
||||
mysql_workbench_password: validValues.mysql_workbench_password,
|
||||
asset: validValues.asset,
|
||||
path: validValues.path
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'vmware_client': {
|
||||
validValues.attrs = {
|
||||
vmware_password: validValues.vmware_password,
|
||||
vmware_username: validValues.vmware_username,
|
||||
vmware_target: validValues.vmware_target,
|
||||
asset: validValues.asset,
|
||||
path: validValues.path
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'custom': {
|
||||
validValues.attrs = {
|
||||
custom_cmdline: validValues.custom_cmdline,
|
||||
custom_target: validValues.custom_target,
|
||||
custom_username: validValues.custom_username,
|
||||
custom_password: validValues.custom_password,
|
||||
asset: validValues.asset,
|
||||
path: validValues.path
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
validValues.category = 'remote_app'
|
||||
console.log(validValues)
|
||||
return this.$axios[method](`${url}?type=${validValues.type}`, validValues)
|
||||
},
|
||||
fieldsMeta: {
|
||||
asset: {
|
||||
rules: [{ required: false }],
|
||||
rules: [{ required: true }],
|
||||
el: {
|
||||
multiple: false,
|
||||
ajax: {
|
||||
@@ -50,10 +112,30 @@ export default {
|
||||
],
|
||||
disabled: true
|
||||
},
|
||||
params: {
|
||||
type: 'group',
|
||||
items: fieldsMap
|
||||
}
|
||||
asset_info: {
|
||||
type: 'input',
|
||||
hidden: () => true
|
||||
},
|
||||
domain: {
|
||||
el: {
|
||||
multiple: false,
|
||||
clearable: true,
|
||||
ajax: {
|
||||
url: '/api/v1/assets/domains/'
|
||||
}
|
||||
}
|
||||
},
|
||||
...fieldsMap
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getMethod() {
|
||||
const params = this.$route.params
|
||||
if (params.id) {
|
||||
return 'put'
|
||||
} else {
|
||||
return 'post'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,17 +32,17 @@ export default {
|
||||
key: this.$t('common.Name'),
|
||||
value: this.object.name
|
||||
},
|
||||
{
|
||||
key: this.$t('applications.asset'),
|
||||
value: this.object.asset_info.hostname
|
||||
},
|
||||
// {
|
||||
// key: this.$t('applications.asset'),
|
||||
// value: this.object.attrs.asset_info.hostname
|
||||
// },
|
||||
{
|
||||
key: this.$t('applications.appType'),
|
||||
value: this.object.get_type_display
|
||||
value: this.object.type_display
|
||||
},
|
||||
{
|
||||
key: this.$t('applications.appPath'),
|
||||
value: this.object.path
|
||||
value: this.object.attrs.path
|
||||
},
|
||||
{
|
||||
key: this.$t('common.dateCreated'),
|
||||
|
||||
@@ -17,9 +17,10 @@ export default {
|
||||
TabPage
|
||||
},
|
||||
data() {
|
||||
const vm = this
|
||||
return {
|
||||
RemoteApp: {
|
||||
name: '', asset: '', get_type_display: '', path: '', date_created: '', created_by: '', comment: ''
|
||||
name: '', asset: '', get_type_display: '', path: '', date_created: '', created_by: '', comment: '', attrs: ''
|
||||
},
|
||||
config: {
|
||||
activeMenu: 'RemoteAppDetail',
|
||||
@@ -28,7 +29,14 @@ export default {
|
||||
title: this.$t('route.RemoteAppDetail'),
|
||||
name: 'RemoteAppDetail'
|
||||
}
|
||||
]
|
||||
],
|
||||
actions: {
|
||||
detailApiUrl: `/api/v1/applications/applications/${this.$route.params.id}/`,
|
||||
deleteApiUrl: `/api/v1/applications/applications/${this.$route.params.id}/`,
|
||||
updateCallback: function(item) {
|
||||
vm.$router.push({ name: 'RemoteAppUpdate', params: { id: vm.RemoteApp.id }, query: { type: vm.RemoteApp.type }})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" :help-message="helpMessage" />
|
||||
<GenericListPage ref="GenericListTable" :table-config="tableConfig" :header-actions="headerActions" :help-message="helpMessage" />
|
||||
</template>
|
||||
|
||||
<script type="text/jsx">
|
||||
@@ -15,26 +15,39 @@ export default {
|
||||
return {
|
||||
helpMessage: this.$t('assets.RemoteAppListHelpMessage'),
|
||||
tableConfig: {
|
||||
url: '/api/v1/applications/remote-apps/',
|
||||
url: '/api/v1/applications/applications/?category=remote_app',
|
||||
columns: [
|
||||
'name', 'type', 'asset', 'comment', 'actions'
|
||||
'name', 'type', 'attrs.asset', 'comment', 'actions'
|
||||
],
|
||||
columnsMeta: {
|
||||
type: {
|
||||
displayKey: 'get_type_display'
|
||||
displayKey: 'get_type_display',
|
||||
width: '140px'
|
||||
},
|
||||
asset: {
|
||||
'attrs.asset': {
|
||||
label: this.$t('assets.Assets'),
|
||||
showOverflowTooltip: true,
|
||||
formatter: function(row, column, cellValue, index) {
|
||||
const route = { to: { name: 'AssetDetail', params: { id: cellValue }}}
|
||||
return <router-link{...{ attrs: route }} >{ row.asset_info.hostname }</router-link>
|
||||
return <router-link{...{ attrs: route }} >{ row.attrs.asset_info.hostname }</router-link>
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
formatterArgs: {
|
||||
hasClone: false,
|
||||
onUpdate: ({ row }) => {
|
||||
vm.$router.push({ name: 'RemoteAppUpdate', params: { id: row.id }, query: { type: row.type }})
|
||||
}
|
||||
},
|
||||
performDelete: function({ row, col, cellValue, reload }) {
|
||||
this.$axios.delete(
|
||||
`/api/v1/applications/applications/${row.id}/`
|
||||
).then(res => {
|
||||
this.$refs.GenericListTable.$refs.ListTable.reloadTable()
|
||||
// this.$message.success(this.$t('common.deleteSuccessMsg'))
|
||||
}).catch(error => {
|
||||
this.$message.error(this.$t('common.deleteErrorMsg' + ' ' + error))
|
||||
})
|
||||
}.bind(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +56,8 @@ export default {
|
||||
hasCreate: false,
|
||||
hasMoreActions: false,
|
||||
hasBulkDelete: false,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
// createRoute: 'RemoteAppCreate',
|
||||
moreActionsTitle: this.$t('common.Create'),
|
||||
moreActionsType: 'primary',
|
||||
|
||||
@@ -18,7 +18,7 @@ export const REMOTE_APP_TYPE_FIELDS_MAP = {
|
||||
label: i18n.t('applications.chrome_username')
|
||||
},
|
||||
{
|
||||
id: 'chrome_password', el: {}, attrs: {}, type: 'input', prop: 'chrome_password',
|
||||
id: 'chrome_password', el: { 'show-password': true }, attrs: {}, type: 'password', prop: 'chrome_password',
|
||||
label: i18n.t('applications.chrome_password')
|
||||
}
|
||||
],
|
||||
@@ -27,6 +27,10 @@ export const REMOTE_APP_TYPE_FIELDS_MAP = {
|
||||
id: 'mysql_workbench_ip', el: {}, attrs: {}, type: 'input', prop: 'mysql_workbench_ip',
|
||||
label: i18n.t('applications.mysql_workbench_ip')
|
||||
},
|
||||
{
|
||||
id: 'mysql_workbench_port', el: {}, attrs: {}, type: 'input', prop: 'mysql_workbench_port',
|
||||
label: i18n.t('applications.mysql_workbench_port')
|
||||
},
|
||||
{
|
||||
id: 'mysql_workbench_name', el: {}, attrs: {}, type: 'input', prop: 'mysql_workbench_name',
|
||||
label: i18n.t('applications.mysql_workbench_name')
|
||||
@@ -36,7 +40,7 @@ export const REMOTE_APP_TYPE_FIELDS_MAP = {
|
||||
label: i18n.t('applications.mysql_workbench_username')
|
||||
},
|
||||
{
|
||||
id: 'mysql_workbench_password', el: {}, attrs: {}, type: 'input', prop: 'mysql_workbench_password',
|
||||
id: 'mysql_workbench_password', el: { 'show-password': true }, attrs: {}, type: 'password', prop: 'mysql_workbench_password',
|
||||
label: i18n.t('applications.mysql_workbench_password')
|
||||
}
|
||||
],
|
||||
@@ -50,7 +54,7 @@ export const REMOTE_APP_TYPE_FIELDS_MAP = {
|
||||
label: i18n.t('applications.vmware_username')
|
||||
},
|
||||
{
|
||||
id: 'vmware_password', el: {}, attrs: {}, type: 'input', prop: 'vmware_password',
|
||||
id: 'vmware_password', el: { 'show-password': true }, attrs: {}, type: 'password', prop: 'vmware_password',
|
||||
label: i18n.t('applications.vmware_password')
|
||||
}
|
||||
],
|
||||
@@ -68,7 +72,7 @@ export const REMOTE_APP_TYPE_FIELDS_MAP = {
|
||||
label: i18n.t('applications.custom_username')
|
||||
},
|
||||
{
|
||||
id: 'custom_password', el: {}, attrs: {}, type: 'input', prop: 'custom_password',
|
||||
id: 'custom_password', el: { 'show-password': true }, attrs: {}, type: 'password', prop: 'custom_password',
|
||||
label: i18n.t('applications.custom_password')
|
||||
}
|
||||
]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user