mirror of
https://github.com/veops/cmdb.git
synced 2025-09-06 05:17:03 +08:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e93d894f04 | ||
|
081f35816f | ||
|
a8fadb2785 | ||
|
72c37c995d | ||
|
f8fbbe4b9a | ||
|
155ba67ecc | ||
|
9c67b1e56a | ||
|
88df3355d8 | ||
|
549056a42d | ||
|
365fdf2bab | ||
|
6bf01786d8 | ||
|
e180f549c8 | ||
|
3a7f4a31d0 |
37
cmdb-api/api/views/common_setting/system_language.py
Normal file
37
cmdb-api/api/views/common_setting/system_language.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import os
|
||||
|
||||
from api.resource import APIView
|
||||
from api.lib.perm.auth import auth_abandoned
|
||||
|
||||
prefix = "/system"
|
||||
|
||||
|
||||
class SystemLanguageView(APIView):
|
||||
url_prefix = (f"{prefix}/language",)
|
||||
|
||||
method_decorators = []
|
||||
|
||||
@auth_abandoned
|
||||
def get(self):
|
||||
"""Get system default language
|
||||
Read from environment variable SYSTEM_DEFAULT_LANGUAGE, default to Chinese if not set
|
||||
"""
|
||||
default_language = os.environ.get("SYSTEM_DEFAULT_LANGUAGE", "")
|
||||
|
||||
return self.jsonify(
|
||||
{
|
||||
"language": default_language,
|
||||
"language_name": self._get_language_name(default_language),
|
||||
}
|
||||
)
|
||||
|
||||
def _get_language_name(self, language_code):
|
||||
"""Return language name based on language code"""
|
||||
language_mapping = {
|
||||
"zh-CN": "中文(简体)",
|
||||
"zh-TW": "中文(繁体)",
|
||||
"en-US": "English",
|
||||
"ja-JP": "日本語",
|
||||
"ko-KR": "한국어",
|
||||
}
|
||||
return language_mapping.get(language_code, "")
|
@@ -54,6 +54,150 @@
|
||||
<div class="content unicode" style="display: block;">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">onterm-symbolic_link</div>
|
||||
<div class="code-name">&#xea23;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">oneterm-batch_execution</div>
|
||||
<div class="code-name">&#xea20;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">oneterm-file_log-selected</div>
|
||||
<div class="code-name">&#xea21;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">oneterm-file_log</div>
|
||||
<div class="code-name">&#xea22;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">file</div>
|
||||
<div class="code-name">&#xea1f;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">folder</div>
|
||||
<div class="code-name">&#xea1e;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">mongoDB (1)</div>
|
||||
<div class="code-name">&#xea1b;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">postgreSQL (1)</div>
|
||||
<div class="code-name">&#xea1c;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">telnet (1)</div>
|
||||
<div class="code-name">&#xea1d;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">command_interception (1)</div>
|
||||
<div class="code-name">&#xea17;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">quick_commands</div>
|
||||
<div class="code-name">&#xea18;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">terminal_settings</div>
|
||||
<div class="code-name">&#xea19;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">basic_settings</div>
|
||||
<div class="code-name">&#xea1a;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">asset_management</div>
|
||||
<div class="code-name">&#xea16;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">ai-seek</div>
|
||||
<div class="code-name">&#xea15;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">ai-hate1</div>
|
||||
<div class="code-name">&#xea13;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">ai-like1</div>
|
||||
<div class="code-name">&#xea14;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">ai-like2</div>
|
||||
<div class="code-name">&#xea11;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">ai-hate2</div>
|
||||
<div class="code-name">&#xea12;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">ai-top_up</div>
|
||||
<div class="code-name">&#xea10;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">ai-top_down</div>
|
||||
<div class="code-name">&#xea0f;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">autoflow-script</div>
|
||||
<div class="code-name">&#xea0d;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">autoflow-dag</div>
|
||||
<div class="code-name">&#xea0e;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">itsm-default_line</div>
|
||||
<div class="code-name">&#xea0c;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">veops-servicetree</div>
|
||||
@@ -6210,9 +6354,9 @@
|
||||
<pre><code class="language-css"
|
||||
>@font-face {
|
||||
font-family: 'iconfont';
|
||||
src: url('iconfont.woff2?t=1735191938771') format('woff2'),
|
||||
url('iconfont.woff?t=1735191938771') format('woff'),
|
||||
url('iconfont.ttf?t=1735191938771') format('truetype');
|
||||
src: url('iconfont.woff2?t=1749393321370') format('woff2'),
|
||||
url('iconfont.woff?t=1749393321370') format('woff'),
|
||||
url('iconfont.ttf?t=1749393321370') format('truetype');
|
||||
}
|
||||
</code></pre>
|
||||
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
||||
@@ -6238,6 +6382,222 @@
|
||||
<div class="content font-class">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont onterm-symbolic_link"></span>
|
||||
<div class="name">
|
||||
onterm-symbolic_link
|
||||
</div>
|
||||
<div class="code-name">.onterm-symbolic_link
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont oneterm-batch_execution"></span>
|
||||
<div class="name">
|
||||
oneterm-batch_execution
|
||||
</div>
|
||||
<div class="code-name">.oneterm-batch_execution
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont ops-oneterm-file_log-selected"></span>
|
||||
<div class="name">
|
||||
oneterm-file_log-selected
|
||||
</div>
|
||||
<div class="code-name">.ops-oneterm-file_log-selected
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont ops-oneterm-file_log"></span>
|
||||
<div class="name">
|
||||
oneterm-file_log
|
||||
</div>
|
||||
<div class="code-name">.ops-oneterm-file_log
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont file"></span>
|
||||
<div class="name">
|
||||
file
|
||||
</div>
|
||||
<div class="code-name">.file
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont folder1"></span>
|
||||
<div class="name">
|
||||
folder
|
||||
</div>
|
||||
<div class="code-name">.folder1
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont a-mongoDB1"></span>
|
||||
<div class="name">
|
||||
mongoDB (1)
|
||||
</div>
|
||||
<div class="code-name">.a-mongoDB1
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont a-postgreSQL1"></span>
|
||||
<div class="name">
|
||||
postgreSQL (1)
|
||||
</div>
|
||||
<div class="code-name">.a-postgreSQL1
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont a-telnet1"></span>
|
||||
<div class="name">
|
||||
telnet (1)
|
||||
</div>
|
||||
<div class="code-name">.a-telnet1
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont a-command_interception1"></span>
|
||||
<div class="name">
|
||||
command_interception (1)
|
||||
</div>
|
||||
<div class="code-name">.a-command_interception1
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont quick_commands"></span>
|
||||
<div class="name">
|
||||
quick_commands
|
||||
</div>
|
||||
<div class="code-name">.quick_commands
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont terminal_settings"></span>
|
||||
<div class="name">
|
||||
terminal_settings
|
||||
</div>
|
||||
<div class="code-name">.terminal_settings
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont basic_settings"></span>
|
||||
<div class="name">
|
||||
basic_settings
|
||||
</div>
|
||||
<div class="code-name">.basic_settings
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont ops-oneterm-asset-management"></span>
|
||||
<div class="name">
|
||||
asset_management
|
||||
</div>
|
||||
<div class="code-name">.ops-oneterm-asset-management
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont ai-seek"></span>
|
||||
<div class="name">
|
||||
ai-seek
|
||||
</div>
|
||||
<div class="code-name">.ai-seek
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont ai-hate1"></span>
|
||||
<div class="name">
|
||||
ai-hate1
|
||||
</div>
|
||||
<div class="code-name">.ai-hate1
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont ai-like1"></span>
|
||||
<div class="name">
|
||||
ai-like1
|
||||
</div>
|
||||
<div class="code-name">.ai-like1
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont ai-like2"></span>
|
||||
<div class="name">
|
||||
ai-like2
|
||||
</div>
|
||||
<div class="code-name">.ai-like2
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont ai-hate2"></span>
|
||||
<div class="name">
|
||||
ai-hate2
|
||||
</div>
|
||||
<div class="code-name">.ai-hate2
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont ai-top_up"></span>
|
||||
<div class="name">
|
||||
ai-top_up
|
||||
</div>
|
||||
<div class="code-name">.ai-top_up
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont ai-top_down"></span>
|
||||
<div class="name">
|
||||
ai-top_down
|
||||
</div>
|
||||
<div class="code-name">.ai-top_down
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont autoflow-script"></span>
|
||||
<div class="name">
|
||||
autoflow-script
|
||||
</div>
|
||||
<div class="code-name">.autoflow-script
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont autoflow-dag"></span>
|
||||
<div class="name">
|
||||
autoflow-dag
|
||||
</div>
|
||||
<div class="code-name">.autoflow-dag
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont itsm-default_line"></span>
|
||||
<div class="name">
|
||||
itsm-default_line
|
||||
</div>
|
||||
<div class="code-name">.itsm-default_line
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont veops-servicetree"></span>
|
||||
<div class="name">
|
||||
@@ -15472,6 +15832,198 @@
|
||||
<div class="content symbol">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#onterm-symbolic_link"></use>
|
||||
</svg>
|
||||
<div class="name">onterm-symbolic_link</div>
|
||||
<div class="code-name">#onterm-symbolic_link</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#oneterm-batch_execution"></use>
|
||||
</svg>
|
||||
<div class="name">oneterm-batch_execution</div>
|
||||
<div class="code-name">#oneterm-batch_execution</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#ops-oneterm-file_log-selected"></use>
|
||||
</svg>
|
||||
<div class="name">oneterm-file_log-selected</div>
|
||||
<div class="code-name">#ops-oneterm-file_log-selected</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#ops-oneterm-file_log"></use>
|
||||
</svg>
|
||||
<div class="name">oneterm-file_log</div>
|
||||
<div class="code-name">#ops-oneterm-file_log</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#file"></use>
|
||||
</svg>
|
||||
<div class="name">file</div>
|
||||
<div class="code-name">#file</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#folder1"></use>
|
||||
</svg>
|
||||
<div class="name">folder</div>
|
||||
<div class="code-name">#folder1</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#a-mongoDB1"></use>
|
||||
</svg>
|
||||
<div class="name">mongoDB (1)</div>
|
||||
<div class="code-name">#a-mongoDB1</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#a-postgreSQL1"></use>
|
||||
</svg>
|
||||
<div class="name">postgreSQL (1)</div>
|
||||
<div class="code-name">#a-postgreSQL1</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#a-telnet1"></use>
|
||||
</svg>
|
||||
<div class="name">telnet (1)</div>
|
||||
<div class="code-name">#a-telnet1</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#a-command_interception1"></use>
|
||||
</svg>
|
||||
<div class="name">command_interception (1)</div>
|
||||
<div class="code-name">#a-command_interception1</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#quick_commands"></use>
|
||||
</svg>
|
||||
<div class="name">quick_commands</div>
|
||||
<div class="code-name">#quick_commands</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#terminal_settings"></use>
|
||||
</svg>
|
||||
<div class="name">terminal_settings</div>
|
||||
<div class="code-name">#terminal_settings</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#basic_settings"></use>
|
||||
</svg>
|
||||
<div class="name">basic_settings</div>
|
||||
<div class="code-name">#basic_settings</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#ops-oneterm-asset-management"></use>
|
||||
</svg>
|
||||
<div class="name">asset_management</div>
|
||||
<div class="code-name">#ops-oneterm-asset-management</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#ai-seek"></use>
|
||||
</svg>
|
||||
<div class="name">ai-seek</div>
|
||||
<div class="code-name">#ai-seek</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#ai-hate1"></use>
|
||||
</svg>
|
||||
<div class="name">ai-hate1</div>
|
||||
<div class="code-name">#ai-hate1</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#ai-like1"></use>
|
||||
</svg>
|
||||
<div class="name">ai-like1</div>
|
||||
<div class="code-name">#ai-like1</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#ai-like2"></use>
|
||||
</svg>
|
||||
<div class="name">ai-like2</div>
|
||||
<div class="code-name">#ai-like2</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#ai-hate2"></use>
|
||||
</svg>
|
||||
<div class="name">ai-hate2</div>
|
||||
<div class="code-name">#ai-hate2</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#ai-top_up"></use>
|
||||
</svg>
|
||||
<div class="name">ai-top_up</div>
|
||||
<div class="code-name">#ai-top_up</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#ai-top_down"></use>
|
||||
</svg>
|
||||
<div class="name">ai-top_down</div>
|
||||
<div class="code-name">#ai-top_down</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#autoflow-script"></use>
|
||||
</svg>
|
||||
<div class="name">autoflow-script</div>
|
||||
<div class="code-name">#autoflow-script</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#autoflow-dag"></use>
|
||||
</svg>
|
||||
<div class="name">autoflow-dag</div>
|
||||
<div class="code-name">#autoflow-dag</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#itsm-default_line"></use>
|
||||
</svg>
|
||||
<div class="name">itsm-default_line</div>
|
||||
<div class="code-name">#itsm-default_line</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#veops-servicetree"></use>
|
||||
|
@@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 3857903 */
|
||||
src: url('iconfont.woff2?t=1735191938771') format('woff2'),
|
||||
url('iconfont.woff?t=1735191938771') format('woff'),
|
||||
url('iconfont.ttf?t=1735191938771') format('truetype');
|
||||
src: url('iconfont.woff2?t=1749393321370') format('woff2'),
|
||||
url('iconfont.woff?t=1749393321370') format('woff'),
|
||||
url('iconfont.ttf?t=1749393321370') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@@ -13,6 +13,102 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.onterm-symbolic_link:before {
|
||||
content: "\ea23";
|
||||
}
|
||||
|
||||
.oneterm-batch_execution:before {
|
||||
content: "\ea20";
|
||||
}
|
||||
|
||||
.ops-oneterm-file_log-selected:before {
|
||||
content: "\ea21";
|
||||
}
|
||||
|
||||
.ops-oneterm-file_log:before {
|
||||
content: "\ea22";
|
||||
}
|
||||
|
||||
.file:before {
|
||||
content: "\ea1f";
|
||||
}
|
||||
|
||||
.folder1:before {
|
||||
content: "\ea1e";
|
||||
}
|
||||
|
||||
.a-mongoDB1:before {
|
||||
content: "\ea1b";
|
||||
}
|
||||
|
||||
.a-postgreSQL1:before {
|
||||
content: "\ea1c";
|
||||
}
|
||||
|
||||
.a-telnet1:before {
|
||||
content: "\ea1d";
|
||||
}
|
||||
|
||||
.a-command_interception1:before {
|
||||
content: "\ea17";
|
||||
}
|
||||
|
||||
.quick_commands:before {
|
||||
content: "\ea18";
|
||||
}
|
||||
|
||||
.terminal_settings:before {
|
||||
content: "\ea19";
|
||||
}
|
||||
|
||||
.basic_settings:before {
|
||||
content: "\ea1a";
|
||||
}
|
||||
|
||||
.ops-oneterm-asset-management:before {
|
||||
content: "\ea16";
|
||||
}
|
||||
|
||||
.ai-seek:before {
|
||||
content: "\ea15";
|
||||
}
|
||||
|
||||
.ai-hate1:before {
|
||||
content: "\ea13";
|
||||
}
|
||||
|
||||
.ai-like1:before {
|
||||
content: "\ea14";
|
||||
}
|
||||
|
||||
.ai-like2:before {
|
||||
content: "\ea11";
|
||||
}
|
||||
|
||||
.ai-hate2:before {
|
||||
content: "\ea12";
|
||||
}
|
||||
|
||||
.ai-top_up:before {
|
||||
content: "\ea10";
|
||||
}
|
||||
|
||||
.ai-top_down:before {
|
||||
content: "\ea0f";
|
||||
}
|
||||
|
||||
.autoflow-script:before {
|
||||
content: "\ea0d";
|
||||
}
|
||||
|
||||
.autoflow-dag:before {
|
||||
content: "\ea0e";
|
||||
}
|
||||
|
||||
.itsm-default_line:before {
|
||||
content: "\ea0c";
|
||||
}
|
||||
|
||||
.veops-servicetree:before {
|
||||
content: "\ea0b";
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@@ -5,6 +5,174 @@
|
||||
"css_prefix_text": "",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "44501032",
|
||||
"name": "onterm-symbolic_link",
|
||||
"font_class": "onterm-symbolic_link",
|
||||
"unicode": "ea23",
|
||||
"unicode_decimal": 59939
|
||||
},
|
||||
{
|
||||
"icon_id": "44497221",
|
||||
"name": "oneterm-batch_execution",
|
||||
"font_class": "oneterm-batch_execution",
|
||||
"unicode": "ea20",
|
||||
"unicode_decimal": 59936
|
||||
},
|
||||
{
|
||||
"icon_id": "44497220",
|
||||
"name": "oneterm-file_log-selected",
|
||||
"font_class": "ops-oneterm-file_log-selected",
|
||||
"unicode": "ea21",
|
||||
"unicode_decimal": 59937
|
||||
},
|
||||
{
|
||||
"icon_id": "44497219",
|
||||
"name": "oneterm-file_log",
|
||||
"font_class": "ops-oneterm-file_log",
|
||||
"unicode": "ea22",
|
||||
"unicode_decimal": 59938
|
||||
},
|
||||
{
|
||||
"icon_id": "44455092",
|
||||
"name": "file",
|
||||
"font_class": "file",
|
||||
"unicode": "ea1f",
|
||||
"unicode_decimal": 59935
|
||||
},
|
||||
{
|
||||
"icon_id": "44455100",
|
||||
"name": "folder",
|
||||
"font_class": "folder1",
|
||||
"unicode": "ea1e",
|
||||
"unicode_decimal": 59934
|
||||
},
|
||||
{
|
||||
"icon_id": "44315758",
|
||||
"name": "mongoDB (1)",
|
||||
"font_class": "a-mongoDB1",
|
||||
"unicode": "ea1b",
|
||||
"unicode_decimal": 59931
|
||||
},
|
||||
{
|
||||
"icon_id": "44315757",
|
||||
"name": "postgreSQL (1)",
|
||||
"font_class": "a-postgreSQL1",
|
||||
"unicode": "ea1c",
|
||||
"unicode_decimal": 59932
|
||||
},
|
||||
{
|
||||
"icon_id": "44315755",
|
||||
"name": "telnet (1)",
|
||||
"font_class": "a-telnet1",
|
||||
"unicode": "ea1d",
|
||||
"unicode_decimal": 59933
|
||||
},
|
||||
{
|
||||
"icon_id": "44276353",
|
||||
"name": "command_interception (1)",
|
||||
"font_class": "a-command_interception1",
|
||||
"unicode": "ea17",
|
||||
"unicode_decimal": 59927
|
||||
},
|
||||
{
|
||||
"icon_id": "44276352",
|
||||
"name": "quick_commands",
|
||||
"font_class": "quick_commands",
|
||||
"unicode": "ea18",
|
||||
"unicode_decimal": 59928
|
||||
},
|
||||
{
|
||||
"icon_id": "44276351",
|
||||
"name": "terminal_settings",
|
||||
"font_class": "terminal_settings",
|
||||
"unicode": "ea19",
|
||||
"unicode_decimal": 59929
|
||||
},
|
||||
{
|
||||
"icon_id": "44276350",
|
||||
"name": "basic_settings",
|
||||
"font_class": "basic_settings",
|
||||
"unicode": "ea1a",
|
||||
"unicode_decimal": 59930
|
||||
},
|
||||
{
|
||||
"icon_id": "44276278",
|
||||
"name": "asset_management",
|
||||
"font_class": "ops-oneterm-asset-management",
|
||||
"unicode": "ea16",
|
||||
"unicode_decimal": 59926
|
||||
},
|
||||
{
|
||||
"icon_id": "43267802",
|
||||
"name": "ai-seek",
|
||||
"font_class": "ai-seek",
|
||||
"unicode": "ea15",
|
||||
"unicode_decimal": 59925
|
||||
},
|
||||
{
|
||||
"icon_id": "43213714",
|
||||
"name": "ai-hate1",
|
||||
"font_class": "ai-hate1",
|
||||
"unicode": "ea13",
|
||||
"unicode_decimal": 59923
|
||||
},
|
||||
{
|
||||
"icon_id": "43213712",
|
||||
"name": "ai-like1",
|
||||
"font_class": "ai-like1",
|
||||
"unicode": "ea14",
|
||||
"unicode_decimal": 59924
|
||||
},
|
||||
{
|
||||
"icon_id": "43213717",
|
||||
"name": "ai-like2",
|
||||
"font_class": "ai-like2",
|
||||
"unicode": "ea11",
|
||||
"unicode_decimal": 59921
|
||||
},
|
||||
{
|
||||
"icon_id": "43213716",
|
||||
"name": "ai-hate2",
|
||||
"font_class": "ai-hate2",
|
||||
"unicode": "ea12",
|
||||
"unicode_decimal": 59922
|
||||
},
|
||||
{
|
||||
"icon_id": "43139007",
|
||||
"name": "ai-top_up",
|
||||
"font_class": "ai-top_up",
|
||||
"unicode": "ea10",
|
||||
"unicode_decimal": 59920
|
||||
},
|
||||
{
|
||||
"icon_id": "43139017",
|
||||
"name": "ai-top_down",
|
||||
"font_class": "ai-top_down",
|
||||
"unicode": "ea0f",
|
||||
"unicode_decimal": 59919
|
||||
},
|
||||
{
|
||||
"icon_id": "43029539",
|
||||
"name": "autoflow-script",
|
||||
"font_class": "autoflow-script",
|
||||
"unicode": "ea0d",
|
||||
"unicode_decimal": 59917
|
||||
},
|
||||
{
|
||||
"icon_id": "43029538",
|
||||
"name": "autoflow-dag",
|
||||
"font_class": "autoflow-dag",
|
||||
"unicode": "ea0e",
|
||||
"unicode_decimal": 59918
|
||||
},
|
||||
{
|
||||
"icon_id": "42960865",
|
||||
"name": "itsm-default_line",
|
||||
"font_class": "itsm-default_line",
|
||||
"unicode": "ea0c",
|
||||
"unicode_decimal": 59916
|
||||
},
|
||||
{
|
||||
"icon_id": "42930714",
|
||||
"name": "veops-servicetree",
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -12,6 +12,7 @@ import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN'
|
||||
import enUS from 'ant-design-vue/lib/locale-provider/en_US'
|
||||
import { AppDeviceEnquire } from '@/utils/mixin'
|
||||
import { debounce } from './utils/util'
|
||||
import { getSystemLanguage } from '@/api/system.js'
|
||||
|
||||
import { h } from 'snabbdom'
|
||||
import { DomEditor, Boot } from '@wangeditor/editor'
|
||||
@@ -45,8 +46,7 @@ export default {
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.SET_LOCALE(localStorage.getItem('ops_locale') || 'zh')
|
||||
this.$i18n.locale = localStorage.getItem('ops_locale') || 'zh'
|
||||
this.initLanguage()
|
||||
this.timer = setInterval(() => {
|
||||
this.setTime(new Date().getTime())
|
||||
}, 1000)
|
||||
@@ -200,6 +200,28 @@ export default {
|
||||
this.alive = true
|
||||
})
|
||||
},
|
||||
async initLanguage() {
|
||||
let saveLocale = localStorage.getItem('ops_locale')
|
||||
if (!saveLocale) {
|
||||
let requestLanguage = ''
|
||||
try {
|
||||
const languageRes = await getSystemLanguage()
|
||||
requestLanguage = languageRes?.language || ''
|
||||
} catch (e) {
|
||||
console.error('getSystemLanguage error:', e)
|
||||
}
|
||||
|
||||
// request language variable || user local system language
|
||||
const userLanguage = requestLanguage || navigator.language || navigator.userLanguage
|
||||
if (userLanguage.includes('zh')) {
|
||||
saveLocale = 'zh'
|
||||
} else {
|
||||
saveLocale = 'en'
|
||||
}
|
||||
}
|
||||
this.SET_LOCALE(saveLocale)
|
||||
this.$i18n.locale = saveLocale
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
8
cmdb-ui/src/api/system.js
Normal file
8
cmdb-ui/src/api/system.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import { axios } from '@/utils/request'
|
||||
|
||||
export function getSystemLanguage() {
|
||||
return axios({
|
||||
url: '/common-setting/v1/system/language',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
@@ -47,7 +47,7 @@ export const commonIconList = ['changyong-ubuntu',
|
||||
export const linearIconList = [
|
||||
{
|
||||
value: 'database',
|
||||
label: '数据库',
|
||||
label: 'components.database',
|
||||
list: [{
|
||||
value: 'icon-xianxing-DB2',
|
||||
label: 'DB2'
|
||||
@@ -81,7 +81,7 @@ export const linearIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'system',
|
||||
label: '操作系统',
|
||||
label: 'components.system',
|
||||
list: [{
|
||||
value: 'icon-xianxing-Windows',
|
||||
label: 'Windows'
|
||||
@@ -106,7 +106,7 @@ export const linearIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'language',
|
||||
label: '语言',
|
||||
label: 'components.language',
|
||||
list: [{
|
||||
value: 'icon-xianxing-python',
|
||||
label: 'python'
|
||||
@@ -137,7 +137,7 @@ export const linearIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'status',
|
||||
label: '状态',
|
||||
label: 'components.status',
|
||||
list: [{
|
||||
value: 'icon-xianxing-yiwen',
|
||||
label: '疑问'
|
||||
@@ -177,7 +177,7 @@ export const linearIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'icon-xianxing-application',
|
||||
label: '常用组件',
|
||||
label: 'components.commonComponent',
|
||||
list: [{
|
||||
value: 'icon-xianxing-yilianjie',
|
||||
label: '已连接'
|
||||
@@ -310,7 +310,7 @@ export const linearIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'data',
|
||||
label: '数据',
|
||||
label: 'components.data',
|
||||
list: [{
|
||||
value: 'icon-xianxing-bingzhuangtu',
|
||||
label: '饼状图'
|
||||
@@ -387,7 +387,7 @@ export const linearIconList = [
|
||||
export const fillIconList = [
|
||||
{
|
||||
value: 'database',
|
||||
label: '数据库',
|
||||
label: 'components.database',
|
||||
list: [{
|
||||
value: 'icon-shidi-DB2',
|
||||
label: 'DB2'
|
||||
@@ -421,7 +421,7 @@ export const fillIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'system',
|
||||
label: '操作系统',
|
||||
label: 'components.system',
|
||||
list: [{
|
||||
value: 'icon-shidi-Windows',
|
||||
label: 'Windows'
|
||||
@@ -446,7 +446,7 @@ export const fillIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'language',
|
||||
label: '语言',
|
||||
label: 'components.language',
|
||||
list: [{
|
||||
value: 'icon-shidi-python',
|
||||
label: 'python'
|
||||
@@ -477,7 +477,7 @@ export const fillIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'status',
|
||||
label: '状态',
|
||||
label: 'components.status',
|
||||
list: [{
|
||||
value: 'icon-shidi-yiwen',
|
||||
label: '疑问'
|
||||
@@ -517,7 +517,7 @@ export const fillIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'icon-shidi-application',
|
||||
label: '常用组件',
|
||||
label: 'components.commonComponent',
|
||||
list: [{
|
||||
value: 'icon-shidi-yilianjie',
|
||||
label: '已连接'
|
||||
@@ -650,7 +650,7 @@ export const fillIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'data',
|
||||
label: '数据',
|
||||
label: 'components.data',
|
||||
list: [{
|
||||
value: 'icon-shidi-bingzhuangtu',
|
||||
label: '饼状图'
|
||||
@@ -727,7 +727,7 @@ export const fillIconList = [
|
||||
export const multicolorIconList = [
|
||||
{
|
||||
value: 'database',
|
||||
label: '数据库',
|
||||
label: 'components.database',
|
||||
list: [{
|
||||
value: 'caise-TIDB',
|
||||
label: 'TIDB'
|
||||
@@ -773,7 +773,7 @@ export const multicolorIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'cloud',
|
||||
label: '云',
|
||||
label: 'components.cloud',
|
||||
list: [{
|
||||
value: 'AWS',
|
||||
label: 'AWS'
|
||||
@@ -819,7 +819,7 @@ export const multicolorIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'system',
|
||||
label: '操作系统',
|
||||
label: 'components.system',
|
||||
list: [{
|
||||
value: 'ciase-aix',
|
||||
label: 'aix'
|
||||
@@ -847,7 +847,7 @@ export const multicolorIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'language',
|
||||
label: '语言',
|
||||
label: 'components.language',
|
||||
list: [{
|
||||
value: 'caise-python',
|
||||
label: 'python'
|
||||
@@ -878,7 +878,7 @@ export const multicolorIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'status',
|
||||
label: '状态',
|
||||
label: 'components.status',
|
||||
list: [{
|
||||
value: 'caise-yiwen',
|
||||
label: '疑问'
|
||||
@@ -918,7 +918,7 @@ export const multicolorIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'caise-application',
|
||||
label: '常用组件',
|
||||
label: 'components.commonComponent',
|
||||
list: [{
|
||||
value: 'caise-websphere',
|
||||
label: 'WebSphere'
|
||||
@@ -1180,7 +1180,7 @@ export const multicolorIconList = [
|
||||
}]
|
||||
}, {
|
||||
value: 'data',
|
||||
label: '数据',
|
||||
label: 'components.data',
|
||||
list: [{
|
||||
value: 'caise-bingzhuangtu',
|
||||
label: '饼状图'
|
||||
|
@@ -33,7 +33,7 @@
|
||||
<template v-if="iconList && iconList.length">
|
||||
<template v-if="currentIconType !== '4'">
|
||||
<div v-for="category in iconList" :key="category.value">
|
||||
<h4 class="category">{{ category.label }}</h4>
|
||||
<h4 class="category">{{ $t(category.label) }}</h4>
|
||||
<div class="custom-icon-select-popover-content-wrapper">
|
||||
<div
|
||||
v-for="name in category.list"
|
||||
|
@@ -6,9 +6,9 @@
|
||||
</div>
|
||||
<div class="content">
|
||||
<h1>{{ config[type].title }}</h1>
|
||||
<div class="desc">{{ config[type].desc }}</div>
|
||||
<div class="desc">{{ $t(config[type].desc) }}</div>
|
||||
<div class="actions">
|
||||
<a-button type="primary" @click="handleToHome">返回首页</a-button>
|
||||
<a-button type="primary" @click="handleToHome">{{ $t('exception.backToHome') }}</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -2,17 +2,17 @@ const types = {
|
||||
403: {
|
||||
img: 'https://gw.alipayobjects.com/zos/rmsportal/wZcnGqRDyhPOEYFcZDnb.svg',
|
||||
title: '403',
|
||||
desc: '抱歉,你无权访问该页面'
|
||||
desc: 'exception.desc1'
|
||||
},
|
||||
404: {
|
||||
img: 'https://gw.alipayobjects.com/zos/rmsportal/KpnpchXsobRgLElEozzI.svg',
|
||||
title: '404',
|
||||
desc: '抱歉,你访问的页面不存在或仍在开发中'
|
||||
desc: 'exception.desc2'
|
||||
},
|
||||
500: {
|
||||
img: 'https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg',
|
||||
title: '500',
|
||||
desc: '抱歉,服务器出错了'
|
||||
desc: 'exception.desc3'
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -109,9 +109,25 @@ export default {
|
||||
default: 'default',
|
||||
tip: 'Tip',
|
||||
cmdbSearch: 'Search',
|
||||
exception: {
|
||||
backToHome: 'Back to home page',
|
||||
desc1: 'Sorry, you are not authorized to access this page',
|
||||
desc2: 'Sorry, the page you are visiting does not exist or is still under development',
|
||||
desc3: 'Sorry, server error'
|
||||
},
|
||||
pagination: {
|
||||
total: '{range0}-{range1} of {total} items'
|
||||
},
|
||||
components: {
|
||||
colorTagSelectTip: 'Enter or select tags',
|
||||
database: 'Database',
|
||||
system: 'System',
|
||||
language: 'Language',
|
||||
status: 'Status',
|
||||
commonComponent: 'Common Component',
|
||||
data: 'Data',
|
||||
cloud: 'Cloud'
|
||||
},
|
||||
topMenu: {
|
||||
personalCenter: 'My Profile',
|
||||
logout: 'Logout',
|
||||
|
@@ -109,9 +109,25 @@ export default {
|
||||
default: '默认',
|
||||
tip: '提示',
|
||||
cmdbSearch: '搜索一下',
|
||||
exception: {
|
||||
backToHome: '返回首页',
|
||||
desc1: '抱歉,你无权访问该页面',
|
||||
desc2: '抱歉,你访问的页面不存在或仍在开发中',
|
||||
desc3: '抱歉,服务器出错了'
|
||||
},
|
||||
pagination: {
|
||||
total: '当前展示 {range0}-{range1} 条数据, 共 {total} 条'
|
||||
},
|
||||
components: {
|
||||
colorTagSelectTip: '选择或输入(回车确定)标签',
|
||||
database: '数据库',
|
||||
system: '操作系统',
|
||||
language: '语言',
|
||||
status: '状态',
|
||||
commonComponent: '常用组件',
|
||||
data: '数据',
|
||||
cloud: '云'
|
||||
},
|
||||
topMenu: {
|
||||
personalCenter: '个人中心',
|
||||
logout: '退出登录',
|
||||
|
@@ -721,7 +721,9 @@ if __name__ == "__main__":
|
||||
batchRollbacking: 'Deleting {total} items in total, {successNum} items successful, {errorNum} items failed',
|
||||
baselineTips: 'Changes at this point in time will also be rollbacked, Unique ID, password and dynamic attributes do not support',
|
||||
cover: 'Cover',
|
||||
detail: 'Detail'
|
||||
detail: 'Detail',
|
||||
upstream: 'Upstream',
|
||||
downstream: 'Downstream'
|
||||
},
|
||||
serviceTree: {
|
||||
remove: 'Remove',
|
||||
|
@@ -720,7 +720,9 @@ if __name__ == "__main__":
|
||||
batchRollbacking: '正在回滚,共{total}个,成功{successNum}个,失败{errorNum}个',
|
||||
baselineTips: '该时间点的变更也会被回滚, 唯一标识、密码属性、动态属性不支持回滚',
|
||||
cover: '覆盖',
|
||||
detail: '详情'
|
||||
detail: '详情',
|
||||
upstream: '上游',
|
||||
downstream: '下游'
|
||||
},
|
||||
serviceTree: {
|
||||
remove: '移除',
|
||||
|
@@ -71,7 +71,7 @@ const genCmdbRoutes = async () => {
|
||||
{
|
||||
path: '/cmdb/adc',
|
||||
name: 'cmdb_auto_discovery_ci',
|
||||
meta: { title: 'cmdb.menu.adCIs', icon: 'ops-cmdb-adc', selectedIcon: 'ops-cmdb-adc', keepAlive: false },
|
||||
meta: { title: 'cmdb.menu.adCIs', icon: 'ops-cmdb-adc', selectedIcon: 'ops-cmdb-adc', keepAlive: false, permission: ['admin', 'cmdb_admin'] },
|
||||
component: () => import('../views/discoveryCI/index.vue')
|
||||
},
|
||||
{
|
||||
|
@@ -23,15 +23,25 @@ export default {
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
icon: '',
|
||||
title: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
findCIType() {
|
||||
return this.ci_types?.find?.((item) => item?.id === this.ci?._type)
|
||||
},
|
||||
icon() {
|
||||
return this?.findCiType?.icon || ''
|
||||
},
|
||||
title() {
|
||||
return this?.ci?.[this.findCIType?.show_name] || this?.ci?.[this.findCIType?.unique_key] || ''
|
||||
return this.ci_types?.find?.((item) => item?.id === this.ci?._type) || {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
findCIType: {
|
||||
deep: true,
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
this.icon = val?.icon || ''
|
||||
this.title = this?.ci?.[val?.show_name] || this?.ci?.[val?.unique_key] || ''
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,29 +5,44 @@
|
||||
<div class="ci-relation-table-wrap">
|
||||
<div class="ci-relation-table-tab">
|
||||
<div
|
||||
v-for="(item) in tabList"
|
||||
:key="item.value"
|
||||
:class="`tab-item ${item.value === currentTab ? 'tab-item-active' : ''}`"
|
||||
@click="clickTab(item.value)"
|
||||
v-for="(group) in tabList"
|
||||
:key="group.key"
|
||||
class="tab-group"
|
||||
>
|
||||
<span class="tab-item-name">
|
||||
<a-tooltip :title="item.name">
|
||||
<span class="tab-item-name-text">{{ item.name }}</span>
|
||||
</a-tooltip>
|
||||
<span
|
||||
v-if="item.count"
|
||||
class="tab-item-name-count"
|
||||
>
|
||||
({{ item.count }})
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
v-if="item.value === currentTab && item.showAdd"
|
||||
class="tab-item-add"
|
||||
@click="openAddModal(item)"
|
||||
<div
|
||||
v-if="group.name"
|
||||
class="tab-group-name"
|
||||
>
|
||||
<a-icon type="plus" />
|
||||
</span>
|
||||
{{ group.name }}
|
||||
</div>
|
||||
<div
|
||||
v-for="(item) in group.list"
|
||||
:key="item.key"
|
||||
:class="`tab-item ${item.key === currentTab ? 'tab-item-active' : ''}`"
|
||||
:style="{
|
||||
paddingLeft: item.key === 'all' ? '8px' : '16px'
|
||||
}"
|
||||
@click="clickTab(item.key)"
|
||||
>
|
||||
<span class="tab-item-name">
|
||||
<a-tooltip :title="item.name">
|
||||
<span class="tab-item-name-text">{{ item.name }}</span>
|
||||
</a-tooltip>
|
||||
<span
|
||||
v-if="item.count"
|
||||
class="tab-item-name-count"
|
||||
>
|
||||
({{ item.count }})
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
v-if="item.key === currentTab && item.showAdd"
|
||||
class="tab-item-add"
|
||||
@click="openAddModal(item)"
|
||||
>
|
||||
<a-icon type="plus" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -37,7 +52,7 @@
|
||||
>
|
||||
<div
|
||||
v-for="(item) in tableIDList"
|
||||
:key="item.id"
|
||||
:key="item.key"
|
||||
class="ci-relation-table-item"
|
||||
>
|
||||
<div
|
||||
@@ -51,8 +66,8 @@
|
||||
<vxe-grid
|
||||
bordered
|
||||
size="mini"
|
||||
:columns="allColumns[item.id]"
|
||||
:data="allCIList[item.id]"
|
||||
:columns="allColumns[item.value]"
|
||||
:data="allCIList[item.key]"
|
||||
overflow
|
||||
showOverflow="tooltip"
|
||||
showHeaderOverflow="tooltip"
|
||||
@@ -77,9 +92,9 @@
|
||||
@confirm="deleteRelation(row)"
|
||||
>
|
||||
<a
|
||||
:disabled="!allCanEdit[item.id]"
|
||||
:disabled="!allCanEdit[item.value]"
|
||||
:style="{
|
||||
color: !allCanEdit[item.id] ? 'rgba(0, 0, 0, 0.25)' : 'red',
|
||||
color: !allCanEdit[item.value] ? 'rgba(0, 0, 0, 0.25)' : 'red',
|
||||
}"
|
||||
>
|
||||
<a-icon type="delete" />
|
||||
@@ -105,6 +120,9 @@ import { getSubscribeAttributes } from '@/modules/cmdb/api/preference'
|
||||
import CIDetailTableTitle from './ciDetailTableTitle.vue'
|
||||
import AddTableModal from '@/modules/cmdb/views/relation_views/modules/AddTableModal.vue'
|
||||
|
||||
const PARENT_KEY = 'parents'
|
||||
const CHILDREN_KEY = 'children'
|
||||
|
||||
export default {
|
||||
name: 'CIRelationTable',
|
||||
components: {
|
||||
@@ -151,24 +169,26 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
tabListFlat() {
|
||||
return this.tabList.reduce((list, group) => list.concat(group.list), [])
|
||||
},
|
||||
tableIDList() {
|
||||
let baseIDs = []
|
||||
const baseKeys = this.currentTab === 'all'
|
||||
? this.tabListFlat.filter(item => item.value !== 'all').map(item => item.key)
|
||||
: [this.currentTab]
|
||||
|
||||
switch (this.currentTab) {
|
||||
case 'all':
|
||||
baseIDs = this.tabList.filter((item) => item.value !== 'all').map((item) => item.value)
|
||||
break
|
||||
default:
|
||||
baseIDs = [this.currentTab]
|
||||
break
|
||||
}
|
||||
return baseKeys.filter((key) => this.allCIList?.[key]?.length).map((key) => {
|
||||
const findTab = this.tabListFlat.find((item) => item.key === key) || {}
|
||||
|
||||
return baseIDs.filter((id) => this.allCIList?.[id]?.length).map((id) => {
|
||||
const findTab = this.tabList.find((item) => item.value === id) || {}
|
||||
let name = findTab?.name || ''
|
||||
if (name && findTab?.value === this.ci._type) {
|
||||
name = `${findTab?.isParent ? this.$t('cmdb.ci.upstream') : this.$t('cmdb.ci.downstream')} - ${name}`
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
name: findTab?.name || '',
|
||||
key,
|
||||
value: findTab?.value || '',
|
||||
name,
|
||||
count: findTab?.count || ''
|
||||
}
|
||||
})
|
||||
@@ -195,10 +215,13 @@ export default {
|
||||
|
||||
const cloneRelationData = _.cloneDeep(relationData)
|
||||
|
||||
const allCITypes = [
|
||||
...cloneRelationData.parentCITypeList,
|
||||
...cloneRelationData.childCITypeList
|
||||
]
|
||||
const allCITypes = _.uniqBy(
|
||||
[
|
||||
...cloneRelationData.parentCITypeList,
|
||||
...cloneRelationData.childCITypeList
|
||||
],
|
||||
'id'
|
||||
)
|
||||
await this.handleSubscribeAttributes(allCITypes)
|
||||
|
||||
const {
|
||||
@@ -231,25 +254,48 @@ export default {
|
||||
...childCIs
|
||||
}
|
||||
|
||||
const tabList = this.allCITypes.map((item) => {
|
||||
return {
|
||||
name: item?.alias ?? item?.name ?? '',
|
||||
value: item.id,
|
||||
count: this.allCIList?.[item.id]?.length || 0,
|
||||
showAdd: this.allCanEdit?.[item.id] ?? false
|
||||
}
|
||||
})
|
||||
tabList.unshift({
|
||||
name: this.$t('all'),
|
||||
value: 'all',
|
||||
count: Object.values(this.allCIList).reduce((acc, cur) => acc + (cur?.length || 0), 0),
|
||||
showAdd: false
|
||||
})
|
||||
const tabList = []
|
||||
|
||||
tabList[0] = {
|
||||
name: '',
|
||||
key: 'all',
|
||||
list: [{
|
||||
name: this.$t('all'),
|
||||
key: 'all',
|
||||
value: 'all',
|
||||
count: Object.values(this.allCIList).reduce((acc, cur) => acc + (cur?.length || 0), 0),
|
||||
showAdd: false
|
||||
}]
|
||||
}
|
||||
tabList[1] = {
|
||||
name: this.$t('cmdb.ci.upstream'),
|
||||
key: PARENT_KEY,
|
||||
list: this.buildTabList(cloneRelationData.parentCITypeList, PARENT_KEY, true)
|
||||
}
|
||||
tabList[2] = {
|
||||
name: this.$t('cmdb.ci.downstream'),
|
||||
key: CHILDREN_KEY,
|
||||
list: this.buildTabList(cloneRelationData.childCITypeList, CHILDREN_KEY, false)
|
||||
}
|
||||
this.tabList = tabList
|
||||
|
||||
this.handleReferenceCINameMap()
|
||||
},
|
||||
|
||||
buildTabList(list, keyPrefix, isParent) {
|
||||
return list.map((item) => {
|
||||
const key = `${keyPrefix}-${item.id}`
|
||||
return {
|
||||
name: item?.alias ?? item?.name ?? '',
|
||||
key,
|
||||
isParent,
|
||||
value: item.id,
|
||||
count: this.allCIList?.[key]?.length || 0,
|
||||
showAdd: this.allCanEdit?.[item.id] ?? false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
handleCITypeList(list, isParent) {
|
||||
const CIColumns = {}
|
||||
const CIJSONAttr = {}
|
||||
@@ -362,11 +408,12 @@ export default {
|
||||
})
|
||||
this.formatCI(item)
|
||||
item.isParent = isParent
|
||||
const CIKey = `${isParent ? PARENT_KEY : CHILDREN_KEY}-${item._type}`
|
||||
|
||||
if (item._type in cis) {
|
||||
cis[item._type].push(item)
|
||||
if (CIKey in cis) {
|
||||
cis[CIKey].push(item)
|
||||
} else {
|
||||
cis[item._type] = [item]
|
||||
cis[CIKey] = [item]
|
||||
}
|
||||
})
|
||||
|
||||
@@ -395,9 +442,11 @@ export default {
|
||||
async handleReferenceCINameMap() {
|
||||
const referenceCINameMap = {}
|
||||
this.allCITypes.forEach((CIType) => {
|
||||
const CIKey = `${CIType.isParent ? PARENT_KEY : CHILDREN_KEY}-${CIType.id}`
|
||||
|
||||
CIType.attributes.forEach((attr) => {
|
||||
if (attr?.is_reference && attr?.reference_type_id) {
|
||||
const currentCIList = this.allCIList[CIType.id]
|
||||
const currentCIList = this.allCIList[CIKey]
|
||||
if (currentCIList?.length) {
|
||||
currentCIList.forEach((ci) => {
|
||||
const ids = Array.isArray(ci[attr.name]) ? ci[attr.name] : ci[attr.name] ? [ci[attr.name]] : []
|
||||
@@ -458,8 +507,8 @@ export default {
|
||||
return this.referenceCINameMap?.[typeId]?.[id] || id
|
||||
},
|
||||
|
||||
clickTab(value) {
|
||||
this.currentTab = value
|
||||
clickTab(key) {
|
||||
this.currentTab = key
|
||||
},
|
||||
|
||||
deleteRelation(row) {
|
||||
@@ -483,7 +532,7 @@ export default {
|
||||
},
|
||||
this.ciId,
|
||||
ciType,
|
||||
ciType?.isParent ? 'parents' : 'children'
|
||||
tabData?.isParent ? 'parents' : 'children'
|
||||
)
|
||||
},
|
||||
|
||||
@@ -509,12 +558,26 @@ export default {
|
||||
&-tab {
|
||||
flex-shrink: 0;
|
||||
width: 160px;
|
||||
max-height: 300px;
|
||||
min-height: 300px;
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 6px 0px;
|
||||
border-right: solid 1px #E4E7ED;
|
||||
|
||||
.tab-group {
|
||||
width: 100%;
|
||||
|
||||
&-name {
|
||||
padding-left: 8px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
width: 100%;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, .45);
|
||||
}
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
height: 32px;
|
||||
width: 100%;
|
||||
@@ -583,6 +646,9 @@ export default {
|
||||
padding: 15px 17px;
|
||||
overflow: hidden;
|
||||
min-height: 300px;
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
&-item {
|
||||
|
@@ -132,10 +132,11 @@ export default {
|
||||
}
|
||||
|
||||
const _findCiType = ci_types_list.find((item) => item.id === this.typeId)
|
||||
const unique_id = _findCiType.show_id || this.attributes().unique_id
|
||||
const unique_name = _findCiType.show_name || this.attributes().unique
|
||||
const unique_id = _findCiType.show_id || _findCiType.unique_id
|
||||
const _findUnique = this.attrList().find((attr) => attr.id === unique_id)
|
||||
const unique_name = _findUnique?.name
|
||||
const unique_alias = _findUnique?.alias || _findUnique?.name || ''
|
||||
|
||||
const nodes = {
|
||||
isRoot: true,
|
||||
id: `Root_${this.typeId}`,
|
||||
|
@@ -1,79 +1,82 @@
|
||||
<template>
|
||||
<div ref="wrapRef">
|
||||
<div class="table-header">
|
||||
<SearchForm
|
||||
ref="search"
|
||||
:preferenceAttrList="preferenceAttrList"
|
||||
:typeId="addressCITypeId"
|
||||
@copyExpression="copyExpression"
|
||||
@refresh="handleSearch"
|
||||
<a-spin :tip="loadTip" :spinning="loading" >
|
||||
<div class="table-header">
|
||||
<SearchForm
|
||||
ref="search"
|
||||
:preferenceAttrList="preferenceAttrList"
|
||||
:typeId="addressCITypeId"
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@copyExpression="copyExpression"
|
||||
@refresh="handleSearch"
|
||||
>
|
||||
<div class="ops-list-batch-action" v-show="!!selectedRowKeys.length">
|
||||
<span @click="$refs.create.handleOpen(true, 'update')">{{ $t('update') }}</span>
|
||||
<a-divider type="vertical" />
|
||||
<span @click="openBatchDownload">{{ $t('download') }}</span>
|
||||
<a-divider type="vertical" />
|
||||
<span @click="batchDelete">{{ $t('delete') }}</span>
|
||||
<span>{{ $t('cmdb.ci.selectRows', { rows: selectedRowKeys.length }) }}</span>
|
||||
</div>
|
||||
</SearchForm>
|
||||
|
||||
<div class="table-header-right">
|
||||
<EditAttrsPopover
|
||||
:typeId="addressCITypeId"
|
||||
@refresh="refreshAfterEditAttrs"
|
||||
>
|
||||
<a-button
|
||||
type="primary"
|
||||
ghost
|
||||
class="ops-button-ghost"
|
||||
>
|
||||
<ops-icon type="veops-configuration_table" />
|
||||
{{ $t('cmdb.configTable') }}
|
||||
</a-button>
|
||||
</EditAttrsPopover>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CITable
|
||||
ref="xTable"
|
||||
:loading="loading"
|
||||
:attrList="preferenceAttrList"
|
||||
:columns="columns"
|
||||
:data="instanceList"
|
||||
:height="tableHeight"
|
||||
@sort-change="handleSortCol"
|
||||
@openDetail="openDetail"
|
||||
@deleteCI="deleteCI"
|
||||
@onSelectChange="onSelectChange"
|
||||
/>
|
||||
|
||||
<div class="table-header-right">
|
||||
<EditAttrsPopover
|
||||
:typeId="addressCITypeId"
|
||||
@refresh="refreshAfterEditAttrs"
|
||||
<div class="table-pagination">
|
||||
<a-pagination
|
||||
:showSizeChanger="true"
|
||||
:current="page"
|
||||
size="small"
|
||||
:total="totalNumber"
|
||||
show-quick-jumper
|
||||
:page-size="pageSize"
|
||||
:page-size-options="pageSizeOptions"
|
||||
:show-total="
|
||||
(total, range) =>
|
||||
$t('pagination.total', {
|
||||
range0: range[0],
|
||||
range1: range[1],
|
||||
total,
|
||||
})
|
||||
"
|
||||
@change="handleChangePage"
|
||||
@showSizeChange="onShowSizeChange"
|
||||
>
|
||||
<a-button
|
||||
type="primary"
|
||||
ghost
|
||||
class="ops-button-ghost"
|
||||
>
|
||||
<ops-icon type="veops-configuration_table" />
|
||||
{{ $t('cmdb.configTable') }}
|
||||
</a-button>
|
||||
</EditAttrsPopover>
|
||||
<a-button
|
||||
v-if="instanceList && instanceList.length"
|
||||
type="primary"
|
||||
class="ops-button-ghost"
|
||||
ghost
|
||||
@click="handleExport"
|
||||
>
|
||||
<ops-icon type="veops-export" />
|
||||
{{ $t('export') }}
|
||||
</a-button>
|
||||
<template slot="buildOptionText" slot-scope="props">
|
||||
<span v-if="props.value !== '100000'">{{ props.value }}{{ $t('itemsPerPage') }}</span>
|
||||
<span v-if="props.value === '100000'">{{ $t('cmdb.ci.all') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CITable
|
||||
ref="xTable"
|
||||
:loading="loading"
|
||||
:attrList="preferenceAttrList"
|
||||
:columns="columns"
|
||||
:data="instanceList"
|
||||
:height="tableHeight"
|
||||
@sort-change="handleSortCol"
|
||||
@openDetail="openDetail"
|
||||
@deleteCI="deleteCI"
|
||||
/>
|
||||
|
||||
<div class="table-pagination">
|
||||
<a-pagination
|
||||
:showSizeChanger="true"
|
||||
:current="page"
|
||||
size="small"
|
||||
:total="totalNumber"
|
||||
show-quick-jumper
|
||||
:page-size="pageSize"
|
||||
:page-size-options="pageSizeOptions"
|
||||
:show-total="
|
||||
(total, range) =>
|
||||
$t('pagination.total', {
|
||||
range0: range[0],
|
||||
range1: range[1],
|
||||
total,
|
||||
})
|
||||
"
|
||||
@change="handleChangePage"
|
||||
@showSizeChange="onShowSizeChange"
|
||||
>
|
||||
<template slot="buildOptionText" slot-scope="props">
|
||||
<span v-if="props.value !== '100000'">{{ props.value }}{{ $t('itemsPerPage') }}</span>
|
||||
<span v-if="props.value === '100000'">{{ $t('cmdb.ci.all') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
</div>
|
||||
</a-spin>
|
||||
|
||||
<BatchDownload
|
||||
ref="batchDownload"
|
||||
@@ -82,6 +85,12 @@
|
||||
/>
|
||||
|
||||
<CIDetailDrawer ref="detail" :typeId="addressCITypeId" />
|
||||
|
||||
<CreateInstanceForm
|
||||
ref="create"
|
||||
:typeIdFromRelation="addressCITypeId"
|
||||
@submit="batchUpdate"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -90,7 +99,7 @@ import _ from 'lodash'
|
||||
import { mapState } from 'vuex'
|
||||
import ExcelJS from 'exceljs'
|
||||
import FileSaver from 'file-saver'
|
||||
import { searchCI, deleteCI } from '@/modules/cmdb/api/ci'
|
||||
import { searchCI, deleteCI, updateCI } from '@/modules/cmdb/api/ci'
|
||||
import { getSubscribeAttributes } from '@/modules/cmdb/api/preference'
|
||||
import { getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
|
||||
import { getCITableColumns } from '@/modules/cmdb/utils/helper'
|
||||
@@ -100,6 +109,7 @@ import CITable from '@/modules/cmdb/components/ciTable/index.vue'
|
||||
import BatchDownload from '@/modules/cmdb/components/batchDownload/batchDownload.vue'
|
||||
import CIDetailDrawer from '@/modules/cmdb/views/ci/modules/ciDetailDrawer.vue'
|
||||
import EditAttrsPopover from '@/modules/cmdb/views/ci/modules/editAttrsPopover.vue'
|
||||
import CreateInstanceForm from '@/modules/cmdb/views/ci/modules/CreateInstanceForm'
|
||||
|
||||
export default {
|
||||
name: 'IPSearch',
|
||||
@@ -108,7 +118,8 @@ export default {
|
||||
CITable,
|
||||
BatchDownload,
|
||||
CIDetailDrawer,
|
||||
EditAttrsPopover
|
||||
EditAttrsPopover,
|
||||
CreateInstanceForm
|
||||
},
|
||||
props: {
|
||||
addressCIType: {
|
||||
@@ -122,6 +133,7 @@ export default {
|
||||
pageSize: 50,
|
||||
pageSizeOptions: ['50', '100', '200'],
|
||||
loading: false,
|
||||
loadTip: '',
|
||||
sortByTable: undefined,
|
||||
|
||||
instanceList: [],
|
||||
@@ -130,6 +142,7 @@ export default {
|
||||
preferenceAttrList: [],
|
||||
attrList: [],
|
||||
attributes: {},
|
||||
selectedRowKeys: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -275,7 +288,7 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
handleExport() {
|
||||
openBatchDownload() {
|
||||
this.$refs.batchDownload.open({
|
||||
preferenceAttrList: this.preferenceAttrList,
|
||||
ciTypeName: this.$t('cmdb.ipam.ipSearch') || '',
|
||||
@@ -336,6 +349,7 @@ export default {
|
||||
FileSaver.saveAs(file, `${filename}.xlsx`)
|
||||
})
|
||||
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
||||
},
|
||||
@@ -361,6 +375,120 @@ export default {
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
onSelectChange(records) {
|
||||
this.selectedRowKeys = records.map((i) => i.ci_id || i._id)
|
||||
},
|
||||
|
||||
batchDelete() {
|
||||
this.$confirm({
|
||||
title: this.$t('warning'),
|
||||
content: this.$t('confirmDelete'),
|
||||
onOk: () => {
|
||||
this.batchDeleteAsync()
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
async batchDeleteAsync() {
|
||||
let successNum = 0
|
||||
let errorNum = 0
|
||||
this.loading = true
|
||||
this.loadTip = this.$t('cmdb.ci.batchDeleting')
|
||||
|
||||
const floor = Math.ceil(this.selectedRowKeys.length / 6)
|
||||
for (let i = 0; i < floor; i++) {
|
||||
const itemList = this.selectedRowKeys.slice(6 * i, 6 * i + 6)
|
||||
const promises = itemList.map((x) => deleteCI(x, false))
|
||||
await Promise.allSettled(promises)
|
||||
.then((res) => {
|
||||
res.forEach((r) => {
|
||||
if (r.status === 'fulfilled') {
|
||||
successNum += 1
|
||||
} else {
|
||||
errorNum += 1
|
||||
}
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.loadTip = this.$t('cmdb.ci.batchDeleting2', {
|
||||
total: this.selectedRowKeys.length,
|
||||
successNum: successNum,
|
||||
errorNum: errorNum,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
this.loading = false
|
||||
this.loadTip = ''
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
||||
this.$nextTick(() => {
|
||||
this.page = 1
|
||||
this.getTableData()
|
||||
})
|
||||
},
|
||||
|
||||
batchUpdate(values) {
|
||||
this.$confirm({
|
||||
title: this.$t('warning'),
|
||||
content: this.$t('cmdb.ci.batchUpdateConfirm'),
|
||||
onOk: () => {
|
||||
this.batchUpdateAsync(values)
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
async batchUpdateAsync(values) {
|
||||
let successNum = 0
|
||||
let errorNum = 0
|
||||
this.loading = true
|
||||
this.loadTip = this.$t('cmdb.ci.batchUpdateInProgress') + '...'
|
||||
|
||||
const payload = {}
|
||||
Object.keys(values).forEach((key) => {
|
||||
if (values[key] === undefined || values[key] === null) {
|
||||
payload[key] = null
|
||||
} else {
|
||||
payload[key] = values[key]
|
||||
}
|
||||
})
|
||||
this.$refs.create.visible = false
|
||||
const key = 'updatable'
|
||||
let errorMsg = ''
|
||||
|
||||
for (let i = 0; i < this.selectedRowKeys.length; i++) {
|
||||
await updateCI(this.selectedRowKeys[i], payload, false)
|
||||
.then(() => {
|
||||
successNum += 1
|
||||
})
|
||||
.catch((error) => {
|
||||
errorMsg = errorMsg + '\n' + `${this.selectedRowKeys[i]}:${error.response?.data?.message ?? ''}`
|
||||
this.$notification.warning({
|
||||
key,
|
||||
message: this.$t('warning'),
|
||||
description: errorMsg,
|
||||
duration: 0,
|
||||
style: { whiteSpace: 'break-spaces', overflow: 'auto', maxHeight: this.windowHeight - 80 + 'px' },
|
||||
})
|
||||
errorNum += 1
|
||||
})
|
||||
.finally(() => {
|
||||
this.loadTip = this.$t('cmdb.ci.batchUpdateInProgress2', {
|
||||
total: this.selectedRowKeys.length,
|
||||
successNum: successNum,
|
||||
errorNum: errorNum,
|
||||
})
|
||||
})
|
||||
}
|
||||
this.loading = false
|
||||
this.loadTip = ''
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
||||
this.getTableData()
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@@ -1,79 +1,82 @@
|
||||
<template>
|
||||
<div ref="wrapRef">
|
||||
<div class="table-header">
|
||||
<SearchForm
|
||||
ref="search"
|
||||
:preferenceAttrList="preferenceAttrList"
|
||||
:typeId="subnetCITypeId"
|
||||
@copyExpression="copyExpression"
|
||||
@refresh="handleSearch"
|
||||
<a-spin :tip="loadTip" :spinning="loading" >
|
||||
<div class="table-header">
|
||||
<SearchForm
|
||||
ref="search"
|
||||
:preferenceAttrList="preferenceAttrList"
|
||||
:typeId="subnetCITypeId"
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@copyExpression="copyExpression"
|
||||
@refresh="handleSearch"
|
||||
>
|
||||
<div class="ops-list-batch-action" v-show="!!selectedRowKeys.length">
|
||||
<span @click="$refs.create.handleOpen(true, 'update')">{{ $t('update') }}</span>
|
||||
<a-divider type="vertical" />
|
||||
<span @click="openBatchDownload">{{ $t('download') }}</span>
|
||||
<a-divider type="vertical" />
|
||||
<span @click="batchDelete">{{ $t('delete') }}</span>
|
||||
<span>{{ $t('cmdb.ci.selectRows', { rows: selectedRowKeys.length }) }}</span>
|
||||
</div>
|
||||
</SearchForm>
|
||||
|
||||
<div class="table-header-right">
|
||||
<EditAttrsPopover
|
||||
:typeId="subnetCITypeId"
|
||||
@refresh="refreshAfterEditAttrs"
|
||||
>
|
||||
<a-button
|
||||
type="primary"
|
||||
ghost
|
||||
class="ops-button-ghost"
|
||||
>
|
||||
<ops-icon type="veops-configuration_table" />
|
||||
{{ $t('cmdb.configTable') }}
|
||||
</a-button>
|
||||
</EditAttrsPopover>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CITable
|
||||
ref="xTable"
|
||||
:loading="loading"
|
||||
:attrList="preferenceAttrList"
|
||||
:columns="columns"
|
||||
:data="instanceList"
|
||||
:height="tableHeight"
|
||||
@sort-change="handleSortCol"
|
||||
@openDetail="openDetail"
|
||||
@deleteCI="deleteCI"
|
||||
@onSelectChange="onSelectChange"
|
||||
/>
|
||||
|
||||
<div class="table-header-right">
|
||||
<EditAttrsPopover
|
||||
:typeId="subnetCITypeId"
|
||||
@refresh="refreshAfterEditAttrs"
|
||||
<div class="table-pagination">
|
||||
<a-pagination
|
||||
:showSizeChanger="true"
|
||||
:current="page"
|
||||
size="small"
|
||||
:total="totalNumber"
|
||||
show-quick-jumper
|
||||
:page-size="pageSize"
|
||||
:page-size-options="pageSizeOptions"
|
||||
:show-total="
|
||||
(total, range) =>
|
||||
$t('pagination.total', {
|
||||
range0: range[0],
|
||||
range1: range[1],
|
||||
total,
|
||||
})
|
||||
"
|
||||
@change="handleChangePage"
|
||||
@showSizeChange="onShowSizeChange"
|
||||
>
|
||||
<a-button
|
||||
type="primary"
|
||||
ghost
|
||||
class="ops-button-ghost"
|
||||
>
|
||||
<ops-icon type="veops-configuration_table" />
|
||||
{{ $t('cmdb.configTable') }}
|
||||
</a-button>
|
||||
</EditAttrsPopover>
|
||||
<a-button
|
||||
v-if="instanceList && instanceList.length"
|
||||
type="primary"
|
||||
class="ops-button-ghost"
|
||||
ghost
|
||||
@click="handleExport"
|
||||
>
|
||||
<ops-icon type="veops-export" />
|
||||
{{ $t('export') }}
|
||||
</a-button>
|
||||
<template slot="buildOptionText" slot-scope="props">
|
||||
<span v-if="props.value !== '100000'">{{ props.value }}{{ $t('itemsPerPage') }}</span>
|
||||
<span v-if="props.value === '100000'">{{ $t('cmdb.ci.all') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CITable
|
||||
ref="xTable"
|
||||
:loading="loading"
|
||||
:attrList="preferenceAttrList"
|
||||
:columns="columns"
|
||||
:data="instanceList"
|
||||
:height="tableHeight"
|
||||
@sort-change="handleSortCol"
|
||||
@openDetail="openDetail"
|
||||
@deleteCI="deleteCI"
|
||||
/>
|
||||
|
||||
<div class="table-pagination">
|
||||
<a-pagination
|
||||
:showSizeChanger="true"
|
||||
:current="page"
|
||||
size="small"
|
||||
:total="totalNumber"
|
||||
show-quick-jumper
|
||||
:page-size="pageSize"
|
||||
:page-size-options="pageSizeOptions"
|
||||
:show-total="
|
||||
(total, range) =>
|
||||
$t('pagination.total', {
|
||||
range0: range[0],
|
||||
range1: range[1],
|
||||
total,
|
||||
})
|
||||
"
|
||||
@change="handleChangePage"
|
||||
@showSizeChange="onShowSizeChange"
|
||||
>
|
||||
<template slot="buildOptionText" slot-scope="props">
|
||||
<span v-if="props.value !== '100000'">{{ props.value }}{{ $t('itemsPerPage') }}</span>
|
||||
<span v-if="props.value === '100000'">{{ $t('cmdb.ci.all') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
</div>
|
||||
</a-spin>
|
||||
|
||||
<BatchDownload
|
||||
ref="batchDownload"
|
||||
@@ -82,6 +85,12 @@
|
||||
/>
|
||||
|
||||
<CIDetailDrawer ref="detail" :typeId="subnetCITypeId" />
|
||||
|
||||
<CreateInstanceForm
|
||||
ref="create"
|
||||
:typeIdFromRelation="subnetCITypeId"
|
||||
@submit="batchUpdate"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -90,7 +99,7 @@ import _ from 'lodash'
|
||||
import { mapState } from 'vuex'
|
||||
import ExcelJS from 'exceljs'
|
||||
import FileSaver from 'file-saver'
|
||||
import { searchCI, deleteCI } from '@/modules/cmdb/api/ci'
|
||||
import { searchCI, deleteCI, updateCI } from '@/modules/cmdb/api/ci'
|
||||
import { getSubscribeAttributes } from '@/modules/cmdb/api/preference'
|
||||
import { getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
|
||||
import { getCITableColumns } from '@/modules/cmdb/utils/helper'
|
||||
@@ -100,6 +109,7 @@ import CITable from '@/modules/cmdb/components/ciTable/index.vue'
|
||||
import BatchDownload from '@/modules/cmdb/components/batchDownload/batchDownload.vue'
|
||||
import CIDetailDrawer from '@/modules/cmdb/views/ci/modules/ciDetailDrawer.vue'
|
||||
import EditAttrsPopover from '@/modules/cmdb/views/ci/modules/editAttrsPopover.vue'
|
||||
import CreateInstanceForm from '@/modules/cmdb/views/ci/modules/CreateInstanceForm'
|
||||
|
||||
export default {
|
||||
name: 'SubnetList',
|
||||
@@ -108,7 +118,8 @@ export default {
|
||||
CITable,
|
||||
BatchDownload,
|
||||
CIDetailDrawer,
|
||||
EditAttrsPopover
|
||||
EditAttrsPopover,
|
||||
CreateInstanceForm
|
||||
},
|
||||
props: {
|
||||
subnetCIType: {
|
||||
@@ -122,6 +133,7 @@ export default {
|
||||
pageSize: 50,
|
||||
pageSizeOptions: ['50', '100', '200'],
|
||||
loading: false,
|
||||
loadTip: '',
|
||||
sortByTable: undefined,
|
||||
|
||||
instanceList: [],
|
||||
@@ -130,6 +142,7 @@ export default {
|
||||
preferenceAttrList: [],
|
||||
attrList: [],
|
||||
attributes: {},
|
||||
selectedRowKeys: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -275,7 +288,7 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
handleExport() {
|
||||
openBatchDownload() {
|
||||
this.$refs.batchDownload.open({
|
||||
preferenceAttrList: this.preferenceAttrList,
|
||||
ciTypeName: this.$t('cmdb.ipam.subnetList') || '',
|
||||
@@ -336,6 +349,7 @@ export default {
|
||||
FileSaver.saveAs(file, `${filename}.xlsx`)
|
||||
})
|
||||
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
||||
},
|
||||
@@ -362,6 +376,120 @@ export default {
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
onSelectChange(records) {
|
||||
this.selectedRowKeys = records.map((i) => i.ci_id || i._id)
|
||||
},
|
||||
|
||||
batchDelete() {
|
||||
this.$confirm({
|
||||
title: this.$t('warning'),
|
||||
content: this.$t('confirmDelete'),
|
||||
onOk: () => {
|
||||
this.batchDeleteAsync()
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
async batchDeleteAsync() {
|
||||
let successNum = 0
|
||||
let errorNum = 0
|
||||
this.loading = true
|
||||
this.loadTip = this.$t('cmdb.ci.batchDeleting')
|
||||
|
||||
const floor = Math.ceil(this.selectedRowKeys.length / 6)
|
||||
for (let i = 0; i < floor; i++) {
|
||||
const itemList = this.selectedRowKeys.slice(6 * i, 6 * i + 6)
|
||||
const promises = itemList.map((x) => deleteCI(x, false))
|
||||
await Promise.allSettled(promises)
|
||||
.then((res) => {
|
||||
res.forEach((r) => {
|
||||
if (r.status === 'fulfilled') {
|
||||
successNum += 1
|
||||
} else {
|
||||
errorNum += 1
|
||||
}
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.loadTip = this.$t('cmdb.ci.batchDeleting2', {
|
||||
total: this.selectedRowKeys.length,
|
||||
successNum: successNum,
|
||||
errorNum: errorNum,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
this.loading = false
|
||||
this.loadTip = ''
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
||||
this.$nextTick(() => {
|
||||
this.page = 1
|
||||
this.getTableData()
|
||||
})
|
||||
},
|
||||
|
||||
batchUpdate(values) {
|
||||
this.$confirm({
|
||||
title: this.$t('warning'),
|
||||
content: this.$t('cmdb.ci.batchUpdateConfirm'),
|
||||
onOk: () => {
|
||||
this.batchUpdateAsync(values)
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
async batchUpdateAsync(values) {
|
||||
let successNum = 0
|
||||
let errorNum = 0
|
||||
this.loading = true
|
||||
this.loadTip = this.$t('cmdb.ci.batchUpdateInProgress') + '...'
|
||||
|
||||
const payload = {}
|
||||
Object.keys(values).forEach((key) => {
|
||||
if (values[key] === undefined || values[key] === null) {
|
||||
payload[key] = null
|
||||
} else {
|
||||
payload[key] = values[key]
|
||||
}
|
||||
})
|
||||
this.$refs.create.visible = false
|
||||
const key = 'updatable'
|
||||
let errorMsg = ''
|
||||
|
||||
for (let i = 0; i < this.selectedRowKeys.length; i++) {
|
||||
await updateCI(this.selectedRowKeys[i], payload, false)
|
||||
.then(() => {
|
||||
successNum += 1
|
||||
})
|
||||
.catch((error) => {
|
||||
errorMsg = errorMsg + '\n' + `${this.selectedRowKeys[i]}:${error.response?.data?.message ?? ''}`
|
||||
this.$notification.warning({
|
||||
key,
|
||||
message: this.$t('warning'),
|
||||
description: errorMsg,
|
||||
duration: 0,
|
||||
style: { whiteSpace: 'break-spaces', overflow: 'auto', maxHeight: this.windowHeight - 80 + 'px' },
|
||||
})
|
||||
errorNum += 1
|
||||
})
|
||||
.finally(() => {
|
||||
this.loadTip = this.$t('cmdb.ci.batchUpdateInProgress2', {
|
||||
total: this.selectedRowKeys.length,
|
||||
successNum: successNum,
|
||||
errorNum: errorNum,
|
||||
})
|
||||
})
|
||||
}
|
||||
this.loading = false
|
||||
this.loadTip = ''
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
||||
this.getTableData()
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@@ -30,13 +30,13 @@
|
||||
>新增</a-button
|
||||
>
|
||||
</SearchForm>
|
||||
<vxe-table
|
||||
<ops-table
|
||||
ref="xTable"
|
||||
row-id="_id"
|
||||
:data="tableData"
|
||||
:height="tableHeight"
|
||||
highlight-hover-row
|
||||
:checkbox-config="{ reserve: true }"
|
||||
:checkbox-config="{ reserve: true, highlight: true, range: true }"
|
||||
@checkbox-change="onSelectChange"
|
||||
@checkbox-all="onSelectChange"
|
||||
show-overflow="tooltip"
|
||||
@@ -76,7 +76,7 @@
|
||||
<span v-if="col.value_type == '6' && row[col.field]">{{ JSON.stringify(row[col.field]) }}</span>
|
||||
</template>
|
||||
</vxe-table-column>
|
||||
</vxe-table>
|
||||
</ops-table>
|
||||
<a-pagination
|
||||
v-model="currentPage"
|
||||
size="small"
|
||||
@@ -216,7 +216,7 @@ export default {
|
||||
this.totalNumber = res.numfound
|
||||
this.columns = this.getColumns(res.result, this.preferenceAttrList)
|
||||
this.$nextTick(() => {
|
||||
const _table = this.$refs.xTable
|
||||
const _table = this.$refs.xTable?.getVxetableRef?.()
|
||||
if (_table) {
|
||||
_table.refreshColumn()
|
||||
}
|
||||
@@ -316,7 +316,11 @@ export default {
|
||||
|
||||
onSelectChange() {},
|
||||
handleClose() {
|
||||
this.$refs.xTable.clearCheckboxRow()
|
||||
const _table = this.$refs.xTable?.getVxetableRef?.()
|
||||
if (_table) {
|
||||
_table.clearCheckboxRow()
|
||||
}
|
||||
|
||||
this.currentPage = 1
|
||||
this.expression = ''
|
||||
this.isFocusExpression = false
|
||||
@@ -324,8 +328,10 @@ export default {
|
||||
this.showCreateBtn = true
|
||||
},
|
||||
async handleOk() {
|
||||
const selectRecordsCurrent = this.$refs.xTable.getCheckboxRecords()
|
||||
const selectRecordsReserved = this.$refs.xTable.getCheckboxReserveRecords()
|
||||
const _table = this.$refs.xTable?.getVxetableRef?.()
|
||||
const selectRecordsCurrent = _table?.getCheckboxRecords?.() || []
|
||||
const selectRecordsReserved = _table?.getCheckboxReserveRecords?.() || []
|
||||
|
||||
const ciIds = [...selectRecordsCurrent, ...selectRecordsReserved].map((record) => record._id)
|
||||
if (ciIds.length) {
|
||||
if (this.type === 'children') {
|
||||
|
@@ -1,8 +1,10 @@
|
||||
import _ from 'lodash'
|
||||
import i18n from '@/lang'
|
||||
|
||||
export function timeFix() {
|
||||
const time = new Date()
|
||||
const hour = time.getHours()
|
||||
return hour < 9 ? '早上好' : hour <= 11 ? '上午好' : hour <= 13 ? '中午好' : hour < 20 ? '下午好' : '晚上好'
|
||||
return hour < 9 ? i18n.t('cs.login.welcomeTime1') : hour <= 11 ? i18n.t('cs.login.welcomeTime2') : hour <= 13 ? i18n.t('cs.login.welcomeTime3') : hour < 20 ? i18n.t('cs.login.welcomeTime4') : i18n.t('cs.login.welcomeTime5')
|
||||
}
|
||||
|
||||
export function welcome() {
|
||||
|
@@ -23,7 +23,7 @@
|
||||
<a-form-model-item :label="$t('cs.auth.oauth2.tokenUrl')" prop="token_url">
|
||||
<a-input v-model="form.token_url" :placeholder="$t('cs.auth.oauth2.tokenUrlPlaceholder')" />
|
||||
</a-form-model-item>
|
||||
<SpanTitle>其他</SpanTitle>
|
||||
<SpanTitle>{{ $t('cs.auth.other') }}</SpanTitle>
|
||||
<a-form-model-item :label="$t('cs.auth.oauth2.userInfo')" prop="user_info" :wrapper-col="{ span: 15 }">
|
||||
<vue-json-editor
|
||||
:style="{ '--custom-height': `${200}px` }"
|
||||
|
@@ -445,6 +445,27 @@ const cs_en = {
|
||||
test: 'Test',
|
||||
selectApp: 'Select App',
|
||||
},
|
||||
login: {
|
||||
loginText: 'OneOps making operations simple',
|
||||
username: 'Username/Email',
|
||||
usernameRequired: 'Please input Username/Email',
|
||||
password: 'Password',
|
||||
passwordRequired: 'Please input Password',
|
||||
captcha: 'Captcha',
|
||||
captchaRequired: 'Please input Captcha',
|
||||
loginBtn: 'Login',
|
||||
autoLogin: 'Auto Login',
|
||||
otherLoginWay: 'Other Login',
|
||||
welcomeMessage: 'Welcome',
|
||||
welcomeDesc: '{name} Welcome Back',
|
||||
welcomeTime1: 'Good Morning',
|
||||
welcomeTime2: 'Good Morning',
|
||||
welcomeTime3: 'Good Afternoon',
|
||||
welcomeTime4: 'Good Afternoon',
|
||||
welcomeTime5: 'Good Evening',
|
||||
oneDeviceLogin: 'Login on one device only',
|
||||
logoutSoon: 'Logging Out Soon...',
|
||||
}
|
||||
}
|
||||
|
||||
export default cs_en
|
||||
|
@@ -443,5 +443,26 @@ const cs_zh = {
|
||||
test: '测试',
|
||||
selectApp: '选择应用',
|
||||
},
|
||||
login: {
|
||||
loginText: '维易科技 让运维变简单',
|
||||
username: '用户名/邮箱',
|
||||
usernameRequired: '请输入用户名或邮箱',
|
||||
password: '密码',
|
||||
passwordRequired: '请输入密码',
|
||||
captcha: '图片验证码',
|
||||
captchaRequired: '请输入验证码',
|
||||
loginBtn: '登录',
|
||||
autoLogin: '自动登录',
|
||||
otherLoginWay: '其他登录方式',
|
||||
welcomeMessage: '欢迎',
|
||||
welcomeDesc: '{name} 欢迎回来',
|
||||
welcomeTime1: '早上好',
|
||||
welcomeTime2: '上午好',
|
||||
welcomeTime3: '中午好',
|
||||
welcomeTime4: '下午好',
|
||||
welcomeTime5: '晚上好',
|
||||
oneDeviceLogin: '只能在一个设备上登录',
|
||||
logoutSoon: '即将登出...',
|
||||
}
|
||||
}
|
||||
export default cs_zh
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="ops-login">
|
||||
<div class="ops-login-left">
|
||||
<span>维易科技 让运维变简单</span>
|
||||
<span>{{ $t('cs.login.loginText') }}</span>
|
||||
</div>
|
||||
<div class="ops-login-right">
|
||||
<img src="../../assets/logo_VECMDB.png" />
|
||||
@@ -12,7 +12,7 @@
|
||||
@submit="handleSubmit"
|
||||
hideRequiredMark
|
||||
:colon="false">
|
||||
<a-form-item label="用户名/邮箱">
|
||||
<a-form-item :label="$t('cs.login.username')">
|
||||
<a-input
|
||||
size="large"
|
||||
type="text"
|
||||
@@ -20,7 +20,10 @@
|
||||
v-decorator="[
|
||||
'username',
|
||||
{
|
||||
rules: [{ required: true, message: '请输入用户名或邮箱' }, { validator: handleUsernameOrEmail }],
|
||||
rules: [
|
||||
{ required: true, message: $t('cs.login.usernameRequired') },
|
||||
{ validator: handleUsernameOrEmail }
|
||||
],
|
||||
validateTrigger: 'change',
|
||||
},
|
||||
]"
|
||||
@@ -28,19 +31,24 @@
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="密码">
|
||||
<a-form-item :label="$t('cs.login.password')">
|
||||
<a-input
|
||||
size="large"
|
||||
type="password"
|
||||
autocomplete="false"
|
||||
class="ops-input"
|
||||
v-decorator="['password', { rules: [{ required: true, message: '请输入密码' }], validateTrigger: 'blur' }]"
|
||||
v-decorator="[
|
||||
'password',
|
||||
{ rules: [{ required: true, message: $t('cs.login.passwordRequired') }], validateTrigger: 'blur' }
|
||||
]"
|
||||
>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item>
|
||||
<a-checkbox v-decorator="['rememberMe', { valuePropName: 'checked' }]">自动登录</a-checkbox>
|
||||
<a-checkbox v-decorator="['rememberMe', { valuePropName: 'checked' }]">
|
||||
{{ $t('cs.login.autoLogin') }}
|
||||
</a-checkbox>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item style="margin-top:24px">
|
||||
@@ -51,17 +59,21 @@
|
||||
class="login-button"
|
||||
:loading="state.loginBtn"
|
||||
:disabled="state.loginBtn"
|
||||
>登录</a-button
|
||||
>
|
||||
{{ $t('cs.login.loginBtn') }}
|
||||
</a-button>
|
||||
<a-checkbox
|
||||
v-if="enable_list && enable_list.length === 1 && enable_list[0].auth_type === 'LDAP'"
|
||||
v-if="hasLDAP"
|
||||
v-model="auth_with_ldap"
|
||||
>LDAP</a-checkbox
|
||||
>
|
||||
LDAP
|
||||
</a-checkbox>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<template v-if="_enable_list && _enable_list.length >= 1">
|
||||
<a-divider style="font-size:14px">其他登录方式</a-divider>
|
||||
<a-divider style="font-size:14px">
|
||||
{{ $t('cs.login.otherLoginWay') }}
|
||||
</a-divider>
|
||||
<div style="text-align:center">
|
||||
<span v-for="(item, index) in _enable_list" :key="item.auth_type">
|
||||
<ops-icon :type="item.auth_type" />
|
||||
@@ -104,21 +116,20 @@ export default {
|
||||
computed: {
|
||||
...mapState({ auth_enable: (state) => state?.user?.auth_enable ?? {} }),
|
||||
enable_list() {
|
||||
return this.auth_enable.enable_list ?? []
|
||||
return this.auth_enable?.enable_list ?? []
|
||||
},
|
||||
hasLDAP() {
|
||||
return this.enable_list.some((en) => en.auth_type === 'LDAP')
|
||||
},
|
||||
_enable_list() {
|
||||
return this.enable_list.filter((en) => en.auth_type !== 'LDAP')
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
enable_list: {
|
||||
hasLDAP: {
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
if (newVal && newVal.length === 1 && newVal[0].auth_type === 'LDAP') {
|
||||
this.auth_with_ldap = true
|
||||
} else {
|
||||
this.auth_with_ldap = false
|
||||
}
|
||||
this.auth_with_ldap = newVal
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -142,7 +153,7 @@ export default {
|
||||
handleSubmit(e) {
|
||||
e.preventDefault()
|
||||
const {
|
||||
enable_list,
|
||||
hasLDAP,
|
||||
form: { validateFields },
|
||||
state,
|
||||
customActiveKey,
|
||||
@@ -160,10 +171,7 @@ export default {
|
||||
delete loginParams.username
|
||||
loginParams.username = values.username
|
||||
loginParams.password = appConfig.useEncryption ? md5(values.password) : values.password
|
||||
loginParams.auth_with_ldap =
|
||||
enable_list && enable_list.length === 1 && enable_list[0].auth_type === 'LDAP'
|
||||
? Number(auth_with_ldap)
|
||||
: undefined
|
||||
loginParams.auth_with_ldap = hasLDAP ? Number(auth_with_ldap) : undefined
|
||||
|
||||
localStorage.setItem('ops_auth_type', '')
|
||||
Login({ userInfo: loginParams })
|
||||
@@ -186,8 +194,8 @@ export default {
|
||||
// 延迟 1 秒显示欢迎信息
|
||||
setTimeout(() => {
|
||||
this.$notification.success({
|
||||
message: '欢迎',
|
||||
description: `${timeFix()},欢迎回来`,
|
||||
message: this.$t('cs.login.welcomeMessage'),
|
||||
description: this.$t('cs.login.welcomeDesc', { name: timeFix() }),
|
||||
})
|
||||
}, 1000)
|
||||
},
|
||||
|
@@ -41,13 +41,14 @@ services:
|
||||
- redis
|
||||
|
||||
cmdb-api:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/veops/cmdb-api:2.5.2
|
||||
image: registry.cn-hangzhou.aliyuncs.com/veops/cmdb-api:2.5.3
|
||||
container_name: cmdb-api
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
WAIT_HOSTS: cmdb-db:3306, cmdb-cache:6379
|
||||
SYSTEM_DEFAULT_LANGUAGE: # en-US, zh-CN
|
||||
depends_on:
|
||||
cmdb-db:
|
||||
condition: service_healthy
|
||||
@@ -84,7 +85,7 @@ services:
|
||||
test: "ps aux|grep -v grep|grep -v '1 root'|grep gunicorn || exit 1"
|
||||
|
||||
cmdb-ui:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/veops/cmdb-ui:2.5.2
|
||||
image: registry.cn-hangzhou.aliyuncs.com/veops/cmdb-ui:2.5.3
|
||||
container_name: cmdb-ui
|
||||
depends_on:
|
||||
cmdb-api:
|
||||
|
Reference in New Issue
Block a user