Compare commits
651 Commits
fix_acl_da
...
v2.4.14
Author | SHA1 | Date | |
---|---|---|---|
|
03fdf5c004 | ||
|
f277cf088e | ||
|
b1f8a0024b | ||
|
aae43a53b5 | ||
|
8c2cdb1ca4 | ||
|
57d4bf5548 | ||
|
5e7c6199bf | ||
|
28dca7f086 | ||
|
4a3c21eec4 | ||
|
5d28c28023 | ||
|
ba6edb3abe | ||
|
2f1d57cee1 | ||
|
4111c634d9 | ||
|
f1fababa3d | ||
|
fe6373422e | ||
|
b3ea776886 | ||
|
c4d2ce313d | ||
|
20103a0fe6 | ||
|
394e2aeac6 | ||
|
8f7d78c26c | ||
|
7eecf3cec3 | ||
|
f6e9c443f7 | ||
|
857cbd82fd | ||
|
9a14296e02 | ||
|
f638b52759 | ||
|
78da728105 | ||
|
eb69029a51 | ||
|
07a097eba2 | ||
|
e843e3eac9 | ||
|
7308cfa6c2 | ||
|
64ea4fb21f | ||
|
e15cefaa38 | ||
|
f32339b969 | ||
|
131d213a73 | ||
|
ff98777689 | ||
|
383d4c88ed | ||
|
bb7157e292 | ||
|
b1a82f1a67 | ||
|
de86ea3852 | ||
|
bf05ea240e | ||
|
8ec0d619d7 | ||
|
61f8c463bc | ||
|
9b4dc3e43b | ||
|
9e69be8256 | ||
|
251b9e7fd5 | ||
|
f3cc12f1f9 | ||
|
56f03e1624 | ||
|
42ad2b6dde | ||
|
5aba1ff257 | ||
|
417e8fe349 | ||
|
02235d8cc0 | ||
|
00c7a644a2 | ||
|
f3e8757450 | ||
|
f0749341ba | ||
|
89da671e46 | ||
|
0e60aae076 | ||
|
4dfa97d404 | ||
|
9b778f9bc7 | ||
|
eafb5f053a | ||
|
834054e216 | ||
|
a97cabbedc | ||
|
ae77852d5f | ||
|
611ee40dca | ||
|
c0d55b2126 | ||
|
2cc4499ef9 | ||
|
1268404bca | ||
|
570a9203c4 | ||
|
adae7b5519 | ||
|
8a91ec7b11 | ||
|
92fca65383 | ||
|
4b8e6c2841 | ||
|
ab240cb003 | ||
|
61e62e4740 | ||
|
1fd72d6c78 | ||
|
51e16f6b23 | ||
|
037378e384 | ||
|
631871a8cf | ||
|
6e02f6a21f | ||
|
a2224ba2ac | ||
|
11a289aac9 | ||
|
55ab04dd28 | ||
|
256a4f4844 | ||
|
018a349336 | ||
|
8f62227adb | ||
|
de51cb3e21 | ||
|
ecb069cf14 | ||
|
937cb84393 | ||
|
40a4db06b5 | ||
|
cc98f903ea | ||
|
fb7471ce04 | ||
|
e2872f041e | ||
|
250fde127c | ||
|
73dbb14944 | ||
|
73c9a6fa72 | ||
|
09d957db79 | ||
|
b73d796891 | ||
|
e7cbd0caa9 | ||
|
3e4c385d91 | ||
|
3aac012ee9 | ||
|
78d762cacc | ||
|
c668ba7d3f | ||
|
542a876ead | ||
|
68b7497bba | ||
|
dfbf3d462d | ||
|
692708fcba | ||
|
330b64edb3 | ||
|
63a3074cb7 | ||
|
31b8cf49dc | ||
|
b01c335456 | ||
|
002fef09e2 | ||
|
175778a162 | ||
|
5050a1bef5 | ||
|
46a6cf67d6 | ||
|
4e857c2775 | ||
|
835df1bdeb | ||
|
579339d13c | ||
|
629967ce82 | ||
|
3a00bfd236 | ||
|
2e97ebd895 | ||
|
eb6a813cbc | ||
|
ff78face48 | ||
|
d55433c438 | ||
|
daf0254616 | ||
|
6b32009955 | ||
|
d53288c1fb | ||
|
586d820a08 | ||
|
6776be4599 | ||
|
ff2b8ea198 | ||
|
ed46a1e1c1 | ||
|
0dc614fb46 | ||
|
bc66d33ce0 | ||
|
d5db68d7d0 | ||
|
b22b8b286b | ||
|
dd4f3b0e9c | ||
|
688f4e0ea4 | ||
|
c1813f525d | ||
|
b405e28498 | ||
|
fa32758462 | ||
|
29995b660a | ||
|
b96fc06a62 | ||
|
c7f30b63ff | ||
|
5bff69a8a8 | ||
|
d5e60fab88 | ||
|
190f452118 | ||
|
98a4824364 | ||
|
c0f9baea79 | ||
|
d4b661c77f | ||
|
75cd7bde77 | ||
|
ec912d3a65 | ||
|
42f02b4986 | ||
|
a13b999820 | ||
|
5f53b0dd0e | ||
|
df22085ff9 | ||
|
06148b402d | ||
|
3fe020505a | ||
|
b34e83124f | ||
|
cdc52d3f80 | ||
|
b3a80d5678 | ||
|
a2e3061bba | ||
|
a8eb5126ea | ||
|
adac2129fc | ||
|
e660c901ce | ||
|
ff002c0a1e | ||
|
88593d6da7 | ||
|
6fa0dd5bc5 | ||
|
3200942373 | ||
|
4fd705cc59 | ||
|
74827ce187 | ||
|
4ed1eb6062 | ||
|
7792204658 | ||
|
8621108906 | ||
|
6437af19b9 | ||
|
735ddb334c | ||
|
4a8032202e | ||
|
c7acea6422 | ||
|
ac4c93de8e | ||
|
8d044cf935 | ||
|
54747fa789 | ||
|
545f1bb30b | ||
|
dc77bca17c | ||
|
4973278c5a | ||
|
d1c9361e47 | ||
|
28c57cacd9 | ||
|
711dcc4bd7 | ||
|
491d3cce00 | ||
|
27354a3927 | ||
|
78495eb976 | ||
|
ae900c7d3b | ||
|
50134e6a0b | ||
|
65ef58dea9 | ||
|
0a2e7aa99f | ||
|
8875e75883 | ||
|
2f03639c57 | ||
|
49bc5d94a9 | ||
|
39354e1293 | ||
|
d3714f3ecf | ||
|
729a616282 | ||
|
2d3a290aa3 | ||
|
9e885a5b12 | ||
|
f5822d7cba | ||
|
21ea553e74 | ||
|
e63038d1b6 | ||
|
d56806f511 | ||
|
7ac7fdc08e | ||
|
ba11707146 | ||
|
d49dc8a067 | ||
|
6bfb34fe2a | ||
|
2c7ed8c32d | ||
|
5b275af54e | ||
|
dde7ec6246 | ||
|
9181817e96 | ||
|
46b54bb7f2 | ||
|
fe63310c4e | ||
|
27c733aa2c | ||
|
2a8e9e684e | ||
|
095190a785 | ||
|
ef25c94b5d | ||
|
06ae1bcf13 | ||
|
9ead4e7d8d | ||
|
994a28dd25 | ||
|
74b587e46c | ||
|
091cd882bd | ||
|
73093db467 | ||
|
66e268ce68 | ||
|
a41d1a5e97 | ||
|
b4b728fe28 | ||
|
d16462d8b7 | ||
|
de7d98c0b4 | ||
|
51332c7236 | ||
|
bf1076fe4a | ||
|
3454a98cfb | ||
|
506dcbb40e | ||
|
5ac4517187 | ||
|
761e98884b | ||
|
073654624e | ||
|
df54244ff1 | ||
|
27e9919198 | ||
|
dc8b1a5de2 | ||
|
d8a7728f1d | ||
|
82881965fb | ||
|
1bb62022f1 | ||
|
ed445a8d82 | ||
|
3626b1a97e | ||
|
32529fba9b | ||
|
a042b4fe39 | ||
|
a0631414dc | ||
|
5266cb5b88 | ||
|
c7d4bec988 | ||
|
099ddd6ca9 | ||
|
bd813174b1 | ||
|
0a43680d6e | ||
|
976c6cfe91 | ||
|
cf594f04ba | ||
|
4232094aed | ||
|
d08827d086 | ||
|
d25ae532cd | ||
|
9fbb6ee64d | ||
|
b62f0e96fd | ||
|
c1bcd0ce45 | ||
|
c8b55c34eb | ||
|
4b5906770f | ||
|
4188ac7252 | ||
|
2efbc6474a | ||
|
03eac0c4d2 | ||
|
2a861250eb | ||
|
8fc19d8b7c | ||
|
430d2ff6d0 | ||
|
2517009d70 | ||
|
67da360d80 | ||
|
24c56fb259 | ||
|
37d5da65de | ||
|
2224ebd533 | ||
|
bf6331d215 | ||
|
b18b90ab4e | ||
|
702e17a7a4 | ||
|
a7586aa140 | ||
|
ad3f96431c | ||
|
1515820713 | ||
|
7728b57878 | ||
|
a419eefd72 | ||
|
a44e5f6cf1 | ||
|
7d46e92c2d | ||
|
4117cf87ec | ||
|
9e0fe0b818 | ||
|
2a8f1ab9a4 | ||
|
c0fe99b8c7 | ||
|
42feb4b862 | ||
|
482d34993b | ||
|
7ff309b8b8 | ||
|
98eb47d44f | ||
|
9ab0f624ef | ||
|
3f3eda8b3c | ||
|
f788adc8cf | ||
|
693ae4ff05 | ||
|
a1a9d99eb4 | ||
|
e045e0fb43 | ||
|
09376dbd2b | ||
|
7fda5a1e7b | ||
|
113b84763f | ||
|
190170acad | ||
|
513d2af4b8 | ||
|
4588bd8996 | ||
|
082da5fade | ||
|
013b116eb5 | ||
|
208d29165b | ||
|
d510330cde | ||
|
ea4f0fc2a5 | ||
|
9bcdaacdc4 | ||
|
5045581ddf | ||
|
232913172c | ||
|
157e1809ed | ||
|
ab8ccf7d1b | ||
|
ae1f0f6b4f | ||
|
ff47e0ade6 | ||
|
0dd272fb04 | ||
|
6bc5c1516d | ||
|
4a4b9e6ef0 | ||
|
6e3f9478b3 | ||
|
691051c254 | ||
|
8f066e95a6 | ||
|
75bca39bf6 | ||
|
3360e4d0fe | ||
|
521fcd0ba2 | ||
|
fc113425cb | ||
|
81a76a9632 | ||
|
9ec105ca37 | ||
|
1e1c92a3ef | ||
|
0b3cad8215 | ||
|
ed41a72900 | ||
|
27854d4e0a | ||
|
0372459f9d | ||
|
f56378e2b5 | ||
|
00b276d5e7 | ||
|
3faefbe8d3 | ||
|
4261f6fb57 | ||
|
c98199e98e | ||
|
82ea1ddc79 | ||
|
995e581315 | ||
|
ec8f626b8f | ||
|
ec884c92e1 | ||
|
9ee2776bdd | ||
|
7186bdac9c | ||
|
0a9964375a | ||
|
bff45d00b6 | ||
|
e429ad59ff | ||
|
ace160ae19 | ||
|
7036fe023c | ||
|
341f5dba53 | ||
|
5883c1616e | ||
|
bee0a3a3e5 | ||
|
7a79a8bbf7 | ||
|
100a889cb8 | ||
|
b093569453 | ||
|
3919dfdfbb | ||
|
ef85ba2542 | ||
|
3d5c2ec5bc | ||
|
c143d6ae5b | ||
|
10b273ee81 | ||
|
855cb91b31 | ||
|
ffae57642c | ||
|
9ed1108c20 | ||
|
72b2f8b6de | ||
|
20f3e917fe | ||
|
c430515377 | ||
|
a6e2aca281 | ||
|
18313b7bd1 | ||
|
dbc44a8ad6 | ||
|
f143e30cf5 | ||
|
4beece5a6e | ||
|
920295d955 | ||
|
6eb8ae1dac | ||
|
f1f86ce25a | ||
|
090007487d | ||
|
aa98a304c1 | ||
|
fe22e363b4 | ||
|
2d2fb6e1d6 | ||
|
9894c77300 | ||
|
4ea947f741 | ||
|
e5ab2c2573 | ||
|
5581fa8d0f | ||
|
76c939fe5c | ||
|
6e9ce08e2c | ||
|
092a8b9b92 | ||
|
b45fd0cbbb | ||
|
5320ecfd62 | ||
|
1d253d7ad3 | ||
|
73d53f0440 | ||
|
d4a37af183 | ||
|
e03849b054 | ||
|
faed3fe6a2 | ||
|
21c9d9accd | ||
|
a06599ce33 | ||
|
2b69217136 | ||
|
03a3b8b169 | ||
|
cd319421d5 | ||
|
c918d54ea5 | ||
|
cf0ad7bad6 | ||
|
e0c8263542 | ||
|
275e8b15f3 | ||
|
6ff942c107 | ||
|
d3c87ee500 | ||
|
a4f65e7fc6 | ||
|
10527bf9b8 | ||
|
0414121c27 | ||
|
edde467c87 | ||
|
d525e1ec54 | ||
|
91c49b690f | ||
|
05453becf9 | ||
|
5fe27f8678 | ||
|
0924b8846f | ||
|
62a669159a | ||
|
2933bf1efa | ||
|
981f8b0145 | ||
|
213bda671c | ||
|
837aabfe77 | ||
|
cc599d414a | ||
|
01fcd7f80e | ||
|
af254ddbeb | ||
|
422e89c6c6 | ||
|
c2c11b38ed | ||
|
45d3f57228 | ||
|
c711c3d3fd | ||
|
2ae4aeee67 | ||
|
46238b8b51 | ||
|
b1528ec511 | ||
|
8ef4edb7d2 | ||
|
0172206c7c | ||
|
9d5bdf1b0d | ||
|
c0726b228d | ||
|
5b314aa907 | ||
|
c9f0de9838 | ||
|
2db41dd992 | ||
|
89e492c1f3 | ||
|
1aeb9a2702 | ||
|
b090a88b76 | ||
|
d5c479f7e5 | ||
|
b342258e75 | ||
|
3d716eff3e | ||
|
9791a184e3 | ||
|
142b8c95c5 | ||
|
363b89011f | ||
|
321372fa88 | ||
|
fc27dc6e64 | ||
|
8ad98f4ba4 | ||
|
9b050fa7fa | ||
|
a30826827a | ||
|
691b50aec4 | ||
|
55ca2d5eb5 | ||
|
779cd1ea9e | ||
|
7d53180a2f | ||
|
b6c41c00dd | ||
|
fff5679f6e | ||
|
7556dfe56b | ||
|
44b6f2b2ad | ||
|
f5607d96f3 | ||
|
2e85a9971b | ||
|
8d177266dc | ||
|
42d870ea4e | ||
|
424cad2130 | ||
|
430308a679 | ||
|
cc7570a4b2 | ||
|
413c0dfdfe | ||
|
f8fee771c4 | ||
|
3d05cef7cd | ||
|
30477f736e | ||
|
0cd5c0277b | ||
|
4fcddd1010 | ||
|
b269ef894f | ||
|
ea13432e4c | ||
|
c8a68bd185 | ||
|
f9ee895f58 | ||
|
59d9f2c79a | ||
|
f629558d60 | ||
|
4cbf70e756 | ||
|
40b9bec122 | ||
|
17b27d492a | ||
|
dd8f66a3fa | ||
|
d501436e3d | ||
|
8c6389b4f8 | ||
|
63ed73fa14 | ||
|
ef90506916 | ||
|
c0541b7e50 | ||
|
388134b38c | ||
|
f57d640c5d | ||
|
42c506ded8 | ||
|
373346e71e | ||
|
983cb4041c | ||
|
718fca57d2 | ||
|
2b1b0333ff | ||
|
9bb787d3f4 | ||
|
9f5979c1b1 | ||
|
b58230fd56 | ||
|
8e6ce05c04 | ||
|
b8d93bc9eb | ||
|
968ef93153 | ||
|
e0a0113e69 | ||
|
7181f2879a | ||
|
ff1626ff07 | ||
|
dca8781a03 | ||
|
43c5d74661 | ||
|
b1d0bdb536 | ||
|
2420631ed5 | ||
|
deabebb922 | ||
|
cd451060e3 | ||
|
82d4c4f961 | ||
|
79f5dac661 | ||
|
1a7c3fcd21 | ||
|
606be7f8e8 | ||
|
7f66f7688b | ||
|
25ad2192fd | ||
|
881b8cc1fa | ||
|
68905281f2 | ||
|
3cb78f30d2 | ||
|
ebce839eaa | ||
|
3170048ea9 | ||
|
976cac6742 | ||
|
99e5a932ae | ||
|
058585504f | ||
|
6d50a13cf0 | ||
|
198ecad13a | ||
|
1660139b27 | ||
|
0155eb98a2 | ||
|
c0c05bca86 | ||
|
32227d375a | ||
|
eb9c20a295 | ||
|
b826de4195 | ||
|
c3b55c2850 | ||
|
33313b6206 | ||
|
00fbe15a19 | ||
|
9e5c926bfd | ||
|
f0467c3d3b | ||
|
6758b994f8 | ||
|
d8646f8e7c | ||
|
0fa95aed36 | ||
|
d82356444a | ||
|
b8fa68ec8d | ||
|
78c542e71d | ||
|
6594863934 | ||
|
61e8c61fc6 | ||
|
ec9b5a0fa0 | ||
|
3664994cc5 | ||
|
366311e59b | ||
|
03f2ff912d | ||
|
ff9af51465 | ||
|
04fc588935 | ||
|
f215e887c9 | ||
|
3e6955fc7a | ||
|
b1cfb88308 | ||
|
d1af0eba79 | ||
|
f41873dc8c | ||
|
63562007df | ||
|
a99ecb9ea5 | ||
|
08f9bd9071 | ||
|
17c851f354 | ||
|
3382195a25 | ||
|
cd70b16eb3 | ||
|
2a98c00d97 | ||
|
5044af5490 | ||
|
320dc07676 | ||
|
95d3b0233a | ||
|
093466ef06 | ||
|
ceacc0ab15 | ||
|
cb3a9d9432 | ||
|
23fd56cf28 | ||
|
dd1c783919 | ||
|
8296e9a552 | ||
|
590565bdf0 | ||
|
9e2bf3d1f0 | ||
|
7547b67805 | ||
|
4abe4d7e8f | ||
|
0ebd52f3fd | ||
|
4cc2e47f02 | ||
|
b16bfdfa03 | ||
|
ece24080d5 | ||
|
a0ea8a193b | ||
|
d8e09d449e | ||
|
44c99e0f2e | ||
|
7110b4bcb3 | ||
|
3989859945 | ||
|
29ed4dd708 | ||
|
dbcbe33ba0 | ||
|
ed340a1c33 | ||
|
17ee7622b4 | ||
|
51877778bf | ||
|
1de8b492ea | ||
|
1fe38c4ec3 | ||
|
92bff08b84 | ||
|
37d0dacd2e | ||
|
e22f45fd25 | ||
|
56ef0a055a | ||
|
522991e23b | ||
|
ff061d4d2e | ||
|
5b84a704b1 | ||
|
3ba83821f2 | ||
|
45b82aa52d | ||
|
c99790bda2 | ||
|
7272880062 | ||
|
8130dd92ab | ||
|
9ca2d38307 | ||
|
e61bbdbcb7 | ||
|
88960c3082 | ||
|
0aa433882e | ||
|
d4f5713e0a | ||
|
790204ea28 | ||
|
927ed393d3 | ||
|
bf92b89a5f | ||
|
7ddaa143da | ||
|
157361cc7a | ||
|
dcf768376a | ||
|
e339ad2c23 | ||
|
8b10c5c72d | ||
|
bd13f6b744 | ||
|
934d00e87d | ||
|
9d421993a0 | ||
|
6751f673d5 | ||
|
c420a2195a | ||
|
ec3a6e0b6e | ||
|
ab0a5399f7 | ||
|
33e63c762f | ||
|
53b2a228ae | ||
|
c687e7ad9b | ||
|
ea3cdbd5f5 | ||
|
1ebe74d966 | ||
|
1f935d25a2 | ||
|
14e4dbacac | ||
|
f7a9257e16 | ||
|
99562df6cd | ||
|
630013cb85 | ||
|
6351d3af64 | ||
|
2d96048828 | ||
|
3e67bb94bc | ||
|
a26c9ff542 | ||
|
252003f76d | ||
|
928149f2a0 | ||
|
0283af812c | ||
|
6ccb2e74e0 | ||
|
5016464016 | ||
|
b787bd9b7b | ||
|
11f69d8679 | ||
|
c3168035ed | ||
|
5140c0a58f | ||
|
ee97582579 | ||
|
83e9172722 | ||
|
341e687987 | ||
|
93d9804127 | ||
|
f3d42cb356 | ||
|
04b9a3c929 | ||
|
e98160b84a | ||
|
7c769a53da | ||
|
08dc343083 | ||
|
52e654ff60 |
11
README.md
@@ -27,6 +27,7 @@
|
||||
|
||||
<img src=docs/images/dashboard.png />
|
||||
|
||||
[查看更多展示](docs/screenshot.md)
|
||||
|
||||
### 相关文章
|
||||
|
||||
@@ -50,12 +51,14 @@
|
||||
|
||||
### 主要功能
|
||||
|
||||
- 自定义模型和模型关系,模型属性支持下拉列表、字体颜色、计算属性等高级特性
|
||||
- 支持计算机、网络设备、存储设备、数据库、中间件、公有云资源等自动发现
|
||||
- 模型属性支持索引、多值、默认排序、字体颜色,支持计算属性
|
||||
- 支持自动发现、定时巡检、文件导入
|
||||
- 支持资源、层级、关系视图展示
|
||||
- 支持模型间关系配置和展示
|
||||
- 细粒度访问控制,完备的操作日志
|
||||
- 通用的资源搜索和关系搜索
|
||||
- 支持IP地址管理(IPAM), 数据中心基础设施管理(DCIM)
|
||||
- 支持跨模型搜索
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -23,7 +23,6 @@ from api.lib.cmdb.const import REDIS_PREFIX_CI_RELATION2
|
||||
from api.lib.cmdb.const import ResourceTypeEnum
|
||||
from api.lib.cmdb.const import RoleEnum
|
||||
from api.lib.cmdb.const import ValueTypeEnum
|
||||
from api.lib.cmdb.dcim.rack import RackManager
|
||||
from api.lib.exception import AbortException
|
||||
from api.lib.perm.acl.acl import ACLManager
|
||||
from api.lib.perm.acl.acl import UserCache
|
||||
@@ -196,7 +195,7 @@ def cmdb_counter():
|
||||
today = datetime.date.today()
|
||||
while True:
|
||||
try:
|
||||
db.session.commit()
|
||||
db.session.remove()
|
||||
|
||||
CMDBCounterCache.reset()
|
||||
|
||||
@@ -210,8 +209,6 @@ def cmdb_counter():
|
||||
|
||||
CMDBCounterCache.flush_sub_counter()
|
||||
|
||||
RackManager().check_u_slot()
|
||||
|
||||
i += 1
|
||||
except:
|
||||
import traceback
|
||||
@@ -256,10 +253,10 @@ def cmdb_trigger():
|
||||
trigger2cis[trigger.id] = (trigger, ready_cis)
|
||||
else:
|
||||
cur = trigger2cis[trigger.id]
|
||||
cur_ci_ids = {_ci.ci_id for _ci in cur[1]}
|
||||
cur_ci_ids = {i.ci_id for i in cur[1]}
|
||||
trigger2cis[trigger.id] = (
|
||||
trigger, cur[1] + [_ci for _ci in ready_cis if _ci.ci_id not in cur_ci_ids
|
||||
and _ci.ci_id not in trigger2completed.get(trigger.id, {})])
|
||||
trigger, cur[1] + [i for i in ready_cis if i.ci_id not in cur_ci_ids
|
||||
and i.ci_id not in trigger2completed.get(trigger.id, {})])
|
||||
|
||||
for tid in trigger2cis:
|
||||
trigger, cis = trigger2cis[tid]
|
||||
|
@@ -512,7 +512,7 @@ class CMDBCounterCache(object):
|
||||
result[i.type_id]['rule_count'] = len(adts) + AutoDiscoveryCITypeRelation.get_by(
|
||||
ad_type_id=i.type_id, only_query=True).count()
|
||||
result[i.type_id]['exec_target_count'] = len(
|
||||
set([j.oneagent_id for adt in adts for j in db.session.query(
|
||||
set([i.oneagent_id for adt in adts for i in db.session.query(
|
||||
AutoDiscoveryRuleSyncHistory.oneagent_id).filter(
|
||||
AutoDiscoveryRuleSyncHistory.adt_id == adt.id)]))
|
||||
|
||||
|
@@ -295,7 +295,7 @@ class CIManager(object):
|
||||
db.session.commit()
|
||||
|
||||
value_table = TableMap(attr_name=attr.name).table
|
||||
with redis_lock.Lock(rd.r, "auto_inc_id_{}".format(attr.name), expire=10):
|
||||
with redis_lock.Lock(rd.r, "auto_inc_id_{}".format(attr.name)):
|
||||
max_v = value_table.get_by(attr_id=attr.id, only_query=True).order_by(
|
||||
getattr(value_table, 'value').desc()).first()
|
||||
if max_v is not None:
|
||||
@@ -357,7 +357,6 @@ class CIManager(object):
|
||||
is_auto_discovery=False,
|
||||
_is_admin=False,
|
||||
ticket_id=None,
|
||||
_sync=False,
|
||||
**ci_dict):
|
||||
"""
|
||||
add ci
|
||||
@@ -367,7 +366,6 @@ class CIManager(object):
|
||||
:param is_auto_discovery: default is False
|
||||
:param _is_admin: default is False
|
||||
:param ticket_id:
|
||||
:param _sync:
|
||||
:param ci_dict:
|
||||
:return:
|
||||
"""
|
||||
@@ -393,7 +391,7 @@ class CIManager(object):
|
||||
ci = None
|
||||
record_id = None
|
||||
password_dict = {}
|
||||
with redis_lock.Lock(rd.r, ci_type.name, expire=10):
|
||||
with redis_lock.Lock(rd.r, ci_type.name):
|
||||
db.session.commit()
|
||||
|
||||
if (unique_key.default and unique_key.default.get('default') == AttributeDefaultValueEnum.AUTO_INC_ID and
|
||||
@@ -498,16 +496,10 @@ class CIManager(object):
|
||||
record_id = cls.save_password(ci.id, attr_id, password_dict[attr_id], record_id, ci_type.id)
|
||||
|
||||
if record_id or has_dynamic: # has changed
|
||||
if not _sync:
|
||||
ci_cache.apply_async(args=(ci.id, operate_type, record_id), queue=CMDB_QUEUE)
|
||||
else:
|
||||
ci_cache(ci.id, operate_type, record_id)
|
||||
ci_cache.apply_async(args=(ci.id, operate_type, record_id), queue=CMDB_QUEUE)
|
||||
|
||||
if ref_ci_dict: # add relations
|
||||
if not _sync:
|
||||
ci_relation_add.apply_async(args=(ref_ci_dict, ci.id, current_user.uid), queue=CMDB_QUEUE)
|
||||
else:
|
||||
ci_relation_add(ref_ci_dict, ci.id, current_user.uid)
|
||||
ci_relation_add.apply_async(args=(ref_ci_dict, ci.id, current_user.uid), queue=CMDB_QUEUE)
|
||||
|
||||
return ci.id
|
||||
|
||||
@@ -550,7 +542,7 @@ class CIManager(object):
|
||||
limit_attrs = self._valid_ci_for_no_read(ci) if not _is_admin else {}
|
||||
|
||||
record_id = None
|
||||
with redis_lock.Lock(rd.r, ci_type.name, expire=10):
|
||||
with redis_lock.Lock(rd.r, ci_type.name):
|
||||
db.session.commit()
|
||||
|
||||
self._valid_unique_constraint(ci.type_id, ci_dict, ci_id)
|
||||
@@ -1268,9 +1260,7 @@ class CIRelationManager(object):
|
||||
else:
|
||||
type_relation = CITypeRelation.get_by_id(relation_type_id)
|
||||
|
||||
with redis_lock.Lock(rd.r,
|
||||
"ci_relation_add_{}_{}".format(first_ci.type_id, second_ci.type_id),
|
||||
expire=10):
|
||||
with redis_lock.Lock(rd.r, "ci_relation_add_{}_{}".format(first_ci.type_id, second_ci.type_id)):
|
||||
|
||||
cls._check_constraint(first_ci_id, first_ci.type_id, second_ci_id, second_ci.type_id, type_relation)
|
||||
|
||||
@@ -1291,10 +1281,10 @@ class CIRelationManager(object):
|
||||
return existed.id
|
||||
|
||||
@staticmethod
|
||||
def delete(cr_id, apply_async=True, valid=True):
|
||||
def delete(cr_id, apply_async=True):
|
||||
cr = CIRelation.get_by_id(cr_id) or abort(404, ErrFormat.relation_not_found.format("id={}".format(cr_id)))
|
||||
|
||||
if current_app.config.get('USE_ACL') and current_user.username != 'worker' and valid:
|
||||
if current_app.config.get('USE_ACL') and current_user.username != 'worker':
|
||||
resource_name = CITypeRelationManager.acl_resource_name(cr.first_ci.ci_type.name, cr.second_ci.ci_type.name)
|
||||
if not ACLManager().has_permission(
|
||||
resource_name,
|
||||
@@ -1333,7 +1323,7 @@ class CIRelationManager(object):
|
||||
return cr
|
||||
|
||||
@classmethod
|
||||
def delete_3(cls, first_ci_id, second_ci_id, apply_async=True, valid=True):
|
||||
def delete_3(cls, first_ci_id, second_ci_id, apply_async=True):
|
||||
cr = CIRelation.get_by(first_ci_id=first_ci_id,
|
||||
second_ci_id=second_ci_id,
|
||||
to_dict=False,
|
||||
@@ -1343,7 +1333,7 @@ class CIRelationManager(object):
|
||||
# ci_relation_delete.apply_async(args=(first_ci_id, second_ci_id, cr.ancestor_ids), queue=CMDB_QUEUE)
|
||||
# delete_id_filter.apply_async(args=(second_ci_id,), queue=CMDB_QUEUE)
|
||||
|
||||
cls.delete(cr.id, apply_async=apply_async, valid=valid)
|
||||
cls.delete(cr.id, apply_async=apply_async)
|
||||
|
||||
return cr
|
||||
|
||||
@@ -1536,8 +1526,7 @@ class CITriggerManager(object):
|
||||
ci_dict.update(attr_dict)
|
||||
|
||||
@classmethod
|
||||
def _exec_webhook(cls, operate_type, webhook, ci_dict, trigger_id, trigger_name, record_id,
|
||||
ci_id=None, app=None, record_history=True):
|
||||
def _exec_webhook(cls, operate_type, webhook, ci_dict, trigger_id, trigger_name, record_id, ci_id=None, app=None):
|
||||
app = app or current_app
|
||||
|
||||
with app.app_context():
|
||||
@@ -1555,20 +1544,19 @@ class CITriggerManager(object):
|
||||
current_app.logger.warning("exec webhook failed: {}".format(e))
|
||||
response = e
|
||||
is_ok = False
|
||||
if record_history:
|
||||
CITriggerHistoryManager.add(operate_type,
|
||||
record_id,
|
||||
ci_dict.get('_id'),
|
||||
trigger_id,
|
||||
trigger_name,
|
||||
is_ok=is_ok,
|
||||
webhook=response)
|
||||
|
||||
CITriggerHistoryManager.add(operate_type,
|
||||
record_id,
|
||||
ci_dict.get('_id'),
|
||||
trigger_id,
|
||||
trigger_name,
|
||||
is_ok=is_ok,
|
||||
webhook=response)
|
||||
|
||||
return is_ok
|
||||
|
||||
@classmethod
|
||||
def _exec_notify(cls, operate_type, notify, ci_dict, trigger_id, trigger_name, record_id,
|
||||
ci_id=None, app=None, record_history=True):
|
||||
def _exec_notify(cls, operate_type, notify, ci_dict, trigger_id, trigger_name, record_id, ci_id=None, app=None):
|
||||
app = app or current_app
|
||||
|
||||
with app.app_context():
|
||||
@@ -1592,14 +1580,13 @@ class CITriggerManager(object):
|
||||
response = "{}\n{}".format(response, e)
|
||||
is_ok = False
|
||||
|
||||
if record_history:
|
||||
CITriggerHistoryManager.add(operate_type,
|
||||
record_id,
|
||||
ci_dict.get('_id'),
|
||||
trigger_id,
|
||||
trigger_name,
|
||||
is_ok=is_ok,
|
||||
notify=response.strip())
|
||||
CITriggerHistoryManager.add(operate_type,
|
||||
record_id,
|
||||
ci_dict.get('_id'),
|
||||
trigger_id,
|
||||
trigger_name,
|
||||
is_ok=is_ok,
|
||||
notify=response.strip())
|
||||
|
||||
return is_ok
|
||||
|
||||
@@ -1676,47 +1663,25 @@ class CITriggerManager(object):
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def trigger_notify(cls, trigger, ci, only_test=False):
|
||||
def trigger_notify(cls, trigger, ci):
|
||||
"""
|
||||
only for date attribute
|
||||
:param trigger:
|
||||
:param ci:
|
||||
:param only_test:
|
||||
:return:
|
||||
"""
|
||||
if (trigger.option.get('notifies', {}).get('notify_at') == datetime.datetime.now().strftime("%H:%M") or
|
||||
not trigger.option.get('notifies', {}).get('notify_at')) or only_test:
|
||||
not trigger.option.get('notifies', {}).get('notify_at')):
|
||||
|
||||
if trigger.option.get('webhooks'):
|
||||
threading.Thread(
|
||||
target=cls._exec_webhook,
|
||||
args=(None, trigger.option['webhooks'], None, trigger.id,
|
||||
trigger.option.get('name'), None,
|
||||
ci and ci.ci_id,
|
||||
current_app._get_current_object(), not only_test)).start()
|
||||
threading.Thread(target=cls._exec_webhook, args=(
|
||||
None, trigger.option['webhooks'], None, trigger.id, trigger.option.get('name'), None, ci.ci_id,
|
||||
current_app._get_current_object())).start()
|
||||
elif trigger.option.get('notifies'):
|
||||
threading.Thread(target=cls._exec_notify, args=(
|
||||
None, trigger.option['notifies'], None, trigger.id,
|
||||
trigger.option.get('name'), None,
|
||||
ci and ci.ci_id,
|
||||
current_app._get_current_object(), not only_test)).start()
|
||||
None, trigger.option['notifies'], None, trigger.id, trigger.option.get('name'), None, ci.ci_id,
|
||||
current_app._get_current_object())).start()
|
||||
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def trigger_notify_test(cls, type_id, trigger_id):
|
||||
trigger = CITypeTrigger.get_by_id(trigger_id) or abort(
|
||||
404, ErrFormat.ci_type_trigger_not_found.format(trigger_id))
|
||||
|
||||
ci_type = CITypeCache.get(type_id) or abort(404, ErrFormat.ci_type_not_found.format(type_id))
|
||||
attr = AttributeCache.get(ci_type.unique_id)
|
||||
value_table = TableMap(attr=attr).table
|
||||
if not value_table:
|
||||
return
|
||||
|
||||
value = value_table.get_by(attr_id=attr.id, only_query=True).join(
|
||||
CI, value_table.ci_id == CI.id).filter(CI.type_id == type_id).first()
|
||||
|
||||
cls.trigger_notify(trigger, value, only_test=True)
|
||||
|
@@ -421,10 +421,7 @@ class CITypeGroupManager(object):
|
||||
group_types = set()
|
||||
for group in groups:
|
||||
for t in sorted(CITypeGroupItem.get_by(group_id=group['id']), key=lambda x: x['order'] or 0):
|
||||
ci_type = CITypeCache.get(t['type_id'])
|
||||
if ci_type is None:
|
||||
continue
|
||||
ci_type = ci_type.to_dict()
|
||||
ci_type = CITypeCache.get(t['type_id']).to_dict()
|
||||
if type_ids is not None and ci_type['id'] not in type_ids:
|
||||
continue
|
||||
if resources is None or (ci_type and ci_type['name'] in resources):
|
||||
@@ -882,8 +879,6 @@ class CITypeRelationManager(object):
|
||||
def _wrap_relation_type_dict(type_id, relation_inst):
|
||||
ci_type_dict = CITypeCache.get(type_id).to_dict()
|
||||
ci_type_dict["ctr_id"] = relation_inst.id
|
||||
show_key = AttributeCache.get(ci_type_dict.get('show_id') or ci_type_dict['unique_id'])
|
||||
ci_type_dict["show_key"] = show_key and show_key.name
|
||||
ci_type_dict["attributes"] = CITypeAttributeManager.get_attributes_by_type_id(ci_type_dict["id"])
|
||||
attr_filter = CIFilterPermsCRUD.get_attr_filter(type_id)
|
||||
if attr_filter:
|
||||
@@ -1556,10 +1551,7 @@ class CITypeTemplateManager(object):
|
||||
if existed is None:
|
||||
_group['type_id'] = type_id_map.get(_group['type_id'], _group['type_id'])
|
||||
|
||||
try:
|
||||
existed = CITypeAttributeGroup.create(flush=True, **_group)
|
||||
except:
|
||||
continue
|
||||
existed = CITypeAttributeGroup.create(flush=True, **_group)
|
||||
|
||||
for order, attr in enumerate(group['attributes'] or []):
|
||||
item_existed = CITypeAttributeGroupItem.get_by(group_id=existed.id,
|
||||
|
@@ -123,11 +123,6 @@ class BuiltinModelEnum(BaseEnum):
|
||||
IPAM_ADDRESS = "ipam_address"
|
||||
IPAM_SCOPE = "ipam_scope"
|
||||
|
||||
DCIM_REGION = "dcim_region"
|
||||
DCIM_IDC = "dcim_idc"
|
||||
DCIM_SERVER_ROOM = "dcim_server_room"
|
||||
DCIM_RACK = "dcim_rack"
|
||||
|
||||
|
||||
BUILTIN_ATTRIBUTES = {
|
||||
"_updated_at": _l("Update Time"),
|
||||
|
@@ -1 +0,0 @@
|
||||
# -*- coding:utf-8 -*-
|
@@ -1,33 +0,0 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from api.lib.cmdb.ci import CIManager
|
||||
from api.lib.cmdb.ci import CIRelationManager
|
||||
from api.lib.cmdb.const import ExistPolicy
|
||||
|
||||
|
||||
class DCIMBase(object):
|
||||
def __init__(self):
|
||||
self.type_id = None
|
||||
|
||||
@staticmethod
|
||||
def add_relation(parent_id, child_id):
|
||||
if not parent_id or not child_id:
|
||||
return
|
||||
|
||||
CIRelationManager().add(parent_id, child_id, valid=False, apply_async=False)
|
||||
|
||||
def add(self, parent_id, **kwargs):
|
||||
ci_id = CIManager().add(self.type_id, exist_policy=ExistPolicy.REJECT, **kwargs)
|
||||
|
||||
if parent_id:
|
||||
self.add_relation(parent_id, ci_id)
|
||||
|
||||
return ci_id
|
||||
|
||||
@classmethod
|
||||
def update(cls, _id, **kwargs):
|
||||
CIManager().update(_id, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def delete(cls, _id):
|
||||
CIManager().delete(_id)
|
@@ -1,17 +0,0 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
|
||||
from api.lib.utils import BaseEnum
|
||||
|
||||
|
||||
class RackBuiltinAttributes(BaseEnum):
|
||||
U_COUNT = 'u_count'
|
||||
U_START = 'u_start'
|
||||
FREE_U_COUNT = 'free_u_count'
|
||||
U_SLOT_ABNORMAL = 'u_slot_abnormal'
|
||||
|
||||
|
||||
class OperateTypeEnum(BaseEnum):
|
||||
ADD_DEVICE = "0"
|
||||
REMOVE_DEVICE = "1"
|
||||
MOVE_DEVICE = "2"
|
@@ -1,40 +0,0 @@
|
||||
from flask_login import current_user
|
||||
|
||||
from api.lib.cmdb.cache import AttributeCache
|
||||
from api.lib.cmdb.cache import CITypeCache
|
||||
from api.lib.cmdb.ci import CIManager
|
||||
from api.lib.mixin import DBMixin
|
||||
from api.models.cmdb import DCIMOperationHistory
|
||||
|
||||
|
||||
class OperateHistoryManager(DBMixin):
|
||||
cls = DCIMOperationHistory
|
||||
|
||||
@classmethod
|
||||
def search(cls, page, page_size, fl=None, only_query=False, reverse=False, count_query=False,
|
||||
last_size=None, **kwargs):
|
||||
numfound, result = super(OperateHistoryManager, cls).search(page, page_size, fl, only_query, reverse,
|
||||
count_query, last_size, **kwargs)
|
||||
|
||||
ci_ids = [i['ci_id'] for i in result]
|
||||
id2ci = {i['_id']: i for i in (CIManager.get_cis_by_ids(ci_ids) or []) if i}
|
||||
type2show_key = dict()
|
||||
for i in id2ci.values():
|
||||
if i.get('_type') not in type2show_key:
|
||||
ci_type = CITypeCache.get(i.get('_type'))
|
||||
if ci_type:
|
||||
show_key = AttributeCache.get(ci_type.show_id or ci_type.unique_id)
|
||||
type2show_key[i['_type']] = show_key and show_key.name
|
||||
|
||||
return numfound, result, id2ci, type2show_key
|
||||
|
||||
def _can_add(self, **kwargs):
|
||||
kwargs['uid'] = current_user.uid
|
||||
|
||||
return kwargs
|
||||
|
||||
def _can_update(self, **kwargs):
|
||||
pass
|
||||
|
||||
def _can_delete(self, **kwargs):
|
||||
pass
|
@@ -1,19 +0,0 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
|
||||
from flask import abort
|
||||
|
||||
from api.lib.cmdb.cache import CITypeCache
|
||||
from api.lib.cmdb.const import BuiltinModelEnum
|
||||
from api.lib.cmdb.dcim.base import DCIMBase
|
||||
from api.lib.cmdb.resp_format import ErrFormat
|
||||
|
||||
|
||||
class IDCManager(DCIMBase):
|
||||
def __init__(self):
|
||||
super(IDCManager, self).__init__()
|
||||
|
||||
self.ci_type = CITypeCache.get(BuiltinModelEnum.DCIM_IDC) or abort(
|
||||
404, ErrFormat.dcim_builtin_model_not_found.format(BuiltinModelEnum.DCIM_IDC))
|
||||
|
||||
self.type_id = self.ci_type.id
|
@@ -1,182 +0,0 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import itertools
|
||||
import redis_lock
|
||||
from flask import abort
|
||||
|
||||
from api.extensions import rd
|
||||
from api.lib.cmdb.cache import CITypeCache
|
||||
from api.lib.cmdb.ci import CIManager
|
||||
from api.lib.cmdb.ci import CIRelationManager
|
||||
from api.lib.cmdb.const import BuiltinModelEnum
|
||||
from api.lib.cmdb.dcim.base import DCIMBase
|
||||
from api.lib.cmdb.dcim.const import OperateTypeEnum
|
||||
from api.lib.cmdb.dcim.const import RackBuiltinAttributes
|
||||
from api.lib.cmdb.dcim.history import OperateHistoryManager
|
||||
from api.lib.cmdb.resp_format import ErrFormat
|
||||
from api.lib.cmdb.search.ci.db.search import Search as SearchFromDB
|
||||
from api.lib.cmdb.search.ci_relation.search import Search as RelationSearch
|
||||
|
||||
|
||||
class RackManager(DCIMBase):
|
||||
def __init__(self):
|
||||
super(RackManager, self).__init__()
|
||||
|
||||
self.ci_type = CITypeCache.get(BuiltinModelEnum.DCIM_RACK) or abort(
|
||||
404, ErrFormat.dcim_builtin_model_not_found.format(BuiltinModelEnum.DCIM_RACK))
|
||||
|
||||
self.type_id = self.ci_type.id
|
||||
|
||||
@classmethod
|
||||
def update(cls, _id, **kwargs):
|
||||
if RackBuiltinAttributes.U_COUNT in kwargs:
|
||||
devices, _, _, _, _, _ = RelationSearch(
|
||||
[_id],
|
||||
level=[1],
|
||||
fl=[RackBuiltinAttributes.U_COUNT, RackBuiltinAttributes.U_START],
|
||||
count=1000000).search()
|
||||
for device in devices:
|
||||
u_start = device.get(RackBuiltinAttributes.U_START)
|
||||
u_count = device.get(RackBuiltinAttributes.U_COUNT) or 2
|
||||
if u_start and u_start + u_count - 1 > kwargs[RackBuiltinAttributes.U_COUNT]:
|
||||
return abort(400, ErrFormat.dcim_rack_u_count_invalid)
|
||||
|
||||
CIManager().update(_id, _sync=True, **kwargs)
|
||||
|
||||
if RackBuiltinAttributes.U_COUNT in kwargs:
|
||||
payload = {RackBuiltinAttributes.FREE_U_COUNT: cls.calc_u_free_count(_id)}
|
||||
|
||||
CIManager().update(_id, _sync=True, **payload)
|
||||
|
||||
def delete(self, _id):
|
||||
super(RackManager, self).delete(_id)
|
||||
|
||||
payload = {RackBuiltinAttributes.U_START: None}
|
||||
_, _, second_cis = CIRelationManager.get_second_cis(_id, per_page='all')
|
||||
for ci in second_cis:
|
||||
CIManager().update(ci['_id'], **payload)
|
||||
|
||||
@staticmethod
|
||||
def calc_u_free_count(rack_id, device_id=None, u_start=None, u_count=None):
|
||||
rack = CIManager.get_ci_by_id(rack_id, need_children=False)
|
||||
if not rack.get(RackBuiltinAttributes.U_COUNT):
|
||||
return 0
|
||||
|
||||
if device_id is not None and u_count is None:
|
||||
ci = CIManager().get_ci_by_id(device_id, need_children=False)
|
||||
u_count = ci.get(RackBuiltinAttributes.U_COUNT) or 2
|
||||
|
||||
if u_start and u_start + u_count - 1 > rack.get(RackBuiltinAttributes.U_COUNT):
|
||||
return abort(400, ErrFormat.dcim_rack_u_slot_invalid)
|
||||
|
||||
devices, _, _, _, _, _ = RelationSearch(
|
||||
[rack_id],
|
||||
level=[1],
|
||||
fl=[RackBuiltinAttributes.U_COUNT, RackBuiltinAttributes.U_START],
|
||||
count=1000000).search()
|
||||
|
||||
u_count_sum = 0
|
||||
for device in devices:
|
||||
u_count_sum += (device.get(RackBuiltinAttributes.U_COUNT) or 2)
|
||||
if device_id is not None:
|
||||
_u_start = device.get(RackBuiltinAttributes.U_START)
|
||||
_u_count = device.get(RackBuiltinAttributes.U_COUNT) or 2
|
||||
if not _u_start:
|
||||
continue
|
||||
|
||||
if device.get('_id') != device_id and set(range(u_start, u_start + u_count)) & set(
|
||||
range(_u_start, _u_start + _u_count)):
|
||||
return abort(400, ErrFormat.dcim_rack_u_slot_invalid)
|
||||
|
||||
return rack[RackBuiltinAttributes.U_COUNT] - u_count_sum
|
||||
|
||||
def check_u_slot(self):
|
||||
racks, _, _, _, _, _ = SearchFromDB(
|
||||
"_type:{}".format(self.type_id),
|
||||
count=10000000,
|
||||
fl=[RackBuiltinAttributes.U_START, RackBuiltinAttributes.U_COUNT, RackBuiltinAttributes.U_SLOT_ABNORMAL],
|
||||
parent_node_perm_passed=True).search()
|
||||
|
||||
for rack in racks:
|
||||
devices, _, _, _, _, _ = RelationSearch(
|
||||
[rack['_id']],
|
||||
level=[1],
|
||||
fl=[RackBuiltinAttributes.U_COUNT, RackBuiltinAttributes.U_START],
|
||||
count=1000000).search()
|
||||
|
||||
u_slot_sets = []
|
||||
for device in devices:
|
||||
u_start = device.get(RackBuiltinAttributes.U_START)
|
||||
u_count = device.get(RackBuiltinAttributes.U_COUNT) or 2
|
||||
if u_start is not None and str(u_start).isdigit():
|
||||
u_slot_sets.append(set(range(u_start, u_start + u_count)))
|
||||
|
||||
if len(u_slot_sets) > 1:
|
||||
u_slot_abnormal = False
|
||||
for a, b in itertools.combinations(u_slot_sets, 2):
|
||||
if a.intersection(b):
|
||||
u_slot_abnormal = True
|
||||
break
|
||||
if u_slot_abnormal != rack.get(RackBuiltinAttributes.U_SLOT_ABNORMAL):
|
||||
payload = {RackBuiltinAttributes.U_SLOT_ABNORMAL: u_slot_abnormal}
|
||||
CIManager().update(rack['_id'], **payload)
|
||||
|
||||
def add_device(self, rack_id, device_id, u_start, u_count=None):
|
||||
with (redis_lock.Lock(rd.r, "DCIM_RACK_OPERATE_{}".format(rack_id), expire=10)):
|
||||
self.calc_u_free_count(rack_id, device_id, u_start, u_count)
|
||||
|
||||
self.add_relation(rack_id, device_id)
|
||||
|
||||
payload = {RackBuiltinAttributes.U_START: u_start}
|
||||
if u_count:
|
||||
payload[RackBuiltinAttributes.U_COUNT] = u_count
|
||||
CIManager().update(device_id, _sync=True, **payload)
|
||||
|
||||
payload = {
|
||||
RackBuiltinAttributes.FREE_U_COUNT: self.calc_u_free_count(rack_id, device_id, u_start, u_count)}
|
||||
CIManager().update(rack_id, _sync=True, **payload)
|
||||
|
||||
OperateHistoryManager().add(operate_type=OperateTypeEnum.ADD_DEVICE, rack_id=rack_id, ci_id=device_id)
|
||||
|
||||
def remove_device(self, rack_id, device_id):
|
||||
with (redis_lock.Lock(rd.r, "DCIM_RACK_OPERATE_{}".format(rack_id), expire=10)):
|
||||
CIRelationManager.delete_3(rack_id, device_id, apply_async=False, valid=False)
|
||||
|
||||
payload = {RackBuiltinAttributes.FREE_U_COUNT: self.calc_u_free_count(rack_id)}
|
||||
CIManager().update(rack_id, _sync=True, **payload)
|
||||
|
||||
payload = {RackBuiltinAttributes.U_START: None}
|
||||
CIManager().update(device_id, _sync=True, **payload)
|
||||
|
||||
OperateHistoryManager().add(operate_type=OperateTypeEnum.REMOVE_DEVICE, rack_id=rack_id, ci_id=device_id)
|
||||
|
||||
def move_device(self, rack_id, device_id, to_u_start):
|
||||
with (redis_lock.Lock(rd.r, "DCIM_RACK_OPERATE_{}".format(rack_id), expire=10)):
|
||||
payload = {RackBuiltinAttributes.FREE_U_COUNT: self.calc_u_free_count(rack_id, device_id, to_u_start)}
|
||||
CIManager().update(rack_id, _sync=True, **payload)
|
||||
|
||||
CIManager().update(device_id, _sync=True, **{RackBuiltinAttributes.U_START: to_u_start})
|
||||
|
||||
OperateHistoryManager().add(operate_type=OperateTypeEnum.MOVE_DEVICE, rack_id=rack_id, ci_id=device_id)
|
||||
|
||||
def migrate_device(self, rack_id, device_id, to_rack_id, to_u_start):
|
||||
with (redis_lock.Lock(rd.r, "DCIM_RACK_OPERATE_{}".format(rack_id), expire=10)):
|
||||
self.calc_u_free_count(to_rack_id, device_id, to_u_start)
|
||||
|
||||
if rack_id != to_rack_id:
|
||||
CIRelationManager.delete_3(rack_id, device_id, apply_async=False, valid=False)
|
||||
|
||||
self.add_relation(to_rack_id, device_id)
|
||||
|
||||
payload = {
|
||||
RackBuiltinAttributes.FREE_U_COUNT: self.calc_u_free_count(to_rack_id, device_id, to_u_start)}
|
||||
CIManager().update(to_rack_id, _sync=True, **payload)
|
||||
|
||||
CIManager().update(device_id, _sync=True, **{RackBuiltinAttributes.U_START: to_u_start})
|
||||
|
||||
if rack_id != to_rack_id:
|
||||
payload = {RackBuiltinAttributes.FREE_U_COUNT: self.calc_u_free_count(rack_id)}
|
||||
CIManager().update(rack_id, _sync=True, **payload)
|
||||
|
||||
OperateHistoryManager().add(operate_type=OperateTypeEnum.REMOVE_DEVICE, rack_id=rack_id, ci_id=device_id)
|
||||
OperateHistoryManager().add(operate_type=OperateTypeEnum.ADD_DEVICE, rack_id=to_rack_id, ci_id=device_id)
|
@@ -1,29 +0,0 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
|
||||
from flask import abort
|
||||
|
||||
from api.lib.cmdb.cache import CITypeCache
|
||||
from api.lib.cmdb.ci import CIManager
|
||||
from api.lib.cmdb.const import BuiltinModelEnum
|
||||
from api.lib.cmdb.const import ExistPolicy
|
||||
from api.lib.cmdb.resp_format import ErrFormat
|
||||
|
||||
|
||||
class RegionManager(object):
|
||||
def __init__(self):
|
||||
self.ci_type = CITypeCache.get(BuiltinModelEnum.DCIM_REGION) or abort(
|
||||
404, ErrFormat.dcim_builtin_model_not_found.format(BuiltinModelEnum.DCIM_REGION))
|
||||
|
||||
self.type_id = self.ci_type.id
|
||||
|
||||
def add(self, **kwargs):
|
||||
return CIManager().add(self.type_id, exist_policy=ExistPolicy.REJECT, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def update(cls, _id, **kwargs):
|
||||
CIManager().update(_id, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def delete(cls, _id):
|
||||
CIManager().delete(_id)
|
@@ -1,56 +0,0 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
|
||||
from flask import abort
|
||||
|
||||
from api.lib.cmdb.cache import CITypeCache
|
||||
from api.lib.cmdb.const import BuiltinModelEnum
|
||||
from api.lib.cmdb.dcim.base import DCIMBase
|
||||
from api.lib.cmdb.dcim.const import RackBuiltinAttributes
|
||||
from api.lib.cmdb.resp_format import ErrFormat
|
||||
from api.lib.cmdb.search.ci.db.search import Search as SearchFromDB
|
||||
from api.models.cmdb import CI
|
||||
from api.models.cmdb import CIRelation
|
||||
|
||||
|
||||
class ServerRoomManager(DCIMBase):
|
||||
def __init__(self):
|
||||
super(ServerRoomManager, self).__init__()
|
||||
|
||||
self.ci_type = CITypeCache.get(BuiltinModelEnum.DCIM_SERVER_ROOM) or abort(
|
||||
404, ErrFormat.dcim_builtin_model_not_found.format(BuiltinModelEnum.DCIM_SERVER_ROOM))
|
||||
self.type_id = self.ci_type.id
|
||||
|
||||
@staticmethod
|
||||
def get_racks(_id, q=None):
|
||||
rack_type = CITypeCache.get(BuiltinModelEnum.DCIM_RACK) or abort(
|
||||
404, ErrFormat.dcim_builtin_model_not_found.format(BuiltinModelEnum.DCIM_RACK))
|
||||
|
||||
relations = CIRelation.get_by(first_ci_id=_id, only_query=True).join(
|
||||
CI, CI.id == CIRelation.second_ci_id).filter(CI.type_id == rack_type.id)
|
||||
rack_ids = [i.second_ci_id for i in relations]
|
||||
|
||||
q = "_type:{}".format(rack_type.id) if not q else "_type:{},{}".format(rack_type.id, q)
|
||||
if rack_ids:
|
||||
response, _, _, _, numfound, _ = SearchFromDB(
|
||||
q,
|
||||
ci_ids=list(rack_ids),
|
||||
count=1000000,
|
||||
parent_node_perm_passed=True).search()
|
||||
else:
|
||||
response, numfound = [], 0
|
||||
|
||||
counter = dict(rack_count=numfound)
|
||||
u_count = 0
|
||||
free_u_count = 0
|
||||
for i in response:
|
||||
_u_count = i.get(RackBuiltinAttributes.U_COUNT) or 0
|
||||
u_count += _u_count
|
||||
free_u_count += (_u_count if i.get(RackBuiltinAttributes.FREE_U_COUNT) is None else
|
||||
i.get(RackBuiltinAttributes.FREE_U_COUNT))
|
||||
counter["u_count"] = u_count
|
||||
counter["u_used_count"] = u_count - free_u_count
|
||||
counter["device_count"] = CIRelation.get_by(only_query=True).filter(
|
||||
CIRelation.first_ci_id.in_(rack_ids)).count()
|
||||
|
||||
return counter, response
|
@@ -1,85 +0,0 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
from flask import abort
|
||||
|
||||
from api.lib.cmdb.cache import AttributeCache
|
||||
from api.lib.cmdb.cache import CITypeCache
|
||||
from api.lib.cmdb.const import BuiltinModelEnum
|
||||
from api.lib.cmdb.resp_format import ErrFormat
|
||||
from api.lib.cmdb.search.ci.db.search import Search as SearchFromDB
|
||||
from api.models.cmdb import CI
|
||||
from api.models.cmdb import CIRelation
|
||||
|
||||
|
||||
class TreeViewManager(object):
|
||||
@classmethod
|
||||
def get(cls):
|
||||
region_type = CITypeCache.get(BuiltinModelEnum.DCIM_REGION) or abort(
|
||||
404, ErrFormat.dcim_builtin_model_not_found.format(BuiltinModelEnum.DCIM_REGION))
|
||||
|
||||
idc_type = CITypeCache.get(BuiltinModelEnum.DCIM_IDC) or abort(
|
||||
404, ErrFormat.dcim_builtin_model_not_found.format(BuiltinModelEnum.DCIM_IDC))
|
||||
|
||||
server_room_type = CITypeCache.get(BuiltinModelEnum.DCIM_SERVER_ROOM) or abort(
|
||||
404, ErrFormat.dcim_builtin_model_not_found.format(BuiltinModelEnum.DCIM_SERVER_ROOM))
|
||||
|
||||
rack_type = CITypeCache.get(BuiltinModelEnum.DCIM_RACK) or abort(
|
||||
404, ErrFormat.dcim_builtin_model_not_found.format(BuiltinModelEnum.DCIM_RACK))
|
||||
|
||||
relations = defaultdict(set)
|
||||
ids = set()
|
||||
has_parent_ids = set()
|
||||
|
||||
for i in CIRelation.get_by(only_query=True).join(CI, CI.id == CIRelation.first_ci_id).filter(
|
||||
CI.type_id.in_([region_type.id, idc_type.id])):
|
||||
relations[i.first_ci_id].add(i.second_ci_id)
|
||||
ids.add(i.first_ci_id)
|
||||
ids.add(i.second_ci_id)
|
||||
has_parent_ids.add(i.second_ci_id)
|
||||
|
||||
for i in CIRelation.get_by(only_query=True).join(
|
||||
CI, CI.id == CIRelation.second_ci_id).filter(CI.type_id.in_([idc_type.id, server_room_type.id])):
|
||||
relations[i.first_ci_id].add(i.second_ci_id)
|
||||
ids.add(i.first_ci_id)
|
||||
ids.add(i.second_ci_id)
|
||||
has_parent_ids.add(i.second_ci_id)
|
||||
|
||||
for i in CI.get_by(only_query=True).filter(CI.type_id.in_([region_type.id, idc_type.id])):
|
||||
ids.add(i.id)
|
||||
|
||||
for _id in ids:
|
||||
if _id not in has_parent_ids:
|
||||
relations[None].add(_id)
|
||||
|
||||
type2name = dict()
|
||||
type2name[region_type.id] = AttributeCache.get(region_type.show_id or region_type.unique_id).name
|
||||
type2name[idc_type.id] = AttributeCache.get(idc_type.show_id or idc_type.unique_id).name
|
||||
type2name[server_room_type.id] = AttributeCache.get(server_room_type.show_id or server_room_type.unique_id).name
|
||||
|
||||
response, _, _, _, _, _ = SearchFromDB(
|
||||
"_type:({})".format(";".join(map(str, [region_type.id, idc_type.id, server_room_type.id]))),
|
||||
ci_ids=list(ids),
|
||||
count=1000000,
|
||||
fl=list(type2name.values()),
|
||||
parent_node_perm_passed=True).search()
|
||||
id2ci = {i['_id']: i for i in response}
|
||||
|
||||
def _build_tree(_tree, parent_id=None):
|
||||
tree = []
|
||||
for child_id in _tree.get(parent_id, []):
|
||||
children = sorted(_build_tree(_tree, child_id), key=lambda x: x['_id'])
|
||||
if not id2ci.get(child_id):
|
||||
continue
|
||||
ci = id2ci[child_id]
|
||||
if ci['ci_type'] == BuiltinModelEnum.DCIM_SERVER_ROOM:
|
||||
ci['rack_count'] = CIRelation.get_by(first_ci_id=child_id, only_query=True).join(
|
||||
CI, CI.id == CIRelation.second_ci_id).filter(CI.type_id == rack_type.id).count()
|
||||
|
||||
tree.append({'children': children, **ci})
|
||||
return tree
|
||||
|
||||
result = sorted(_build_tree(relations), key=lambda x: x['_id'])
|
||||
|
||||
return result, type2name
|
@@ -3,6 +3,7 @@
|
||||
import redis_lock
|
||||
from flask import abort
|
||||
|
||||
from api.extensions import db
|
||||
from api.extensions import rd
|
||||
from api.lib.cmdb.cache import CITypeCache
|
||||
from api.lib.cmdb.ci import CIManager
|
||||
@@ -20,8 +21,9 @@ from api.lib.cmdb.search.ci_relation.search import Search as RelationSearch
|
||||
|
||||
class IpAddressManager(object):
|
||||
def __init__(self):
|
||||
self.ci_type = CITypeCache.get(BuiltinModelEnum.IPAM_ADDRESS) or abort(
|
||||
404, ErrFormat.ipam_address_model_not_found.format(BuiltinModelEnum.IPAM_ADDRESS))
|
||||
self.ci_type = CITypeCache.get(BuiltinModelEnum.IPAM_ADDRESS)
|
||||
not self.ci_type and abort(400, ErrFormat.ipam_address_model_not_found.format(
|
||||
BuiltinModelEnum.IPAM_ADDRESS))
|
||||
|
||||
self.type_id = self.ci_type.id
|
||||
|
||||
@@ -31,11 +33,10 @@ class IpAddressManager(object):
|
||||
|
||||
return numfound, result
|
||||
|
||||
def _get_cis(self, subnet_id, ips):
|
||||
|
||||
q = "_type:{},{}:({})".format(self.type_id, IPAddressBuiltinAttributes.IP, ";".join(ips or []))
|
||||
|
||||
response, _, _, _, _, _ = RelationSearch([subnet_id], level=[1], query=q, count=1000000).search()
|
||||
def _get_cis(self, ips):
|
||||
response, _, _, _, _, _ = SearchFromDB(
|
||||
"_type:{},{}:({})".format(self.type_id, IPAddressBuiltinAttributes.IP, ";".join(ips or [])),
|
||||
count=10000000, parent_node_perm_passed=True).search()
|
||||
|
||||
return response
|
||||
|
||||
@@ -47,28 +48,25 @@ class IpAddressManager(object):
|
||||
CIRelationManager().add(parent_id, child_id, valid=False, apply_async=False)
|
||||
|
||||
@staticmethod
|
||||
def calc_used_count(subnet_id):
|
||||
def calc_free_count(subnet_id):
|
||||
db.session.commit()
|
||||
q = "{}:(0;2),-{}:true".format(IPAddressBuiltinAttributes.ASSIGN_STATUS, IPAddressBuiltinAttributes.IS_USED)
|
||||
|
||||
return len(set(RelationSearch([subnet_id], level=[1], query=q, count=1000000).search(only_ids=True) or []))
|
||||
return len(set(RelationSearch([subnet_id], level=[1], query=q).search(only_ids=True) or []))
|
||||
|
||||
@staticmethod
|
||||
def _calc_assign_count(subnet_id):
|
||||
q = "{}:(0;2)".format(IPAddressBuiltinAttributes.ASSIGN_STATUS)
|
||||
|
||||
return len(set(RelationSearch([subnet_id], level=[1], query=q, count=1000000).search(only_ids=True) or []))
|
||||
|
||||
def _update_subnet_count(self, subnet_id, assign_count_computed, used_count=None):
|
||||
def _update_subnet_count(self, subnet_id, assign_count, used_count=None):
|
||||
payload = {}
|
||||
|
||||
cur = CIManager.get_ci_by_id(subnet_id, need_children=False)
|
||||
if assign_count_computed:
|
||||
payload[SubnetBuiltinAttributes.ASSIGN_COUNT] = self._calc_assign_count(subnet_id)
|
||||
if assign_count is not None:
|
||||
payload[SubnetBuiltinAttributes.ASSIGN_COUNT] = (cur.get(
|
||||
SubnetBuiltinAttributes.ASSIGN_COUNT) or 0) + assign_count
|
||||
|
||||
if used_count is not None:
|
||||
payload[SubnetBuiltinAttributes.USED_COUNT] = used_count
|
||||
|
||||
payload[SubnetBuiltinAttributes.FREE_COUNT] = (cur[SubnetBuiltinAttributes.HOSTS_COUNT] -
|
||||
self.calc_used_count(subnet_id))
|
||||
self.calc_free_count(subnet_id))
|
||||
CIManager().update(subnet_id, **payload)
|
||||
|
||||
def assign_ips(self, ips, subnet_id, cidr, **kwargs):
|
||||
@@ -92,33 +90,40 @@ class IpAddressManager(object):
|
||||
else:
|
||||
return abort(400, ErrFormat.ipam_address_model_not_found)
|
||||
|
||||
with (redis_lock.Lock(rd.r, "IPAM_ASSIGN_ADDRESS_{}".format(subnet_id), expire=10)):
|
||||
cis = self._get_cis(subnet_id, ips)
|
||||
with (redis_lock.Lock(rd.r, "IPAM_ASSIGN_ADDRESS_{}".format(subnet_id))):
|
||||
cis = self._get_cis(ips)
|
||||
ip2ci = {ci[IPAddressBuiltinAttributes.IP]: ci for ci in cis}
|
||||
|
||||
ci_ids = []
|
||||
status_change_num = 0
|
||||
for ip in ips:
|
||||
kwargs['name'] = ip
|
||||
kwargs[IPAddressBuiltinAttributes.IP] = ip
|
||||
if ip not in ip2ci:
|
||||
ci_id = CIManager.add(self.type_id, _sync=True, **kwargs)
|
||||
status_change_num += 1
|
||||
else:
|
||||
ci_id = ip2ci[ip]['_id']
|
||||
CIManager().update(ci_id, _sync=True, **kwargs)
|
||||
if IPAddressBuiltinAttributes.ASSIGN_STATUS in kwargs and (
|
||||
(kwargs[IPAddressBuiltinAttributes.ASSIGN_STATUS] or 2) !=
|
||||
(ip2ci[ip].get(IPAddressBuiltinAttributes.ASSIGN_STATUS) or 2)):
|
||||
status_change_num += 1
|
||||
ci_ids.append(ci_id)
|
||||
|
||||
self._add_relation(subnet_id, ci_id)
|
||||
|
||||
if ips and IPAddressBuiltinAttributes.ASSIGN_STATUS in kwargs:
|
||||
self._update_subnet_count(subnet_id, True)
|
||||
self._update_subnet_count(subnet_id, -status_change_num if kwargs.get(
|
||||
IPAddressBuiltinAttributes.ASSIGN_STATUS) == IPAddressAssignStatus.UNASSIGNED else status_change_num)
|
||||
|
||||
if ips and IPAddressBuiltinAttributes.IS_USED in kwargs:
|
||||
q = "{}:true".format(IPAddressBuiltinAttributes.IS_USED)
|
||||
cur_used_ids = RelationSearch([subnet_id], level=[1], query=q).search(only_ids=True)
|
||||
for _id in set(cur_used_ids) - set(ci_ids):
|
||||
CIManager().update(_id, **{IPAddressBuiltinAttributes.IS_USED: False})
|
||||
CIManager().update(_id, _sync=True, **{IPAddressBuiltinAttributes.IS_USED: False})
|
||||
|
||||
self._update_subnet_count(subnet_id, False, used_count=len(ips))
|
||||
self._update_subnet_count(subnet_id, None, used_count=len(ips))
|
||||
|
||||
if kwargs.get(IPAddressBuiltinAttributes.ASSIGN_STATUS) in (
|
||||
IPAddressAssignStatus.ASSIGNED, IPAddressAssignStatus.RESERVED):
|
||||
|
@@ -50,10 +50,6 @@ class ScanHistoryManager(DBMixin):
|
||||
if scan_rule is not None:
|
||||
scan_rule.update(last_scan_time=kwargs.get('start_at'))
|
||||
|
||||
for i in self.cls.get_by(subnet_scan_id=kwargs.get('subnet_scan_id'), only_query=True).order_by(
|
||||
self.cls.id.desc()).offset(100):
|
||||
i.delete()
|
||||
|
||||
def _can_update(self, **kwargs):
|
||||
pass
|
||||
|
||||
|
@@ -18,13 +18,15 @@ from api.models.cmdb import IPAMSubnetScan
|
||||
|
||||
class Stats(object):
|
||||
def __init__(self):
|
||||
self.address_type = CITypeCache.get(BuiltinModelEnum.IPAM_ADDRESS) or abort(
|
||||
404, ErrFormat.ipam_address_model_not_found.format(BuiltinModelEnum.IPAM_ADDRESS))
|
||||
self.address_type = CITypeCache.get(BuiltinModelEnum.IPAM_ADDRESS)
|
||||
not self.address_type and abort(400, ErrFormat.ipam_address_model_not_found.format(
|
||||
BuiltinModelEnum.IPAM_ADDRESS))
|
||||
|
||||
self.address_type_id = self.address_type.id
|
||||
|
||||
self.subnet_type = CITypeCache.get(BuiltinModelEnum.IPAM_SUBNET) or abort(
|
||||
404, ErrFormat.ipam_address_model_not_found.format(BuiltinModelEnum.IPAM_ADDRESS))
|
||||
self.subnet_type = CITypeCache.get(BuiltinModelEnum.IPAM_SUBNET)
|
||||
not self.subnet_type and abort(400, ErrFormat.ipam_address_model_not_found.format(
|
||||
BuiltinModelEnum.IPAM_ADDRESS))
|
||||
|
||||
self.subnet_type_id = self.subnet_type.id
|
||||
|
||||
@@ -38,10 +40,8 @@ class Stats(object):
|
||||
return list(set(ci_ids) - set(has_children_ci_ids))
|
||||
|
||||
else:
|
||||
_type = CIManager().get_by_id(parent_id)
|
||||
if not _type:
|
||||
return abort(404, ErrFormat.ipam_subnet_not_found)
|
||||
key = [(str(parent_id), _type.type_id)]
|
||||
type_id = CIManager().get_by_id(parent_id).type_id
|
||||
key = [(str(parent_id), type_id)]
|
||||
result = []
|
||||
while True:
|
||||
res = [json.loads(x).items() for x in [i or '{}' for i in rd.get(
|
||||
|
@@ -2,7 +2,6 @@
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
import datetime
|
||||
import ipaddress
|
||||
from flask import abort
|
||||
|
||||
@@ -10,7 +9,7 @@ from api.lib.cmdb.cache import AttributeCache
|
||||
from api.lib.cmdb.cache import CITypeCache
|
||||
from api.lib.cmdb.ci import CIManager
|
||||
from api.lib.cmdb.ci import CIRelationManager
|
||||
from api.lib.cmdb.const import BuiltinModelEnum
|
||||
from api.lib.cmdb.const import BuiltinModelEnum, BUILTIN_ATTRIBUTES
|
||||
from api.lib.cmdb.ipam.const import OperateTypeEnum
|
||||
from api.lib.cmdb.ipam.const import SubnetBuiltinAttributes
|
||||
from api.lib.cmdb.ipam.history import OperateHistoryManager
|
||||
@@ -23,8 +22,9 @@ from api.models.cmdb import IPAMSubnetScan
|
||||
|
||||
class SubnetManager(object):
|
||||
def __init__(self):
|
||||
self.ci_type = CITypeCache.get(BuiltinModelEnum.IPAM_SUBNET) or abort(
|
||||
404, ErrFormat.ipam_subnet_model_not_found.format(BuiltinModelEnum.IPAM_SUBNET))
|
||||
self.ci_type = CITypeCache.get(BuiltinModelEnum.IPAM_SUBNET)
|
||||
not self.ci_type and abort(400, ErrFormat.ipam_subnet_model_not_found.format(
|
||||
BuiltinModelEnum.IPAM_SUBNET))
|
||||
|
||||
self.type_id = self.ci_type.id
|
||||
|
||||
@@ -47,7 +47,7 @@ class SubnetManager(object):
|
||||
|
||||
new_last_update_at = ""
|
||||
for i in result:
|
||||
__last_update_at = max([i['rule_updated_at'] or "", i['created_at'] or ""])
|
||||
__last_update_at = max([i['updated_at'] or "", i['created_at'] or ""])
|
||||
if new_last_update_at < __last_update_at:
|
||||
new_last_update_at = __last_update_at
|
||||
|
||||
@@ -131,11 +131,7 @@ class SubnetManager(object):
|
||||
@staticmethod
|
||||
def _is_valid_cidr(cidr):
|
||||
try:
|
||||
cidr = ipaddress.ip_network(cidr)
|
||||
if not (8 <= cidr.prefixlen <= 31):
|
||||
raise ValueError
|
||||
|
||||
return str(cidr)
|
||||
return str(ipaddress.ip_network(cidr))
|
||||
except ValueError:
|
||||
return abort(400, ErrFormat.ipam_cidr_invalid_notation.format(cidr))
|
||||
|
||||
@@ -147,7 +143,6 @@ class SubnetManager(object):
|
||||
root_nodes = set(all_nodes) - set(none_root_nodes) - set(_id and [_id] or [])
|
||||
response, _, _, _, _, _ = SearchFromDB("_type:{}".format(self.type_id),
|
||||
ci_ids=list(root_nodes),
|
||||
count=1000000,
|
||||
parent_node_perm_passed=True).search()
|
||||
|
||||
cur_subnet = ipaddress.ip_network(cidr)
|
||||
@@ -168,7 +163,6 @@ class SubnetManager(object):
|
||||
|
||||
response, _, _, _, _, _ = SearchFromDB("_type:{}".format(self.type_id),
|
||||
ci_ids=list(child_nodes),
|
||||
count=1000000,
|
||||
parent_node_perm_passed=True).search()
|
||||
|
||||
cur_subnet = ipaddress.ip_network(cidr)
|
||||
@@ -205,7 +199,7 @@ class SubnetManager(object):
|
||||
return cidr
|
||||
|
||||
def _add_subnet(self, cidr, **kwargs):
|
||||
kwargs[SubnetBuiltinAttributes.HOSTS_COUNT] = len(list(ipaddress.ip_network(cidr).hosts()))
|
||||
kwargs[SubnetBuiltinAttributes.HOSTS_COUNT] = ipaddress.ip_network(cidr).num_addresses - 2
|
||||
kwargs[SubnetBuiltinAttributes.USED_COUNT] = 0
|
||||
kwargs[SubnetBuiltinAttributes.ASSIGN_COUNT] = 0
|
||||
kwargs[SubnetBuiltinAttributes.FREE_COUNT] = kwargs[SubnetBuiltinAttributes.HOSTS_COUNT]
|
||||
@@ -246,8 +240,7 @@ class SubnetManager(object):
|
||||
def _update_scan_rule(ci_id, agent_id, cron, scan_enabled=True):
|
||||
existed = IPAMSubnetScan.get_by(ci_id=ci_id, first=True, to_dict=False)
|
||||
if existed is not None:
|
||||
existed.update(ci_id=ci_id, agent_id=agent_id, cron=cron, scan_enabled=scan_enabled,
|
||||
rule_updated_at=datetime.datetime.now())
|
||||
existed.update(ci_id=ci_id, agent_id=agent_id, cron=cron, scan_enabled=scan_enabled)
|
||||
else:
|
||||
IPAMSubnetScan.create(ci_id=ci_id, agent_id=agent_id, cron=cron, scan_enabled=scan_enabled)
|
||||
|
||||
@@ -280,9 +273,7 @@ class SubnetManager(object):
|
||||
existed = IPAMSubnetScan.get_by(ci_id=_id, first=True, to_dict=False)
|
||||
existed and existed.delete()
|
||||
|
||||
delete_ci_ids = []
|
||||
for i in CIRelation.get_by(first_ci_id=_id, to_dict=False):
|
||||
delete_ci_ids.append(i.second_ci_id)
|
||||
i.delete()
|
||||
|
||||
cur = CIManager.get_ci_by_id(_id, need_children=False)
|
||||
@@ -293,8 +284,6 @@ class SubnetManager(object):
|
||||
cidr=cur.get(SubnetBuiltinAttributes.CIDR),
|
||||
description=cur.get(SubnetBuiltinAttributes.CIDR))
|
||||
|
||||
# batch_delete_ci.apply_async(args=(delete_ci_ids,))
|
||||
|
||||
return _id
|
||||
|
||||
|
||||
|
@@ -163,7 +163,7 @@ class CIFilterPermsCRUD(DBMixin):
|
||||
|
||||
def add(self, **kwargs):
|
||||
kwargs = self._can_add(**kwargs) or kwargs
|
||||
with redis_lock.Lock(rd.r, 'CMDB_FILTER_{}_{}'.format(kwargs['type_id'], kwargs['rid']), expire=10):
|
||||
with redis_lock.Lock(rd.r, 'CMDB_FILTER_{}_{}'.format(kwargs['type_id'], kwargs['rid'])):
|
||||
request_id_filter = {}
|
||||
if kwargs.get('id_filter'):
|
||||
obj = self.cls.get_by(type_id=kwargs.get('type_id'),
|
||||
@@ -232,7 +232,7 @@ class CIFilterPermsCRUD(DBMixin):
|
||||
pass
|
||||
|
||||
def delete(self, **kwargs):
|
||||
with redis_lock.Lock(rd.r, 'CMDB_FILTER_{}_{}'.format(kwargs['type_id'], kwargs['rid']), expire=10):
|
||||
with redis_lock.Lock(rd.r, 'CMDB_FILTER_{}_{}'.format(kwargs['type_id'], kwargs['rid'])):
|
||||
obj = self.cls.get_by(type_id=kwargs.get('type_id'),
|
||||
rid=kwargs.get('rid'),
|
||||
id_filter=None,
|
||||
@@ -249,7 +249,7 @@ class CIFilterPermsCRUD(DBMixin):
|
||||
|
||||
def delete2(self, **kwargs):
|
||||
|
||||
with redis_lock.Lock(rd.r, 'CMDB_FILTER_{}_{}'.format(kwargs['type_id'], kwargs['rid']), expire=10):
|
||||
with redis_lock.Lock(rd.r, 'CMDB_FILTER_{}_{}'.format(kwargs['type_id'], kwargs['rid'])):
|
||||
obj = self.cls.get_by(type_id=kwargs.get('type_id'),
|
||||
rid=kwargs.get('rid'),
|
||||
ci_filter=None,
|
||||
|
@@ -169,8 +169,3 @@ class ErrFormat(CommonErrFormat):
|
||||
ipam_subnet_cannot_delete = _l("Cannot delete because child nodes exist")
|
||||
ipam_subnet_not_found = _l("Subnet is not found")
|
||||
ipam_scope_cannot_delete = _l("Cannot delete because child nodes exist")
|
||||
|
||||
# # DCIM
|
||||
dcim_builtin_model_not_found = _l("The dcim model {} does not exist")
|
||||
dcim_rack_u_slot_invalid = _l("Irregularities in Rack Units")
|
||||
dcim_rack_u_count_invalid = _l("The device's position is greater than the rack unit height")
|
||||
|
@@ -64,7 +64,7 @@ class Search(object):
|
||||
|
||||
self.ancestor_ids = ancestor_ids
|
||||
self.descendant_ids = descendant_ids
|
||||
self.root_parent_path = root_parent_path or []
|
||||
self.root_parent_path = root_parent_path
|
||||
self.has_m2m = has_m2m or False
|
||||
if not self.has_m2m:
|
||||
if self.ancestor_ids:
|
||||
|
@@ -54,7 +54,6 @@ class CMDBApp(BaseApp):
|
||||
"create_topology_view"],
|
||||
},
|
||||
{"page": "IPAM", "page_cn": "IPAM", "perms": ["read"]},
|
||||
{"page": "DCIM", "page_cn": "数据中心", "perms": ["read"]},
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
|
@@ -138,14 +138,14 @@ class HasResourceRoleCache(object):
|
||||
|
||||
@classmethod
|
||||
def add(cls, rid, app_id):
|
||||
with redis_lock.Lock(rd.r, 'HasResourceRoleCache', expire=10):
|
||||
with redis_lock.Lock(rd.r, 'HasResourceRoleCache'):
|
||||
c = cls.get(app_id)
|
||||
c[rid] = 1
|
||||
cache.set(cls.PREFIX_KEY.format(app_id), c, timeout=0)
|
||||
|
||||
@classmethod
|
||||
def remove(cls, rid, app_id):
|
||||
with redis_lock.Lock(rd.r, 'HasResourceRoleCache', expire=10):
|
||||
with redis_lock.Lock(rd.r, 'HasResourceRoleCache'):
|
||||
c = cls.get(app_id)
|
||||
c.pop(rid, None)
|
||||
cache.set(cls.PREFIX_KEY.format(app_id), c, timeout=0)
|
||||
|
@@ -145,7 +145,7 @@ class RoleRelationCRUD(object):
|
||||
|
||||
@classmethod
|
||||
def add(cls, role, parent_id, child_ids, app_id):
|
||||
with redis_lock.Lock(rd.r, "ROLE_RELATION_ADD", expire=10):
|
||||
with redis_lock.Lock(rd.r, "ROLE_RELATION_ADD"):
|
||||
db.session.commit()
|
||||
|
||||
result = []
|
||||
|
@@ -105,8 +105,8 @@ class User(CRUDModel, SoftDeleteMixin):
|
||||
_password = db.Column("password", db.String(80))
|
||||
key = db.Column(db.String(32), nullable=False)
|
||||
secret = db.Column(db.String(32), nullable=False)
|
||||
date_joined = db.Column(db.DateTime, default=datetime.now)
|
||||
last_login = db.Column(db.DateTime, default=datetime.now)
|
||||
date_joined = db.Column(db.DateTime, default=datetime.utcnow)
|
||||
last_login = db.Column(db.DateTime, default=datetime.utcnow)
|
||||
block = db.Column(db.Boolean, default=False)
|
||||
has_logined = db.Column(db.Boolean, default=False)
|
||||
wx_id = db.Column(db.String(32))
|
||||
|
@@ -676,7 +676,6 @@ class IPAMSubnetScan(Model):
|
||||
|
||||
ci_id = db.Column(db.Integer, index=True, nullable=False)
|
||||
scan_enabled = db.Column(db.Boolean, default=True)
|
||||
rule_updated_at = db.Column(db.DateTime)
|
||||
last_scan_time = db.Column(db.DateTime)
|
||||
|
||||
# scan rules
|
||||
@@ -707,14 +706,3 @@ class IPAMOperationHistory(Model2):
|
||||
cidr = db.Column(db.String(18), index=True)
|
||||
operate_type = db.Column(db.Enum(*OperateTypeEnum.all()))
|
||||
description = db.Column(db.Text)
|
||||
|
||||
|
||||
class DCIMOperationHistory(Model2):
|
||||
__tablename__ = "c_dcim_operation_histories"
|
||||
|
||||
from api.lib.cmdb.dcim.const import OperateTypeEnum
|
||||
|
||||
uid = db.Column(db.Integer, index=True)
|
||||
rack_id = db.Column(db.Integer, index=True)
|
||||
ci_id = db.Column(db.Integer, index=True)
|
||||
operate_type = db.Column(db.Enum(*OperateTypeEnum.all()))
|
||||
|
@@ -32,7 +32,7 @@ from api.models.acl import Trigger
|
||||
def role_rebuild(rids, app_id):
|
||||
rids = rids if isinstance(rids, list) else [rids]
|
||||
for rid in rids:
|
||||
with redis_lock.Lock(rd.r, "ROLE_REBUILD_{}_{}".format(rid, app_id), expire=10):
|
||||
with redis_lock.Lock(rd.r, "ROLE_REBUILD_{}_{}".format(rid, app_id)):
|
||||
RoleRelationCache.rebuild(rid, app_id)
|
||||
|
||||
current_app.logger.info("Role {0} App {1} rebuild..........".format(rids, app_id))
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
|
||||
import datetime
|
||||
@@ -145,7 +145,7 @@ def ci_delete_trigger(trigger, operate_type, ci_dict):
|
||||
@flush_db
|
||||
@reconnect_db
|
||||
def ci_relation_cache(parent_id, child_id, ancestor_ids):
|
||||
with redis_lock.Lock(rd.r, "CIRelation_{}".format(parent_id), expire=10):
|
||||
with redis_lock.Lock(rd.r, "CIRelation_{}".format(parent_id)):
|
||||
children = rd.get([parent_id], REDIS_PREFIX_CI_RELATION)[0]
|
||||
children = json.loads(children) if children is not None else {}
|
||||
|
||||
@@ -223,7 +223,7 @@ def ci_relation_add(parent_dict, child_id, uid):
|
||||
@celery.task(name="cmdb.ci_relation_delete", queue=CMDB_QUEUE)
|
||||
@reconnect_db
|
||||
def ci_relation_delete(parent_id, child_id, ancestor_ids):
|
||||
with redis_lock.Lock(rd.r, "CIRelation_{}".format(parent_id), expire=10):
|
||||
with redis_lock.Lock(rd.r, "CIRelation_{}".format(parent_id)):
|
||||
children = rd.get([parent_id], REDIS_PREFIX_CI_RELATION)[0]
|
||||
children = json.loads(children) if children is not None else {}
|
||||
|
||||
@@ -374,25 +374,3 @@ def build_relations_for_ad_accept(adc, ci_id, ad_key2attr):
|
||||
source=RelationSourceEnum.AUTO_DISCOVERY)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
@celery.task(name="cmdb.dcim_calc_u_free_count", queue=CMDB_QUEUE)
|
||||
@reconnect_db
|
||||
def dcim_calc_u_free_count():
|
||||
from api.lib.cmdb.ci import CIManager
|
||||
from api.lib.cmdb.dcim.rack import RackManager
|
||||
from api.lib.cmdb.dcim.const import RackBuiltinAttributes
|
||||
|
||||
if not has_request_context():
|
||||
current_app.test_request_context().push()
|
||||
login_user(UserCache.get('worker'))
|
||||
|
||||
try:
|
||||
rack_m = RackManager()
|
||||
except Exception:
|
||||
return
|
||||
|
||||
racks = CI.get_by(type_id=rack_m.type_id, to_dict=False)
|
||||
for rack in racks:
|
||||
payload = {RackBuiltinAttributes.FREE_U_COUNT: rack_m.calc_u_free_count(rack.id)}
|
||||
CIManager().update(rack.id, **payload)
|
||||
|
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2024-11-26 18:54+0800\n"
|
||||
"POT-Creation-Date: 2024-11-11 17:40+0800\n"
|
||||
"PO-Revision-Date: 2023-12-25 20:21+0800\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: zh\n"
|
||||
@@ -92,11 +92,11 @@ msgstr "您没有操作权限!"
|
||||
msgid "Only the creator or administrator has permission!"
|
||||
msgstr "只有创建人或者管理员才有权限!"
|
||||
|
||||
#: api/lib/cmdb/const.py:133
|
||||
#: api/lib/cmdb/const.py:128
|
||||
msgid "Update Time"
|
||||
msgstr "更新时间"
|
||||
|
||||
#: api/lib/cmdb/const.py:134
|
||||
#: api/lib/cmdb/const.py:129
|
||||
msgid "Updated By"
|
||||
msgstr "更新人"
|
||||
|
||||
@@ -544,18 +544,6 @@ msgstr "因为子节点已经存在,不能删除"
|
||||
msgid "Subnet is not found"
|
||||
msgstr "子网不存在"
|
||||
|
||||
#: api/lib/cmdb/resp_format.py:174
|
||||
msgid "The dcim model {} does not exist"
|
||||
msgstr "DCIM模型 {} 不存在!"
|
||||
|
||||
#: api/lib/cmdb/resp_format.py:175
|
||||
msgid "Irregularities in Rack Units"
|
||||
msgstr "机架U位异常!"
|
||||
|
||||
#: api/lib/cmdb/resp_format.py:176
|
||||
msgid "The device's position is greater than the rack unit height"
|
||||
msgstr "有设备的位置大于机柜的U数!"
|
||||
|
||||
#: api/lib/common_setting/resp_format.py:8
|
||||
msgid "Company info already existed"
|
||||
msgstr "公司信息已存在,无法创建!"
|
||||
|
@@ -2,14 +2,14 @@
|
||||
|
||||
|
||||
import json
|
||||
from io import BytesIO
|
||||
|
||||
from flask import abort
|
||||
from flask import current_app
|
||||
from flask import request
|
||||
from io import BytesIO
|
||||
|
||||
from api.lib.cmdb.cache import AttributeCache
|
||||
from api.lib.cmdb.cache import CITypeCache
|
||||
from api.lib.cmdb.ci import CITriggerManager
|
||||
from api.lib.cmdb.ci_type import CITypeAttributeGroupManager
|
||||
from api.lib.cmdb.ci_type import CITypeAttributeManager
|
||||
from api.lib.cmdb.ci_type import CITypeGroupManager
|
||||
@@ -497,16 +497,6 @@ class CITypeTriggerView(APIView):
|
||||
return self.jsonify(code=200)
|
||||
|
||||
|
||||
class CITypeTriggerTestView(APIView):
|
||||
url_prefix = ("/ci_types/<int:type_id>/triggers/<int:_id>/test_notify",)
|
||||
|
||||
@has_perm_from_args("type_id", ResourceTypeEnum.CI, PermEnum.CONFIG, CITypeManager.get_name_by_id)
|
||||
def post(self, type_id, _id):
|
||||
CITriggerManager().trigger_notify_test(type_id, _id)
|
||||
|
||||
return self.jsonify(code=200)
|
||||
|
||||
|
||||
class CITypeGrantView(APIView):
|
||||
url_prefix = "/ci_types/<int:type_id>/roles/<int:rid>/grant"
|
||||
|
||||
|
@@ -1 +0,0 @@
|
||||
# -*- coding:utf-8 -*-
|
@@ -1,30 +0,0 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from flask import request
|
||||
|
||||
from api.lib.cmdb.dcim.history import OperateHistoryManager
|
||||
from api.lib.common_setting.decorator import perms_role_required
|
||||
from api.lib.common_setting.role_perm_base import CMDBApp
|
||||
from api.lib.utils import get_page
|
||||
from api.lib.utils import get_page_size
|
||||
from api.lib.utils import handle_arg_list
|
||||
from api.resource import APIView
|
||||
|
||||
app_cli = CMDBApp()
|
||||
|
||||
|
||||
class DCIMOperateHistoryView(APIView):
|
||||
url_prefix = ("/dcim/history/operate",)
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
def get(self):
|
||||
page = get_page(request.values.pop("page", 1))
|
||||
page_size = get_page_size(request.values.pop("page_size", None))
|
||||
operate_type = handle_arg_list(request.values.pop('operate_type', []))
|
||||
if operate_type:
|
||||
request.values["operate_type"] = operate_type
|
||||
|
||||
numfound, result, id2ci, type2show_key = OperateHistoryManager.search(page, page_size, **request.values)
|
||||
|
||||
return self.jsonify(numfound=numfound, result=result, id2ci=id2ci, type2show_key=type2show_key)
|
@@ -1,35 +0,0 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from flask import request
|
||||
|
||||
from api.lib.cmdb.dcim.idc import IDCManager
|
||||
from api.lib.common_setting.decorator import perms_role_required
|
||||
from api.lib.common_setting.role_perm_base import CMDBApp
|
||||
from api.resource import APIView
|
||||
|
||||
app_cli = CMDBApp()
|
||||
|
||||
|
||||
class IDCView(APIView):
|
||||
url_prefix = ("/dcim/idc", "/dcim/idc/<int:_id>")
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
def post(self):
|
||||
parent_id = request.values.pop("parent_id")
|
||||
|
||||
return self.jsonify(ci_id=IDCManager().add(parent_id, **request.values))
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
def put(self, _id):
|
||||
IDCManager().update(_id, **request.values)
|
||||
|
||||
return self.jsonify(ci_id=_id)
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
def delete(self, _id):
|
||||
IDCManager().delete(_id)
|
||||
|
||||
return self.jsonify(ci_id=_id)
|
@@ -1,102 +0,0 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from flask import request
|
||||
|
||||
from api.lib.cmdb.const import CMDB_QUEUE
|
||||
from api.lib.cmdb.dcim.const import RackBuiltinAttributes
|
||||
from api.lib.cmdb.dcim.rack import RackManager
|
||||
from api.lib.common_setting.decorator import perms_role_required
|
||||
from api.lib.common_setting.role_perm_base import CMDBApp
|
||||
from api.lib.decorator import args_required
|
||||
from api.resource import APIView
|
||||
from api.tasks.cmdb import dcim_calc_u_free_count
|
||||
|
||||
app_cli = CMDBApp()
|
||||
|
||||
|
||||
class RackView(APIView):
|
||||
url_prefix = ("/dcim/rack", "/dcim/rack/<int:_id>")
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
@args_required("parent_id")
|
||||
def post(self):
|
||||
parent_id = request.values.pop("parent_id")
|
||||
|
||||
return self.jsonify(ci_id=RackManager().add(parent_id, **request.values))
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
def put(self, _id):
|
||||
RackManager().update(_id, **request.values)
|
||||
|
||||
return self.jsonify(ci_id=_id)
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
def delete(self, _id):
|
||||
RackManager().delete(_id)
|
||||
|
||||
return self.jsonify(ci_id=_id)
|
||||
|
||||
|
||||
class RackDetailView(APIView):
|
||||
url_prefix = ("/dcim/rack/<int:rack_id>/device/<int:device_id>",)
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
@args_required(RackBuiltinAttributes.U_START)
|
||||
def post(self, rack_id, device_id):
|
||||
u_start = request.values.pop(RackBuiltinAttributes.U_START)
|
||||
u_count = request.values.get(RackBuiltinAttributes.U_COUNT)
|
||||
|
||||
RackManager().add_device(rack_id, device_id, u_start, u_count)
|
||||
|
||||
return self.jsonify(rack_id=rack_id, device_id=device_id)
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
@args_required("to_u_start")
|
||||
def put(self, rack_id, device_id):
|
||||
to_u_start = request.values.pop("to_u_start")
|
||||
|
||||
RackManager().move_device(rack_id, device_id, to_u_start)
|
||||
|
||||
return self.jsonify(rack_id=rack_id, device_id=device_id, to_u_start=to_u_start)
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
def delete(self, rack_id, device_id):
|
||||
RackManager().remove_device(rack_id, device_id)
|
||||
|
||||
return self.jsonify(code=200)
|
||||
|
||||
|
||||
class RackDeviceMigrateView(APIView):
|
||||
url_prefix = ("/dcim/rack/<int:rack_id>/device/<int:device_id>/migrate",)
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
@args_required("to_rack_id")
|
||||
@args_required("to_u_start")
|
||||
def put(self, rack_id, device_id):
|
||||
to_rack_id = request.values.pop("to_rack_id")
|
||||
to_u_start = request.values.pop("to_u_start")
|
||||
|
||||
RackManager().migrate_device(rack_id, device_id, to_rack_id, to_u_start)
|
||||
|
||||
return self.jsonify(rack_id=rack_id,
|
||||
device_id=device_id,
|
||||
to_u_start=to_u_start,
|
||||
to_rack_id=to_rack_id)
|
||||
|
||||
|
||||
class RackCalcUFreeCountView(APIView):
|
||||
url_prefix = ("/dcim/rack/calc_u_free_count",)
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
def post(self):
|
||||
dcim_calc_u_free_count.apply_async(queue=CMDB_QUEUE)
|
||||
|
||||
return self.jsonify(code=200)
|
@@ -1,33 +0,0 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from flask import request
|
||||
|
||||
from api.lib.cmdb.dcim.region import RegionManager
|
||||
from api.lib.common_setting.decorator import perms_role_required
|
||||
from api.lib.common_setting.role_perm_base import CMDBApp
|
||||
from api.resource import APIView
|
||||
|
||||
app_cli = CMDBApp()
|
||||
|
||||
|
||||
class RegionView(APIView):
|
||||
url_prefix = ("/dcim/region", "/dcim/region/<int:_id>")
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
def post(self):
|
||||
return self.jsonify(ci_id=RegionManager().add(**request.values))
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
def put(self, _id):
|
||||
RegionManager().update(_id, **request.values)
|
||||
|
||||
return self.jsonify(ci_id=_id)
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
def delete(self, _id):
|
||||
RegionManager().delete(_id)
|
||||
|
||||
return self.jsonify(ci_id=_id)
|
@@ -1,43 +0,0 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from flask import request
|
||||
|
||||
from api.lib.cmdb.dcim.server_room import ServerRoomManager
|
||||
from api.lib.common_setting.decorator import perms_role_required
|
||||
from api.lib.common_setting.role_perm_base import CMDBApp
|
||||
from api.lib.decorator import args_required
|
||||
from api.resource import APIView
|
||||
|
||||
app_cli = CMDBApp()
|
||||
|
||||
|
||||
class ServerRoomView(APIView):
|
||||
url_prefix = ("/dcim/server_room", "/dcim/server_room/<int:_id>", "/dcim/server_room/<int:_id>/racks")
|
||||
|
||||
def get(self, _id):
|
||||
q = request.values.get('q')
|
||||
counter, result = ServerRoomManager.get_racks(_id, q)
|
||||
|
||||
return self.jsonify(counter=counter, result=result)
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
@args_required("parent_id")
|
||||
def post(self):
|
||||
parent_id = request.values.pop("parent_id")
|
||||
|
||||
return self.jsonify(ci_id=ServerRoomManager().add(parent_id, **request.values))
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
def put(self, _id):
|
||||
ServerRoomManager().update(_id, **request.values)
|
||||
|
||||
return self.jsonify(ci_id=_id)
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
def delete(self, _id):
|
||||
ServerRoomManager().delete(_id)
|
||||
|
||||
return self.jsonify(ci_id=_id)
|
@@ -1,19 +0,0 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from api.lib.cmdb.dcim.tree_view import TreeViewManager
|
||||
from api.lib.common_setting.decorator import perms_role_required
|
||||
from api.lib.common_setting.role_perm_base import CMDBApp
|
||||
from api.resource import APIView
|
||||
|
||||
app_cli = CMDBApp()
|
||||
|
||||
|
||||
class DCIMTreeView(APIView):
|
||||
url_prefix = "/dcim/tree_view"
|
||||
|
||||
@perms_role_required(app_cli.app_name, app_cli.resource_type_name, app_cli.op.DCIM,
|
||||
app_cli.op.read, app_cli.admin_name)
|
||||
def get(self):
|
||||
result, type2name = TreeViewManager.get()
|
||||
|
||||
return self.jsonify(result=result, type2name=type2name)
|
@@ -54,66 +54,6 @@
|
||||
<div class="content unicode" style="display: block;">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">veops-rear</div>
|
||||
<div class="code-name">&#xea02;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">veops-front</div>
|
||||
<div class="code-name">&#xea03;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">veops-xianggang</div>
|
||||
<div class="code-name">&#xea01;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">veops-device (2)</div>
|
||||
<div class="code-name">&#xea00;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">veops-room (1)</div>
|
||||
<div class="code-name">&#xe9ff;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">veops-IDC</div>
|
||||
<div class="code-name">&#xe9fe;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">veops-region</div>
|
||||
<div class="code-name">&#xe9fd;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">veops-device</div>
|
||||
<div class="code-name">&#xe9fb;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">veops-cabinet</div>
|
||||
<div class="code-name">&#xe9fc;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">veops-data_center</div>
|
||||
<div class="code-name">&#xe9f9;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">ops-setting-holiday_management-copy</div>
|
||||
@@ -6162,9 +6102,9 @@
|
||||
<pre><code class="language-css"
|
||||
>@font-face {
|
||||
font-family: 'iconfont';
|
||||
src: url('iconfont.woff2?t=1732673294759') format('woff2'),
|
||||
url('iconfont.woff?t=1732673294759') format('woff'),
|
||||
url('iconfont.ttf?t=1732673294759') format('truetype');
|
||||
src: url('iconfont.woff2?t=1731312848138') format('woff2'),
|
||||
url('iconfont.woff?t=1731312848138') format('woff'),
|
||||
url('iconfont.ttf?t=1731312848138') format('truetype');
|
||||
}
|
||||
</code></pre>
|
||||
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
||||
@@ -6190,96 +6130,6 @@
|
||||
<div class="content font-class">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont veops-rear"></span>
|
||||
<div class="name">
|
||||
veops-rear
|
||||
</div>
|
||||
<div class="code-name">.veops-rear
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont veops-front"></span>
|
||||
<div class="name">
|
||||
veops-front
|
||||
</div>
|
||||
<div class="code-name">.veops-front
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont veops-xianggang"></span>
|
||||
<div class="name">
|
||||
veops-xianggang
|
||||
</div>
|
||||
<div class="code-name">.veops-xianggang
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont a-veops-device2"></span>
|
||||
<div class="name">
|
||||
veops-device (2)
|
||||
</div>
|
||||
<div class="code-name">.a-veops-device2
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont a-veops-room1"></span>
|
||||
<div class="name">
|
||||
veops-room (1)
|
||||
</div>
|
||||
<div class="code-name">.a-veops-room1
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont veops-IDC"></span>
|
||||
<div class="name">
|
||||
veops-IDC
|
||||
</div>
|
||||
<div class="code-name">.veops-IDC
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont veops-region"></span>
|
||||
<div class="name">
|
||||
veops-region
|
||||
</div>
|
||||
<div class="code-name">.veops-region
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont veops-device"></span>
|
||||
<div class="name">
|
||||
veops-device
|
||||
</div>
|
||||
<div class="code-name">.veops-device
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont veops-cabinet"></span>
|
||||
<div class="name">
|
||||
veops-cabinet
|
||||
</div>
|
||||
<div class="code-name">.veops-cabinet
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont veops-data_center"></span>
|
||||
<div class="name">
|
||||
veops-data_center
|
||||
</div>
|
||||
<div class="code-name">.veops-data_center
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont ops-setting-holidays"></span>
|
||||
<div class="name">
|
||||
@@ -15352,86 +15202,6 @@
|
||||
<div class="content symbol">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#veops-rear"></use>
|
||||
</svg>
|
||||
<div class="name">veops-rear</div>
|
||||
<div class="code-name">#veops-rear</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#veops-front"></use>
|
||||
</svg>
|
||||
<div class="name">veops-front</div>
|
||||
<div class="code-name">#veops-front</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#veops-xianggang"></use>
|
||||
</svg>
|
||||
<div class="name">veops-xianggang</div>
|
||||
<div class="code-name">#veops-xianggang</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#a-veops-device2"></use>
|
||||
</svg>
|
||||
<div class="name">veops-device (2)</div>
|
||||
<div class="code-name">#a-veops-device2</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#a-veops-room1"></use>
|
||||
</svg>
|
||||
<div class="name">veops-room (1)</div>
|
||||
<div class="code-name">#a-veops-room1</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#veops-IDC"></use>
|
||||
</svg>
|
||||
<div class="name">veops-IDC</div>
|
||||
<div class="code-name">#veops-IDC</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#veops-region"></use>
|
||||
</svg>
|
||||
<div class="name">veops-region</div>
|
||||
<div class="code-name">#veops-region</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#veops-device"></use>
|
||||
</svg>
|
||||
<div class="name">veops-device</div>
|
||||
<div class="code-name">#veops-device</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#veops-cabinet"></use>
|
||||
</svg>
|
||||
<div class="name">veops-cabinet</div>
|
||||
<div class="code-name">#veops-cabinet</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#veops-data_center"></use>
|
||||
</svg>
|
||||
<div class="name">veops-data_center</div>
|
||||
<div class="code-name">#veops-data_center</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#ops-setting-holidays"></use>
|
||||
|
@@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 3857903 */
|
||||
src: url('iconfont.woff2?t=1732673294759') format('woff2'),
|
||||
url('iconfont.woff?t=1732673294759') format('woff'),
|
||||
url('iconfont.ttf?t=1732673294759') format('truetype');
|
||||
src: url('iconfont.woff2?t=1731312848138') format('woff2'),
|
||||
url('iconfont.woff?t=1731312848138') format('woff'),
|
||||
url('iconfont.ttf?t=1731312848138') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@@ -13,46 +13,6 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.veops-rear:before {
|
||||
content: "\ea02";
|
||||
}
|
||||
|
||||
.veops-front:before {
|
||||
content: "\ea03";
|
||||
}
|
||||
|
||||
.veops-xianggang:before {
|
||||
content: "\ea01";
|
||||
}
|
||||
|
||||
.a-veops-device2:before {
|
||||
content: "\ea00";
|
||||
}
|
||||
|
||||
.a-veops-room1:before {
|
||||
content: "\e9ff";
|
||||
}
|
||||
|
||||
.veops-IDC:before {
|
||||
content: "\e9fe";
|
||||
}
|
||||
|
||||
.veops-region:before {
|
||||
content: "\e9fd";
|
||||
}
|
||||
|
||||
.veops-device:before {
|
||||
content: "\e9fb";
|
||||
}
|
||||
|
||||
.veops-cabinet:before {
|
||||
content: "\e9fc";
|
||||
}
|
||||
|
||||
.veops-data_center:before {
|
||||
content: "\e9f9";
|
||||
}
|
||||
|
||||
.ops-setting-holidays:before {
|
||||
content: "\e9fa";
|
||||
}
|
||||
|
@@ -5,76 +5,6 @@
|
||||
"css_prefix_text": "",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "42510712",
|
||||
"name": "veops-rear",
|
||||
"font_class": "veops-rear",
|
||||
"unicode": "ea02",
|
||||
"unicode_decimal": 59906
|
||||
},
|
||||
{
|
||||
"icon_id": "42510708",
|
||||
"name": "veops-front",
|
||||
"font_class": "veops-front",
|
||||
"unicode": "ea03",
|
||||
"unicode_decimal": 59907
|
||||
},
|
||||
{
|
||||
"icon_id": "42497603",
|
||||
"name": "veops-xianggang",
|
||||
"font_class": "veops-xianggang",
|
||||
"unicode": "ea01",
|
||||
"unicode_decimal": 59905
|
||||
},
|
||||
{
|
||||
"icon_id": "42485038",
|
||||
"name": "veops-device (2)",
|
||||
"font_class": "a-veops-device2",
|
||||
"unicode": "ea00",
|
||||
"unicode_decimal": 59904
|
||||
},
|
||||
{
|
||||
"icon_id": "42455620",
|
||||
"name": "veops-room (1)",
|
||||
"font_class": "a-veops-room1",
|
||||
"unicode": "e9ff",
|
||||
"unicode_decimal": 59903
|
||||
},
|
||||
{
|
||||
"icon_id": "42455607",
|
||||
"name": "veops-IDC",
|
||||
"font_class": "veops-IDC",
|
||||
"unicode": "e9fe",
|
||||
"unicode_decimal": 59902
|
||||
},
|
||||
{
|
||||
"icon_id": "42455609",
|
||||
"name": "veops-region",
|
||||
"font_class": "veops-region",
|
||||
"unicode": "e9fd",
|
||||
"unicode_decimal": 59901
|
||||
},
|
||||
{
|
||||
"icon_id": "42448953",
|
||||
"name": "veops-device",
|
||||
"font_class": "veops-device",
|
||||
"unicode": "e9fb",
|
||||
"unicode_decimal": 59899
|
||||
},
|
||||
{
|
||||
"icon_id": "42448948",
|
||||
"name": "veops-cabinet",
|
||||
"font_class": "veops-cabinet",
|
||||
"unicode": "e9fc",
|
||||
"unicode_decimal": 59900
|
||||
},
|
||||
{
|
||||
"icon_id": "42433324",
|
||||
"name": "veops-data_center",
|
||||
"font_class": "veops-data_center",
|
||||
"unicode": "e9f9",
|
||||
"unicode_decimal": 59897
|
||||
},
|
||||
{
|
||||
"icon_id": "42337844",
|
||||
"name": "ops-setting-holiday_management-copy",
|
||||
|
@@ -139,9 +139,9 @@
|
||||
:normalizer="
|
||||
(node) => {
|
||||
return {
|
||||
id: node.id,
|
||||
label: node.label,
|
||||
children: node.children,
|
||||
id: String(node[0] || ''),
|
||||
label: node[1] ? node[1].label || node[0] : node[0],
|
||||
children: node.children && node.children.length ? node.children : undefined,
|
||||
}
|
||||
}
|
||||
"
|
||||
@@ -352,12 +352,8 @@ export default {
|
||||
},
|
||||
getChoiceValueByProperty(property) {
|
||||
const _find = this.canSearchPreferenceAttrList.find((item) => item.name === property)
|
||||
if (_find?.choice_value?.length) {
|
||||
return _find.choice_value.map((node) => ({
|
||||
id: String(node?.[0] ?? ''),
|
||||
label: node?.[1]?.label || node?.[0] || '',
|
||||
children: node?.children?.length ? node.children : undefined
|
||||
}))
|
||||
if (_find) {
|
||||
return _find.choice_value
|
||||
}
|
||||
return []
|
||||
},
|
||||
|
@@ -11,19 +11,10 @@
|
||||
|
||||
.ant-input {
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
background-color: #F7F8FA;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
border-radius: 30px;
|
||||
|
||||
&:focus {
|
||||
border: solid 1px #B1C9FF;
|
||||
}
|
||||
}
|
||||
|
||||
.cmdb-side-menu-search-focused {
|
||||
.ant-input {
|
||||
border: solid 1px #B1C9FF;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input-suffix {
|
||||
|
@@ -92,7 +92,7 @@ export default {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
this.$confirm({
|
||||
title: this.$t('warning'),
|
||||
title: this.$t('alert'),
|
||||
content: this.$t('cmdb.preference.confirmcancelSub2', { name: menu.meta.title }),
|
||||
onOk() {
|
||||
const citypeId = menu.meta.typeId
|
||||
@@ -313,7 +313,10 @@ export default {
|
||||
<Item class={styles['cmdb-side-menu-search']}>
|
||||
<a-input
|
||||
ref="cmdbSideMenuSearchInputRef"
|
||||
class={`ops-input ${this.$route.name === 'cmdb_resource_search' ? 'cmdb-side-menu-search-focused' : ''}`}
|
||||
class={styles['cmdb-side-menu-search-input']}
|
||||
style={{
|
||||
border: this.$route.name === 'cmdb_resource_search' ? 'solid 1px #B1C9FF' : ''
|
||||
}}
|
||||
placeholder={this.$t('cmdbSearch')}
|
||||
onPressEnter={(e) => {
|
||||
this.jumpCMDBSearch(e.target.value)
|
||||
|
@@ -1,121 +1,121 @@
|
||||
<template>
|
||||
<vxe-table v-bind="$attrs" v-on="new$listeners" ref="xTable">
|
||||
<slot></slot>
|
||||
<template #empty>
|
||||
<slot name="empty">
|
||||
<div :style="{ paddingTop: '10px' }">
|
||||
<img :style="{ width: '140px', height: '120px' }" :src="require('@/assets/data_empty.png')" />
|
||||
<div>{{ $t('noData') }}</div>
|
||||
</div>
|
||||
</slot>
|
||||
</template>
|
||||
<template #loading>
|
||||
<slot name="loading"></slot>
|
||||
</template>
|
||||
</vxe-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
// 该组件使用方法与vxe-table一致,但调用它的方法时,需先调用getVxetableRef()获取到vxe-table实体
|
||||
export default {
|
||||
name: 'OpsTable',
|
||||
data() {
|
||||
return {
|
||||
// isShifting: false,
|
||||
// lastIndex: -1,
|
||||
lastSelected: [],
|
||||
currentSelected: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
new$listeners() {
|
||||
if (!Object.keys(this.$listeners).length) {
|
||||
return this.$listeners
|
||||
}
|
||||
return Object.assign(this.$listeners, {
|
||||
// 在这里覆盖原有的change事件
|
||||
// 'checkbox-change': this.selectChangeEvent,
|
||||
'checkbox-range-change': this.checkboxRangeChange,
|
||||
'checkbox-range-start': this.checkboxRangeStart,
|
||||
'checkbox-range-end': this.checkboxRangeEnd,
|
||||
})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// window.onkeydown = (e) => {
|
||||
// if (e.key === 'Shift') {
|
||||
// this.isShifting = true
|
||||
// }
|
||||
// }
|
||||
// window.onkeyup = (e) => {
|
||||
// if (e.key === 'Shift') {
|
||||
// this.isShifting = false
|
||||
// this.lastIndex = -1
|
||||
// }
|
||||
// }
|
||||
},
|
||||
beforeDestroy() {
|
||||
// window.onkeydown = ''
|
||||
// window.onkeyup = ''
|
||||
},
|
||||
methods: {
|
||||
getVxetableRef() {
|
||||
return this.$refs.xTable
|
||||
},
|
||||
// selectChangeEvent(e) {
|
||||
// const xTable = this.$refs.xTable
|
||||
// const { lastIndex } = this
|
||||
// const currentIndex = e.rowIndex
|
||||
// const { tableData } = xTable.getTableData()
|
||||
// if (lastIndex > -1 && this.isShifting) {
|
||||
// let start = lastIndex
|
||||
// let end = currentIndex
|
||||
// if (lastIndex > currentIndex) {
|
||||
// start = currentIndex
|
||||
// end = lastIndex
|
||||
// }
|
||||
// const rangeData = tableData.slice(start, end + 1)
|
||||
// xTable.setCheckboxRow(rangeData, true)
|
||||
// }
|
||||
// this.lastIndex = currentIndex
|
||||
// this.$emit('checkbox-change', { ...e, records: xTable.getCheckboxRecords() })
|
||||
// },
|
||||
checkboxRangeStart(e) {
|
||||
const xTable = this.$refs.xTable
|
||||
const lastSelected = xTable.getCheckboxRecords()
|
||||
const selectedReserve = xTable.getCheckboxReserveRecords()
|
||||
this.lastSelected = [...lastSelected, ...selectedReserve]
|
||||
this.$emit('checkbox-range-start', e)
|
||||
},
|
||||
checkboxRangeChange(e) {
|
||||
const xTable = this.$refs.xTable
|
||||
xTable.setCheckboxRow(this.lastSelected, true)
|
||||
this.currentSelected = e.records
|
||||
// this.lastSelected = [...new Set([...this.lastSelected, ...e.records])]
|
||||
this.$emit('checkbox-range-change', {
|
||||
...e,
|
||||
records: [...xTable.getCheckboxRecords(), ...xTable.getCheckboxReserveRecords()],
|
||||
})
|
||||
},
|
||||
checkboxRangeEnd(e) {
|
||||
const xTable = this.$refs.xTable
|
||||
const isAllSelected = this.currentSelected.every((item) => {
|
||||
const _idx = this.lastSelected.findIndex((ele) => _.isEqual(ele, item))
|
||||
return _idx > -1
|
||||
})
|
||||
if (isAllSelected) {
|
||||
xTable.setCheckboxRow(this.currentSelected, false)
|
||||
}
|
||||
this.currentSelected = []
|
||||
this.lastSelected = []
|
||||
this.$emit('checkbox-range-end', {
|
||||
...e,
|
||||
records: [...xTable.getCheckboxRecords(), ...xTable.getCheckboxReserveRecords()],
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less"></style>
|
||||
<template>
|
||||
<vxe-table v-bind="$attrs" v-on="new$listeners" ref="xTable">
|
||||
<slot></slot>
|
||||
<template #empty>
|
||||
<slot name="empty">
|
||||
<div :style="{ paddingTop: '10px' }">
|
||||
<img :style="{ width: '140px', height: '90px' }" :src="require('@/assets/data_empty.png')" />
|
||||
<div>{{ $t('noData') }}</div>
|
||||
</div>
|
||||
</slot>
|
||||
</template>
|
||||
<template #loading>
|
||||
<slot name="loading"></slot>
|
||||
</template>
|
||||
</vxe-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
// 该组件使用方法与vxe-table一致,但调用它的方法时,需先调用getVxetableRef()获取到vxe-table实体
|
||||
export default {
|
||||
name: 'OpsTable',
|
||||
data() {
|
||||
return {
|
||||
// isShifting: false,
|
||||
// lastIndex: -1,
|
||||
lastSelected: [],
|
||||
currentSelected: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
new$listeners() {
|
||||
if (!Object.keys(this.$listeners).length) {
|
||||
return this.$listeners
|
||||
}
|
||||
return Object.assign(this.$listeners, {
|
||||
// 在这里覆盖原有的change事件
|
||||
// 'checkbox-change': this.selectChangeEvent,
|
||||
'checkbox-range-change': this.checkboxRangeChange,
|
||||
'checkbox-range-start': this.checkboxRangeStart,
|
||||
'checkbox-range-end': this.checkboxRangeEnd,
|
||||
})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// window.onkeydown = (e) => {
|
||||
// if (e.key === 'Shift') {
|
||||
// this.isShifting = true
|
||||
// }
|
||||
// }
|
||||
// window.onkeyup = (e) => {
|
||||
// if (e.key === 'Shift') {
|
||||
// this.isShifting = false
|
||||
// this.lastIndex = -1
|
||||
// }
|
||||
// }
|
||||
},
|
||||
beforeDestroy() {
|
||||
// window.onkeydown = ''
|
||||
// window.onkeyup = ''
|
||||
},
|
||||
methods: {
|
||||
getVxetableRef() {
|
||||
return this.$refs.xTable
|
||||
},
|
||||
// selectChangeEvent(e) {
|
||||
// const xTable = this.$refs.xTable
|
||||
// const { lastIndex } = this
|
||||
// const currentIndex = e.rowIndex
|
||||
// const { tableData } = xTable.getTableData()
|
||||
// if (lastIndex > -1 && this.isShifting) {
|
||||
// let start = lastIndex
|
||||
// let end = currentIndex
|
||||
// if (lastIndex > currentIndex) {
|
||||
// start = currentIndex
|
||||
// end = lastIndex
|
||||
// }
|
||||
// const rangeData = tableData.slice(start, end + 1)
|
||||
// xTable.setCheckboxRow(rangeData, true)
|
||||
// }
|
||||
// this.lastIndex = currentIndex
|
||||
// this.$emit('checkbox-change', { ...e, records: xTable.getCheckboxRecords() })
|
||||
// },
|
||||
checkboxRangeStart(e) {
|
||||
const xTable = this.$refs.xTable
|
||||
const lastSelected = xTable.getCheckboxRecords()
|
||||
const selectedReserve = xTable.getCheckboxReserveRecords()
|
||||
this.lastSelected = [...lastSelected, ...selectedReserve]
|
||||
this.$emit('checkbox-range-start', e)
|
||||
},
|
||||
checkboxRangeChange(e) {
|
||||
const xTable = this.$refs.xTable
|
||||
xTable.setCheckboxRow(this.lastSelected, true)
|
||||
this.currentSelected = e.records
|
||||
// this.lastSelected = [...new Set([...this.lastSelected, ...e.records])]
|
||||
this.$emit('checkbox-range-change', {
|
||||
...e,
|
||||
records: [...xTable.getCheckboxRecords(), ...xTable.getCheckboxReserveRecords()],
|
||||
})
|
||||
},
|
||||
checkboxRangeEnd(e) {
|
||||
const xTable = this.$refs.xTable
|
||||
const isAllSelected = this.currentSelected.every((item) => {
|
||||
const _idx = this.lastSelected.findIndex((ele) => _.isEqual(ele, item))
|
||||
return _idx > -1
|
||||
})
|
||||
if (isAllSelected) {
|
||||
xTable.setCheckboxRow(this.currentSelected, false)
|
||||
}
|
||||
this.currentSelected = []
|
||||
this.lastSelected = []
|
||||
this.$emit('checkbox-range-end', {
|
||||
...e,
|
||||
records: [...xTable.getCheckboxRecords(), ...xTable.getCheckboxReserveRecords()],
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less"></style>
|
||||
|
@@ -195,11 +195,11 @@ export default {
|
||||
background-color: #fff;
|
||||
height: calc(100vh - 64px);
|
||||
margin-bottom: -24px;
|
||||
padding: 20px;
|
||||
padding: 24px;
|
||||
.acl-resource-types-header {
|
||||
width: 100%;
|
||||
display: inline-flex;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 15px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
@@ -358,11 +358,11 @@ export default {
|
||||
background-color: #fff;
|
||||
height: calc(100vh - 64px);
|
||||
margin-bottom: -24px;
|
||||
padding: 8px 20px 20px 20px;
|
||||
padding: 12px 24px 24px 24px;
|
||||
.acl-resources-header {
|
||||
width: 100%;
|
||||
display: inline-flex;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 15px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.ant-switch {
|
||||
|
@@ -291,11 +291,11 @@ export default {
|
||||
background-color: #fff;
|
||||
height: calc(100vh - 64px);
|
||||
margin-bottom: -24px;
|
||||
padding: 20px;
|
||||
padding: 24px;
|
||||
.acl-roles-header {
|
||||
width: 100%;
|
||||
display: inline-flex;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 15px;
|
||||
align-items: center;
|
||||
.ant-checkbox-wrapper {
|
||||
margin-left: auto;
|
||||
|
@@ -326,11 +326,11 @@ export default {
|
||||
background-color: #fff;
|
||||
height: calc(100vh - 64px);
|
||||
margin-bottom: -24px;
|
||||
padding: 20px;
|
||||
padding: 24px;
|
||||
.acl-trigger-header {
|
||||
width: 100%;
|
||||
display: inline-flex;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 15px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
@@ -207,13 +207,6 @@ export function deleteTrigger(type_id, id) {
|
||||
})
|
||||
}
|
||||
|
||||
export function testTrigger(type_id, id) {
|
||||
return axios({
|
||||
url: `/v0.1/ci_types/${type_id}/triggers/${id}/test_notify`,
|
||||
method: 'post',
|
||||
})
|
||||
}
|
||||
|
||||
// CMDB的模型和实例的授权接口
|
||||
export function grantCiType(type_id, rid, data) {
|
||||
return axios({
|
||||
|
@@ -1,93 +0,0 @@
|
||||
import { axios } from '@/utils/request'
|
||||
|
||||
export function getDCIMTreeView(params) {
|
||||
return axios({
|
||||
url: '/v0.1/dcim/tree_view ',
|
||||
method: 'GET',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function getDCIMById(type, id) {
|
||||
return axios({
|
||||
url: `/v0.1/dcim/${type}/${id}`,
|
||||
method: 'GET'
|
||||
})
|
||||
}
|
||||
|
||||
export function postDCIM(type, data) {
|
||||
return axios({
|
||||
url: `/v0.1/dcim/${type}`,
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function putDCIM(type, id, data) {
|
||||
return axios({
|
||||
url: `/v0.1/dcim/${type}/${id}`,
|
||||
method: 'PUT',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteDCIM(type, id) {
|
||||
return axios({
|
||||
url: `/v0.1/dcim/${type}/${id}`,
|
||||
method: 'DELETE',
|
||||
})
|
||||
}
|
||||
|
||||
export function getDCIMRacks(id, params) {
|
||||
return axios({
|
||||
url: `/v0.1/dcim/server_room/${id}/racks`,
|
||||
method: 'GET',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function postDevice(rackId, deviceId, data) {
|
||||
return axios({
|
||||
url: `/v0.1/dcim/rack/${rackId}/device/${deviceId}`,
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteDevice(rackId, deviceId) {
|
||||
return axios({
|
||||
url: `/v0.1/dcim/rack/${rackId}/device/${deviceId}`,
|
||||
method: 'DELETE'
|
||||
})
|
||||
}
|
||||
|
||||
export function putDevice(rackId, deviceId, data) {
|
||||
return axios({
|
||||
url: `/v0.1/dcim/rack/${rackId}/device/${deviceId}`,
|
||||
method: 'PUT',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function migrateDevice(rackId, deviceId, data) {
|
||||
return axios({
|
||||
url: `/v0.1/dcim/rack/${rackId}/device/${deviceId}/migrate`,
|
||||
method: 'PUT',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function getDCIMHistoryOperate(params) {
|
||||
return axios({
|
||||
url: `/v0.1/dcim/history/operate`,
|
||||
method: 'GET',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function calcUnitFreeCount() {
|
||||
return axios({
|
||||
url: `/v0.1/dcim/rack/calc_u_free_count`,
|
||||
method: 'POST'
|
||||
})
|
||||
}
|
Before Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 554 KiB |
Before Width: | Height: | Size: 13 KiB |
@@ -15,7 +15,7 @@
|
||||
highlight-hover-row
|
||||
:checkbox-config="{ reserve: true, highlight: true, range: true }"
|
||||
:edit-config="{ trigger: 'dblclick', mode: 'row', showIcon: false }"
|
||||
:sort-config="sortConfig"
|
||||
:sort-config="{ remote: true, trigger: 'cell' }"
|
||||
:row-key="true"
|
||||
:column-key="true"
|
||||
:cell-style="getCellStyle"
|
||||
@@ -170,7 +170,7 @@
|
||||
</template>
|
||||
</template>
|
||||
</vxe-table-column>
|
||||
<vxe-column v-if="showOperation" align="left" field="operate" fixed="right" width="80">
|
||||
<vxe-column align="left" field="operate" fixed="right" width="80">
|
||||
<template #header>
|
||||
<span>{{ $t('operation') }}</span>
|
||||
</template>
|
||||
@@ -272,18 +272,6 @@ export default {
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
sortConfig: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
remote: true,
|
||||
trigger: 'cell'
|
||||
})
|
||||
},
|
||||
// 是否展示操作列
|
||||
showOperation: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@@ -1,370 +1,371 @@
|
||||
<template>
|
||||
<div class="cmdb-grant" :style="{ }">
|
||||
<template v-if="cmdbGrantType.includes('ci_type')">
|
||||
<div class="cmdb-grant-title">{{ $t('cmdb.components.ciTypeGrant') }}</div>
|
||||
<CiTypeGrant
|
||||
:CITypeId="CITypeId"
|
||||
:tableData="tableData"
|
||||
grantType="ci_type"
|
||||
@grantDepart="grantDepart"
|
||||
@grantRole="grantRole"
|
||||
@getTableData="getTableData"
|
||||
ref="grant_ci_type"
|
||||
:addedRids="addedRids"
|
||||
/>
|
||||
</template>
|
||||
<template
|
||||
v-if="
|
||||
cmdbGrantType.includes('ci_type,ci') || (cmdbGrantType.includes('ci') && !cmdbGrantType.includes('ci_type'))
|
||||
"
|
||||
>
|
||||
<div class="cmdb-grant-title">{{ $t('cmdb.components.ciGrant') }}</div>
|
||||
<CiTypeGrant
|
||||
:CITypeId="CITypeId"
|
||||
:tableData="tableData"
|
||||
grantType="ci"
|
||||
@grantDepart="grantDepart"
|
||||
@grantRole="grantRole"
|
||||
@getTableData="getTableData"
|
||||
@openReadGrantModal="openReadGrantModal"
|
||||
ref="grant_ci"
|
||||
:addedRids="addedRids"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="cmdbGrantType.includes('type_relation')">
|
||||
<div class="cmdb-grant-title">{{ $t('cmdb.components.relationGrant') }}</div>
|
||||
<TypeRelationGrant
|
||||
:typeRelationIds="typeRelationIds"
|
||||
:tableData="tableData"
|
||||
grantType="type_relation"
|
||||
@grantDepart="grantDepart"
|
||||
@grantRole="grantRole"
|
||||
@getTableData="getTableData"
|
||||
ref="grant_type_relation"
|
||||
:addedRids="addedRids"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="cmdbGrantType.includes('relation_view')">
|
||||
<div class="cmdb-grant-title">{{ resourceTypeName }}{{ $t('cmdb.components.perm') }}</div>
|
||||
<RelationViewGrant
|
||||
:resourceTypeName="resourceTypeName"
|
||||
:tableData="tableData"
|
||||
grantType="relation_view"
|
||||
@grantDepart="grantDepart"
|
||||
@grantRole="grantRole"
|
||||
@getTableData="getTableData"
|
||||
ref="grant_relation_view"
|
||||
:addedRids="addedRids"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="cmdbGrantType.includes('TopologyView')">
|
||||
<div class="cmdb-grant-title">{{ resourceTypeName }}{{ $t('cmdb.components.perm') }}</div>
|
||||
<TopologyViewGrant
|
||||
:resourceTypeName="resourceTypeName"
|
||||
:tableData="tableData"
|
||||
:viewId="CITypeId"
|
||||
grantType="TopologyView"
|
||||
@grantDepart="grantDepart"
|
||||
@grantRole="grantRole"
|
||||
@getTableData="getTableData"
|
||||
ref="grantTopologyView"
|
||||
:addedRids="addedRids"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<GrantModal ref="grantModal" @handleOk="handleOk" />
|
||||
<ReadGrantModal ref="readGrantModal" :CITypeId="CITypeId" @updateTableDataRead="updateTableDataRead" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import CiTypeGrant from './ciTypeGrant.vue'
|
||||
import TypeRelationGrant from './typeRelationGrant.vue'
|
||||
import { searchResource } from '@/modules/acl/api/resource'
|
||||
import { getResourcePerms } from '@/modules/acl/api/permission'
|
||||
import GrantModal from './grantModal.vue'
|
||||
import ReadGrantModal from './readGrantModal'
|
||||
import RelationViewGrant from './relationViewGrant.vue'
|
||||
import TopologyViewGrant from './topologyViewGrant.vue'
|
||||
import { getCITypeGroupById, ciTypeFilterPermissions } from '../../api/CIType'
|
||||
|
||||
export default {
|
||||
name: 'GrantComp',
|
||||
components: { CiTypeGrant, TypeRelationGrant, RelationViewGrant, TopologyViewGrant, GrantModal, ReadGrantModal },
|
||||
props: {
|
||||
CITypeId: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
resourceTypeName: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
resourceType: {
|
||||
type: String,
|
||||
default: 'CIType',
|
||||
},
|
||||
app_id: {
|
||||
type: String,
|
||||
default: 'cmdb',
|
||||
},
|
||||
cmdbGrantType: {
|
||||
type: String,
|
||||
default: 'ci_type,ci',
|
||||
},
|
||||
typeRelationIds: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
isModal: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
inject: ['resource_type'],
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
grantType: '',
|
||||
resource_id: null,
|
||||
attrGroup: [],
|
||||
filerPerimissions: {},
|
||||
loading: false,
|
||||
addedRids: [], // added rid this time
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
allEmployees: (state) => state.user.allEmployees,
|
||||
allDepartments: (state) => state.user.allDepartments,
|
||||
}),
|
||||
child_resource_type() {
|
||||
return this.resource_type()
|
||||
},
|
||||
windowHeight() {
|
||||
return this.$store.state.windowHeight
|
||||
},
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
attrGroup: () => {
|
||||
return this.attrGroup
|
||||
},
|
||||
filerPerimissions: () => {
|
||||
return this.filerPerimissions
|
||||
},
|
||||
loading: () => {
|
||||
return this.loading
|
||||
},
|
||||
isModal: this.isModal,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resourceTypeName: {
|
||||
immediate: true,
|
||||
handler() {
|
||||
this.init()
|
||||
},
|
||||
},
|
||||
CITypeId: {
|
||||
immediate: true,
|
||||
handler() {
|
||||
if (this.CITypeId && this.cmdbGrantType.includes('ci')) {
|
||||
this.getFilterPermissions()
|
||||
this.getAttrGroup()
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
getAttrGroup() {
|
||||
getCITypeGroupById(this.CITypeId, { need_other: true }).then((res) => {
|
||||
this.attrGroup = res
|
||||
})
|
||||
},
|
||||
getFilterPermissions() {
|
||||
ciTypeFilterPermissions(this.CITypeId).then((res) => {
|
||||
this.filerPerimissions = res
|
||||
})
|
||||
},
|
||||
async init() {
|
||||
const _find = this.child_resource_type.groups.find((item) => item.name === this.resourceType)
|
||||
const resource_type_id = _find?.id ?? 0
|
||||
const res = await searchResource({
|
||||
app_id: this.app_id,
|
||||
resource_type_id,
|
||||
page_size: 9999,
|
||||
})
|
||||
const _tempFind = res.resources.find((item) => item.name === this.resourceTypeName)
|
||||
console.log(this.resourceTypeName)
|
||||
this.resource_id = _tempFind?.id || 0
|
||||
this.getTableData()
|
||||
},
|
||||
async getTableData() {
|
||||
this.loading = true
|
||||
const _tableData = await getResourcePerms(this.resource_id, { need_users: 0 })
|
||||
const perms = []
|
||||
for (const key in _tableData) {
|
||||
const obj = {}
|
||||
obj.name = key
|
||||
_tableData[key].perms.forEach((perm) => {
|
||||
obj[`${perm.name}`] = true
|
||||
obj.rid = perm?.rid ?? null
|
||||
})
|
||||
perms.push(obj)
|
||||
}
|
||||
this.tableData = perms
|
||||
this.loading = false
|
||||
},
|
||||
// Grant the department in common-setting and get the roleid from it
|
||||
grantDepart(grantType) {
|
||||
this.$refs.grantModal.open('depart')
|
||||
this.grantType = grantType
|
||||
},
|
||||
// Grant the oldest role permissions
|
||||
grantRole(grantType) {
|
||||
this.$refs.grantModal.open('role')
|
||||
this.grantType = grantType
|
||||
},
|
||||
handleOk(params, type) {
|
||||
const { grantType } = this
|
||||
let rids
|
||||
if (type === 'depart') {
|
||||
rids = [
|
||||
...params.department.map((rid) => {
|
||||
const _find = this.allDepartments.find((dep) => dep.acl_rid === rid)
|
||||
return { rid, name: _find?.department_name ?? rid }
|
||||
}),
|
||||
...params.user.map((rid) => {
|
||||
const _find = this.allEmployees.find((dep) => dep.acl_rid === rid)
|
||||
return { rid, name: _find?.nickname ?? rid }
|
||||
}),
|
||||
]
|
||||
}
|
||||
if (type === 'role') {
|
||||
rids = [
|
||||
...params.map((role) => {
|
||||
return { rid: role.id, name: role.name }
|
||||
}),
|
||||
]
|
||||
}
|
||||
if (grantType === 'ci_type') {
|
||||
this.tableData.unshift(
|
||||
...rids.map(({ rid, name }) => {
|
||||
const _find = this.tableData.find((item) => item.rid === rid)
|
||||
return {
|
||||
rid,
|
||||
name,
|
||||
conifg: false,
|
||||
grant: false,
|
||||
..._find,
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
if (grantType === 'ci') {
|
||||
this.tableData.unshift(
|
||||
...rids.map(({ rid, name }) => {
|
||||
const _find = this.tableData.find((item) => item.rid === rid)
|
||||
return {
|
||||
rid,
|
||||
name,
|
||||
read_attr: false,
|
||||
read_ci: false,
|
||||
create: false,
|
||||
update: false,
|
||||
delete: false,
|
||||
..._find,
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
if (grantType === 'type_relation') {
|
||||
this.tableData.unshift(
|
||||
...rids.map(({ rid, name }) => {
|
||||
return {
|
||||
rid,
|
||||
name,
|
||||
create: false,
|
||||
grant: false,
|
||||
delete: false,
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
if (grantType === 'relation_view') {
|
||||
this.tableData.unshift(
|
||||
...rids.map(({ rid, name }) => {
|
||||
return {
|
||||
rid,
|
||||
name,
|
||||
read: false,
|
||||
grant: false,
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
if (grantType === 'TopologyView') {
|
||||
this.tableData.unshift(
|
||||
...rids.map(({ rid, name }) => {
|
||||
return {
|
||||
rid,
|
||||
name,
|
||||
read: false,
|
||||
update: false,
|
||||
delete: false,
|
||||
grant: false,
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
this.addedRids = rids
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.$refs[`grant_${grantType}`].$refs.xTable.elemStore['main-body-wrapper'].scrollTo(0, 0)
|
||||
}, 300)
|
||||
})
|
||||
},
|
||||
openReadGrantModal(col, row) {
|
||||
this.$refs.readGrantModal.open(col, row)
|
||||
},
|
||||
updateTableDataRead(row, hasRead) {
|
||||
const _idx = this.tableData.findIndex((item) => item.rid === row.rid)
|
||||
this.$set(this.tableData, _idx, { ...this.tableData[_idx], read: hasRead })
|
||||
this.getFilterPermissions()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.cmdb-grant {
|
||||
position: relative;
|
||||
padding: 0 20px;
|
||||
overflow: auto;
|
||||
.cmdb-grant-title {
|
||||
border-left: 4px solid @primary-color;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
.cmdb-grant {
|
||||
.grant-button {
|
||||
padding: 6px 8px;
|
||||
color: @primary-color;
|
||||
background-color: @primary-color_5;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
margin: 15px 0;
|
||||
display: inline-block;
|
||||
transition: all 0.3s;
|
||||
z-index: 1;
|
||||
|
||||
.btn-wave-hover(@primary-color_4, -1);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<div class="cmdb-grant" :style="{ }">
|
||||
<template v-if="cmdbGrantType.includes('ci_type')">
|
||||
<div class="cmdb-grant-title">{{ $t('cmdb.components.ciTypeGrant') }}</div>
|
||||
<CiTypeGrant
|
||||
:CITypeId="CITypeId"
|
||||
:tableData="tableData"
|
||||
grantType="ci_type"
|
||||
@grantDepart="grantDepart"
|
||||
@grantRole="grantRole"
|
||||
@getTableData="getTableData"
|
||||
ref="grant_ci_type"
|
||||
:addedRids="addedRids"
|
||||
/>
|
||||
</template>
|
||||
<template
|
||||
v-if="
|
||||
cmdbGrantType.includes('ci_type,ci') || (cmdbGrantType.includes('ci') && !cmdbGrantType.includes('ci_type'))
|
||||
"
|
||||
>
|
||||
<div class="cmdb-grant-title">{{ $t('cmdb.components.ciGrant') }}</div>
|
||||
<CiTypeGrant
|
||||
:CITypeId="CITypeId"
|
||||
:tableData="tableData"
|
||||
grantType="ci"
|
||||
@grantDepart="grantDepart"
|
||||
@grantRole="grantRole"
|
||||
@getTableData="getTableData"
|
||||
@openReadGrantModal="openReadGrantModal"
|
||||
ref="grant_ci"
|
||||
:addedRids="addedRids"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="cmdbGrantType.includes('type_relation')">
|
||||
<div class="cmdb-grant-title">{{ $t('cmdb.components.relationGrant') }}</div>
|
||||
<TypeRelationGrant
|
||||
:typeRelationIds="typeRelationIds"
|
||||
:tableData="tableData"
|
||||
grantType="type_relation"
|
||||
@grantDepart="grantDepart"
|
||||
@grantRole="grantRole"
|
||||
@getTableData="getTableData"
|
||||
ref="grant_type_relation"
|
||||
:addedRids="addedRids"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="cmdbGrantType.includes('relation_view')">
|
||||
<div class="cmdb-grant-title">{{ resourceTypeName }}{{ $t('cmdb.components.perm') }}</div>
|
||||
<RelationViewGrant
|
||||
:resourceTypeName="resourceTypeName"
|
||||
:tableData="tableData"
|
||||
grantType="relation_view"
|
||||
@grantDepart="grantDepart"
|
||||
@grantRole="grantRole"
|
||||
@getTableData="getTableData"
|
||||
ref="grant_relation_view"
|
||||
:addedRids="addedRids"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="cmdbGrantType.includes('TopologyView')">
|
||||
<div class="cmdb-grant-title">{{ resourceTypeName }}{{ $t('cmdb.components.perm') }}</div>
|
||||
<TopologyViewGrant
|
||||
:resourceTypeName="resourceTypeName"
|
||||
:tableData="tableData"
|
||||
:viewId="CITypeId"
|
||||
grantType="TopologyView"
|
||||
@grantDepart="grantDepart"
|
||||
@grantRole="grantRole"
|
||||
@getTableData="getTableData"
|
||||
ref="grantTopologyView"
|
||||
:addedRids="addedRids"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<GrantModal ref="grantModal" @handleOk="handleOk" />
|
||||
<ReadGrantModal ref="readGrantModal" :CITypeId="CITypeId" @updateTableDataRead="updateTableDataRead" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import CiTypeGrant from './ciTypeGrant.vue'
|
||||
import TypeRelationGrant from './typeRelationGrant.vue'
|
||||
import { searchResource } from '@/modules/acl/api/resource'
|
||||
import { getResourcePerms } from '@/modules/acl/api/permission'
|
||||
import GrantModal from './grantModal.vue'
|
||||
import ReadGrantModal from './readGrantModal'
|
||||
import RelationViewGrant from './relationViewGrant.vue'
|
||||
import TopologyViewGrant from './topologyViewGrant.vue'
|
||||
import { getCITypeGroupById, ciTypeFilterPermissions } from '../../api/CIType'
|
||||
|
||||
export default {
|
||||
name: 'GrantComp',
|
||||
components: { CiTypeGrant, TypeRelationGrant, RelationViewGrant, TopologyViewGrant, GrantModal, ReadGrantModal },
|
||||
props: {
|
||||
CITypeId: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
resourceTypeName: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
resourceType: {
|
||||
type: String,
|
||||
default: 'CIType',
|
||||
},
|
||||
app_id: {
|
||||
type: String,
|
||||
default: 'cmdb',
|
||||
},
|
||||
cmdbGrantType: {
|
||||
type: String,
|
||||
default: 'ci_type,ci',
|
||||
},
|
||||
typeRelationIds: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
isModal: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
inject: ['resource_type'],
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
grantType: '',
|
||||
resource_id: null,
|
||||
attrGroup: [],
|
||||
filerPerimissions: {},
|
||||
loading: false,
|
||||
addedRids: [], // added rid this time
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
allEmployees: (state) => state.user.allEmployees,
|
||||
allDepartments: (state) => state.user.allDepartments,
|
||||
}),
|
||||
child_resource_type() {
|
||||
return this.resource_type()
|
||||
},
|
||||
windowHeight() {
|
||||
return this.$store.state.windowHeight
|
||||
},
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
attrGroup: () => {
|
||||
return this.attrGroup
|
||||
},
|
||||
filerPerimissions: () => {
|
||||
return this.filerPerimissions
|
||||
},
|
||||
loading: () => {
|
||||
return this.loading
|
||||
},
|
||||
isModal: this.isModal,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
resourceTypeName: {
|
||||
immediate: true,
|
||||
handler() {
|
||||
this.init()
|
||||
},
|
||||
},
|
||||
CITypeId: {
|
||||
immediate: true,
|
||||
handler() {
|
||||
if (this.CITypeId && this.cmdbGrantType.includes('ci')) {
|
||||
this.getFilterPermissions()
|
||||
this.getAttrGroup()
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
getAttrGroup() {
|
||||
getCITypeGroupById(this.CITypeId, { need_other: true }).then((res) => {
|
||||
this.attrGroup = res
|
||||
})
|
||||
},
|
||||
getFilterPermissions() {
|
||||
ciTypeFilterPermissions(this.CITypeId).then((res) => {
|
||||
this.filerPerimissions = res
|
||||
})
|
||||
},
|
||||
async init() {
|
||||
const _find = this.child_resource_type.groups.find((item) => item.name === this.resourceType)
|
||||
const resource_type_id = _find?.id ?? 0
|
||||
const res = await searchResource({
|
||||
app_id: this.app_id,
|
||||
resource_type_id,
|
||||
page_size: 9999,
|
||||
})
|
||||
const _tempFind = res.resources.find((item) => item.name === this.resourceTypeName)
|
||||
console.log(this.resourceTypeName)
|
||||
this.resource_id = _tempFind?.id || 0
|
||||
this.getTableData()
|
||||
},
|
||||
async getTableData() {
|
||||
this.loading = true
|
||||
const _tableData = await getResourcePerms(this.resource_id, { need_users: 0 })
|
||||
const perms = []
|
||||
for (const key in _tableData) {
|
||||
const obj = {}
|
||||
obj.name = key
|
||||
_tableData[key].perms.forEach((perm) => {
|
||||
obj[`${perm.name}`] = true
|
||||
obj.rid = perm?.rid ?? null
|
||||
})
|
||||
perms.push(obj)
|
||||
}
|
||||
this.tableData = perms
|
||||
this.loading = false
|
||||
},
|
||||
// Grant the department in common-setting and get the roleid from it
|
||||
grantDepart(grantType) {
|
||||
this.$refs.grantModal.open('depart')
|
||||
this.grantType = grantType
|
||||
},
|
||||
// Grant the oldest role permissions
|
||||
grantRole(grantType) {
|
||||
this.$refs.grantModal.open('role')
|
||||
this.grantType = grantType
|
||||
},
|
||||
handleOk(params, type) {
|
||||
const { grantType } = this
|
||||
let rids
|
||||
if (type === 'depart') {
|
||||
rids = [
|
||||
...params.department.map((rid) => {
|
||||
const _find = this.allDepartments.find((dep) => dep.acl_rid === rid)
|
||||
return { rid, name: _find?.department_name ?? rid }
|
||||
}),
|
||||
...params.user.map((rid) => {
|
||||
const _find = this.allEmployees.find((dep) => dep.acl_rid === rid)
|
||||
return { rid, name: _find?.nickname ?? rid }
|
||||
}),
|
||||
]
|
||||
}
|
||||
if (type === 'role') {
|
||||
rids = [
|
||||
...params.map((role) => {
|
||||
return { rid: role.id, name: role.name }
|
||||
}),
|
||||
]
|
||||
}
|
||||
if (grantType === 'ci_type') {
|
||||
this.tableData.unshift(
|
||||
...rids.map(({ rid, name }) => {
|
||||
const _find = this.tableData.find((item) => item.rid === rid)
|
||||
return {
|
||||
rid,
|
||||
name,
|
||||
conifg: false,
|
||||
grant: false,
|
||||
..._find,
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
if (grantType === 'ci') {
|
||||
this.tableData.unshift(
|
||||
...rids.map(({ rid, name }) => {
|
||||
const _find = this.tableData.find((item) => item.rid === rid)
|
||||
return {
|
||||
rid,
|
||||
name,
|
||||
read_attr: false,
|
||||
read_ci: false,
|
||||
create: false,
|
||||
update: false,
|
||||
delete: false,
|
||||
..._find,
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
if (grantType === 'type_relation') {
|
||||
this.tableData.unshift(
|
||||
...rids.map(({ rid, name }) => {
|
||||
return {
|
||||
rid,
|
||||
name,
|
||||
create: false,
|
||||
grant: false,
|
||||
delete: false,
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
if (grantType === 'relation_view') {
|
||||
this.tableData.unshift(
|
||||
...rids.map(({ rid, name }) => {
|
||||
return {
|
||||
rid,
|
||||
name,
|
||||
read: false,
|
||||
grant: false,
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
if (grantType === 'TopologyView') {
|
||||
this.tableData.unshift(
|
||||
...rids.map(({ rid, name }) => {
|
||||
return {
|
||||
rid,
|
||||
name,
|
||||
read: false,
|
||||
update: false,
|
||||
delete: false,
|
||||
grant: false,
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
this.addedRids = rids
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.$refs[`grant_${grantType}`].$refs.xTable.elemStore['main-body-wrapper'].scrollTo(0, 0)
|
||||
}, 300)
|
||||
})
|
||||
},
|
||||
openReadGrantModal(col, row) {
|
||||
this.$refs.readGrantModal.open(col, row)
|
||||
},
|
||||
updateTableDataRead(row, hasRead) {
|
||||
const _idx = this.tableData.findIndex((item) => item.rid === row.rid)
|
||||
this.$set(this.tableData, _idx, { ...this.tableData[_idx], read: hasRead })
|
||||
this.getFilterPermissions()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.cmdb-grant {
|
||||
position: relative;
|
||||
padding: 0 20px;
|
||||
overflow: auto;
|
||||
.cmdb-grant-title {
|
||||
border-left: 4px solid @primary-color;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
.cmdb-grant {
|
||||
.grant-button {
|
||||
padding: 6px 8px;
|
||||
color: @primary-color;
|
||||
background-color: @primary-color_5;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
margin: 15px 0;
|
||||
display: inline-block;
|
||||
transition: all 0.3s;
|
||||
&:hover {
|
||||
box-shadow: 2px 3px 4px @primary-color_5;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -1,118 +1,122 @@
|
||||
<template>
|
||||
<a-modal :visible="visible" @cancel="handleCancel" @ok="handleOK" :title="$t('revoke')">
|
||||
<a-form-model :model="form" :label-col="{ span: 4 }" :wrapper-col="{ span: 16 }">
|
||||
<a-form-model-item :label="$t('user')">
|
||||
<EmployeeTreeSelect
|
||||
class="custom-treeselect custom-treeselect-white"
|
||||
:style="{
|
||||
'--custom-height': '32px',
|
||||
lineHeight: '32px',
|
||||
'--custom-multiple-lineHeight': '18px',
|
||||
}"
|
||||
:multiple="true"
|
||||
v-model="form.users"
|
||||
:placeholder="$t('cmdb.serviceTree.userPlaceholder')"
|
||||
:idType="2"
|
||||
departmentKey="acl_rid"
|
||||
employeeKey="acl_rid"
|
||||
/>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item :label="$t('role')">
|
||||
<treeselect
|
||||
v-model="form.roles"
|
||||
:multiple="true"
|
||||
:options="filterAllRoles"
|
||||
class="custom-treeselect custom-treeselect-white"
|
||||
:style="{
|
||||
'--custom-height': '32px',
|
||||
lineHeight: '32px',
|
||||
'--custom-multiple-lineHeight': '18px',
|
||||
}"
|
||||
:limit="10"
|
||||
:limitText="(count) => `+ ${count}`"
|
||||
:normalizer="
|
||||
(node) => {
|
||||
return {
|
||||
id: node.id,
|
||||
label: node.name,
|
||||
}
|
||||
}
|
||||
"
|
||||
appendToBody
|
||||
zIndex="1050"
|
||||
:placeholder="$t('cmdb.serviceTree.rolePlaceholder')"
|
||||
@search-change="searchRole"
|
||||
/>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EmployeeTreeSelect from '@/views/setting/components/employeeTreeSelect.vue'
|
||||
import { getAllDepAndEmployee } from '@/api/company'
|
||||
import { searchRole } from '@/modules/acl/api/role'
|
||||
|
||||
export default {
|
||||
name: 'RevokeModal',
|
||||
components: { EmployeeTreeSelect },
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
form: {
|
||||
users: undefined,
|
||||
roles: undefined,
|
||||
},
|
||||
allTreeDepAndEmp: [],
|
||||
allRoles: [],
|
||||
filterAllRoles: [],
|
||||
}
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
provide_allTreeDepAndEmp: () => {
|
||||
return this.allTreeDepAndEmp
|
||||
},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getAllDepAndEmployee()
|
||||
this.loadRoles()
|
||||
},
|
||||
methods: {
|
||||
async loadRoles() {
|
||||
const res = await searchRole({ page_size: 9999, app_id: 'cmdb', is_all: true })
|
||||
this.allRoles = res.roles
|
||||
this.filterAllRoles = this.allRoles.slice(0, 100)
|
||||
},
|
||||
getAllDepAndEmployee() {
|
||||
getAllDepAndEmployee({ block: 0 }).then((res) => {
|
||||
this.allTreeDepAndEmp = res
|
||||
})
|
||||
},
|
||||
open() {
|
||||
this.visible = true
|
||||
this.$nextTick(() => {
|
||||
this.form = {
|
||||
users: undefined,
|
||||
roles: undefined,
|
||||
}
|
||||
})
|
||||
},
|
||||
handleCancel() {
|
||||
this.visible = false
|
||||
},
|
||||
searchRole(searchQuery) {
|
||||
this.filterAllRoles = this.allRoles
|
||||
.filter((item) => item.name.toLowerCase().includes(searchQuery.toLowerCase()))
|
||||
.slice(0, 100)
|
||||
},
|
||||
handleOK() {
|
||||
this.$emit('handleRevoke', this.form)
|
||||
this.handleCancel()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
<template>
|
||||
<a-modal :visible="visible" @cancel="handleCancel" @ok="handleOK" :title="$t('revoke')">
|
||||
<a-form-model :model="form" :label-col="{ span: 4 }" :wrapper-col="{ span: 16 }">
|
||||
<a-form-model-item :label="$t('user')">
|
||||
<EmployeeTreeSelect
|
||||
class="custom-treeselect custom-treeselect-bgcAndBorder"
|
||||
:style="{
|
||||
'--custom-height': '32px',
|
||||
lineHeight: '32px',
|
||||
'--custom-bg-color': '#fff',
|
||||
'--custom-border': '1px solid #d9d9d9',
|
||||
'--custom-multiple-lineHeight': '18px',
|
||||
}"
|
||||
:multiple="true"
|
||||
v-model="form.users"
|
||||
:placeholder="$t('cmdb.serviceTree.userPlaceholder')"
|
||||
:idType="2"
|
||||
departmentKey="acl_rid"
|
||||
employeeKey="acl_rid"
|
||||
/>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item :label="$t('role')">
|
||||
<treeselect
|
||||
v-model="form.roles"
|
||||
:multiple="true"
|
||||
:options="filterAllRoles"
|
||||
class="custom-treeselect custom-treeselect-bgcAndBorder"
|
||||
:style="{
|
||||
'--custom-height': '32px',
|
||||
lineHeight: '32px',
|
||||
'--custom-bg-color': '#fff',
|
||||
'--custom-border': '1px solid #d9d9d9',
|
||||
'--custom-multiple-lineHeight': '18px',
|
||||
}"
|
||||
:limit="10"
|
||||
:limitText="(count) => `+ ${count}`"
|
||||
:normalizer="
|
||||
(node) => {
|
||||
return {
|
||||
id: node.id,
|
||||
label: node.name,
|
||||
}
|
||||
}
|
||||
"
|
||||
appendToBody
|
||||
zIndex="1050"
|
||||
:placeholder="$t('cmdb.serviceTree.rolePlaceholder')"
|
||||
@search-change="searchRole"
|
||||
/>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EmployeeTreeSelect from '@/views/setting/components/employeeTreeSelect.vue'
|
||||
import { getAllDepAndEmployee } from '@/api/company'
|
||||
import { searchRole } from '@/modules/acl/api/role'
|
||||
|
||||
export default {
|
||||
name: 'RevokeModal',
|
||||
components: { EmployeeTreeSelect },
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
form: {
|
||||
users: undefined,
|
||||
roles: undefined,
|
||||
},
|
||||
allTreeDepAndEmp: [],
|
||||
allRoles: [],
|
||||
filterAllRoles: [],
|
||||
}
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
provide_allTreeDepAndEmp: () => {
|
||||
return this.allTreeDepAndEmp
|
||||
},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getAllDepAndEmployee()
|
||||
this.loadRoles()
|
||||
},
|
||||
methods: {
|
||||
async loadRoles() {
|
||||
const res = await searchRole({ page_size: 9999, app_id: 'cmdb', is_all: true })
|
||||
this.allRoles = res.roles
|
||||
this.filterAllRoles = this.allRoles.slice(0, 100)
|
||||
},
|
||||
getAllDepAndEmployee() {
|
||||
getAllDepAndEmployee({ block: 0 }).then((res) => {
|
||||
this.allTreeDepAndEmp = res
|
||||
})
|
||||
},
|
||||
open() {
|
||||
this.visible = true
|
||||
this.$nextTick(() => {
|
||||
this.form = {
|
||||
users: undefined,
|
||||
roles: undefined,
|
||||
}
|
||||
})
|
||||
},
|
||||
handleCancel() {
|
||||
this.visible = false
|
||||
},
|
||||
searchRole(searchQuery) {
|
||||
this.filterAllRoles = this.allRoles
|
||||
.filter((item) => item.name.toLowerCase().includes(searchQuery.toLowerCase()))
|
||||
.slice(0, 100)
|
||||
},
|
||||
handleOK() {
|
||||
this.$emit('handleRevoke', this.form)
|
||||
this.handleCancel()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
@@ -3,10 +3,12 @@
|
||||
:disabled="disabled"
|
||||
ref="cmdb_type_select"
|
||||
:disable-branch-nodes="true"
|
||||
class="custom-treeselect custom-treeselect-white"
|
||||
class="custom-treeselect custom-treeselect-bgcAndBorder"
|
||||
:style="{
|
||||
'--custom-height': '30px',
|
||||
lineHeight: '30px'
|
||||
lineHeight: '30px',
|
||||
'--custom-bg-color': '#fff',
|
||||
'--custom-border': '1px solid #d9d9d9',
|
||||
}"
|
||||
v-model="currenCiType"
|
||||
:multiple="multiple"
|
||||
|
@@ -35,8 +35,8 @@
|
||||
:key="`${item.id}_${index}`"
|
||||
class="preference-search-tag"
|
||||
:style="{
|
||||
backgroundColor: item.id === currentPreferenceSearch ? '#2f54eb' : '',
|
||||
color: item.id === currentPreferenceSearch ? '#fff' : '',
|
||||
backgroundColor: item.id === currentPreferenceSearch ? '#2f54eb' : '#fafafa',
|
||||
color: item.id === currentPreferenceSearch ? '#fff' : '#000000a6',
|
||||
}"
|
||||
>
|
||||
<span @click="clickPreferenceSearch(item)">{{ item.name }}</span>
|
||||
@@ -189,10 +189,6 @@ export default {
|
||||
> i {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
.preference-search-delete {
|
||||
color: #a9a9a9;
|
||||
|
@@ -5,11 +5,13 @@
|
||||
<a-space>
|
||||
<treeselect
|
||||
v-if="type === 'resourceSearch'"
|
||||
class="custom-treeselect"
|
||||
class="custom-treeselect custom-treeselect-bgcAndBorder"
|
||||
:style="{
|
||||
width: '200px',
|
||||
marginRight: '10px',
|
||||
'--custom-height': '32px',
|
||||
'--custom-bg-color': '#fff',
|
||||
'--custom-border': '1px solid #d9d9d9',
|
||||
'--custom-multiple-lineHeight': '16px',
|
||||
}"
|
||||
v-model="currenCiType"
|
||||
|
@@ -135,15 +135,9 @@ export default {
|
||||
border: 1px solid #f3f4f6;
|
||||
}
|
||||
.authorization-input {
|
||||
border: 1px solid transparent;
|
||||
|
||||
border: none;
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
border-color: @primary-color;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@
|
||||
<tr v-for="(item, index) in headers" :key="item.id">
|
||||
<td><a-input class="headers-input" v-model="item.key" :placeholder="$t('cmdb.components.param', { param: `${index + 1}` })" /></td>
|
||||
<td><a-input class="headers-input" v-model="item.value" :placeholder="$t('cmdb.components.value', { value: `${index + 1}` })" /></td>
|
||||
<td class="headers-delete">
|
||||
<td>
|
||||
<a style="color:red">
|
||||
<ops-icon type="icon-xianxing-delete" @click="deleteParam(index)" />
|
||||
</a>
|
||||
@@ -92,20 +92,10 @@ export default {
|
||||
border: 1px solid #f3f4f6;
|
||||
}
|
||||
.headers-input {
|
||||
border: 1px solid transparent;
|
||||
|
||||
border: none;
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
border-color: @primary-color;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
.headers-delete {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -3,10 +3,12 @@
|
||||
<a-input-group compact>
|
||||
<treeselect
|
||||
:disable-branch-nodes="true"
|
||||
class="custom-treeselect custom-treeselect-white"
|
||||
class="custom-treeselect custom-treeselect-bgcAndBorder"
|
||||
:style="{
|
||||
'--custom-height': '30px',
|
||||
lineHeight: '30px',
|
||||
'--custom-bg-color': '#fff',
|
||||
'--custom-border': '1px solid #d9d9d9',
|
||||
display: 'inline-block',
|
||||
width: '100px',
|
||||
}"
|
||||
|
@@ -23,7 +23,7 @@
|
||||
<tr v-for="(item, index) in parameters" :key="item.id">
|
||||
<td><a-input class="parameters-input" v-model="item.key" :placeholder="$t('cmdb.components.param', { param: `${index + 1}` })" /></td>
|
||||
<td><a-input class="parameters-input" v-model="item.value" :placeholder="$t('cmdb.components.value', { value: `${index + 1}` })" /></td>
|
||||
<td class="parameters-delete">
|
||||
<td>
|
||||
<a style="color:red">
|
||||
<ops-icon type="icon-xianxing-delete" @click="deleteParam(index)" />
|
||||
</a>
|
||||
@@ -91,20 +91,10 @@ export default {
|
||||
border: 1px solid #f3f4f6;
|
||||
}
|
||||
.parameters-input {
|
||||
border: 1px solid transparent;
|
||||
|
||||
border: none;
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
border-color: @primary-color;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
.parameters-delete {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -25,8 +25,7 @@ const cmdb_en = {
|
||||
relationType: 'Relation Type',
|
||||
ad: 'AutoDiscovery',
|
||||
cidetail: 'CI Detail',
|
||||
scene: 'Scene',
|
||||
dcim: 'DCIM'
|
||||
scene: 'Scene'
|
||||
},
|
||||
ciType: {
|
||||
ciType: 'CIType',
|
||||
@@ -186,9 +185,6 @@ const cmdb_en = {
|
||||
botSelect: 'Please select a robot',
|
||||
refAttributeTips: 'The title and content can reference the attribute value of the CIType. The reference method is: {{ attr_name }}',
|
||||
webhookRefAttributeTips: 'Request parameters can reference the attribute value of the model. The reference method is: {{ attr_name }}',
|
||||
testSend: 'Test Send',
|
||||
testSendTip: 'Please save the trigger first',
|
||||
testSendSuccess: 'Send Success',
|
||||
newTrigger: 'Add trigger',
|
||||
editTriggerTitle: 'Edit trigger {name}',
|
||||
newTriggerTitle: 'Add trigger {name}',
|
||||
@@ -841,67 +837,7 @@ if __name__ == "__main__":
|
||||
onlineRatio: 'Online Ratio',
|
||||
scanEnable: 'Scan Enable',
|
||||
lastScanTime: 'Last Scan Time',
|
||||
isSuccess: 'Is Success',
|
||||
batchAssign: 'Batch Assign',
|
||||
batchAssignInProgress: 'Assign in batches, {total} in total, {successNum} successful, {errorNum} failed',
|
||||
batchAssignCompleted: 'Batch Assign Completed',
|
||||
batchRecycle: 'Batch Recycle',
|
||||
batchRecycleInProgress: 'Recycle in batches, {total} in total, {successNum} successful, {errorNum} failed',
|
||||
batchRecycleCompleted: 'Batch Recycle Completed',
|
||||
},
|
||||
dcim: {
|
||||
addRegion: 'Add Region',
|
||||
addIDC: 'Add IDC',
|
||||
addServerRoom: 'Add Server Room',
|
||||
addRack: 'Add Rack',
|
||||
editRegion: 'Edit Region',
|
||||
editIDC: 'Edit IDC',
|
||||
editServerRoom: 'Edit Server Room',
|
||||
editRack: 'Edit Rack',
|
||||
rackCount: 'Rack Count',
|
||||
total: 'Total',
|
||||
deviceCount: 'Device Count',
|
||||
utilizationRation: 'Utilization Ration',
|
||||
used: 'Used',
|
||||
unused: 'Unused',
|
||||
rackSearchTip: 'Please search for rack name',
|
||||
viewDetail: 'View Detail',
|
||||
deleteNode: 'Delete Node',
|
||||
editNode: 'Edit Node',
|
||||
roomNullTip: 'Please select the server room on the left first',
|
||||
unitAbnormal: 'Unit Abnormal',
|
||||
rack: 'Rack',
|
||||
unitCount: 'Unit Count',
|
||||
rackView: 'Rack View',
|
||||
deviceList: 'Device List',
|
||||
operationLog: 'Operation Log',
|
||||
frontView: 'Front View',
|
||||
rearView: 'Rear View',
|
||||
addDevice: 'Add Device',
|
||||
device: 'Device',
|
||||
ciType: 'CIType',
|
||||
unitStart: 'Unit Start',
|
||||
toChange: 'To Change',
|
||||
abnormalModalTip1: 'and',
|
||||
abnormalModalTip2: ' location duplication',
|
||||
abnormalModalTip3: 'Please select one of the devices to change',
|
||||
remove: 'Remove',
|
||||
migrate: 'Migrate',
|
||||
deviceMigrate: 'Device Migrate',
|
||||
migrationSuccess: 'Migration Success',
|
||||
removeDeviceTip: 'Confirmed to remove {deviceName} device?',
|
||||
operationTime: 'Operation Time',
|
||||
operationUser: 'Operation User',
|
||||
operationType: 'Operation Type',
|
||||
deviceType: 'Device Type',
|
||||
deviceName: 'Device Name',
|
||||
removeDevice: 'Remove Device',
|
||||
moveDevice: 'Move Device',
|
||||
rackDetail: 'Rack Detail',
|
||||
calcUnitFreeCount: 'Calculate Rack Free Unit Count',
|
||||
calcUnitFreeCountTip: 'Calculating in the background, refresh the page later to see the result',
|
||||
calcUnitFreeCountTip1: 'Calculate Trigger Success, refresh the page later to see the result',
|
||||
calcUnitFreeCountTip2: `Confirm that you want to calculate the number of free Units for all rack?`
|
||||
isSuccess: 'Is Success'
|
||||
}
|
||||
}
|
||||
export default cmdb_en
|
||||
|
@@ -25,8 +25,7 @@ const cmdb_zh = {
|
||||
relationType: '关系类型',
|
||||
ad: '自动发现',
|
||||
cidetail: 'CI 详情',
|
||||
scene: '场景',
|
||||
dcim: '数据中心'
|
||||
scene: '场景'
|
||||
},
|
||||
ciType: {
|
||||
ciType: '模型',
|
||||
@@ -186,9 +185,6 @@ const cmdb_zh = {
|
||||
botSelect: '请选择机器人',
|
||||
refAttributeTips: '标题、内容可以引用该模型的属性值,引用方法为: {{ attr_name }}',
|
||||
webhookRefAttributeTips: '请求参数可以引用该模型的属性值,引用方法为: {{ attr_name }}',
|
||||
testSend: '测试发送',
|
||||
testSendTip: '请先保存触发器',
|
||||
testSendSuccess: '发送成功',
|
||||
newTrigger: '新增触发器',
|
||||
editTriggerTitle: '编辑触发器 {name}',
|
||||
newTriggerTitle: '新增触发器 {name}',
|
||||
@@ -840,67 +836,7 @@ if __name__ == "__main__":
|
||||
onlineRatio: '在线率',
|
||||
scanEnable: '是否扫描',
|
||||
lastScanTime: '最后扫描时间',
|
||||
isSuccess: '是否成功',
|
||||
batchAssign: '批量分配',
|
||||
batchAssignInProgress: '正在批量分配,共{total}个,成功{successNum}个,失败{errorNum}个',
|
||||
batchAssignCompleted: '批量分配已完成',
|
||||
batchRecycle: '批量回收',
|
||||
batchRecycleInProgress: '正在批量回收,共{total}个,成功{successNum}个,失败{errorNum}个',
|
||||
batchRecycleCompleted: '批量回收已完成',
|
||||
},
|
||||
dcim: {
|
||||
addRegion: '新增区域',
|
||||
addIDC: '新增数据中心',
|
||||
addServerRoom: '新增机房',
|
||||
addRack: '添加机柜',
|
||||
editRegion: '编辑区域',
|
||||
editIDC: '编辑数据中心',
|
||||
editServerRoom: '编辑机房',
|
||||
editRack: '编辑机柜',
|
||||
rackCount: '机柜数',
|
||||
total: '总数',
|
||||
deviceCount: '设备数',
|
||||
utilizationRation: '利用率',
|
||||
used: '已使用',
|
||||
unused: '未使用',
|
||||
rackSearchTip: '请搜索机柜名称',
|
||||
viewDetail: '查看详情',
|
||||
deleteNode: '删除节点',
|
||||
editNode: '编辑节点',
|
||||
roomNullTip: '请先选择左侧的机房',
|
||||
unitAbnormal: 'U位异常',
|
||||
rack: '机柜',
|
||||
unitCount: 'U位数',
|
||||
rackView: '机柜视图',
|
||||
deviceList: '设备列表',
|
||||
operationLog: '操作记录',
|
||||
frontView: '前视图',
|
||||
rearView: '后视图',
|
||||
addDevice: '添加设备',
|
||||
device: '设备',
|
||||
ciType: '模型',
|
||||
unitStart: '起始U位',
|
||||
toChange: '去修改',
|
||||
abnormalModalTip1: '和',
|
||||
abnormalModalTip2: ' 位置重复',
|
||||
abnormalModalTip3: '请选择其中一台设备进行修改',
|
||||
remove: '移除',
|
||||
migrate: '迁移',
|
||||
deviceMigrate: '设备迁移',
|
||||
migrationSuccess: '迁移成功',
|
||||
removeDeviceTip: '确认要移除 {deviceName} 设备吗?',
|
||||
operationTime: '操作时间',
|
||||
operationUser: '操作人',
|
||||
operationType: '操作类型',
|
||||
deviceType: '设备类型',
|
||||
deviceName: '设备名',
|
||||
removeDevice: '删除设备',
|
||||
moveDevice: '移动设备',
|
||||
rackDetail: '机柜详情',
|
||||
calcUnitFreeCount: '计算机柜空闲U数',
|
||||
calcUnitFreeCountTip: '后台计算中,稍后刷新页面查看结果',
|
||||
calcUnitFreeCountTip1: '计算触发成功,稍后刷新页面查看结果',
|
||||
calcUnitFreeCountTip2: '确认要计算所有机柜的空闲U数?'
|
||||
isSuccess: '是否成功'
|
||||
}
|
||||
}
|
||||
export default cmdb_zh
|
||||
|
@@ -81,12 +81,6 @@ const genCmdbRoutes = async () => {
|
||||
name: 'cmdb_ipam',
|
||||
meta: { title: 'IPAM', appName: 'cmdb', icon: 'veops-ipam', selectedIcon: 'veops-ipam', keepAlive: false, permission: ['admin', 'cmdb_admin'] }
|
||||
},
|
||||
{
|
||||
path: '/cmdb/dcim',
|
||||
component: () => import('../views/dcim'),
|
||||
name: 'cmdb_dcim',
|
||||
meta: { title: 'cmdb.menu.dcim', appName: 'cmdb', icon: 'veops-data_center', selectedIcon: 'veops-data_center', keepAlive: false, permission: ['cmdb_admin', 'admin'] }
|
||||
},
|
||||
{
|
||||
path: '/cmdb/disabled2',
|
||||
name: 'cmdb_disabled2',
|
||||
|
@@ -104,16 +104,6 @@ export default {
|
||||
.cmdb-batch-upload-tips {
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(90deg, @primary-color_2 50%, transparent 0) repeat-x,
|
||||
linear-gradient(90deg, @primary-color_2 50%, transparent 0) repeat-x,
|
||||
linear-gradient(0deg, @primary-color_2 50%, transparent 0) repeat-y,
|
||||
linear-gradient(0deg, @primary-color_2 50%, transparent 0) repeat-y;
|
||||
background-size: 15px 1px, 15px 1px, 1px 15px, 1px 15px;
|
||||
background-position: 0 0, 0 100%, 0 0, 100% 0;
|
||||
background-color: @primary-color_7;
|
||||
}
|
||||
}
|
||||
.ant-upload.ant-upload-drag .ant-upload-drag-container {
|
||||
vertical-align: baseline;
|
||||
|
@@ -9,18 +9,22 @@
|
||||
"
|
||||
:title="$t('cmdb.ci.attributeDesc')"
|
||||
width="72%"
|
||||
:bodyStyle="{ height: '100vh', paddingTop: '16px' }"
|
||||
:bodyStyle="{ height: '100vh' }"
|
||||
>
|
||||
<a-input
|
||||
v-model="searchKey"
|
||||
:style="{ display: 'inline-block', width: '244px', marginBottom: '16px' }"
|
||||
class="ops-input ops-input-radius"
|
||||
type="search"
|
||||
:placeholder="$t('cmdb.ci.tips5')"
|
||||
@keyup="searchAttributes"
|
||||
>
|
||||
<a-icon type="search" slot="suffix" />
|
||||
</a-input>
|
||||
<vxe-toolbar>
|
||||
<template #buttons>
|
||||
<a-input
|
||||
v-model="searchKey"
|
||||
:style="{ display: 'inline-block', width: '244px' }"
|
||||
class="ops-input ops-input-radius"
|
||||
type="search"
|
||||
:placeholder="$t('cmdb.ci.tips5')"
|
||||
@keyup="searchAttributes"
|
||||
>
|
||||
<a-icon type="search" slot="suffix" />
|
||||
</a-input>
|
||||
</template>
|
||||
</vxe-toolbar>
|
||||
|
||||
<a-spin :spinning="loading">
|
||||
<vxe-table
|
||||
|
@@ -178,7 +178,7 @@
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
<a v-if="!isEdit && !attr.is_computed && !attr.sys_computed && showEdit" @click="handleEdit" :style="{ opacity: 0 }"><a-icon type="edit"/></a>
|
||||
<a v-if="!isEdit && !attr.is_computed && !attr.sys_computed" @click="handleEdit" :style="{ opacity: 0 }"><a-icon type="edit"/></a>
|
||||
<JsonEditor ref="jsonEditor" @jsonEditorOk="jsonEditorOk" />
|
||||
</span>
|
||||
</template>
|
||||
@@ -204,10 +204,6 @@ export default {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
showEdit: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@@ -45,7 +45,7 @@
|
||||
:href="`/cmdb/cidetail/${column.params.attr.reference_type_id}/${id}`"
|
||||
target="_blank"
|
||||
>
|
||||
{{ getReferenceName(id, column) }}
|
||||
{{ id }}
|
||||
</a>
|
||||
</template>
|
||||
<template #operation_default="{ row }">
|
||||
@@ -102,7 +102,7 @@
|
||||
:href="`/cmdb/cidetail/${column.params.attr.reference_type_id}/${id}`"
|
||||
target="_blank"
|
||||
>
|
||||
{{ getReferenceName(id, column) }}
|
||||
{{ id }}
|
||||
</a>
|
||||
</template>
|
||||
<template #operation_default="{ row }">
|
||||
@@ -133,11 +133,9 @@
|
||||
import _ from 'lodash'
|
||||
import { getCITypeChildren, getCITypeParent, getCanEditByParentIdChildId } from '@/modules/cmdb/api/CITypeRelation'
|
||||
import { searchCIRelation, deleteCIRelationView } from '@/modules/cmdb/api/CIRelation'
|
||||
import { searchCI } from '@/modules/cmdb/api/ci'
|
||||
import CiDetailRelationTopo from './ciDetailRelationTopo/index.vue'
|
||||
import Node from './ciDetailRelationTopo/node.js'
|
||||
import AddTableModal from '../../relation_views/modules/AddTableModal.vue'
|
||||
|
||||
export default {
|
||||
name: 'CiDetailRelation',
|
||||
components: { CiDetailRelationTopo, AddTableModal },
|
||||
@@ -174,8 +172,7 @@ export default {
|
||||
topoData: {
|
||||
nodes: {},
|
||||
edges: []
|
||||
},
|
||||
referenceCINameMap: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -214,14 +211,9 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async init(isFirst) {
|
||||
const ci_types_list = this.ci_types()
|
||||
const _findCiType = ci_types_list.find((item) => item.id === this.typeId)
|
||||
if (!_findCiType) {
|
||||
return
|
||||
}
|
||||
|
||||
await Promise.all([this.getParentCITypes(), this.getChildCITypes()])
|
||||
Promise.all([this.getFirstCIs(), this.getSecondCIs()]).then(() => {
|
||||
const ci_types_list = this.ci_types()
|
||||
this.handleTopoData()
|
||||
if (
|
||||
isFirst &&
|
||||
@@ -231,8 +223,6 @@ export default {
|
||||
this.$refs.ciDetailRelationTopo.exsited_ci = this.exsited_ci
|
||||
this.$refs.ciDetailRelationTopo.setTopoData(this.topoData)
|
||||
}
|
||||
|
||||
this.handleReferenceCINameMap()
|
||||
})
|
||||
},
|
||||
async getFirstCIs() {
|
||||
@@ -404,98 +394,6 @@ export default {
|
||||
this.secondCIColumns = secondCIColumns
|
||||
this.secondCIJsonAttr = secondCIJsonAttr
|
||||
},
|
||||
|
||||
async handleReferenceCINameMap() {
|
||||
const CITypes = _.unionBy(
|
||||
[
|
||||
...this.parentCITypes,
|
||||
...this.childCITypes
|
||||
],
|
||||
'id'
|
||||
)
|
||||
const CIList = _.unionBy(
|
||||
_.flatten(
|
||||
[
|
||||
...Object.values(this.firstCIs),
|
||||
...Object.values(this.secondCIs)
|
||||
]
|
||||
),
|
||||
'_id'
|
||||
)
|
||||
|
||||
const CIMap = {}
|
||||
CIList.forEach((ci) => {
|
||||
if (!CIMap[ci._type]) {
|
||||
CIMap[ci._type] = []
|
||||
}
|
||||
CIMap[ci._type].push(ci)
|
||||
})
|
||||
|
||||
const referenceCINameMap = {}
|
||||
CITypes.forEach((CIType) => {
|
||||
CIType.attributes.forEach((attr) => {
|
||||
if (attr?.is_reference && attr?.reference_type_id) {
|
||||
const currentCIList = CIMap[CIType.id]
|
||||
if (currentCIList?.length) {
|
||||
currentCIList.forEach((ci) => {
|
||||
const ids = Array.isArray(ci[attr.name]) ? ci[attr.name] : ci[attr.name] ? [ci[attr.name]] : []
|
||||
|
||||
if (ids.length) {
|
||||
if (!referenceCINameMap?.[attr.reference_type_id]) {
|
||||
referenceCINameMap[attr.reference_type_id] = {}
|
||||
}
|
||||
ids.forEach((id) => {
|
||||
referenceCINameMap[attr.reference_type_id][id] = ''
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (!Object.keys(referenceCINameMap).length) {
|
||||
return
|
||||
}
|
||||
|
||||
const allRes = await Promise.all(
|
||||
Object.keys(referenceCINameMap).map((key) => {
|
||||
return searchCI({
|
||||
q: `_type:${key},_id:(${Object.keys(referenceCINameMap[key]).join(';')})`,
|
||||
count: 9999
|
||||
})
|
||||
})
|
||||
)
|
||||
const CITypeList = this.ci_types()
|
||||
const showNameMap = {}
|
||||
|
||||
Object.keys(referenceCINameMap).forEach((id) => {
|
||||
const CIType = CITypeList.find((CIType) => Number(CIType.id) === Number(id))
|
||||
|
||||
showNameMap[id] = {
|
||||
show_name: CIType?.show_name,
|
||||
unique_key: CIType?.unique_key
|
||||
}
|
||||
})
|
||||
|
||||
allRes.forEach((res) => {
|
||||
res.result.forEach((item) => {
|
||||
if (referenceCINameMap?.[item._type]?.[item._id] === '') {
|
||||
const showName = showNameMap?.[item._type]
|
||||
|
||||
referenceCINameMap[item._type][item._id] = item?.[showName?.show_name] ?? item?.[showName?.unique_key] ?? ''
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
this.referenceCINameMap = referenceCINameMap
|
||||
},
|
||||
|
||||
getReferenceName(id, column) {
|
||||
const typeId = column?.params?.attr?.reference_type_id
|
||||
return this.referenceCINameMap?.[typeId]?.[id] || id
|
||||
},
|
||||
|
||||
reload() {
|
||||
this.init()
|
||||
},
|
||||
|
@@ -33,8 +33,8 @@
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="tab_3">
|
||||
<span slot="tab"><a-icon type="clock-circle" />{{ $t('cmdb.ci.history') }}</span>
|
||||
<div :style="{ padding: '16px 24px 24px', height: '100%' }">
|
||||
<a-space :style="{ marginBottom: '16px', display: 'flex' }">
|
||||
<div :style="{ padding: '24px', height: '100%' }">
|
||||
<a-space :style="{ 'margin-bottom': '10px', display: 'flex' }">
|
||||
<a-button type="primary" class="ops-button-ghost" ghost @click="handleRollbackCI()">
|
||||
<ops-icon type="shishizhuangtai" />{{ $t('cmdb.ci.rollback') }}
|
||||
</a-button>
|
||||
@@ -180,7 +180,7 @@ export default {
|
||||
ci_types: [],
|
||||
hasPermission: true,
|
||||
itsmInstalled: true,
|
||||
tableHeight: this.attributeHistoryTableHeight || (this.$store.state.windowHeight - 130),
|
||||
tableHeight: this.attributeHistoryTableHeight || (this.$store.state.windowHeight - 120),
|
||||
initQueryLoading: true,
|
||||
}
|
||||
},
|
||||
|
@@ -61,20 +61,16 @@ export default {
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: @text-color_2;
|
||||
background-color: @primary-color_7;
|
||||
color: #4E5969;
|
||||
background-color: #F7F8FA;
|
||||
width: 105px;
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
|
||||
&-active {
|
||||
border: solid 1px @primary-color_8;
|
||||
background-color: @primary-color_4;
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
border: solid 1px #B1C9FF;
|
||||
background-color: #E1EFFF;
|
||||
color: #2F54EB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -154,17 +154,6 @@ export default {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: @primary-color_5;
|
||||
|
||||
.attr-ad-tab-edit {
|
||||
display: inline-block;
|
||||
}
|
||||
.attr-ad-tab-delete {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
&_active {
|
||||
border: solid 1px @primary-color_8;
|
||||
background-color: @primary-color_6;
|
||||
@@ -172,9 +161,14 @@ export default {
|
||||
.attr-ad-tab-name {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: @primary-color_6;
|
||||
&:hover {
|
||||
.attr-ad-tab-edit {
|
||||
display: inline-block;
|
||||
}
|
||||
.attr-ad-tab-delete {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,11 +178,6 @@ export default {
|
||||
background-color: @primary-color_7;
|
||||
font-size: 12px;
|
||||
color: @text-color_4;
|
||||
|
||||
&:hover {
|
||||
background-color: @primary-color_5;
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -3,14 +3,12 @@
|
||||
<div class="attr-ad-header attr-ad-header-margin">{{ $t('cmdb.ciType.configCheckTitle') }}</div>
|
||||
<div class="attr-ad-content">
|
||||
<div class="ad-test-title-info">{{ $t('cmdb.ciType.checkTestTip') }}</div>
|
||||
<a-button
|
||||
type="primary"
|
||||
class="ops-button-ghost ad-test-btn"
|
||||
ghost
|
||||
<div
|
||||
class="ad-test-btn"
|
||||
@click="showCheckModal"
|
||||
>
|
||||
{{ $t('cmdb.ciType.checkTestBtn') }}
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="ad-test-btn-info">{{ $t('cmdb.ciType.checkTestTip2') }}</div>
|
||||
<!-- <div
|
||||
class="ad-test-btn"
|
||||
@@ -142,6 +140,15 @@ export default {
|
||||
|
||||
.ad-test-btn {
|
||||
margin-top: 30px;
|
||||
padding: 5px 12px;
|
||||
background-color: #F4F9FF;
|
||||
border: solid 1px @primary-color_8;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
|
||||
color: @link-color;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.ad-test-btn-info {
|
||||
|
@@ -1194,7 +1194,7 @@ export default {
|
||||
.selected {
|
||||
background-color: @primary-color_3;
|
||||
.ci-types-left-detail-title {
|
||||
color: @primary-color;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -61,11 +61,13 @@
|
||||
:disable-branch-nodes="true"
|
||||
:class="{
|
||||
'custom-treeselect': true,
|
||||
'custom-treeselect-white': true,
|
||||
'custom-treeselect-bgcAndBorder': true,
|
||||
}"
|
||||
:style="{
|
||||
'--custom-height': '32px',
|
||||
lineHeight: '32px',
|
||||
'--custom-bg-color': '#fff',
|
||||
'--custom-border': '1px solid #d9d9d9',
|
||||
'--custom-multiple-lineHeight': '14px',
|
||||
}"
|
||||
v-model="choice_other.type_ids"
|
||||
|
@@ -688,19 +688,19 @@ export default {
|
||||
font-size: 12px;
|
||||
color: #A5A9BC;
|
||||
}
|
||||
</style>
|
||||
|
||||
.ops-stripe-table {
|
||||
/deep/ .relation-table-divider {
|
||||
background-color: #b1b8d3 !important;
|
||||
|
||||
td {
|
||||
height: 2px !important;
|
||||
line-height: 2px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .relation-table-parent {
|
||||
background-color: #f5f8ff !important;
|
||||
<style lang="less">
|
||||
.ops-stripe-table .vxe-body--row.row--stripe.relation-table-divider {
|
||||
background-color: #b1b8d3 !important;
|
||||
}
|
||||
.ops-stripe-table .vxe-body--row.relation-table-parent {
|
||||
background-color: #f5f8ff !important;
|
||||
}
|
||||
.relation-table-divider {
|
||||
td {
|
||||
height: 1px !important;
|
||||
line-height: 1px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -198,11 +198,13 @@
|
||||
:disable-branch-nodes="true"
|
||||
:class="{
|
||||
'custom-treeselect': true,
|
||||
'custom-treeselect-white': true,
|
||||
'custom-treeselect-bgcAndBorder': true,
|
||||
}"
|
||||
:style="{
|
||||
'--custom-height': '32px',
|
||||
lineHeight: '32px',
|
||||
'--custom-bg-color': '#fff',
|
||||
'--custom-border': '1px solid #d9d9d9',
|
||||
'--custom-multiple-lineHeight': '14px',
|
||||
}"
|
||||
v-model="selectedBot"
|
||||
@@ -240,18 +242,6 @@
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-checkbox-group>
|
||||
|
||||
<a-row v-if="category === 2">
|
||||
<a-button
|
||||
@click="clickTestSend"
|
||||
:disabled="!dateForm.attr_id"
|
||||
type="primary"
|
||||
ghost
|
||||
class="ops-button-ghost"
|
||||
>
|
||||
{{ $t('cmdb.ciType.testSend') }}
|
||||
</a-button>
|
||||
</a-row>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
<div class="auto-complete-wrapper" v-if="triggerAction === '3'">
|
||||
@@ -283,7 +273,7 @@
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import { addTrigger, updateTrigger, deleteTrigger, testTrigger } from '../../api/CIType'
|
||||
import { addTrigger, updateTrigger, deleteTrigger } from '../../api/CIType'
|
||||
import FilterComp from '@/components/CMDBFilterComp'
|
||||
import EmployeeTreeSelect from '@/views/setting/components/employeeTreeSelect.vue'
|
||||
import Webhook from '../../components/webhook'
|
||||
@@ -579,13 +569,10 @@ export default {
|
||||
}
|
||||
if (this.triggerId) {
|
||||
await updateTrigger(this.CITypeId, this.triggerId, params)
|
||||
this.$message.success(this.$t('editSuccess'))
|
||||
} else {
|
||||
const res = await addTrigger(this.CITypeId, params)
|
||||
this.triggerId = res.id
|
||||
this.$message.success(this.$t('createSuccess'))
|
||||
await addTrigger(this.CITypeId, params)
|
||||
}
|
||||
|
||||
this.handleCancel()
|
||||
if (this.refresh) {
|
||||
this.refresh()
|
||||
}
|
||||
@@ -627,15 +614,6 @@ export default {
|
||||
this.searchValue = item.label
|
||||
this.dag_id = item.id
|
||||
},
|
||||
async clickTestSend() {
|
||||
if (!this.triggerId) {
|
||||
this.$message.warning(this.$t('cmdb.ciType.testSendTip'))
|
||||
return
|
||||
}
|
||||
|
||||
await testTrigger(this.CITypeId, this.triggerId)
|
||||
this.$message.success(this.$t('cmdb.ciType.testSendSuccess'))
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
@@ -195,14 +195,12 @@
|
||||
</template>
|
||||
</div>
|
||||
<a-form-model-item
|
||||
:label="$t('cmdb.custom_dashboard.showIcon')"
|
||||
prop="showIcon"
|
||||
:label-col="{ span: 0 }"
|
||||
:wrapper-col="{ span: 23 }"
|
||||
:label-col="{ span: 5 }"
|
||||
:wrapper-col="{ span: 18 }"
|
||||
>
|
||||
<div class="chart-left-show-icon">
|
||||
<span class="chart-left-show-icon-label">{{ $t('cmdb.custom_dashboard.showIcon') }}:</span>
|
||||
<a-switch v-model="form.showIcon"></a-switch>
|
||||
</div>
|
||||
<a-switch v-model="form.showIcon"></a-switch>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</div>
|
||||
@@ -735,9 +733,6 @@ export default {
|
||||
width: 92%;
|
||||
position: relative;
|
||||
padding: 12px;
|
||||
margin-top: 4px;
|
||||
display: inline-block;
|
||||
|
||||
.chart-left-preview-operation {
|
||||
color: #86909c;
|
||||
position: absolute;
|
||||
@@ -758,26 +753,12 @@ export default {
|
||||
background-position-x: center;
|
||||
background-position-y: center;
|
||||
}
|
||||
|
||||
&-show-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&-label {
|
||||
flex-shrink: 0;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.chart-right {
|
||||
width: 50%;
|
||||
h4 {
|
||||
font-weight: 700;
|
||||
color: #000;
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top: 14px;
|
||||
}
|
||||
}
|
||||
.chart-right-type {
|
||||
display: flex;
|
||||
@@ -816,7 +797,7 @@ export default {
|
||||
<style lang="less">
|
||||
.chart-wrapper {
|
||||
.ant-form-item {
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -1,331 +0,0 @@
|
||||
<template>
|
||||
<a-modal
|
||||
:visible="visible"
|
||||
:width="700"
|
||||
:title="$t(modalTitle)"
|
||||
:confirmLoading="confirmLoading"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-form-model
|
||||
ref="dcimFormRef"
|
||||
:model="form"
|
||||
:rules="formRules"
|
||||
:label-col="{ span: 6 }"
|
||||
:wrapper-col="{ span: 18 }"
|
||||
class="dcim-form"
|
||||
>
|
||||
<a-form-model-item
|
||||
v-for="(item) in formList"
|
||||
:key="item.name"
|
||||
:label="item.alias || item.name"
|
||||
:prop="item.name"
|
||||
>
|
||||
<CIReferenceAttr
|
||||
v-if="item.is_reference"
|
||||
:referenceTypeId="item.reference_type_id"
|
||||
:isList="item.is_list"
|
||||
:referenceShowAttrName="item.showAttrName"
|
||||
:initSelectOption="getInitReferenceSelectOption(item)"
|
||||
v-model="form[item.name]"
|
||||
/>
|
||||
<a-select
|
||||
v-else-if="item.is_choice"
|
||||
:mode="item.is_list ? 'multiple' : 'default'"
|
||||
showSearch
|
||||
allowClear
|
||||
v-model="form[item.name]"
|
||||
>
|
||||
<a-icon slot="suffixIcon" type="caret-down" />
|
||||
<a-select-option
|
||||
v-for="(choiceItem, choiceIndex) in item.selectOption"
|
||||
:key="choiceIndex"
|
||||
:value="choiceItem.value"
|
||||
>
|
||||
{{ choiceItem.label }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-switch
|
||||
v-else-if="item.is_bool"
|
||||
v-model="form[item.name]"
|
||||
/>
|
||||
|
||||
<a-input-number
|
||||
v-model="form[item.name]"
|
||||
class="dcim-form-input"
|
||||
v-else-if="(item.value_type === '0' || item.value_type === '1') && !item.is_list"
|
||||
/>
|
||||
|
||||
<a-date-picker
|
||||
v-else-if="(item.value_type === '4' || item.value_type === '3') && !item.is_list"
|
||||
v-model="form[item.name]"
|
||||
class="dcim-form-input"
|
||||
:format="item.value_type === '4' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
|
||||
:valueFormat="item.value_type === '4' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
|
||||
:showTime="item.value_type === '4' ? false : { format: 'HH:mm:ss' }"
|
||||
/>
|
||||
|
||||
<a-input
|
||||
v-else
|
||||
:placeholder="$t('placeholder1')"
|
||||
v-model="form[item.name]"
|
||||
/>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import { postDCIM, putDCIM } from '@/modules/cmdb/api/dcim.js'
|
||||
import { getCITypes } from '@/modules/cmdb/api/CIType'
|
||||
import { searchCI } from '@/modules/cmdb/api/ci'
|
||||
import { DCIM_TYPE } from '../constants'
|
||||
|
||||
import CIReferenceAttr from '@/components/ciReferenceAttr/index.vue'
|
||||
|
||||
export default {
|
||||
name: 'DCIMForm',
|
||||
components: {
|
||||
CIReferenceAttr
|
||||
},
|
||||
props: {
|
||||
allAttrList: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
nodeId: null,
|
||||
parentId: null,
|
||||
dcimType: '',
|
||||
|
||||
formList: [],
|
||||
form: {},
|
||||
formRules: {},
|
||||
|
||||
confirmLoading: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
modalTitle() {
|
||||
switch (this.dcimType) {
|
||||
case DCIM_TYPE.REGION:
|
||||
return this.nodeId ? 'cmdb.dcim.editRegion' : 'cmdb.dcim.addRegion'
|
||||
case DCIM_TYPE.IDC:
|
||||
return this.nodeId ? 'cmdb.dcim.editIDC' : 'cmdb.dcim.addIDC'
|
||||
case DCIM_TYPE.SERVER_ROOM:
|
||||
return this.nodeId ? 'cmdb.dcim.editServerRoom' : 'cmdb.dcim.addServerRoom'
|
||||
case DCIM_TYPE.RACK:
|
||||
return this.nodeId ? 'cmdb.dcim.editRack' : 'cmdb.dcim.addRack'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async open({
|
||||
nodeId = null,
|
||||
parentId = null,
|
||||
dcimType = ''
|
||||
}) {
|
||||
this.nodeId = nodeId
|
||||
|
||||
let nodeData = {}
|
||||
if (nodeId) {
|
||||
const res = await searchCI({
|
||||
q: `_id:${nodeId}`,
|
||||
count: 9999
|
||||
})
|
||||
nodeData = res?.result?.[0] || {}
|
||||
}
|
||||
|
||||
this.parentId = parentId
|
||||
this.dcimType = dcimType
|
||||
this.visible = true
|
||||
|
||||
const form = {}
|
||||
const formRules = {}
|
||||
let formList = []
|
||||
|
||||
let attrList = _.cloneDeep(this.allAttrList?.[dcimType]?.attributes)
|
||||
attrList = attrList?.filter?.((attr) => !attr.sys_computed && !attr.is_computed) || []
|
||||
|
||||
if (attrList.length) {
|
||||
attrList.forEach((attr) => {
|
||||
let value = nodeData?.[attr.name] ?? attr?.default?.default ?? undefined
|
||||
|
||||
if (
|
||||
Array.isArray(value) &&
|
||||
['0', '1', '2', '9'].includes(attr.value_type)
|
||||
) {
|
||||
value = value.join(',')
|
||||
}
|
||||
form[attr.name] = value
|
||||
|
||||
if (attr?.is_choice) {
|
||||
const choice_value = attr?.choice_value || []
|
||||
attr.selectOption = choice_value.map((item) => {
|
||||
return {
|
||||
label: item?.[1]?.label || item?.[0] || '',
|
||||
value: item?.[0]
|
||||
}
|
||||
})
|
||||
}
|
||||
formList.push(attr)
|
||||
|
||||
if (attr.is_required) {
|
||||
formRules[attr.name] = [
|
||||
{
|
||||
required: true, message: attr?.is_choice ? this.$t('placeholder2') : this.$t('placeholder1')
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
formList = await this.handleReferenceAttr(formList, form)
|
||||
|
||||
this.form = form
|
||||
this.formList = formList
|
||||
this.formRules = formRules
|
||||
},
|
||||
|
||||
async handleReferenceAttr(formList, ci) {
|
||||
const map = {}
|
||||
formList.forEach((attr) => {
|
||||
if (attr?.is_reference && attr?.reference_type_id && ci[attr.name]) {
|
||||
const ids = Array.isArray(ci[attr.name]) ? ci[attr.name] : ci[attr.name] ? [ci[attr.name]] : []
|
||||
if (ids.length) {
|
||||
if (!map?.[attr.reference_type_id]) {
|
||||
map[attr.reference_type_id] = {}
|
||||
}
|
||||
ids.forEach((id) => {
|
||||
map[attr.reference_type_id][id] = {}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
if (!Object.keys(map).length) {
|
||||
return formList
|
||||
}
|
||||
|
||||
const ciTypesRes = await getCITypes({
|
||||
type_ids: Object.keys(map).join(',')
|
||||
})
|
||||
const showAttrNameMap = {}
|
||||
ciTypesRes.ci_types.forEach((ciType) => {
|
||||
showAttrNameMap[ciType.id] = ciType?.show_name || ciType?.unique_name || ''
|
||||
})
|
||||
|
||||
const allRes = await Promise.all(
|
||||
Object.keys(map).map((key) => {
|
||||
return searchCI({
|
||||
q: `_type:${key},_id:(${Object.keys(map[key]).join(';')})`,
|
||||
count: 9999
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
const ciNameMap = {}
|
||||
allRes.forEach((res) => {
|
||||
res.result.forEach((item) => {
|
||||
ciNameMap[item._id] = item
|
||||
})
|
||||
})
|
||||
|
||||
formList.forEach((attr) => {
|
||||
if (attr?.is_reference && attr?.reference_type_id) {
|
||||
attr.showAttrName = showAttrNameMap?.[attr?.reference_type_id] || ''
|
||||
|
||||
const referenceShowAttrNameMap = {}
|
||||
const referenceCIIds = ci[attr.name];
|
||||
(Array.isArray(referenceCIIds) ? referenceCIIds : referenceCIIds ? [referenceCIIds] : []).forEach((id) => {
|
||||
referenceShowAttrNameMap[id] = ciNameMap?.[id]?.[attr.showAttrName] ?? id
|
||||
})
|
||||
attr.referenceShowAttrNameMap = referenceShowAttrNameMap
|
||||
}
|
||||
})
|
||||
|
||||
return formList
|
||||
},
|
||||
|
||||
handleCancel() {
|
||||
this.visible = false
|
||||
this.nodeId = null
|
||||
this.parentId = null
|
||||
this.dcimType = ''
|
||||
this.form = {}
|
||||
this.formRules = {}
|
||||
this.formList = []
|
||||
this.confirmLoading = false
|
||||
|
||||
this.$refs.dcimFormRef.clearValidate()
|
||||
},
|
||||
|
||||
handleOk() {
|
||||
this.$refs.dcimFormRef.validate(async (valid) => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
this.confirmLoading = true
|
||||
|
||||
try {
|
||||
if (this.nodeId) {
|
||||
await putDCIM(
|
||||
this.dcimType,
|
||||
this.nodeId,
|
||||
{
|
||||
...this.form,
|
||||
parent_id: Number(this.parentId)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
await postDCIM(
|
||||
this.dcimType,
|
||||
{
|
||||
...this.form,
|
||||
parent_id: Number(this.parentId)
|
||||
}
|
||||
)
|
||||
}
|
||||
this.$emit('ok', {
|
||||
dcimType: this.dcimType,
|
||||
editType: this.nodeId ? 'edit' : 'create'
|
||||
})
|
||||
this.handleCancel()
|
||||
} catch (error) {
|
||||
console.log('submit fail', error)
|
||||
}
|
||||
|
||||
this.confirmLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
getInitReferenceSelectOption(attr) {
|
||||
const option = Object.keys(attr?.referenceShowAttrNameMap || {}).map((key) => {
|
||||
return {
|
||||
key: Number(key),
|
||||
title: attr?.referenceShowAttrNameMap?.[Number(key)] ?? ''
|
||||
}
|
||||
})
|
||||
return option
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.dcim-form {
|
||||
padding-right: 12px;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
|
||||
&-input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -1,184 +0,0 @@
|
||||
<template>
|
||||
<div class="dcim-stats">
|
||||
<div
|
||||
v-for="(item, index) in statsList"
|
||||
:key="index"
|
||||
class="dcim-stats-card"
|
||||
>
|
||||
<div class="dcim-stats-card-left">
|
||||
<div class="dcim-stat-card-title">{{ $t(item.title) }}</div>
|
||||
|
||||
<div class="dcim-stats-card-row">
|
||||
<div
|
||||
v-for="(data, dataIndex) in item.countList"
|
||||
:key="dataIndex"
|
||||
class="dcim-stats-card-count"
|
||||
>
|
||||
<span class="dcim-stats-card-count-label">{{ $t(data.label) }}:</span>
|
||||
<span class="dcim-stats-card-count-value">{{ data.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="item.icon"
|
||||
class="dcim-stats-card-icon"
|
||||
>
|
||||
<ops-icon
|
||||
:type="item.icon"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<DCIMStatsChart
|
||||
v-else-if="item.chartData"
|
||||
:chartData="item.chartData"
|
||||
:chartRatio="item.chartRatio"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DCIMStatsChart from './dcimStatsChart.vue'
|
||||
|
||||
export default {
|
||||
name: 'DCIMStats',
|
||||
props: {
|
||||
statsData: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
DCIMStatsChart
|
||||
},
|
||||
computed: {
|
||||
statsList() {
|
||||
const {
|
||||
device_count = 0,
|
||||
rack_count = 0,
|
||||
u_count = 0,
|
||||
u_used_count = 0,
|
||||
} = this.statsData || {}
|
||||
|
||||
return [
|
||||
{
|
||||
title: 'cmdb.dcim.rackCount',
|
||||
icon: 'veops-cabinet',
|
||||
countList: [
|
||||
{
|
||||
label: 'cmdb.dcim.total',
|
||||
value: rack_count
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'cmdb.dcim.deviceCount',
|
||||
icon: 'veops-device',
|
||||
countList: [
|
||||
{
|
||||
label: 'cmdb.dcim.total',
|
||||
value: device_count
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'cmdb.dcim.utilizationRation',
|
||||
countList: [
|
||||
{
|
||||
label: 'cmdb.dcim.used',
|
||||
value: `${u_used_count}u`
|
||||
},
|
||||
{
|
||||
label: 'cmdb.dcim.unused',
|
||||
value: `${u_count - u_used_count}u`
|
||||
}
|
||||
],
|
||||
chartRatio: u_used_count > 0 && u_count > 0 ? Math.round((u_used_count / u_count) * 100) : 0,
|
||||
chartData: [
|
||||
{
|
||||
label: 'cmdb.dcim.used',
|
||||
value: u_used_count,
|
||||
color: '#009FA9'
|
||||
},
|
||||
{
|
||||
label: 'cmdb.dcim.unused',
|
||||
value: u_count - u_used_count,
|
||||
color: '#17D4B0'
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.dcim-stats {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
column-gap: 16px;
|
||||
flex-shrink: 0;
|
||||
|
||||
&-card {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 14px 24px;
|
||||
background-color: #F7F8FA;
|
||||
filter: drop-shadow(0px 0px 12px rgba(231, 236, 239, 0.10));
|
||||
|
||||
&-left {
|
||||
width: 100%;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
&-title {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #4E5969;
|
||||
}
|
||||
|
||||
&-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 12px;
|
||||
column-gap: 12px;
|
||||
}
|
||||
|
||||
&-count {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
||||
&-label {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #1D2129;
|
||||
}
|
||||
|
||||
&-value {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #1D2129;
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
&-icon {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
border-radius: 52px;
|
||||
background-color: #FFFFFF;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|