mirror of https://github.com/veops/cmdb.git
Merge branch 'veops:master' into master
This commit is contained in:
commit
de51cb3e21
|
@ -167,24 +167,30 @@ class AttributeManager(object):
|
||||||
def get_attribute_by_name(self, name):
|
def get_attribute_by_name(self, name):
|
||||||
attr = Attribute.get_by(name=name, first=True)
|
attr = Attribute.get_by(name=name, first=True)
|
||||||
if attr.get("is_choice"):
|
if attr.get("is_choice"):
|
||||||
attr["choice_value"] = self.get_choice_values(attr["id"], attr["value_type"],
|
attr["choice_value"] = self.get_choice_values(attr["id"],
|
||||||
attr["choice_web_hook"], attr.get("choice_other"))
|
attr["value_type"],
|
||||||
|
attr["choice_web_hook"],
|
||||||
|
attr.get("choice_other"))
|
||||||
|
|
||||||
return attr
|
return attr
|
||||||
|
|
||||||
def get_attribute_by_alias(self, alias):
|
def get_attribute_by_alias(self, alias):
|
||||||
attr = Attribute.get_by(alias=alias, first=True)
|
attr = Attribute.get_by(alias=alias, first=True)
|
||||||
if attr.get("is_choice"):
|
if attr.get("is_choice"):
|
||||||
attr["choice_value"] = self.get_choice_values(attr["id"], attr["value_type"],
|
attr["choice_value"] = self.get_choice_values(attr["id"],
|
||||||
attr["choice_web_hook"], attr.get("choice_other"))
|
attr["value_type"],
|
||||||
|
attr["choice_web_hook"],
|
||||||
|
attr.get("choice_other"))
|
||||||
|
|
||||||
return attr
|
return attr
|
||||||
|
|
||||||
def get_attribute_by_id(self, _id):
|
def get_attribute_by_id(self, _id):
|
||||||
attr = Attribute.get_by_id(_id).to_dict()
|
attr = Attribute.get_by_id(_id).to_dict()
|
||||||
if attr.get("is_choice"):
|
if attr.get("is_choice"):
|
||||||
attr["choice_value"] = self.get_choice_values(attr["id"], attr["value_type"],
|
attr["choice_value"] = self.get_choice_values(attr["id"],
|
||||||
attr["choice_web_hook"], attr.get("choice_other"))
|
attr["value_type"],
|
||||||
|
attr["choice_web_hook"],
|
||||||
|
attr.get("choice_other"))
|
||||||
|
|
||||||
return attr
|
return attr
|
||||||
|
|
||||||
|
|
|
@ -266,7 +266,7 @@ class CIManager(object):
|
||||||
value_table = TableMap(attr_name=id2name[attr_id]).table
|
value_table = TableMap(attr_name=id2name[attr_id]).table
|
||||||
|
|
||||||
values = value_table.get_by(attr_id=attr_id,
|
values = value_table.get_by(attr_id=attr_id,
|
||||||
value=ci_dict.get(id2name[attr_id]) or None,
|
value=ci_dict.get(id2name[attr_id]),
|
||||||
only_query=True).join(
|
only_query=True).join(
|
||||||
CI, CI.id == value_table.ci_id).filter(CI.type_id == type_id)
|
CI, CI.id == value_table.ci_id).filter(CI.type_id == type_id)
|
||||||
_ci_ids = set([i.ci_id for i in values])
|
_ci_ids = set([i.ci_id for i in values])
|
||||||
|
@ -292,6 +292,53 @@ class CIManager(object):
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _reference_to_ci_id(attr, payload):
|
||||||
|
def __unique_value2id(_type, _v):
|
||||||
|
value_table = TableMap(attr_name=_type.unique_id).table
|
||||||
|
ci = value_table.get_by(attr_id=attr.id, value=_v)
|
||||||
|
if ci is not None:
|
||||||
|
return ci.ci_id
|
||||||
|
|
||||||
|
return abort(400, ErrFormat.ci_reference_invalid.format(attr.alias, _v))
|
||||||
|
|
||||||
|
def __valid_reference_id_existed(_id, _type_id):
|
||||||
|
ci = CI.get_by_id(_id) or abort(404, ErrFormat.ci_reference_not_found.format(attr.alias, _id))
|
||||||
|
|
||||||
|
if ci.type_id != _type_id:
|
||||||
|
return abort(400, ErrFormat.ci_reference_invalid.format(attr.alias, _id))
|
||||||
|
|
||||||
|
if attr.name in payload:
|
||||||
|
k, reference_value = attr.name, payload[attr.name]
|
||||||
|
elif attr.alias in payload:
|
||||||
|
k, reference_value = attr.alias, payload[attr.alias]
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
if not reference_value:
|
||||||
|
return
|
||||||
|
|
||||||
|
reference_type = None
|
||||||
|
if isinstance(reference_value, list):
|
||||||
|
for idx, v in enumerate(reference_value):
|
||||||
|
if isinstance(v, dict) and v.get('unique'):
|
||||||
|
if reference_type is None:
|
||||||
|
reference_type = CITypeCache.get(attr.reference_type_id)
|
||||||
|
if reference_type is not None:
|
||||||
|
reference_value[idx] = __unique_value2id(reference_type, v)
|
||||||
|
else:
|
||||||
|
__valid_reference_id_existed(v, attr.reference_type_id)
|
||||||
|
|
||||||
|
elif isinstance(reference_value, dict) and reference_value.get('unique'):
|
||||||
|
if reference_type is None:
|
||||||
|
reference_type = CITypeCache.get(attr.reference_type_id)
|
||||||
|
if reference_type is not None:
|
||||||
|
reference_value = __unique_value2id(reference_type, reference_value)
|
||||||
|
elif str(reference_value).isdigit():
|
||||||
|
reference_value = int(reference_value)
|
||||||
|
__valid_reference_id_existed(reference_value, attr.reference_type_id)
|
||||||
|
|
||||||
|
payload[k] = reference_value
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add(cls, ci_type_name,
|
def add(cls, ci_type_name,
|
||||||
exist_policy=ExistPolicy.REPLACE,
|
exist_policy=ExistPolicy.REPLACE,
|
||||||
|
@ -392,6 +439,8 @@ class CIManager(object):
|
||||||
|
|
||||||
if attr.re_check and password_dict.get(attr.id):
|
if attr.re_check and password_dict.get(attr.id):
|
||||||
value_manager.check_re(attr.re_check, attr.alias, password_dict[attr.id][0])
|
value_manager.check_re(attr.re_check, attr.alias, password_dict[attr.id][0])
|
||||||
|
elif attr.is_reference:
|
||||||
|
cls._reference_to_ci_id(attr, ci_dict)
|
||||||
|
|
||||||
cls._valid_unique_constraint(ci_type.id, ci_dict, ci and ci.id)
|
cls._valid_unique_constraint(ci_type.id, ci_dict, ci and ci.id)
|
||||||
|
|
||||||
|
@ -443,9 +492,10 @@ class CIManager(object):
|
||||||
|
|
||||||
return ci.id
|
return ci.id
|
||||||
|
|
||||||
def update(self, ci_id, _is_admin=False, ticket_id=None, __sync=False, **ci_dict):
|
def update(self, ci_id, _is_admin=False, ticket_id=None, _sync=False, **ci_dict):
|
||||||
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||||
ci = self.confirm_ci_existed(ci_id)
|
ci = self.confirm_ci_existed(ci_id)
|
||||||
|
ci_type = ci.ci_type
|
||||||
|
|
||||||
attrs = CITypeAttributeManager.get_all_attributes(ci.type_id)
|
attrs = CITypeAttributeManager.get_all_attributes(ci.type_id)
|
||||||
ci_type_attrs_name = {attr.name: attr for _, attr in attrs}
|
ci_type_attrs_name = {attr.name: attr for _, attr in attrs}
|
||||||
|
@ -475,11 +525,13 @@ class CIManager(object):
|
||||||
|
|
||||||
if attr.re_check and password_dict.get(attr.id):
|
if attr.re_check and password_dict.get(attr.id):
|
||||||
value_manager.check_re(attr.re_check, attr.alias, password_dict[attr.id][0])
|
value_manager.check_re(attr.re_check, attr.alias, password_dict[attr.id][0])
|
||||||
|
elif attr.is_reference:
|
||||||
|
self._reference_to_ci_id(attr, ci_dict)
|
||||||
|
|
||||||
limit_attrs = self._valid_ci_for_no_read(ci) if not _is_admin else {}
|
limit_attrs = self._valid_ci_for_no_read(ci) if not _is_admin else {}
|
||||||
|
|
||||||
record_id = None
|
record_id = None
|
||||||
with redis_lock.Lock(rd.r, ci.ci_type.name):
|
with redis_lock.Lock(rd.r, ci_type.name):
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
self._valid_unique_constraint(ci.type_id, ci_dict, ci_id)
|
self._valid_unique_constraint(ci.type_id, ci_dict, ci_id)
|
||||||
|
@ -510,14 +562,14 @@ class CIManager(object):
|
||||||
record_id = self.save_password(ci.id, attr_id, password_dict[attr_id], record_id, ci.type_id)
|
record_id = self.save_password(ci.id, attr_id, password_dict[attr_id], record_id, ci.type_id)
|
||||||
|
|
||||||
if record_id or has_dynamic: # has changed
|
if record_id or has_dynamic: # has changed
|
||||||
if not __sync:
|
if not _sync:
|
||||||
ci_cache.apply_async(args=(ci_id, OperateType.UPDATE, record_id), queue=CMDB_QUEUE)
|
ci_cache.apply_async(args=(ci_id, OperateType.UPDATE, record_id), queue=CMDB_QUEUE)
|
||||||
else:
|
else:
|
||||||
ci_cache(ci_id, OperateType.UPDATE, record_id)
|
ci_cache(ci_id, OperateType.UPDATE, record_id)
|
||||||
|
|
||||||
ref_ci_dict = {k: v for k, v in ci_dict.items() if k.startswith("$") and "." in k}
|
ref_ci_dict = {k: v for k, v in ci_dict.items() if k.startswith("$") and "." in k}
|
||||||
if ref_ci_dict:
|
if ref_ci_dict:
|
||||||
if not __sync:
|
if not _sync:
|
||||||
ci_relation_add.apply_async(args=(ref_ci_dict, ci.id), queue=CMDB_QUEUE)
|
ci_relation_add.apply_async(args=(ref_ci_dict, ci.id), queue=CMDB_QUEUE)
|
||||||
else:
|
else:
|
||||||
ci_relation_add(ref_ci_dict, ci.id)
|
ci_relation_add(ref_ci_dict, ci.id)
|
||||||
|
@ -578,7 +630,7 @@ class CIManager(object):
|
||||||
if ci_dict:
|
if ci_dict:
|
||||||
AttributeHistoryManger.add(None, ci_id, [(None, OperateType.DELETE, ci_dict, None)], ci.type_id)
|
AttributeHistoryManger.add(None, ci_id, [(None, OperateType.DELETE, ci_dict, None)], ci.type_id)
|
||||||
|
|
||||||
ci_delete.apply_async(args=(ci_id,), queue=CMDB_QUEUE)
|
ci_delete.apply_async(args=(ci_id, ci.type_id), queue=CMDB_QUEUE)
|
||||||
delete_id_filter.apply_async(args=(ci_id,), queue=CMDB_QUEUE)
|
delete_id_filter.apply_async(args=(ci_id,), queue=CMDB_QUEUE)
|
||||||
|
|
||||||
return ci_id
|
return ci_id
|
||||||
|
@ -773,7 +825,7 @@ class CIManager(object):
|
||||||
value_table = ValueTypeMap.table[ValueTypeEnum.PASSWORD]
|
value_table = ValueTypeMap.table[ValueTypeEnum.PASSWORD]
|
||||||
if current_app.config.get('SECRETS_ENGINE') == 'inner':
|
if current_app.config.get('SECRETS_ENGINE') == 'inner':
|
||||||
if value:
|
if value:
|
||||||
encrypt_value, status = InnerCrypt().encrypt(value)
|
encrypt_value, status = InnerCrypt().encrypt(str(value))
|
||||||
if not status:
|
if not status:
|
||||||
current_app.logger.error('save password failed: {}'.format(encrypt_value))
|
current_app.logger.error('save password failed: {}'.format(encrypt_value))
|
||||||
return abort(400, ErrFormat.password_save_failed.format(encrypt_value))
|
return abort(400, ErrFormat.password_save_failed.format(encrypt_value))
|
||||||
|
@ -801,7 +853,7 @@ class CIManager(object):
|
||||||
vault = VaultClient(current_app.config.get('VAULT_URL'), current_app.config.get('VAULT_TOKEN'))
|
vault = VaultClient(current_app.config.get('VAULT_URL'), current_app.config.get('VAULT_TOKEN'))
|
||||||
if value:
|
if value:
|
||||||
try:
|
try:
|
||||||
vault.update("/{}/{}".format(ci_id, attr_id), dict(v=value))
|
vault.update("/{}/{}".format(ci_id, attr_id), dict(v=str(value)))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
current_app.logger.error('save password to vault failed: {}'.format(e))
|
current_app.logger.error('save password to vault failed: {}'.format(e))
|
||||||
return abort(400, ErrFormat.password_save_failed.format('write vault failed'))
|
return abort(400, ErrFormat.password_save_failed.format('write vault failed'))
|
||||||
|
|
|
@ -145,7 +145,7 @@ class CITypeManager(object):
|
||||||
kwargs["alias"] = kwargs["name"] if not kwargs.get("alias") else kwargs["alias"]
|
kwargs["alias"] = kwargs["name"] if not kwargs.get("alias") else kwargs["alias"]
|
||||||
|
|
||||||
cls._validate_unique(name=kwargs['name'])
|
cls._validate_unique(name=kwargs['name'])
|
||||||
cls._validate_unique(alias=kwargs['alias'])
|
# cls._validate_unique(alias=kwargs['alias'])
|
||||||
|
|
||||||
kwargs["unique_id"] = unique_key.id
|
kwargs["unique_id"] = unique_key.id
|
||||||
kwargs['uid'] = current_user.uid
|
kwargs['uid'] = current_user.uid
|
||||||
|
@ -184,7 +184,7 @@ class CITypeManager(object):
|
||||||
ci_type = cls.check_is_existed(type_id)
|
ci_type = cls.check_is_existed(type_id)
|
||||||
|
|
||||||
cls._validate_unique(type_id=type_id, name=kwargs.get('name'))
|
cls._validate_unique(type_id=type_id, name=kwargs.get('name'))
|
||||||
cls._validate_unique(type_id=type_id, alias=kwargs.get('alias') or kwargs.get('name'))
|
# cls._validate_unique(type_id=type_id, alias=kwargs.get('alias') or kwargs.get('name'))
|
||||||
|
|
||||||
unique_key = kwargs.pop("unique_key", None)
|
unique_key = kwargs.pop("unique_key", None)
|
||||||
unique_key = AttributeCache.get(unique_key)
|
unique_key = AttributeCache.get(unique_key)
|
||||||
|
@ -234,6 +234,10 @@ class CITypeManager(object):
|
||||||
if CITypeInheritance.get_by(parent_id=type_id, first=True):
|
if CITypeInheritance.get_by(parent_id=type_id, first=True):
|
||||||
return abort(400, ErrFormat.ci_type_inheritance_cannot_delete)
|
return abort(400, ErrFormat.ci_type_inheritance_cannot_delete)
|
||||||
|
|
||||||
|
reference = Attribute.get_by(reference_type_id=type_id, first=True, to_dict=False)
|
||||||
|
if reference is not None:
|
||||||
|
return abort(400, ErrFormat.ci_type_referenced_cannot_delete.format(reference.alias))
|
||||||
|
|
||||||
relation_views = PreferenceRelationView.get_by(to_dict=False)
|
relation_views = PreferenceRelationView.get_by(to_dict=False)
|
||||||
for rv in relation_views:
|
for rv in relation_views:
|
||||||
for item in (rv.cr_ids or []):
|
for item in (rv.cr_ids or []):
|
||||||
|
@ -1323,6 +1327,7 @@ class CITypeTemplateManager(object):
|
||||||
def _import_attributes(self, type2attributes):
|
def _import_attributes(self, type2attributes):
|
||||||
attributes = [attr for type_id in type2attributes for attr in type2attributes[type_id]]
|
attributes = [attr for type_id in type2attributes for attr in type2attributes[type_id]]
|
||||||
attrs = []
|
attrs = []
|
||||||
|
references = []
|
||||||
for i in copy.deepcopy(attributes):
|
for i in copy.deepcopy(attributes):
|
||||||
if i.pop('inherited', None):
|
if i.pop('inherited', None):
|
||||||
continue
|
continue
|
||||||
|
@ -1337,6 +1342,10 @@ class CITypeTemplateManager(object):
|
||||||
if not choice_value:
|
if not choice_value:
|
||||||
i['is_choice'] = False
|
i['is_choice'] = False
|
||||||
|
|
||||||
|
if i.get('reference_type_id'):
|
||||||
|
references.append(copy.deepcopy(i))
|
||||||
|
i.pop('reference_type_id')
|
||||||
|
|
||||||
attrs.append((i, choice_value))
|
attrs.append((i, choice_value))
|
||||||
|
|
||||||
attr_id_map = self.__import(Attribute, [i[0] for i in copy.deepcopy(attrs)])
|
attr_id_map = self.__import(Attribute, [i[0] for i in copy.deepcopy(attrs)])
|
||||||
|
@ -1345,7 +1354,7 @@ class CITypeTemplateManager(object):
|
||||||
if choice_value and not i.get('choice_web_hook') and not i.get('choice_other'):
|
if choice_value and not i.get('choice_web_hook') and not i.get('choice_other'):
|
||||||
AttributeManager.add_choice_values(attr_id_map.get(i['id'], i['id']), i['value_type'], choice_value)
|
AttributeManager.add_choice_values(attr_id_map.get(i['id'], i['id']), i['value_type'], choice_value)
|
||||||
|
|
||||||
return attr_id_map
|
return attr_id_map, references
|
||||||
|
|
||||||
def _import_ci_types(self, ci_types, attr_id_map):
|
def _import_ci_types(self, ci_types, attr_id_map):
|
||||||
for i in ci_types:
|
for i in ci_types:
|
||||||
|
@ -1359,6 +1368,11 @@ class CITypeTemplateManager(object):
|
||||||
|
|
||||||
return self.__import(CIType, ci_types)
|
return self.__import(CIType, ci_types)
|
||||||
|
|
||||||
|
def _import_reference_attributes(self, attrs, type_id_map):
|
||||||
|
for attr in attrs:
|
||||||
|
attr['reference_type_id'] = type_id_map.get(attr['reference_type_id'], attr['reference_type_id'])
|
||||||
|
self.__import(Attribute, attrs)
|
||||||
|
|
||||||
def _import_ci_type_groups(self, ci_type_groups, type_id_map):
|
def _import_ci_type_groups(self, ci_type_groups, type_id_map):
|
||||||
_ci_type_groups = copy.deepcopy(ci_type_groups)
|
_ci_type_groups = copy.deepcopy(ci_type_groups)
|
||||||
for i in _ci_type_groups:
|
for i in _ci_type_groups:
|
||||||
|
@ -1584,13 +1598,15 @@ class CITypeTemplateManager(object):
|
||||||
|
|
||||||
import time
|
import time
|
||||||
s = time.time()
|
s = time.time()
|
||||||
attr_id_map = self._import_attributes(tpt.get('type2attributes') or {})
|
attr_id_map, references = self._import_attributes(tpt.get('type2attributes') or {})
|
||||||
current_app.logger.info('import attributes cost: {}'.format(time.time() - s))
|
current_app.logger.info('import attributes cost: {}'.format(time.time() - s))
|
||||||
|
|
||||||
s = time.time()
|
s = time.time()
|
||||||
ci_type_id_map = self._import_ci_types(tpt.get('ci_types') or [], attr_id_map)
|
ci_type_id_map = self._import_ci_types(tpt.get('ci_types') or [], attr_id_map)
|
||||||
current_app.logger.info('import ci_types cost: {}'.format(time.time() - s))
|
current_app.logger.info('import ci_types cost: {}'.format(time.time() - s))
|
||||||
|
|
||||||
|
self._import_reference_attributes(references, ci_type_id_map)
|
||||||
|
|
||||||
s = time.time()
|
s = time.time()
|
||||||
self._import_ci_type_groups(tpt.get('ci_type_groups') or [], ci_type_id_map)
|
self._import_ci_type_groups(tpt.get('ci_type_groups') or [], ci_type_id_map)
|
||||||
current_app.logger.info('import ci_type_groups cost: {}'.format(time.time() - s))
|
current_app.logger.info('import ci_type_groups cost: {}'.format(time.time() - s))
|
||||||
|
@ -1675,6 +1691,16 @@ class CITypeTemplateManager(object):
|
||||||
type_ids.extend(extend_type_ids)
|
type_ids.extend(extend_type_ids)
|
||||||
ci_types.extend(CITypeManager.get_ci_types(type_ids=extend_type_ids))
|
ci_types.extend(CITypeManager.get_ci_types(type_ids=extend_type_ids))
|
||||||
|
|
||||||
|
# handle reference type
|
||||||
|
references = Attribute.get_by(only_query=True).join(
|
||||||
|
CITypeAttribute, CITypeAttribute.attr_id == Attribute.id).filter(
|
||||||
|
CITypeAttribute.type_id.in_(type_ids)).filter(CITypeAttribute.deleted.is_(False)).filter(
|
||||||
|
Attribute.reference_type_id.isnot(None))
|
||||||
|
reference_type_ids = list(set([i.reference_type_id for i in references if i.reference_type_id]))
|
||||||
|
if reference_type_ids:
|
||||||
|
type_ids.extend(reference_type_ids)
|
||||||
|
ci_types.extend(CITypeManager.get_ci_types(type_ids=reference_type_ids))
|
||||||
|
|
||||||
tpt = dict(
|
tpt = dict(
|
||||||
ci_types=ci_types,
|
ci_types=ci_types,
|
||||||
relation_types=[i.to_dict() for i in RelationTypeManager.get_all()],
|
relation_types=[i.to_dict() for i in RelationTypeManager.get_all()],
|
||||||
|
@ -1687,6 +1713,7 @@ class CITypeTemplateManager(object):
|
||||||
icons=dict()
|
icons=dict()
|
||||||
)
|
)
|
||||||
tpt['ci_type_groups'] = CITypeGroupManager.get(ci_types=tpt['ci_types'], type_ids=type_ids)
|
tpt['ci_type_groups'] = CITypeGroupManager.get(ci_types=tpt['ci_types'], type_ids=type_ids)
|
||||||
|
tpt['ci_type_groups'] = [i for i in tpt['ci_type_groups'] if i.get('ci_types')]
|
||||||
|
|
||||||
def get_icon_value(icon):
|
def get_icon_value(icon):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -14,6 +14,8 @@ class ValueTypeEnum(BaseEnum):
|
||||||
JSON = "6"
|
JSON = "6"
|
||||||
PASSWORD = TEXT
|
PASSWORD = TEXT
|
||||||
LINK = TEXT
|
LINK = TEXT
|
||||||
|
BOOL = "7"
|
||||||
|
REFERENCE = INT
|
||||||
|
|
||||||
|
|
||||||
class ConstraintEnum(BaseEnum):
|
class ConstraintEnum(BaseEnum):
|
||||||
|
|
|
@ -44,6 +44,8 @@ class ErrFormat(CommonErrFormat):
|
||||||
unique_value_not_found = _l("The model's primary key {} does not exist!") # 模型的主键 {} 不存在!
|
unique_value_not_found = _l("The model's primary key {} does not exist!") # 模型的主键 {} 不存在!
|
||||||
unique_key_required = _l("Primary key {} is missing") # 主键字段 {} 缺失
|
unique_key_required = _l("Primary key {} is missing") # 主键字段 {} 缺失
|
||||||
ci_is_already_existed = _l("CI already exists!") # CI 已经存在!
|
ci_is_already_existed = _l("CI already exists!") # CI 已经存在!
|
||||||
|
ci_reference_not_found = _l("{}: CI reference {} does not exist!") # {}: CI引用 {} 不存在!
|
||||||
|
ci_reference_invalid = _l("{}: CI reference {} is illegal!") # {}, CI引用 {} 不合法!
|
||||||
relation_constraint = _l("Relationship constraint: {}, verification failed") # 关系约束: {}, 校验失败
|
relation_constraint = _l("Relationship constraint: {}, verification failed") # 关系约束: {}, 校验失败
|
||||||
# 多对多关系 限制: 模型 {} <-> {} 已经存在多对多关系!
|
# 多对多关系 限制: 模型 {} <-> {} 已经存在多对多关系!
|
||||||
m2m_relation_constraint = _l(
|
m2m_relation_constraint = _l(
|
||||||
|
@ -63,6 +65,8 @@ class ErrFormat(CommonErrFormat):
|
||||||
ci_exists_and_cannot_delete_inheritance = _l(
|
ci_exists_and_cannot_delete_inheritance = _l(
|
||||||
"The inheritance cannot be deleted because the CI already exists") # 因为CI已经存在,不能删除继承关系
|
"The inheritance cannot be deleted because the CI already exists") # 因为CI已经存在,不能删除继承关系
|
||||||
ci_type_inheritance_cannot_delete = _l("The model is inherited and cannot be deleted") # 该模型被继承, 不能删除
|
ci_type_inheritance_cannot_delete = _l("The model is inherited and cannot be deleted") # 该模型被继承, 不能删除
|
||||||
|
ci_type_referenced_cannot_delete = _l(
|
||||||
|
"The model is referenced by attribute {} and cannot be deleted") # 该模型被属性 {} 引用, 不能删除
|
||||||
|
|
||||||
# 因为关系视图 {} 引用了该模型,不能删除模型
|
# 因为关系视图 {} 引用了该模型,不能删除模型
|
||||||
ci_relation_view_exists_and_cannot_delete_type = _l(
|
ci_relation_view_exists_and_cannot_delete_type = _l(
|
||||||
|
|
|
@ -451,6 +451,9 @@ class Search(object):
|
||||||
if field_type == ValueTypeEnum.DATE and len(v) == 10:
|
if field_type == ValueTypeEnum.DATE and len(v) == 10:
|
||||||
v = "{} 00:00:00".format(v)
|
v = "{} 00:00:00".format(v)
|
||||||
|
|
||||||
|
if field_type == ValueTypeEnum.BOOL and "*" not in str(v):
|
||||||
|
v = str(int(v in current_app.config.get('BOOL_TRUE')))
|
||||||
|
|
||||||
# in query
|
# in query
|
||||||
if v.startswith("(") and v.endswith(")"):
|
if v.startswith("(") and v.endswith(")"):
|
||||||
_query_sql = self._in_query_handler(attr, v, is_not)
|
_query_sql = self._in_query_handler(attr, v, is_not)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import json
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
from flask import current_app
|
||||||
|
|
||||||
import api.models.cmdb as model
|
import api.models.cmdb as model
|
||||||
from api.lib.cmdb.cache import AttributeCache
|
from api.lib.cmdb.cache import AttributeCache
|
||||||
|
@ -64,6 +65,7 @@ class ValueTypeMap(object):
|
||||||
ValueTypeEnum.DATETIME: str2datetime,
|
ValueTypeEnum.DATETIME: str2datetime,
|
||||||
ValueTypeEnum.DATE: str2date,
|
ValueTypeEnum.DATE: str2date,
|
||||||
ValueTypeEnum.JSON: lambda x: json.loads(x) if isinstance(x, six.string_types) and x else x,
|
ValueTypeEnum.JSON: lambda x: json.loads(x) if isinstance(x, six.string_types) and x else x,
|
||||||
|
ValueTypeEnum.BOOL: lambda x: x in current_app.config.get('BOOL_TRUE'),
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize = {
|
serialize = {
|
||||||
|
@ -74,6 +76,7 @@ class ValueTypeMap(object):
|
||||||
ValueTypeEnum.DATE: lambda x: x.strftime("%Y-%m-%d") if not isinstance(x, six.string_types) else x,
|
ValueTypeEnum.DATE: lambda x: x.strftime("%Y-%m-%d") if not isinstance(x, six.string_types) else x,
|
||||||
ValueTypeEnum.DATETIME: lambda x: x.strftime("%Y-%m-%d %H:%M:%S") if not isinstance(x, six.string_types) else x,
|
ValueTypeEnum.DATETIME: lambda x: x.strftime("%Y-%m-%d %H:%M:%S") if not isinstance(x, six.string_types) else x,
|
||||||
ValueTypeEnum.JSON: lambda x: json.loads(x) if isinstance(x, six.string_types) and x else x,
|
ValueTypeEnum.JSON: lambda x: json.loads(x) if isinstance(x, six.string_types) and x else x,
|
||||||
|
ValueTypeEnum.BOOL: lambda x: x in current_app.config.get('BOOL_TRUE'),
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize2 = {
|
serialize2 = {
|
||||||
|
@ -84,6 +87,7 @@ class ValueTypeMap(object):
|
||||||
ValueTypeEnum.DATE: lambda x: (x.decode() if not isinstance(x, six.string_types) else x).split()[0],
|
ValueTypeEnum.DATE: lambda x: (x.decode() if not isinstance(x, six.string_types) else x).split()[0],
|
||||||
ValueTypeEnum.DATETIME: lambda x: x.decode() if not isinstance(x, six.string_types) else x,
|
ValueTypeEnum.DATETIME: lambda x: x.decode() if not isinstance(x, six.string_types) else x,
|
||||||
ValueTypeEnum.JSON: lambda x: json.loads(x) if isinstance(x, six.string_types) and x else x,
|
ValueTypeEnum.JSON: lambda x: json.loads(x) if isinstance(x, six.string_types) and x else x,
|
||||||
|
ValueTypeEnum.BOOL: lambda x: x in current_app.config.get('BOOL_TRUE'),
|
||||||
}
|
}
|
||||||
|
|
||||||
choice = {
|
choice = {
|
||||||
|
@ -105,6 +109,7 @@ class ValueTypeMap(object):
|
||||||
'index_{0}'.format(ValueTypeEnum.TIME): model.CIIndexValueText,
|
'index_{0}'.format(ValueTypeEnum.TIME): model.CIIndexValueText,
|
||||||
'index_{0}'.format(ValueTypeEnum.FLOAT): model.CIIndexValueFloat,
|
'index_{0}'.format(ValueTypeEnum.FLOAT): model.CIIndexValueFloat,
|
||||||
'index_{0}'.format(ValueTypeEnum.JSON): model.CIValueJson,
|
'index_{0}'.format(ValueTypeEnum.JSON): model.CIValueJson,
|
||||||
|
'index_{0}'.format(ValueTypeEnum.BOOL): model.CIIndexValueInteger,
|
||||||
}
|
}
|
||||||
|
|
||||||
table_name = {
|
table_name = {
|
||||||
|
@ -117,6 +122,7 @@ class ValueTypeMap(object):
|
||||||
'index_{0}'.format(ValueTypeEnum.TIME): 'c_value_index_texts',
|
'index_{0}'.format(ValueTypeEnum.TIME): 'c_value_index_texts',
|
||||||
'index_{0}'.format(ValueTypeEnum.FLOAT): 'c_value_index_floats',
|
'index_{0}'.format(ValueTypeEnum.FLOAT): 'c_value_index_floats',
|
||||||
'index_{0}'.format(ValueTypeEnum.JSON): 'c_value_json',
|
'index_{0}'.format(ValueTypeEnum.JSON): 'c_value_json',
|
||||||
|
'index_{0}'.format(ValueTypeEnum.BOOL): 'c_value_index_integers',
|
||||||
}
|
}
|
||||||
|
|
||||||
es_type = {
|
es_type = {
|
||||||
|
|
|
@ -128,14 +128,20 @@ class AttributeValueManager(object):
|
||||||
return abort(400, ErrFormat.attribute_value_invalid2.format(alias, value))
|
return abort(400, ErrFormat.attribute_value_invalid2.format(alias, value))
|
||||||
|
|
||||||
def _validate(self, attr, value, value_table, ci=None, type_id=None, ci_id=None, type_attr=None):
|
def _validate(self, attr, value, value_table, ci=None, type_id=None, ci_id=None, type_attr=None):
|
||||||
|
if not attr.is_reference:
|
||||||
ci = ci or {}
|
ci = ci or {}
|
||||||
v = self._deserialize_value(attr.alias, attr.value_type, value)
|
v = self._deserialize_value(attr.alias, attr.value_type, value)
|
||||||
|
|
||||||
attr.is_choice and value and self._check_is_choice(attr, attr.value_type, v)
|
attr.is_choice and value and self._check_is_choice(attr, attr.value_type, v)
|
||||||
|
|
||||||
|
else:
|
||||||
|
v = value or None
|
||||||
|
|
||||||
attr.is_unique and self._check_is_unique(
|
attr.is_unique and self._check_is_unique(
|
||||||
value_table, attr, ci and ci.id or ci_id, ci and ci.type_id or type_id, v)
|
value_table, attr, ci and ci.id or ci_id, ci and ci.type_id or type_id, v)
|
||||||
|
|
||||||
self._check_is_required(ci and ci.type_id or type_id, attr, v, type_attr=type_attr)
|
self._check_is_required(ci and ci.type_id or type_id, attr, v, type_attr=type_attr)
|
||||||
|
if attr.is_reference:
|
||||||
|
return v
|
||||||
|
|
||||||
if v == "" and attr.value_type not in (ValueTypeEnum.TEXT,):
|
if v == "" and attr.value_type not in (ValueTypeEnum.TEXT,):
|
||||||
v = None
|
v = None
|
||||||
|
|
|
@ -58,7 +58,7 @@ def _request_messenger(subject, body, tos, sender, payload):
|
||||||
|
|
||||||
def notify_send(subject, body, methods, tos, payload=None):
|
def notify_send(subject, body, methods, tos, payload=None):
|
||||||
payload = payload or {}
|
payload = payload or {}
|
||||||
payload = {k: v or '' for k, v in payload.items()}
|
payload = {k: '' if v is None else v for k, v in payload.items()}
|
||||||
subject = Template(subject).render(payload)
|
subject = Template(subject).render(payload)
|
||||||
body = Template(body).render(payload)
|
body = Template(body).render(payload)
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,10 @@ class Attribute(Model):
|
||||||
is_password = db.Column(db.Boolean, default=False)
|
is_password = db.Column(db.Boolean, default=False)
|
||||||
is_sortable = db.Column(db.Boolean, default=False)
|
is_sortable = db.Column(db.Boolean, default=False)
|
||||||
is_dynamic = db.Column(db.Boolean, default=False)
|
is_dynamic = db.Column(db.Boolean, default=False)
|
||||||
|
is_bool = db.Column(db.Boolean, default=False)
|
||||||
|
|
||||||
|
is_reference = db.Column(db.Boolean, default=False)
|
||||||
|
reference_type_id = db.Column(db.Integer, db.ForeignKey('c_ci_types.id'))
|
||||||
|
|
||||||
default = db.Column(db.JSON) # {"default": None}
|
default = db.Column(db.JSON) # {"default": None}
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,12 @@ from api.lib.cmdb.const import REDIS_PREFIX_CI_RELATION
|
||||||
from api.lib.cmdb.const import REDIS_PREFIX_CI_RELATION2
|
from api.lib.cmdb.const import REDIS_PREFIX_CI_RELATION2
|
||||||
from api.lib.cmdb.const import RelationSourceEnum
|
from api.lib.cmdb.const import RelationSourceEnum
|
||||||
from api.lib.cmdb.perms import CIFilterPermsCRUD
|
from api.lib.cmdb.perms import CIFilterPermsCRUD
|
||||||
|
from api.lib.cmdb.utils import TableMap
|
||||||
from api.lib.decorator import flush_db
|
from api.lib.decorator import flush_db
|
||||||
from api.lib.decorator import reconnect_db
|
from api.lib.decorator import reconnect_db
|
||||||
from api.lib.perm.acl.cache import UserCache
|
from api.lib.perm.acl.cache import UserCache
|
||||||
from api.lib.utils import handle_arg_list
|
from api.lib.utils import handle_arg_list
|
||||||
|
from api.models.cmdb import Attribute
|
||||||
from api.models.cmdb import AutoDiscoveryCI
|
from api.models.cmdb import AutoDiscoveryCI
|
||||||
from api.models.cmdb import AutoDiscoveryCIType
|
from api.models.cmdb import AutoDiscoveryCIType
|
||||||
from api.models.cmdb import AutoDiscoveryCITypeRelation
|
from api.models.cmdb import AutoDiscoveryCITypeRelation
|
||||||
|
@ -84,7 +86,7 @@ def batch_ci_cache(ci_ids, ): # only for attribute change index
|
||||||
|
|
||||||
@celery.task(name="cmdb.ci_delete", queue=CMDB_QUEUE)
|
@celery.task(name="cmdb.ci_delete", queue=CMDB_QUEUE)
|
||||||
@reconnect_db
|
@reconnect_db
|
||||||
def ci_delete(ci_id):
|
def ci_delete(ci_id, type_id):
|
||||||
current_app.logger.info(ci_id)
|
current_app.logger.info(ci_id)
|
||||||
|
|
||||||
if current_app.config.get("USE_ES"):
|
if current_app.config.get("USE_ES"):
|
||||||
|
@ -99,6 +101,12 @@ def ci_delete(ci_id):
|
||||||
adt.update(updated_at=datetime.datetime.now())
|
adt.update(updated_at=datetime.datetime.now())
|
||||||
instance.delete()
|
instance.delete()
|
||||||
|
|
||||||
|
for attr in Attribute.get_by(reference_type_id=type_id, to_dict=False):
|
||||||
|
table = TableMap(attr=attr).table
|
||||||
|
for i in getattr(table, 'get_by')(attr_id=attr.id, value=ci_id, to_dict=False):
|
||||||
|
i.delete()
|
||||||
|
ci_cache(i.ci_id, None, None)
|
||||||
|
|
||||||
current_app.logger.info("{0} delete..........".format(ci_id))
|
current_app.logger.info("{0} delete..........".format(ci_id))
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -7,7 +7,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PROJECT VERSION\n"
|
"Project-Id-Version: PROJECT VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
"POT-Creation-Date: 2024-06-20 19:12+0800\n"
|
"POT-Creation-Date: 2024-08-20 13:47+0800\n"
|
||||||
"PO-Revision-Date: 2023-12-25 20:21+0800\n"
|
"PO-Revision-Date: 2023-12-25 20:21+0800\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language: zh\n"
|
"Language: zh\n"
|
||||||
|
@ -16,7 +16,7 @@ msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 2.14.0\n"
|
"Generated-By: Babel 2.16.0\n"
|
||||||
|
|
||||||
#: api/lib/resp_format.py:7
|
#: api/lib/resp_format.py:7
|
||||||
msgid "unauthorized"
|
msgid "unauthorized"
|
||||||
|
@ -169,8 +169,8 @@ msgstr "目前只允许 属性创建人、管理员 删除属性!"
|
||||||
#: api/lib/cmdb/resp_format.py:37
|
#: api/lib/cmdb/resp_format.py:37
|
||||||
msgid ""
|
msgid ""
|
||||||
"Attribute field names cannot be built-in fields: id, _id, ci_id, type, "
|
"Attribute field names cannot be built-in fields: id, _id, ci_id, type, "
|
||||||
"_type, ci_type"
|
"_type, ci_type, ticket_id"
|
||||||
msgstr "属性字段名不能是内置字段: id, _id, ci_id, type, _type, ci_type"
|
msgstr "属性字段名不能是内置字段: id, _id, ci_id, type, _type, ci_type, ci_type, ticket_id"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:39
|
#: api/lib/cmdb/resp_format.py:39
|
||||||
msgid "Predefined value: Other model request parameters are illegal!"
|
msgid "Predefined value: Other model request parameters are illegal!"
|
||||||
|
@ -197,286 +197,298 @@ msgid "CI already exists!"
|
||||||
msgstr "CI 已经存在!"
|
msgstr "CI 已经存在!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:47
|
#: api/lib/cmdb/resp_format.py:47
|
||||||
|
msgid "{}: CI reference {} does not exist!"
|
||||||
|
msgstr "{}: CI引用 {} 不存在!"
|
||||||
|
|
||||||
|
#: api/lib/cmdb/resp_format.py:48
|
||||||
|
msgid "{}: CI reference {} is illegal!"
|
||||||
|
msgstr "{}, CI引用 {} 不合法!"
|
||||||
|
|
||||||
|
#: api/lib/cmdb/resp_format.py:49
|
||||||
msgid "Relationship constraint: {}, verification failed"
|
msgid "Relationship constraint: {}, verification failed"
|
||||||
msgstr "关系约束: {}, 校验失败"
|
msgstr "关系约束: {}, 校验失败"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:49
|
#: api/lib/cmdb/resp_format.py:51
|
||||||
msgid ""
|
msgid ""
|
||||||
"Many-to-many relationship constraint: Model {} <-> {} already has a many-"
|
"Many-to-many relationship constraint: Model {} <-> {} already has a many-"
|
||||||
"to-many relationship!"
|
"to-many relationship!"
|
||||||
msgstr "多对多关系 限制: 模型 {} <-> {} 已经存在多对多关系!"
|
msgstr "多对多关系 限制: 模型 {} <-> {} 已经存在多对多关系!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:52
|
#: api/lib/cmdb/resp_format.py:54
|
||||||
msgid "CI relationship: {} does not exist"
|
msgid "CI relationship: {} does not exist"
|
||||||
msgstr "CI关系: {} 不存在"
|
msgstr "CI关系: {} 不存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:55
|
#: api/lib/cmdb/resp_format.py:57
|
||||||
msgid "In search expressions, not supported before parentheses: or, not"
|
msgid "In search expressions, not supported before parentheses: or, not"
|
||||||
msgstr "搜索表达式里小括号前不支持: 或、非"
|
msgstr "搜索表达式里小括号前不支持: 或、非"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:57
|
#: api/lib/cmdb/resp_format.py:59
|
||||||
msgid "Model {} does not exist"
|
msgid "Model {} does not exist"
|
||||||
msgstr "模型 {} 不存在"
|
msgstr "模型 {} 不存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:58
|
#: api/lib/cmdb/resp_format.py:60
|
||||||
msgid "Model {} already exists"
|
msgid "Model {} already exists"
|
||||||
msgstr "模型 {} 已经存在"
|
msgstr "模型 {} 已经存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:59
|
#: api/lib/cmdb/resp_format.py:61
|
||||||
msgid "The primary key is undefined or has been deleted"
|
msgid "The primary key is undefined or has been deleted"
|
||||||
msgstr "主键未定义或者已被删除"
|
msgstr "主键未定义或者已被删除"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:60
|
#: api/lib/cmdb/resp_format.py:62
|
||||||
msgid "Only the creator can delete it!"
|
msgid "Only the creator can delete it!"
|
||||||
msgstr "只有创建人才能删除它!"
|
msgstr "只有创建人才能删除它!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:61
|
#: api/lib/cmdb/resp_format.py:63
|
||||||
msgid "The model cannot be deleted because the CI already exists"
|
msgid "The model cannot be deleted because the CI already exists"
|
||||||
msgstr "因为CI已经存在,不能删除模型"
|
msgstr "因为CI已经存在,不能删除模型"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:63
|
#: api/lib/cmdb/resp_format.py:65
|
||||||
msgid "The inheritance cannot be deleted because the CI already exists"
|
msgid "The inheritance cannot be deleted because the CI already exists"
|
||||||
msgstr "因为CI已经存在,不能删除继承关系"
|
msgstr "因为CI已经存在,不能删除继承关系"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:65
|
#: api/lib/cmdb/resp_format.py:67
|
||||||
msgid "The model is inherited and cannot be deleted"
|
msgid "The model is inherited and cannot be deleted"
|
||||||
msgstr "该模型被继承, 不能删除"
|
msgstr "该模型被继承, 不能删除"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:68
|
#: api/lib/cmdb/resp_format.py:68
|
||||||
|
msgid "The model is referenced by attribute {} and cannot be deleted"
|
||||||
|
msgstr "该模型被属性 {} 引用, 不能删除"
|
||||||
|
|
||||||
|
#: api/lib/cmdb/resp_format.py:72
|
||||||
msgid ""
|
msgid ""
|
||||||
"The model cannot be deleted because the model is referenced by the "
|
"The model cannot be deleted because the model is referenced by the "
|
||||||
"relational view {}"
|
"relational view {}"
|
||||||
msgstr "因为关系视图 {} 引用了该模型,不能删除模型"
|
msgstr "因为关系视图 {} 引用了该模型,不能删除模型"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:70
|
#: api/lib/cmdb/resp_format.py:74
|
||||||
msgid "Model group {} does not exist"
|
msgid "Model group {} does not exist"
|
||||||
msgstr "模型分组 {} 不存在"
|
msgstr "模型分组 {} 不存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:71
|
#: api/lib/cmdb/resp_format.py:75
|
||||||
msgid "Model group {} already exists"
|
msgid "Model group {} already exists"
|
||||||
msgstr "模型分组 {} 已经存在"
|
msgstr "模型分组 {} 已经存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:72
|
#: api/lib/cmdb/resp_format.py:76
|
||||||
msgid "Model relationship {} does not exist"
|
msgid "Model relationship {} does not exist"
|
||||||
msgstr "模型关系 {} 不存在"
|
msgstr "模型关系 {} 不存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:73
|
#: api/lib/cmdb/resp_format.py:77
|
||||||
msgid "Attribute group {} already exists"
|
msgid "Attribute group {} already exists"
|
||||||
msgstr "属性分组 {} 已存在"
|
msgstr "属性分组 {} 已存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:74
|
#: api/lib/cmdb/resp_format.py:78
|
||||||
msgid "Attribute group {} does not exist"
|
msgid "Attribute group {} does not exist"
|
||||||
msgstr "属性分组 {} 不存在"
|
msgstr "属性分组 {} 不存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:76
|
#: api/lib/cmdb/resp_format.py:80
|
||||||
msgid "Attribute group <{0}> - attribute <{1}> does not exist"
|
msgid "Attribute group <{0}> - attribute <{1}> does not exist"
|
||||||
msgstr "属性组<{0}> - 属性<{1}> 不存在"
|
msgstr "属性组<{0}> - 属性<{1}> 不存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:77
|
#: api/lib/cmdb/resp_format.py:81
|
||||||
msgid "The unique constraint already exists!"
|
msgid "The unique constraint already exists!"
|
||||||
msgstr "唯一约束已经存在!"
|
msgstr "唯一约束已经存在!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:79
|
#: api/lib/cmdb/resp_format.py:83
|
||||||
msgid "Uniquely constrained attributes cannot be JSON and multi-valued"
|
msgid "Uniquely constrained attributes cannot be JSON and multi-valued"
|
||||||
msgstr "唯一约束的属性不能是 JSON 和 多值"
|
msgstr "唯一约束的属性不能是 JSON 和 多值"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:80
|
#: api/lib/cmdb/resp_format.py:84
|
||||||
msgid "Duplicated trigger"
|
msgid "Duplicated trigger"
|
||||||
msgstr "重复的触发器"
|
msgstr "重复的触发器"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:81
|
#: api/lib/cmdb/resp_format.py:85
|
||||||
msgid "Trigger {} does not exist"
|
msgid "Trigger {} does not exist"
|
||||||
msgstr "触发器 {} 不存在"
|
msgstr "触发器 {} 不存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:82
|
#: api/lib/cmdb/resp_format.py:86
|
||||||
msgid "Duplicated reconciliation rule"
|
msgid "Duplicated reconciliation rule"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:83
|
#: api/lib/cmdb/resp_format.py:87
|
||||||
msgid "Reconciliation rule {} does not exist"
|
msgid "Reconciliation rule {} does not exist"
|
||||||
msgstr "关系类型 {} 不存在"
|
msgstr "关系类型 {} 不存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:85
|
#: api/lib/cmdb/resp_format.py:89
|
||||||
msgid "Operation record {} does not exist"
|
msgid "Operation record {} does not exist"
|
||||||
msgstr "操作记录 {} 不存在"
|
msgstr "操作记录 {} 不存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:86
|
#: api/lib/cmdb/resp_format.py:90
|
||||||
msgid "Unique identifier cannot be deleted"
|
msgid "Unique identifier cannot be deleted"
|
||||||
msgstr "不能删除唯一标识"
|
msgstr "不能删除唯一标识"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:87
|
#: api/lib/cmdb/resp_format.py:91
|
||||||
msgid "Cannot delete default sorted attributes"
|
msgid "Cannot delete default sorted attributes"
|
||||||
msgstr "不能删除默认排序的属性"
|
msgstr "不能删除默认排序的属性"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:89
|
#: api/lib/cmdb/resp_format.py:93
|
||||||
msgid "No node selected"
|
msgid "No node selected"
|
||||||
msgstr "没有选择节点"
|
msgstr "没有选择节点"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:90
|
#: api/lib/cmdb/resp_format.py:94
|
||||||
msgid "This search option does not exist!"
|
msgid "This search option does not exist!"
|
||||||
msgstr "该搜索选项不存在!"
|
msgstr "该搜索选项不存在!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:91
|
#: api/lib/cmdb/resp_format.py:95
|
||||||
msgid "This search option has a duplicate name!"
|
msgid "This search option has a duplicate name!"
|
||||||
msgstr "该搜索选项命名重复!"
|
msgstr "该搜索选项命名重复!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:93
|
#: api/lib/cmdb/resp_format.py:97
|
||||||
msgid "Relationship type {} already exists"
|
msgid "Relationship type {} already exists"
|
||||||
msgstr "关系类型 {} 已经存在"
|
msgstr "关系类型 {} 已经存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:94
|
#: api/lib/cmdb/resp_format.py:98
|
||||||
msgid "Relationship type {} does not exist"
|
msgid "Relationship type {} does not exist"
|
||||||
msgstr "关系类型 {} 不存在"
|
msgstr "关系类型 {} 不存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:96
|
#: api/lib/cmdb/resp_format.py:100
|
||||||
msgid "Invalid attribute value: {}"
|
msgid "Invalid attribute value: {}"
|
||||||
msgstr "无效的属性值: {}"
|
msgstr "无效的属性值: {}"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:97
|
#: api/lib/cmdb/resp_format.py:101
|
||||||
msgid "{} Invalid value: {}"
|
msgid "{} Invalid value: {}"
|
||||||
msgstr "{} 无效的值: {}"
|
msgstr "{} 无效的值: {}"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:98
|
#: api/lib/cmdb/resp_format.py:102
|
||||||
msgid "{} is not in the predefined values"
|
msgid "{} is not in the predefined values"
|
||||||
msgstr "{} 不在预定义值里"
|
msgstr "{} 不在预定义值里"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:100
|
#: api/lib/cmdb/resp_format.py:104
|
||||||
msgid "The value of attribute {} must be unique, {} already exists"
|
msgid "The value of attribute {} must be unique, {} already exists"
|
||||||
msgstr "属性 {} 的值必须是唯一的, 当前值 {} 已存在"
|
msgstr "属性 {} 的值必须是唯一的, 当前值 {} 已存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:101
|
#: api/lib/cmdb/resp_format.py:105
|
||||||
msgid "Attribute {} value must exist"
|
msgid "Attribute {} value must exist"
|
||||||
msgstr "属性 {} 值必须存在"
|
msgstr "属性 {} 值必须存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:102
|
#: api/lib/cmdb/resp_format.py:106
|
||||||
msgid "Out of range value, the maximum value is 2147483647"
|
msgid "Out of range value, the maximum value is 2147483647"
|
||||||
msgstr "超过最大值限制, 最大值是2147483647"
|
msgstr "超过最大值限制, 最大值是2147483647"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:104
|
#: api/lib/cmdb/resp_format.py:108
|
||||||
msgid "Unknown error when adding or modifying attribute value: {}"
|
msgid "Unknown error when adding or modifying attribute value: {}"
|
||||||
msgstr "新增或者修改属性值未知错误: {}"
|
msgstr "新增或者修改属性值未知错误: {}"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:106
|
#: api/lib/cmdb/resp_format.py:110
|
||||||
msgid "Duplicate custom name"
|
msgid "Duplicate custom name"
|
||||||
msgstr "订制名重复"
|
msgstr "订制名重复"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:108
|
#: api/lib/cmdb/resp_format.py:112
|
||||||
msgid "Number of models exceeds limit: {}"
|
msgid "Number of models exceeds limit: {}"
|
||||||
msgstr "模型数超过限制: {}"
|
msgstr "模型数超过限制: {}"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:109
|
#: api/lib/cmdb/resp_format.py:113
|
||||||
msgid "The number of CIs exceeds the limit: {}"
|
msgid "The number of CIs exceeds the limit: {}"
|
||||||
msgstr "CI数超过限制: {}"
|
msgstr "CI数超过限制: {}"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:111
|
#: api/lib/cmdb/resp_format.py:115
|
||||||
msgid "Auto-discovery rule: {} already exists!"
|
msgid "Auto-discovery rule: {} already exists!"
|
||||||
msgstr "自动发现规则: {} 已经存在!"
|
msgstr "自动发现规则: {} 已经存在!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:112
|
#: api/lib/cmdb/resp_format.py:116
|
||||||
msgid "Auto-discovery rule: {} does not exist!"
|
msgid "Auto-discovery rule: {} does not exist!"
|
||||||
msgstr "自动发现规则: {} 不存在!"
|
msgstr "自动发现规则: {} 不存在!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:114
|
#: api/lib/cmdb/resp_format.py:118
|
||||||
msgid "This auto-discovery rule is referenced by the model and cannot be deleted!"
|
msgid "This auto-discovery rule is referenced by the model and cannot be deleted!"
|
||||||
msgstr "该自动发现规则被模型引用, 不能删除!"
|
msgstr "该自动发现规则被模型引用, 不能删除!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:116
|
#: api/lib/cmdb/resp_format.py:120
|
||||||
msgid "The application of auto-discovery rules cannot be defined repeatedly!"
|
msgid "The application of auto-discovery rules cannot be defined repeatedly!"
|
||||||
msgstr "自动发现规则的应用不能重复定义!"
|
msgstr "自动发现规则的应用不能重复定义!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:117
|
#: api/lib/cmdb/resp_format.py:121
|
||||||
msgid "The auto-discovery you want to modify: {} does not exist!"
|
msgid "The auto-discovery you want to modify: {} does not exist!"
|
||||||
msgstr "您要修改的自动发现: {} 不存在!"
|
msgstr "您要修改的自动发现: {} 不存在!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:118
|
#: api/lib/cmdb/resp_format.py:122
|
||||||
msgid "Attribute does not include unique identifier: {}"
|
msgid "Attribute does not include unique identifier: {}"
|
||||||
msgstr "属性字段没有包括唯一标识: {}"
|
msgstr "属性字段没有包括唯一标识: {}"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:119
|
#: api/lib/cmdb/resp_format.py:123
|
||||||
msgid "The auto-discovery instance does not exist!"
|
msgid "The auto-discovery instance does not exist!"
|
||||||
msgstr "自动发现的实例不存在!"
|
msgstr "自动发现的实例不存在!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:120
|
#: api/lib/cmdb/resp_format.py:124
|
||||||
msgid "The model is not associated with this auto-discovery!"
|
msgid "The model is not associated with this auto-discovery!"
|
||||||
msgstr "模型并未关联该自动发现!"
|
msgstr "模型并未关联该自动发现!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:121
|
#: api/lib/cmdb/resp_format.py:125
|
||||||
msgid "Only the creator can modify the Secret!"
|
msgid "Only the creator can modify the Secret!"
|
||||||
msgstr "只有创建人才能修改Secret!"
|
msgstr "只有创建人才能修改Secret!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:123
|
#: api/lib/cmdb/resp_format.py:127
|
||||||
msgid "This rule already has auto-discovery instances and cannot be deleted!"
|
msgid "This rule already has auto-discovery instances and cannot be deleted!"
|
||||||
msgstr "该规则已经有自动发现的实例, 不能被删除!"
|
msgstr "该规则已经有自动发现的实例, 不能被删除!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:125
|
#: api/lib/cmdb/resp_format.py:129
|
||||||
msgid "The default auto-discovery rule is already referenced by model {}!"
|
msgid "The default auto-discovery rule is already referenced by model {}!"
|
||||||
msgstr "该默认的自动发现规则 已经被模型 {} 引用!"
|
msgstr "该默认的自动发现规则 已经被模型 {} 引用!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:127
|
#: api/lib/cmdb/resp_format.py:131
|
||||||
msgid "The unique_key method must return a non-empty string!"
|
msgid "The unique_key method must return a non-empty string!"
|
||||||
msgstr "unique_key方法必须返回非空字符串!"
|
msgstr "unique_key方法必须返回非空字符串!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:128
|
#: api/lib/cmdb/resp_format.py:132
|
||||||
msgid "The attributes method must return a list"
|
msgid "The attributes method must return a list"
|
||||||
msgstr "attributes方法必须返回的是list"
|
msgstr "attributes方法必须返回的是list"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:130
|
#: api/lib/cmdb/resp_format.py:134
|
||||||
msgid "The list returned by the attributes method cannot be empty!"
|
msgid "The list returned by the attributes method cannot be empty!"
|
||||||
msgstr "attributes方法返回的list不能为空!"
|
msgstr "attributes方法返回的list不能为空!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:132
|
#: api/lib/cmdb/resp_format.py:136
|
||||||
msgid "Only administrators can define execution targets as: all nodes!"
|
msgid "Only administrators can define execution targets as: all nodes!"
|
||||||
msgstr "只有管理员才可以定义执行机器为: 所有节点!"
|
msgstr "只有管理员才可以定义执行机器为: 所有节点!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:133
|
#: api/lib/cmdb/resp_format.py:137
|
||||||
msgid "Execute targets permission check failed: {}"
|
msgid "Execute targets permission check failed: {}"
|
||||||
msgstr "执行机器权限检查不通过: {}"
|
msgstr "执行机器权限检查不通过: {}"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:135
|
#: api/lib/cmdb/resp_format.py:139
|
||||||
msgid "CI filter authorization must be named!"
|
msgid "CI filter authorization must be named!"
|
||||||
msgstr "CI过滤授权 必须命名!"
|
msgstr "CI过滤授权 必须命名!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:136
|
#: api/lib/cmdb/resp_format.py:140
|
||||||
msgid "CI filter authorization is currently not supported or query"
|
msgid "CI filter authorization is currently not supported or query"
|
||||||
msgstr "CI过滤授权 暂时不支持 或 查询"
|
msgstr "CI过滤授权 暂时不支持 或 查询"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:139
|
#: api/lib/cmdb/resp_format.py:143
|
||||||
msgid "You do not have permission to operate attribute {}!"
|
msgid "You do not have permission to operate attribute {}!"
|
||||||
msgstr "您没有属性 {} 的操作权限!"
|
msgstr "您没有属性 {} 的操作权限!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:140
|
#: api/lib/cmdb/resp_format.py:144
|
||||||
msgid "You do not have permission to operate this CI!"
|
msgid "You do not have permission to operate this CI!"
|
||||||
msgstr "您没有该CI的操作权限!"
|
msgstr "您没有该CI的操作权限!"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:142
|
#: api/lib/cmdb/resp_format.py:146
|
||||||
msgid "Failed to save password: {}"
|
msgid "Failed to save password: {}"
|
||||||
msgstr "保存密码失败: {}"
|
msgstr "保存密码失败: {}"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:143
|
#: api/lib/cmdb/resp_format.py:147
|
||||||
msgid "Failed to get password: {}"
|
msgid "Failed to get password: {}"
|
||||||
msgstr "获取密码失败: {}"
|
msgstr "获取密码失败: {}"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:145
|
#: api/lib/cmdb/resp_format.py:149
|
||||||
msgid "Scheduling time format error"
|
msgid "Scheduling time format error"
|
||||||
msgstr "{}格式错误,应该为:%Y-%m-%d %H:%M:%S"
|
msgstr "{}格式错误,应该为:%Y-%m-%d %H:%M:%S"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:146
|
#: api/lib/cmdb/resp_format.py:150
|
||||||
msgid "CMDB data reconciliation results"
|
msgid "CMDB data reconciliation results"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:147
|
#: api/lib/cmdb/resp_format.py:151
|
||||||
msgid "Number of {} illegal: {}"
|
msgid "Number of {} illegal: {}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:149
|
#: api/lib/cmdb/resp_format.py:153
|
||||||
msgid "Topology view {} already exists"
|
msgid "Topology view {} already exists"
|
||||||
msgstr "拓扑视图 {} 已经存在"
|
msgstr "拓扑视图 {} 已经存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:150
|
#: api/lib/cmdb/resp_format.py:154
|
||||||
msgid "Topology group {} already exists"
|
msgid "Topology group {} already exists"
|
||||||
msgstr "拓扑视图分组 {} 已经存在"
|
msgstr "拓扑视图分组 {} 已经存在"
|
||||||
|
|
||||||
#: api/lib/cmdb/resp_format.py:152
|
#: api/lib/cmdb/resp_format.py:156
|
||||||
msgid "The group cannot be deleted because the topology view already exists"
|
msgid "The group cannot be deleted because the topology view already exists"
|
||||||
msgstr "因为该分组下定义了拓扑视图,不能删除"
|
msgstr "因为该分组下定义了拓扑视图,不能删除"
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ from api.lib.cmdb.const import ResourceTypeEnum, PermEnum
|
||||||
from api.lib.cmdb.const import RetKey
|
from api.lib.cmdb.const import RetKey
|
||||||
from api.lib.cmdb.perms import has_perm_for_ci
|
from api.lib.cmdb.perms import has_perm_for_ci
|
||||||
from api.lib.cmdb.search import SearchError
|
from api.lib.cmdb.search import SearchError
|
||||||
from api.lib.cmdb.search.ci import search
|
from api.lib.cmdb.search.ci import search as ci_search
|
||||||
from api.lib.decorator import args_required
|
from api.lib.decorator import args_required
|
||||||
from api.lib.perm.acl.acl import has_perm_from_args
|
from api.lib.perm.acl.acl import has_perm_from_args
|
||||||
from api.lib.utils import get_page
|
from api.lib.utils import get_page
|
||||||
|
@ -160,7 +160,7 @@ class CISearchView(APIView):
|
||||||
use_id_filter = request.values.get("use_id_filter", False) in current_app.config.get('BOOL_TRUE')
|
use_id_filter = request.values.get("use_id_filter", False) in current_app.config.get('BOOL_TRUE')
|
||||||
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
s = search(query, fl, facet, page, ret_key, count, sort, excludes, use_id_filter=use_id_filter)
|
s = ci_search(query, fl, facet, page, ret_key, count, sort, excludes, use_id_filter=use_id_filter)
|
||||||
try:
|
try:
|
||||||
response, counter, total, page, numfound, facet = s.search()
|
response, counter, total, page, numfound, facet = s.search()
|
||||||
except SearchError as e:
|
except SearchError as e:
|
||||||
|
|
|
@ -48,16 +48,21 @@ class CITypeView(APIView):
|
||||||
if request.url.endswith("icons"):
|
if request.url.endswith("icons"):
|
||||||
return self.jsonify(CITypeManager().get_icons())
|
return self.jsonify(CITypeManager().get_icons())
|
||||||
|
|
||||||
q = request.args.get("type_name")
|
q = request.values.get("type_name")
|
||||||
|
type_ids = handle_arg_list(request.values.get("type_ids"))
|
||||||
if type_id is not None:
|
type_ids = type_ids or (type_id and [type_id])
|
||||||
ci_type = CITypeCache.get(type_id)
|
if type_ids:
|
||||||
|
ci_types = []
|
||||||
|
for _type_id in type_ids:
|
||||||
|
ci_type = CITypeCache.get(_type_id)
|
||||||
if ci_type is None:
|
if ci_type is None:
|
||||||
return abort(404, ErrFormat.ci_type_not_found)
|
return abort(404, ErrFormat.ci_type_not_found)
|
||||||
|
|
||||||
ci_type = ci_type.to_dict()
|
ci_type = ci_type.to_dict()
|
||||||
ci_type['parent_ids'] = CITypeInheritanceManager.get_parents(type_id)
|
ci_type['parent_ids'] = CITypeInheritanceManager.get_parents(_type_id)
|
||||||
ci_types = [ci_type]
|
ci_type['show_name'] = ci_type.get('show_id') and AttributeCache.get(ci_type['show_id']).name
|
||||||
|
ci_type['unique_name'] = ci_type['unique_id'] and AttributeCache.get(ci_type['unique_id']).name
|
||||||
|
ci_types.append(ci_type)
|
||||||
elif type_name is not None:
|
elif type_name is not None:
|
||||||
ci_type = CITypeCache.get(type_name).to_dict()
|
ci_type = CITypeCache.get(type_name).to_dict()
|
||||||
ci_type['parent_ids'] = CITypeInheritanceManager.get_parents(ci_type['id'])
|
ci_type['parent_ids'] = CITypeInheritanceManager.get_parents(ci_type['id'])
|
||||||
|
|
|
@ -54,6 +54,12 @@
|
||||||
<div class="content unicode" style="display: block;">
|
<div class="content unicode" style="display: block;">
|
||||||
<ul class="icon_lists dib-box">
|
<ul class="icon_lists dib-box">
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">duose-changwenben (1)</div>
|
||||||
|
<div class="code-name">&#xe997;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="dib">
|
<li class="dib">
|
||||||
<span class="icon iconfont"></span>
|
<span class="icon iconfont"></span>
|
||||||
<div class="name">duose-quote</div>
|
<div class="name">duose-quote</div>
|
||||||
|
@ -5508,9 +5514,9 @@
|
||||||
<pre><code class="language-css"
|
<pre><code class="language-css"
|
||||||
>@font-face {
|
>@font-face {
|
||||||
font-family: 'iconfont';
|
font-family: 'iconfont';
|
||||||
src: url('iconfont.woff2?t=1723012344599') format('woff2'),
|
src: url('iconfont.woff2?t=1724135954264') format('woff2'),
|
||||||
url('iconfont.woff?t=1723012344599') format('woff'),
|
url('iconfont.woff?t=1724135954264') format('woff'),
|
||||||
url('iconfont.ttf?t=1723012344599') format('truetype');
|
url('iconfont.ttf?t=1724135954264') format('truetype');
|
||||||
}
|
}
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
||||||
|
@ -5536,6 +5542,15 @@
|
||||||
<div class="content font-class">
|
<div class="content font-class">
|
||||||
<ul class="icon_lists dib-box">
|
<ul class="icon_lists dib-box">
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont duose-changwenben1"></span>
|
||||||
|
<div class="name">
|
||||||
|
duose-changwenben (1)
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.duose-changwenben1
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="dib">
|
<li class="dib">
|
||||||
<span class="icon iconfont duose-quote"></span>
|
<span class="icon iconfont duose-quote"></span>
|
||||||
<div class="name">
|
<div class="name">
|
||||||
|
@ -13717,6 +13732,14 @@
|
||||||
<div class="content symbol">
|
<div class="content symbol">
|
||||||
<ul class="icon_lists dib-box">
|
<ul class="icon_lists dib-box">
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#duose-changwenben1"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">duose-changwenben (1)</div>
|
||||||
|
<div class="code-name">#duose-changwenben1</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="dib">
|
<li class="dib">
|
||||||
<svg class="icon svg-icon" aria-hidden="true">
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
<use xlink:href="#duose-quote"></use>
|
<use xlink:href="#duose-quote"></use>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 3857903 */
|
font-family: "iconfont"; /* Project id 3857903 */
|
||||||
src: url('iconfont.woff2?t=1723012344599') format('woff2'),
|
src: url('iconfont.woff2?t=1724135954264') format('woff2'),
|
||||||
url('iconfont.woff?t=1723012344599') format('woff'),
|
url('iconfont.woff?t=1724135954264') format('woff'),
|
||||||
url('iconfont.ttf?t=1723012344599') format('truetype');
|
url('iconfont.ttf?t=1724135954264') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
|
@ -13,6 +13,10 @@
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.duose-changwenben1:before {
|
||||||
|
content: "\e997";
|
||||||
|
}
|
||||||
|
|
||||||
.duose-quote:before {
|
.duose-quote:before {
|
||||||
content: "\e995";
|
content: "\e995";
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,6 +5,13 @@
|
||||||
"css_prefix_text": "",
|
"css_prefix_text": "",
|
||||||
"description": "",
|
"description": "",
|
||||||
"glyphs": [
|
"glyphs": [
|
||||||
|
{
|
||||||
|
"icon_id": "41437322",
|
||||||
|
"name": "duose-changwenben (1)",
|
||||||
|
"font_class": "duose-changwenben1",
|
||||||
|
"unicode": "e997",
|
||||||
|
"unicode_decimal": 59799
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"icon_id": "41363381",
|
"icon_id": "41363381",
|
||||||
"name": "duose-quote",
|
"name": "duose-quote",
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,18 @@
|
||||||
|
import { axios } from '@/utils/request'
|
||||||
|
|
||||||
|
export function searchCI(params, isShowMessage = true) {
|
||||||
|
return axios({
|
||||||
|
url: `/v0.1/ci/s`,
|
||||||
|
method: 'GET',
|
||||||
|
params: params,
|
||||||
|
isShowMessage
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCIType(CITypeName, parameter) {
|
||||||
|
return axios({
|
||||||
|
url: `/v0.1/ci_types/${CITypeName}`,
|
||||||
|
method: 'GET',
|
||||||
|
params: parameter
|
||||||
|
})
|
||||||
|
}
|
|
@ -85,6 +85,29 @@
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
>
|
>
|
||||||
</treeselect>
|
</treeselect>
|
||||||
|
<CIReferenceAttr
|
||||||
|
v-if="getAttr(item.property).is_reference && (item.exp === 'is' || item.exp === '~is')"
|
||||||
|
:style="{ width: '175px' }"
|
||||||
|
class="select-filter-component"
|
||||||
|
:referenceTypeId="getAttr(item.property).reference_type_id"
|
||||||
|
:disabled="disabled"
|
||||||
|
v-model="item.value"
|
||||||
|
/>
|
||||||
|
<a-select
|
||||||
|
v-else-if="getAttr(item.property).is_bool && (item.exp === 'is' || item.exp === '~is')"
|
||||||
|
v-model="item.value"
|
||||||
|
class="select-filter-component"
|
||||||
|
:style="{ width: '175px' }"
|
||||||
|
:disabled="disabled"
|
||||||
|
:placeholder="$t('placeholder2')"
|
||||||
|
>
|
||||||
|
<a-select-option key="1">
|
||||||
|
true
|
||||||
|
</a-select-option>
|
||||||
|
<a-select-option key="0">
|
||||||
|
false
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
<treeselect
|
<treeselect
|
||||||
class="custom-treeselect"
|
class="custom-treeselect"
|
||||||
:style="{ width: '175px', '--custom-height': '24px' }"
|
:style="{ width: '175px', '--custom-height': '24px' }"
|
||||||
|
@ -92,7 +115,7 @@
|
||||||
:multiple="false"
|
:multiple="false"
|
||||||
:clearable="false"
|
:clearable="false"
|
||||||
searchable
|
searchable
|
||||||
v-if="isChoiceByProperty(item.property) && (item.exp === 'is' || item.exp === '~is')"
|
v-else-if="isChoiceByProperty(item.property) && (item.exp === 'is' || item.exp === '~is')"
|
||||||
:options="getChoiceValueByProperty(item.property)"
|
:options="getChoiceValueByProperty(item.property)"
|
||||||
:placeholder="$t('placeholder2')"
|
:placeholder="$t('placeholder2')"
|
||||||
:normalizer="
|
:normalizer="
|
||||||
|
@ -199,10 +222,11 @@ import _ from 'lodash'
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
import { ruleTypeList, expList, advancedExpList, compareTypeList } from './constants'
|
import { ruleTypeList, expList, advancedExpList, compareTypeList } from './constants'
|
||||||
import ValueTypeMapIcon from '../CMDBValueTypeMapIcon'
|
import ValueTypeMapIcon from '../CMDBValueTypeMapIcon'
|
||||||
|
import CIReferenceAttr from '../ciReferenceAttr/index.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Expression',
|
name: 'Expression',
|
||||||
components: { ValueTypeMapIcon },
|
components: { ValueTypeMapIcon, CIReferenceAttr },
|
||||||
model: {
|
model: {
|
||||||
prop: 'value',
|
prop: 'value',
|
||||||
event: 'change',
|
event: 'change',
|
||||||
|
@ -255,7 +279,7 @@ export default {
|
||||||
getExpListByProperty(property) {
|
getExpListByProperty(property) {
|
||||||
if (property) {
|
if (property) {
|
||||||
const _find = this.canSearchPreferenceAttrList.find((item) => item.name === property)
|
const _find = this.canSearchPreferenceAttrList.find((item) => item.name === property)
|
||||||
if (_find && ['0', '1', '3', '4', '5'].includes(_find.value_type)) {
|
if (_find && (['0', '1', '3', '4', '5'].includes(_find.value_type) || _find.is_reference || _find.is_bool)) {
|
||||||
return [
|
return [
|
||||||
{ value: 'is', label: this.$t('cmdbFilterComp.is') },
|
{ value: 'is', label: this.$t('cmdbFilterComp.is') },
|
||||||
{ value: '~is', label: this.$t('cmdbFilterComp.~is') },
|
{ value: '~is', label: this.$t('cmdbFilterComp.~is') },
|
||||||
|
@ -315,6 +339,9 @@ export default {
|
||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
|
getAttr(property) {
|
||||||
|
return this.canSearchPreferenceAttrList.find((item) => item.name === property) || {}
|
||||||
|
},
|
||||||
handleChangeExp({ value }, item, index) {
|
handleChangeExp({ value }, item, index) {
|
||||||
const _ruleList = _.cloneDeep(this.ruleList)
|
const _ruleList = _.cloneDeep(this.ruleList)
|
||||||
if (value === 'range') {
|
if (value === 'range') {
|
||||||
|
@ -343,4 +370,20 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style></style>
|
<style lang="less" scoped>
|
||||||
|
.select-filter-component {
|
||||||
|
height: 24px;
|
||||||
|
|
||||||
|
/deep/ .ant-select-selection {
|
||||||
|
height: 24px;
|
||||||
|
background: #f7f8fa;
|
||||||
|
line-height: 24px;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
.ant-select-selection__rendered {
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -15,18 +15,38 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getPropertyIcon(attr) {
|
getPropertyIcon(attr) {
|
||||||
switch (attr.value_type) {
|
let valueType = attr.value_type
|
||||||
|
|
||||||
|
if (valueType === '2') {
|
||||||
|
if (attr.is_password) {
|
||||||
|
valueType = '7'
|
||||||
|
} else if (attr.is_link) {
|
||||||
|
valueType = '8'
|
||||||
|
} else if (!attr.is_index) {
|
||||||
|
valueType = '9'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
valueType === '7' &&
|
||||||
|
attr.is_bool
|
||||||
|
) {
|
||||||
|
valueType = '10'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
valueType === '0' &&
|
||||||
|
attr.is_reference
|
||||||
|
) {
|
||||||
|
valueType = '11'
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (valueType) {
|
||||||
case '0':
|
case '0':
|
||||||
return 'duose-shishu'
|
return 'duose-shishu'
|
||||||
case '1':
|
case '1':
|
||||||
return 'duose-fudianshu'
|
return 'duose-fudianshu'
|
||||||
case '2':
|
case '2':
|
||||||
if (attr.is_password) {
|
|
||||||
return 'duose-password'
|
|
||||||
}
|
|
||||||
if (attr.is_link) {
|
|
||||||
return 'duose-link'
|
|
||||||
}
|
|
||||||
return 'duose-wenben'
|
return 'duose-wenben'
|
||||||
case '3':
|
case '3':
|
||||||
return 'duose-datetime'
|
return 'duose-datetime'
|
||||||
|
@ -40,6 +60,14 @@ export default {
|
||||||
return 'duose-password'
|
return 'duose-password'
|
||||||
case '8':
|
case '8':
|
||||||
return 'duose-link'
|
return 'duose-link'
|
||||||
|
case '9':
|
||||||
|
return 'duose-changwenben1'
|
||||||
|
case '10':
|
||||||
|
return 'duose-boole'
|
||||||
|
case '11':
|
||||||
|
return 'duose-quote'
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -61,7 +61,13 @@
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a-input ref="regInput" :placeholder="$t('regexSelect.placeholder')" :value="current.label" @change="changeLabel">
|
<a-input
|
||||||
|
ref="regInput"
|
||||||
|
:placeholder="$t('regexSelect.placeholder')"
|
||||||
|
:value="current.label"
|
||||||
|
:disabled="disabled"
|
||||||
|
@change="changeLabel"
|
||||||
|
>
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</template>
|
</template>
|
||||||
|
@ -88,6 +94,10 @@ export default {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -0,0 +1,178 @@
|
||||||
|
<template>
|
||||||
|
<div class="reference-attr-select-wrap">
|
||||||
|
<a-select
|
||||||
|
v-bind="$attrs"
|
||||||
|
v-model="selectCIIds"
|
||||||
|
optionFilterProp="title"
|
||||||
|
:mode="isList ? 'multiple' : 'default'"
|
||||||
|
showSearch
|
||||||
|
allowClear
|
||||||
|
:getPopupContainer="(trigger) => trigger.parentElement"
|
||||||
|
class="reference-attr-select"
|
||||||
|
:maxTagCount="2"
|
||||||
|
@dropdownVisibleChange="handleDropdownVisibleChange"
|
||||||
|
@search="handleSearch"
|
||||||
|
@change="handleChange"
|
||||||
|
>
|
||||||
|
<template v-if="!isInit">
|
||||||
|
<a-select-option
|
||||||
|
v-for="(item) in initSelectOption"
|
||||||
|
:key="item.key"
|
||||||
|
:title="item.title"
|
||||||
|
>
|
||||||
|
{{ item.title }}
|
||||||
|
</a-select-option>
|
||||||
|
</template>
|
||||||
|
<a-select-option
|
||||||
|
v-for="(item) in options"
|
||||||
|
:key="item.key"
|
||||||
|
:title="item.title"
|
||||||
|
>
|
||||||
|
{{ item.title }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import _ from 'lodash'
|
||||||
|
import debounce from 'lodash/debounce'
|
||||||
|
import { searchCI, getCIType } from '@/api/cmdb'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CIReferenceAttr',
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: [Number, String, Array],
|
||||||
|
default: () => '',
|
||||||
|
},
|
||||||
|
isList: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
referenceShowAttrName: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
referenceTypeId: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
initSelectOption: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
prop: 'value',
|
||||||
|
event: 'change',
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isInit: false,
|
||||||
|
options: [],
|
||||||
|
innerReferenceShowAttrName: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
referenceTypeId: {
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
handler() {
|
||||||
|
this.isInit = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
selectCIIds: {
|
||||||
|
get() {
|
||||||
|
if (this.isList) {
|
||||||
|
return this.value || []
|
||||||
|
} else {
|
||||||
|
return this.value ? Number(this.value) : ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$emit('change', val ?? (this.isList ? [] : null))
|
||||||
|
return val
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async handleDropdownVisibleChange(open) {
|
||||||
|
if (!this.isInit && open && this.referenceTypeId) {
|
||||||
|
this.isInit = true
|
||||||
|
|
||||||
|
if (!this.referenceShowAttrName) {
|
||||||
|
const res = await getCIType(this.referenceTypeId)
|
||||||
|
const ciType = res?.ci_types?.[0]
|
||||||
|
this.innerReferenceShowAttrName = ciType?.show_name || ciType?.unique_name || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const attrName = this.referenceShowAttrName || this.innerReferenceShowAttrName || ''
|
||||||
|
if (!attrName) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await searchCI({
|
||||||
|
q: `_type:${this.referenceTypeId}`,
|
||||||
|
fl: attrName,
|
||||||
|
count: 25,
|
||||||
|
})
|
||||||
|
|
||||||
|
let options = res?.result?.map((item) => {
|
||||||
|
return {
|
||||||
|
key: item._id,
|
||||||
|
title: String(item?.[attrName] ?? '')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
options = _.uniqBy([...this.initSelectOption, ...options], 'key')
|
||||||
|
|
||||||
|
this.options = options
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSearch: debounce(async function(v) {
|
||||||
|
const attrName = this.referenceShowAttrName || this.innerReferenceShowAttrName || ''
|
||||||
|
|
||||||
|
if (!attrName || !this.referenceTypeId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await searchCI({
|
||||||
|
q: `_type:${this.referenceTypeId}${v ? ',*' + v + '*' : ''}`,
|
||||||
|
fl: attrName,
|
||||||
|
count: v ? 100 : 25,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.options = res?.result?.map((item) => {
|
||||||
|
return {
|
||||||
|
key: item._id,
|
||||||
|
title: String(item?.[attrName] ?? '')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 300),
|
||||||
|
|
||||||
|
handleChange(v) {
|
||||||
|
if (Array.isArray(v) ? !v.length : !v) {
|
||||||
|
this.handleSearch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.reference-attr-select-wrap {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.reference-attr-select {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
/deep/ .ant-select-dropdown {
|
||||||
|
z-index: 15;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -8,6 +8,7 @@
|
||||||
resizable
|
resizable
|
||||||
ref="xTable"
|
ref="xTable"
|
||||||
size="small"
|
size="small"
|
||||||
|
:data="data"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:row-config="{ useKey: true, keyField: '_id' }"
|
:row-config="{ useKey: true, keyField: '_id' }"
|
||||||
show-header-overflow
|
show-header-overflow
|
||||||
|
@ -56,8 +57,20 @@
|
||||||
<span>{{ col.title }}</span>
|
<span>{{ col.title }}</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="col.is_choice || col.is_password" #edit="{ row }">
|
<template v-if="col.is_choice || col.is_password || col.is_bool || col.is_reference" #edit="{ row }">
|
||||||
<vxe-input v-if="col.is_password" v-model="passwordValue[col.field]" />
|
<CIReferenceAttr
|
||||||
|
v-if="col.is_reference"
|
||||||
|
:referenceTypeId="col.reference_type_id"
|
||||||
|
:isList="col.is_list"
|
||||||
|
:referenceShowAttrName="referenceShowAttrNameMap[col.reference_type_id] || ''"
|
||||||
|
:initSelectOption="getInitReferenceSelectOption(row[col.field], col)"
|
||||||
|
v-model="row[col.field]"
|
||||||
|
/>
|
||||||
|
<a-switch
|
||||||
|
v-else-if="col.is_bool"
|
||||||
|
v-model="row[col.field]"
|
||||||
|
/>
|
||||||
|
<vxe-input v-else-if="col.is_password" v-model="passwordValue[col.field]" />
|
||||||
<a-select
|
<a-select
|
||||||
v-if="col.is_choice"
|
v-if="col.is_choice"
|
||||||
v-model="row[col.field]"
|
v-model="row[col.field]"
|
||||||
|
@ -100,10 +113,20 @@
|
||||||
</a-select>
|
</a-select>
|
||||||
</template>
|
</template>
|
||||||
<template
|
<template
|
||||||
v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice"
|
v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice || col.is_reference"
|
||||||
#default="{ row }"
|
#default="{ row }"
|
||||||
>
|
>
|
||||||
<span v-if="col.value_type === '6' && row[col.field]">{{ row[col.field] }}</span>
|
<template v-if="col.is_reference" >
|
||||||
|
<a
|
||||||
|
v-for="(ciId) in (col.is_list ? row[col.field] : [row[col.field]])"
|
||||||
|
:key="ciId"
|
||||||
|
:href="`/cmdb/cidetail/${col.reference_type_id}/${ciId}`"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{{ getReferenceAttrValue(ciId, col) }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
<span v-else-if="col.value_type === '6' && row[col.field]">{{ row[col.field] }}</span>
|
||||||
<template v-else-if="col.is_link && row[col.field]">
|
<template v-else-if="col.is_link && row[col.field]">
|
||||||
<a
|
<a
|
||||||
v-for="(item, linkIndex) in (col.is_list ? row[col.field] : [row[col.field]])"
|
v-for="(item, linkIndex) in (col.is_list ? row[col.field] : [row[col.field]])"
|
||||||
|
@ -187,16 +210,21 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import _ from 'lodash'
|
||||||
|
import { getCITypes } from '@/modules/cmdb/api/CIType'
|
||||||
|
import { searchCI } from '@/modules/cmdb/api/ci'
|
||||||
import JsonEditor from '../JsonEditor/jsonEditor.vue'
|
import JsonEditor from '../JsonEditor/jsonEditor.vue'
|
||||||
import PasswordField from '../passwordField/index.vue'
|
import PasswordField from '../passwordField/index.vue'
|
||||||
import { ops_move_icon as OpsMoveIcon } from '@/core/icons'
|
import { ops_move_icon as OpsMoveIcon } from '@/core/icons'
|
||||||
|
import CIReferenceAttr from '@/components/ciReferenceAttr/index.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CITable',
|
name: 'CITable',
|
||||||
components: {
|
components: {
|
||||||
JsonEditor,
|
JsonEditor,
|
||||||
PasswordField,
|
PasswordField,
|
||||||
OpsMoveIcon
|
OpsMoveIcon,
|
||||||
|
CIReferenceAttr
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
// table ID
|
// table ID
|
||||||
|
@ -237,6 +265,18 @@ export default {
|
||||||
showDelete: {
|
showDelete: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
|
},
|
||||||
|
// 表格数据
|
||||||
|
data: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
referenceShowAttrNameMap: {},
|
||||||
|
referenceCIIdMap: {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -245,6 +285,46 @@ export default {
|
||||||
const idx = this.columns.findIndex((item) => item.is_fixed)
|
const idx = this.columns.findIndex((item) => item.is_fixed)
|
||||||
return idx > -1
|
return idx > -1
|
||||||
},
|
},
|
||||||
|
tableDataWatch() {
|
||||||
|
return {
|
||||||
|
data: this.data,
|
||||||
|
columns: this.columns
|
||||||
|
}
|
||||||
|
},
|
||||||
|
referenceCIIdWatch() {
|
||||||
|
const referenceTypeCol = this.columns?.filter((col) => col?.is_reference && col?.reference_type_id) || []
|
||||||
|
if (!this.data?.length || !referenceTypeCol?.length) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const ids = []
|
||||||
|
this.data.forEach((row) => {
|
||||||
|
referenceTypeCol.forEach((col) => {
|
||||||
|
if (row[col.field]) {
|
||||||
|
ids.push(...(Array.isArray(row[col.field]) ? row[col.field] : [row[col.field]]))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return _.uniq(ids)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
columns: {
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
handler(newVal) {
|
||||||
|
this.handleReferenceShowAttrName(newVal)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
referenceCIIdWatch: {
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
handler() {
|
||||||
|
this.handleReferenceCIIdMap()
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -330,6 +410,101 @@ export default {
|
||||||
|
|
||||||
getRowSeq(row) {
|
getRowSeq(row) {
|
||||||
return this.getVxetableRef().getRowSeq(row)
|
return this.getVxetableRef().getRowSeq(row)
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleReferenceShowAttrName(columns) {
|
||||||
|
const needRequiredCITypeIds = columns?.filter((col) => col?.is_reference && col?.reference_type_id).map((col) => col.reference_type_id) || []
|
||||||
|
if (!needRequiredCITypeIds.length) {
|
||||||
|
this.referenceShowAttrNameMap = {}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await getCITypes({
|
||||||
|
type_ids: needRequiredCITypeIds.join(',')
|
||||||
|
})
|
||||||
|
|
||||||
|
const map = {}
|
||||||
|
res.ci_types.forEach((ciType) => {
|
||||||
|
map[ciType.id] = ciType?.show_name || ciType?.unique_name || ''
|
||||||
|
})
|
||||||
|
|
||||||
|
this.referenceShowAttrNameMap = map
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleReferenceCIIdMap() {
|
||||||
|
const referenceTypeCol = this.columns.filter((col) => col?.is_reference && col?.reference_type_id) || []
|
||||||
|
if (!this.data?.length || !referenceTypeCol?.length) {
|
||||||
|
this.referenceCIIdMap = {}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const map = {}
|
||||||
|
this.data.forEach((row) => {
|
||||||
|
referenceTypeCol.forEach((col) => {
|
||||||
|
const ids = Array.isArray(row[col.field]) ? row[col.field] : row[col.field] ? [row[col.field]] : []
|
||||||
|
if (ids.length) {
|
||||||
|
if (!map?.[col.reference_type_id]) {
|
||||||
|
map[col.reference_type_id] = {}
|
||||||
|
}
|
||||||
|
ids.forEach((id) => {
|
||||||
|
map[col.reference_type_id][id] = {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!Object.keys(map).length) {
|
||||||
|
this.referenceCIIdMap = {}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const allRes = await Promise.all(
|
||||||
|
Object.keys(map).map((key) => {
|
||||||
|
return searchCI({
|
||||||
|
q: `_type:${key},_id:(${Object.keys(map[key]).join(';')})`,
|
||||||
|
count: 9999
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
allRes.forEach((res) => {
|
||||||
|
res.result.forEach((item) => {
|
||||||
|
if (map?.[item._type]?.[item._id]) {
|
||||||
|
map[item._type][item._id] = item
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.referenceCIIdMap = map
|
||||||
|
},
|
||||||
|
|
||||||
|
getReferenceAttrValue(id, col) {
|
||||||
|
const ci = this?.referenceCIIdMap?.[col?.reference_type_id]?.[id]
|
||||||
|
if (!ci) {
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
const attrName = this.referenceShowAttrNameMap?.[col.reference_type_id]
|
||||||
|
return ci?.[attrName] || id
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitReferenceSelectOption(value, col) {
|
||||||
|
const ids = Array.isArray(value) ? value : value ? [value] : []
|
||||||
|
if (!ids.length) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const map = this?.referenceCIIdMap?.[col?.reference_type_id]
|
||||||
|
const attrName = this.referenceShowAttrNameMap?.[col?.reference_type_id]
|
||||||
|
|
||||||
|
const option = (Array.isArray(value) ? value : [value]).map((id) => {
|
||||||
|
return {
|
||||||
|
key: id,
|
||||||
|
title: map?.[id]?.[attrName] || id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return option
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,11 @@ export default {
|
||||||
this.editor.insertNode(node)
|
this.editor.insertNode(node)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
destroy() {
|
||||||
|
const editor = this.editor
|
||||||
|
if (editor == null) return
|
||||||
|
editor.destroy()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -190,6 +190,14 @@ const cmdb_en = {
|
||||||
confirmDeleteTrigger: 'Are you sure to delete this trigger?',
|
confirmDeleteTrigger: 'Are you sure to delete this trigger?',
|
||||||
int: 'Integer',
|
int: 'Integer',
|
||||||
float: 'Float',
|
float: 'Float',
|
||||||
|
longText: 'Long Text',
|
||||||
|
shortText: 'Short Text',
|
||||||
|
shortTextTip: 'Text length <= 128',
|
||||||
|
referenceModel: 'Reference Model',
|
||||||
|
referenceModelTip: 'Please select reference model',
|
||||||
|
referenceModelTip1: 'For quick view of referenced model instances',
|
||||||
|
bool: 'Bool',
|
||||||
|
reference: 'Reference',
|
||||||
text: 'Text',
|
text: 'Text',
|
||||||
datetime: 'DateTime',
|
datetime: 'DateTime',
|
||||||
date: 'Date',
|
date: 'Date',
|
||||||
|
@ -207,7 +215,7 @@ const cmdb_en = {
|
||||||
otherGroupTips: 'Non sortable within the other group',
|
otherGroupTips: 'Non sortable within the other group',
|
||||||
filterTips: 'click to show {name}',
|
filterTips: 'click to show {name}',
|
||||||
attributeAssociation: 'Attribute Association',
|
attributeAssociation: 'Attribute Association',
|
||||||
attributeAssociationTip1: 'Automatically establish relationships through the attributes except password, json and multiple of two models',
|
attributeAssociationTip1: 'Automatically establish relationships through attribute values (except password, json, multi-value, long text, boolean, reference) of two models',
|
||||||
attributeAssociationTip2: 'Double click to edit',
|
attributeAssociationTip2: 'Double click to edit',
|
||||||
attributeAssociationTip3: 'Two Attributes must be selected',
|
attributeAssociationTip3: 'Two Attributes must be selected',
|
||||||
attributeAssociationTip4: 'Please select a attribute from Source CIType',
|
attributeAssociationTip4: 'Please select a attribute from Source CIType',
|
||||||
|
@ -283,6 +291,9 @@ const cmdb_en = {
|
||||||
rule: 'Rule',
|
rule: 'Rule',
|
||||||
cascadeAttr: 'Cascade',
|
cascadeAttr: 'Cascade',
|
||||||
cascadeAttrTip: 'Cascading attributes note the order',
|
cascadeAttrTip: 'Cascading attributes note the order',
|
||||||
|
enumValue: 'Value',
|
||||||
|
label: 'Label',
|
||||||
|
valueInputTip: 'Please input value'
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
unselectAttributes: 'Unselected',
|
unselectAttributes: 'Unselected',
|
||||||
|
@ -324,7 +335,7 @@ const cmdb_en = {
|
||||||
pleaseSearch: 'Please search',
|
pleaseSearch: 'Please search',
|
||||||
conditionFilter: 'Conditional filtering',
|
conditionFilter: 'Conditional filtering',
|
||||||
attributeDesc: 'Attribute Description',
|
attributeDesc: 'Attribute Description',
|
||||||
ciSearchTips: '1. JSON/password/link attributes cannot be searched\n2. If the search content includes commas, they need to be escaped\n3. Only index attributes are searched, non-index attributes use conditional filtering',
|
ciSearchTips: '1. JSON/password/link/longText/reference attributes cannot be searched\n2. If the search content includes commas, they need to be escaped\n3. Only index attributes are searched, non-index attributes use conditional filtering',
|
||||||
ciSearchTips2: 'For example: q=hostname:*0.0.0.0*',
|
ciSearchTips2: 'For example: q=hostname:*0.0.0.0*',
|
||||||
subCIType: 'Subscription CIType',
|
subCIType: 'Subscription CIType',
|
||||||
already: 'already',
|
already: 'already',
|
||||||
|
@ -549,7 +560,7 @@ class AutoDiscovery(object):
|
||||||
"""
|
"""
|
||||||
Define attribute fields
|
Define attribute fields
|
||||||
:return: Returns a list of attribute fields. The list items are (name, type, description). The name must be in English.
|
:return: Returns a list of attribute fields. The list items are (name, type, description). The name must be in English.
|
||||||
type: String Integer Float Date DateTime Time JSON
|
type: String Integer Float Date DateTime Time JSON Bool Reference
|
||||||
For example:
|
For example:
|
||||||
return [
|
return [
|
||||||
("ci_type", "String", "CIType name"),
|
("ci_type", "String", "CIType name"),
|
||||||
|
|
|
@ -190,6 +190,14 @@ const cmdb_zh = {
|
||||||
confirmDeleteTrigger: '确认删除该触发器吗?',
|
confirmDeleteTrigger: '确认删除该触发器吗?',
|
||||||
int: '整数',
|
int: '整数',
|
||||||
float: '浮点数',
|
float: '浮点数',
|
||||||
|
longText: '长文本',
|
||||||
|
shortText: '短文本',
|
||||||
|
shortTextTip: '文本长度 <= 128',
|
||||||
|
referenceModel: '引用模型',
|
||||||
|
referenceModelTip: '请选择引用模型',
|
||||||
|
referenceModelTip1: '用于快捷查看引用模型实例',
|
||||||
|
bool: '布尔',
|
||||||
|
reference: '引用',
|
||||||
text: '文本',
|
text: '文本',
|
||||||
datetime: '日期时间',
|
datetime: '日期时间',
|
||||||
date: '日期',
|
date: '日期',
|
||||||
|
@ -207,7 +215,7 @@ const cmdb_zh = {
|
||||||
otherGroupTips: '其他分组属性不可排序',
|
otherGroupTips: '其他分组属性不可排序',
|
||||||
filterTips: '点击可仅查看{name}属性',
|
filterTips: '点击可仅查看{name}属性',
|
||||||
attributeAssociation: '属性关联',
|
attributeAssociation: '属性关联',
|
||||||
attributeAssociationTip1: '通过2个模型的属性值(除密码、json、多值)来自动建立关系',
|
attributeAssociationTip1: '通过2个模型的属性值(除密码、json、多值、长文本、布尔、引用)来自动建立关系',
|
||||||
attributeAssociationTip2: '双击可编辑',
|
attributeAssociationTip2: '双击可编辑',
|
||||||
attributeAssociationTip3: '属性关联必须选择两个属性',
|
attributeAssociationTip3: '属性关联必须选择两个属性',
|
||||||
attributeAssociationTip4: '请选择原模型属性',
|
attributeAssociationTip4: '请选择原模型属性',
|
||||||
|
@ -283,6 +291,9 @@ const cmdb_zh = {
|
||||||
rule: '规则',
|
rule: '规则',
|
||||||
cascadeAttr: '级联',
|
cascadeAttr: '级联',
|
||||||
cascadeAttrTip: '级联属性注意顺序',
|
cascadeAttrTip: '级联属性注意顺序',
|
||||||
|
enumValue: '枚举值',
|
||||||
|
label: '标签',
|
||||||
|
valueInputTip: '请输入枚举值'
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
unselectAttributes: '未选属性',
|
unselectAttributes: '未选属性',
|
||||||
|
@ -324,7 +335,7 @@ const cmdb_zh = {
|
||||||
pleaseSearch: '请查找',
|
pleaseSearch: '请查找',
|
||||||
conditionFilter: '条件过滤',
|
conditionFilter: '条件过滤',
|
||||||
attributeDesc: '属性说明',
|
attributeDesc: '属性说明',
|
||||||
ciSearchTips: '1. json、密码、链接属性不能搜索\n2. 搜索内容包括逗号, 则需转义\n3. 只搜索索引属性, 非索引属性使用条件过滤',
|
ciSearchTips: '1. json、密码、链接、长文本、引用属性不能搜索\n2. 搜索内容包括逗号, 则需转义\n3. 只搜索索引属性, 非索引属性使用条件过滤',
|
||||||
ciSearchTips2: '例: q=hostname:*0.0.0.0*',
|
ciSearchTips2: '例: q=hostname:*0.0.0.0*',
|
||||||
subCIType: '订阅模型',
|
subCIType: '订阅模型',
|
||||||
already: '已',
|
already: '已',
|
||||||
|
@ -548,7 +559,7 @@ class AutoDiscovery(object):
|
||||||
"""
|
"""
|
||||||
Define attribute fields
|
Define attribute fields
|
||||||
:return: Returns a list of attribute fields. The list items are (name, type, description). The name must be in English.
|
:return: Returns a list of attribute fields. The list items are (name, type, description). The name must be in English.
|
||||||
type: String Integer Float Date DateTime Time JSON
|
type: String Integer Float Date DateTime Time JSON Bool Reference
|
||||||
For example:
|
For example:
|
||||||
return [
|
return [
|
||||||
("ci_type", "String", "CIType name"),
|
("ci_type", "String", "CIType name"),
|
||||||
|
|
|
@ -4,13 +4,16 @@ export const valueTypeMap = () => {
|
||||||
return {
|
return {
|
||||||
'0': i18n.t('cmdb.ciType.int'),
|
'0': i18n.t('cmdb.ciType.int'),
|
||||||
'1': i18n.t('cmdb.ciType.float'),
|
'1': i18n.t('cmdb.ciType.float'),
|
||||||
'2': i18n.t('cmdb.ciType.text'),
|
'2': i18n.t('cmdb.ciType.shortText'),
|
||||||
'3': i18n.t('cmdb.ciType.datetime'),
|
'3': i18n.t('cmdb.ciType.datetime'),
|
||||||
'4': i18n.t('cmdb.ciType.date'),
|
'4': i18n.t('cmdb.ciType.date'),
|
||||||
'5': i18n.t('cmdb.ciType.time'),
|
'5': i18n.t('cmdb.ciType.time'),
|
||||||
'6': 'JSON',
|
'6': 'JSON',
|
||||||
'7': i18n.t('cmdb.ciType.password'),
|
'7': i18n.t('cmdb.ciType.password'),
|
||||||
'8': i18n.t('cmdb.ciType.link')
|
'8': i18n.t('cmdb.ciType.link'),
|
||||||
|
'9': i18n.t('cmdb.ciType.longText'),
|
||||||
|
'10': i18n.t('cmdb.ciType.bool'),
|
||||||
|
'11': i18n.t('cmdb.ciType.reference'),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,9 @@ export function getCITableColumns(data, attrList, width = 1600, height) {
|
||||||
is_list: attr.is_list,
|
is_list: attr.is_list,
|
||||||
is_choice: attr.is_choice,
|
is_choice: attr.is_choice,
|
||||||
is_fixed: attr.is_fixed,
|
is_fixed: attr.is_fixed,
|
||||||
|
is_bool: attr.is_bool,
|
||||||
|
is_reference: attr.is_reference,
|
||||||
|
reference_type_id: attr.reference_type_id
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,6 +140,10 @@ export const getPropertyStyle = (attr) => {
|
||||||
export const getPropertyIcon = (attr) => {
|
export const getPropertyIcon = (attr) => {
|
||||||
switch (attr.value_type) {
|
switch (attr.value_type) {
|
||||||
case '0':
|
case '0':
|
||||||
|
if (attr.is_reference) {
|
||||||
|
return 'duose-quote'
|
||||||
|
}
|
||||||
|
|
||||||
return 'duose-shishu'
|
return 'duose-shishu'
|
||||||
case '1':
|
case '1':
|
||||||
return 'duose-fudianshu'
|
return 'duose-fudianshu'
|
||||||
|
@ -147,6 +154,9 @@ export const getPropertyIcon = (attr) => {
|
||||||
if (attr.is_link) {
|
if (attr.is_link) {
|
||||||
return 'duose-link'
|
return 'duose-link'
|
||||||
}
|
}
|
||||||
|
if (attr.is_index === false) {
|
||||||
|
return 'duose-changwenben1'
|
||||||
|
}
|
||||||
return 'duose-wenben'
|
return 'duose-wenben'
|
||||||
case '3':
|
case '3':
|
||||||
return 'duose-datetime'
|
return 'duose-datetime'
|
||||||
|
@ -157,9 +167,49 @@ export const getPropertyIcon = (attr) => {
|
||||||
case '6':
|
case '6':
|
||||||
return 'duose-json'
|
return 'duose-json'
|
||||||
case '7':
|
case '7':
|
||||||
|
if (attr.is_bool) {
|
||||||
|
return 'duose-boole'
|
||||||
|
}
|
||||||
return 'duose-password'
|
return 'duose-password'
|
||||||
case '8':
|
case '8':
|
||||||
return 'duose-link'
|
return 'duose-link'
|
||||||
|
case '9':
|
||||||
|
return 'duose-changwenben1'
|
||||||
|
case '10':
|
||||||
|
return 'duose-boole'
|
||||||
|
case '11':
|
||||||
|
return 'duose-quote'
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getPropertyType = (attr) => {
|
||||||
|
if (attr.is_password) {
|
||||||
|
return '7'
|
||||||
|
}
|
||||||
|
if (attr.is_link) {
|
||||||
|
return '8'
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (attr.value_type) {
|
||||||
|
case '0':
|
||||||
|
if (attr.is_reference) {
|
||||||
|
return '11'
|
||||||
|
}
|
||||||
|
return '0'
|
||||||
|
case '2':
|
||||||
|
if (!attr.is_index) {
|
||||||
|
return '9'
|
||||||
|
}
|
||||||
|
return '2'
|
||||||
|
case '7':
|
||||||
|
if (attr.is_bool) {
|
||||||
|
return '10'
|
||||||
|
}
|
||||||
|
return '7'
|
||||||
|
default:
|
||||||
|
return attr?.value_type ?? ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -465,13 +465,12 @@ export default {
|
||||||
this.loadTip = this.$t('cmdb.ci.batchUpdateInProgress') + '...'
|
this.loadTip = this.$t('cmdb.ci.batchUpdateInProgress') + '...'
|
||||||
const payload = {}
|
const payload = {}
|
||||||
Object.keys(values).forEach((key) => {
|
Object.keys(values).forEach((key) => {
|
||||||
if (values[key] || values[key] === 0) {
|
|
||||||
payload[key] = values[key]
|
|
||||||
}
|
|
||||||
// Field values support blanking
|
// Field values support blanking
|
||||||
// There are currently field values that do not support blanking and will be returned by the backend.
|
// There are currently field values that do not support blanking and will be returned by the backend.
|
||||||
if (values[key] === undefined || values[key] === null) {
|
if (values[key] === undefined || values[key] === null) {
|
||||||
payload[key] = null
|
payload[key] = null
|
||||||
|
} else {
|
||||||
|
payload[key] = values[key]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.$refs.create.visible = false
|
this.$refs.create.visible = false
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
<a-select v-model="parentsForm[item.name].attr">
|
<a-select v-model="parentsForm[item.name].attr">
|
||||||
<a-select-option
|
<a-select-option
|
||||||
:title="attr.alias || attr.name"
|
:title="attr.alias || attr.name"
|
||||||
v-for="attr in item.attributes"
|
v-for="attr in filterAttributes(item.attributes)"
|
||||||
:key="attr.name"
|
:key="attr.name"
|
||||||
:value="attr.name"
|
:value="attr.name"
|
||||||
>
|
>
|
||||||
|
@ -87,11 +87,32 @@
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="showListOperation(list.name) ? 10 : 13">
|
<a-col :span="showListOperation(list.name) ? 10 : 13">
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
|
<CIReferenceAttr
|
||||||
|
v-if="getAttr(list.name).is_reference"
|
||||||
|
:referenceTypeId="getAttr(list.name).reference_type_id"
|
||||||
|
:isList="getAttr(list.name).is_list"
|
||||||
|
v-decorator="[
|
||||||
|
list.name,
|
||||||
|
{
|
||||||
|
initialValue: getAttr(list.name).is_list ? [] : ''
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
<a-switch
|
||||||
|
v-else-if="getAttr(list.name).is_bool"
|
||||||
|
v-decorator="[
|
||||||
|
list.name,
|
||||||
|
{
|
||||||
|
valuePropName: 'checked',
|
||||||
|
initialValue: false
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
/>
|
||||||
<a-select
|
<a-select
|
||||||
:style="{ width: '100%' }"
|
:style="{ width: '100%' }"
|
||||||
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
||||||
:placeholder="$t('placeholder2')"
|
:placeholder="$t('placeholder2')"
|
||||||
v-if="getFieldType(list.name).split('%%')[0] === 'select'"
|
v-else-if="getFieldType(list.name).split('%%')[0] === 'select'"
|
||||||
:mode="getFieldType(list.name).split('%%')[1] === 'multiple' ? 'multiple' : 'default'"
|
:mode="getFieldType(list.name).split('%%')[1] === 'multiple' ? 'multiple' : 'default'"
|
||||||
showSearch
|
showSearch
|
||||||
allowClear
|
allowClear
|
||||||
|
@ -114,18 +135,18 @@
|
||||||
<a-input-number
|
<a-input-number
|
||||||
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
v-if="getFieldType(list.name) === 'input_number'"
|
v-else-if="getFieldType(list.name) === 'input_number'"
|
||||||
/>
|
/>
|
||||||
<a-date-picker
|
<a-date-picker
|
||||||
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
:format="getFieldType(list.name) == '4' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
|
:format="getFieldType(list.name) == '4' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
|
||||||
:valueFormat="getFieldType(list.name) == '4' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
|
:valueFormat="getFieldType(list.name) == '4' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
|
||||||
v-if="getFieldType(list.name) === '4' || getFieldType(list.name) === '3'"
|
v-else-if="getFieldType(list.name) === '4' || getFieldType(list.name) === '3'"
|
||||||
:showTime="getFieldType(list.name) === '4' ? false : { format: 'HH:mm:ss' }"
|
:showTime="getFieldType(list.name) === '4' ? false : { format: 'HH:mm:ss' }"
|
||||||
/>
|
/>
|
||||||
<a-input
|
<a-input
|
||||||
v-if="getFieldType(list.name) === 'input'"
|
v-else-if="getFieldType(list.name) === 'input'"
|
||||||
@focus="(e) => handleFocusInput(e, list)"
|
@focus="(e) => handleFocusInput(e, list)"
|
||||||
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
v-decorator="[list.name, { rules: getDecoratorRules(list) }]"
|
||||||
/>
|
/>
|
||||||
|
@ -156,6 +177,7 @@ import JsonEditor from '../../../components/JsonEditor/jsonEditor.vue'
|
||||||
import { valueTypeMap } from '../../../utils/const'
|
import { valueTypeMap } from '../../../utils/const'
|
||||||
import CreateInstanceFormByGroup from './createInstanceFormByGroup.vue'
|
import CreateInstanceFormByGroup from './createInstanceFormByGroup.vue'
|
||||||
import { getCITypeParent, getCanEditByParentIdChildId } from '@/modules/cmdb/api/CITypeRelation'
|
import { getCITypeParent, getCanEditByParentIdChildId } from '@/modules/cmdb/api/CITypeRelation'
|
||||||
|
import CIReferenceAttr from '@/components/ciReferenceAttr/index.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CreateInstanceForm',
|
name: 'CreateInstanceForm',
|
||||||
|
@ -164,6 +186,7 @@ export default {
|
||||||
ElOption: Option,
|
ElOption: Option,
|
||||||
JsonEditor,
|
JsonEditor,
|
||||||
CreateInstanceFormByGroup,
|
CreateInstanceFormByGroup,
|
||||||
|
CIReferenceAttr
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
typeIdFromRelation: {
|
typeIdFromRelation: {
|
||||||
|
@ -261,6 +284,11 @@ export default {
|
||||||
}
|
}
|
||||||
Object.keys(values).forEach((k) => {
|
Object.keys(values).forEach((k) => {
|
||||||
const _tempFind = this.attributeList.find((item) => item.name === k)
|
const _tempFind = this.attributeList.find((item) => item.name === k)
|
||||||
|
|
||||||
|
if (_tempFind.is_reference) {
|
||||||
|
values[k] = values[k] ? values[k] : null
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
_tempFind.value_type === '3' &&
|
_tempFind.value_type === '3' &&
|
||||||
values[k] &&
|
values[k] &&
|
||||||
|
@ -309,6 +337,11 @@ export default {
|
||||||
|
|
||||||
Object.keys(values).forEach((k) => {
|
Object.keys(values).forEach((k) => {
|
||||||
const _tempFind = this.attributeList.find((item) => item.name === k)
|
const _tempFind = this.attributeList.find((item) => item.name === k)
|
||||||
|
|
||||||
|
if (_tempFind.is_reference) {
|
||||||
|
values[k] = values[k] ? values[k] : null
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
_tempFind.value_type === '3' &&
|
_tempFind.value_type === '3' &&
|
||||||
values[k] &&
|
values[k] &&
|
||||||
|
@ -426,6 +459,9 @@ export default {
|
||||||
}
|
}
|
||||||
return 'input'
|
return 'input'
|
||||||
},
|
},
|
||||||
|
getAttr(name) {
|
||||||
|
return this.attributeList.find((item) => item.name === name) ?? {}
|
||||||
|
},
|
||||||
getSelectFieldOptions(name) {
|
getSelectFieldOptions(name) {
|
||||||
const _find = this.attributeList.find((item) => item.name === name)
|
const _find = this.attributeList.find((item) => item.name === name)
|
||||||
if (_find) {
|
if (_find) {
|
||||||
|
@ -487,7 +523,12 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return rules
|
return rules
|
||||||
}
|
},
|
||||||
|
filterAttributes(attributes) {
|
||||||
|
return attributes.filter((attr) => {
|
||||||
|
return !attr.is_bool && !attr.is_reference
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -498,7 +539,7 @@ export default {
|
||||||
}
|
}
|
||||||
.ant-drawer-body {
|
.ant-drawer-body {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
max-height: calc(100vh - 110px);
|
height: calc(100vh - 110px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -79,6 +79,8 @@
|
||||||
import XEUtils from 'xe-utils'
|
import XEUtils from 'xe-utils'
|
||||||
import { getCITypeAttributesByName } from '@/modules/cmdb/api/CITypeAttr'
|
import { getCITypeAttributesByName } from '@/modules/cmdb/api/CITypeAttr'
|
||||||
import { valueTypeMap } from '@/modules/cmdb/utils/const'
|
import { valueTypeMap } from '@/modules/cmdb/utils/const'
|
||||||
|
import { getPropertyType } from '@/modules/cmdb/utils/helper'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MetadataDrawer',
|
name: 'MetadataDrawer',
|
||||||
data() {
|
data() {
|
||||||
|
@ -187,12 +189,7 @@ export default {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
const { attributes = [] } = await getCITypeAttributesByName(this.typeId)
|
const { attributes = [] } = await getCITypeAttributesByName(this.typeId)
|
||||||
this.tableData = attributes.map((attr) => {
|
this.tableData = attributes.map((attr) => {
|
||||||
if (attr.is_password) {
|
attr.value_type = getPropertyType(attr)
|
||||||
attr.value_type = '7'
|
|
||||||
}
|
|
||||||
if (attr.is_link) {
|
|
||||||
attr.value_type = '8'
|
|
||||||
}
|
|
||||||
return attr
|
return attr
|
||||||
})
|
})
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<span :id="`ci-detail-attr-${attr.name}`">
|
<span :id="`ci-detail-attr-${attr.name}`">
|
||||||
<span v-if="!isEdit || attr.value_type === '6'">
|
<span v-if="!isEdit || attr.value_type === '6'">
|
||||||
|
<template v-if="attr.is_reference" >
|
||||||
|
<a
|
||||||
|
v-for="(ciId) in (attr.is_list ? ci[attr.name] : [ci[attr.name]])"
|
||||||
|
:key="ciId"
|
||||||
|
:href="`/cmdb/cidetail/${attr.reference_type_id}/${ciId}`"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{{ attr.referenceShowAttrNameMap ? attr.referenceShowAttrNameMap[ciId] || ciId : ciId }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
<PasswordField
|
<PasswordField
|
||||||
:style="{ display: 'inline-block' }"
|
:style="{ display: 'inline-block' }"
|
||||||
v-if="attr.is_password && ci[attr.name]"
|
v-else-if="attr.is_password && ci[attr.name]"
|
||||||
:ci_id="ci._id"
|
:ci_id="ci._id"
|
||||||
:attr_id="attr.id"
|
:attr_id="attr.id"
|
||||||
></PasswordField>
|
></PasswordField>
|
||||||
|
@ -67,6 +77,29 @@
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<a-form :form="form">
|
<a-form :form="form">
|
||||||
<a-form-item label="" :colon="false">
|
<a-form-item label="" :colon="false">
|
||||||
|
<CIReferenceAttr
|
||||||
|
v-if="attr.is_reference"
|
||||||
|
:referenceTypeId="attr.reference_type_id"
|
||||||
|
:isList="attr.is_list"
|
||||||
|
:referenceShowAttrName="attr.showAttrName"
|
||||||
|
:initSelectOption="getInitReferenceSelectOption(attr)"
|
||||||
|
v-decorator="[
|
||||||
|
attr.name,
|
||||||
|
{
|
||||||
|
rules: [{ required: attr.is_required, message: $t('placeholder2') + `${attr.alias || attr.name}` }],
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
<a-switch
|
||||||
|
v-else-if="attr.is_bool"
|
||||||
|
v-decorator="[
|
||||||
|
attr.name,
|
||||||
|
{
|
||||||
|
rules: [{ required: attr.is_required }],
|
||||||
|
valuePropName: 'checked',
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
/>
|
||||||
<a-select
|
<a-select
|
||||||
:style="{ width: '100%' }"
|
:style="{ width: '100%' }"
|
||||||
v-decorator="[
|
v-decorator="[
|
||||||
|
@ -76,7 +109,7 @@
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
:placeholder="$t('placeholder2')"
|
:placeholder="$t('placeholder2')"
|
||||||
v-if="attr.is_choice"
|
v-else-if="attr.is_choice"
|
||||||
:mode="attr.is_list ? 'multiple' : 'default'"
|
:mode="attr.is_list ? 'multiple' : 'default'"
|
||||||
showSearch
|
showSearch
|
||||||
allowClear
|
allowClear
|
||||||
|
@ -157,10 +190,11 @@ import { updateCI } from '@/modules/cmdb/api/ci'
|
||||||
import JsonEditor from '../../../components/JsonEditor/jsonEditor.vue'
|
import JsonEditor from '../../../components/JsonEditor/jsonEditor.vue'
|
||||||
import PasswordField from '../../../components/passwordField/index.vue'
|
import PasswordField from '../../../components/passwordField/index.vue'
|
||||||
import { getAttrPassword } from '../../../api/CITypeAttr'
|
import { getAttrPassword } from '../../../api/CITypeAttr'
|
||||||
|
import CIReferenceAttr from '@/components/ciReferenceAttr/index.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CiDetailAttrContent',
|
name: 'CiDetailAttrContent',
|
||||||
components: { JsonEditor, PasswordField },
|
components: { JsonEditor, PasswordField, CIReferenceAttr },
|
||||||
props: {
|
props: {
|
||||||
ci: {
|
ci: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -209,7 +243,7 @@ export default {
|
||||||
}
|
}
|
||||||
this.isEdit = true
|
this.isEdit = true
|
||||||
this.$nextTick(async () => {
|
this.$nextTick(async () => {
|
||||||
if (this.attr.is_list && !this.attr.is_choice) {
|
if (this.attr.is_list && !this.attr.is_choice && !this.attr.is_reference) {
|
||||||
this.form.setFieldsValue({
|
this.form.setFieldsValue({
|
||||||
[`${this.attr.name}`]: Array.isArray(this.ci[this.attr.name])
|
[`${this.attr.name}`]: Array.isArray(this.ci[this.attr.name])
|
||||||
? this.ci[this.attr.name].join(',')
|
? this.ci[this.attr.name].join(',')
|
||||||
|
@ -237,6 +271,10 @@ export default {
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$message.success(this.$t('updateSuccess'))
|
this.$message.success(this.$t('updateSuccess'))
|
||||||
this.$emit('updateCIByself', { [`${this.attr.name}`]: newData }, this.attr.name)
|
this.$emit('updateCIByself', { [`${this.attr.name}`]: newData }, this.attr.name)
|
||||||
|
|
||||||
|
if (this.attr.is_reference) {
|
||||||
|
this.$emit('refreshReferenceAttr')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
this.$emit('refresh', this.attr.name)
|
this.$emit('refresh', this.attr.name)
|
||||||
|
@ -283,6 +321,16 @@ export default {
|
||||||
getName(name) {
|
getName(name) {
|
||||||
return name ?? ''
|
return name ?? ''
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getInitReferenceSelectOption(attr) {
|
||||||
|
const option = Object.keys(attr?.referenceShowAttrNameMap || {}).map((key) => {
|
||||||
|
return {
|
||||||
|
key: Number(key),
|
||||||
|
title: attr?.referenceShowAttrNameMap?.[key] ?? ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return option
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -38,6 +38,16 @@
|
||||||
resizable
|
resizable
|
||||||
class="ops-stripe-table"
|
class="ops-stripe-table"
|
||||||
>
|
>
|
||||||
|
<template #reference_default="{ row, column }">
|
||||||
|
<a
|
||||||
|
v-for="(id) in (column.params.attr.is_list ? row[column.field] : [row[column.field]])"
|
||||||
|
:key="id"
|
||||||
|
:href="`/cmdb/cidetail/${column.params.attr.reference_type_id}/${id}`"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{{ id }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
<template #operation_default="{ row }">
|
<template #operation_default="{ row }">
|
||||||
<a-popconfirm
|
<a-popconfirm
|
||||||
arrowPointAtCenter
|
arrowPointAtCenter
|
||||||
|
@ -85,6 +95,16 @@
|
||||||
resizable
|
resizable
|
||||||
class="ops-stripe-table"
|
class="ops-stripe-table"
|
||||||
>
|
>
|
||||||
|
<template #reference_default="{ row, column }">
|
||||||
|
<a
|
||||||
|
v-for="(id) in (column.params.attr.is_list ? row[column.field] : [row[column.field]])"
|
||||||
|
:key="id"
|
||||||
|
:href="`/cmdb/cidetail/${column.params.attr.reference_type_id}/${id}`"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{{ id }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
<template #operation_default="{ row }">
|
<template #operation_default="{ row }">
|
||||||
<a-popconfirm
|
<a-popconfirm
|
||||||
arrowPointAtCenter
|
arrowPointAtCenter
|
||||||
|
@ -258,7 +278,22 @@ export default {
|
||||||
const columns = []
|
const columns = []
|
||||||
const jsonAttr = []
|
const jsonAttr = []
|
||||||
item.attributes.forEach((attr) => {
|
item.attributes.forEach((attr) => {
|
||||||
columns.push({ key: 'p_' + attr.id, field: attr.name, title: attr.alias, minWidth: '100px' })
|
const column = {
|
||||||
|
key: 'p_' + attr.id,
|
||||||
|
field: attr.name,
|
||||||
|
title: attr.alias,
|
||||||
|
minWidth: '100px',
|
||||||
|
params: {
|
||||||
|
attr
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if (attr.is_reference) {
|
||||||
|
column.slots = {
|
||||||
|
default: 'reference_default'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
columns.push(column)
|
||||||
|
|
||||||
if (attr.value_type === '6') {
|
if (attr.value_type === '6') {
|
||||||
jsonAttr.push(attr.name)
|
jsonAttr.push(attr.name)
|
||||||
}
|
}
|
||||||
|
@ -299,7 +334,22 @@ export default {
|
||||||
const columns = []
|
const columns = []
|
||||||
const jsonAttr = []
|
const jsonAttr = []
|
||||||
item.attributes.forEach((attr) => {
|
item.attributes.forEach((attr) => {
|
||||||
columns.push({ key: 'c_' + attr.id, field: attr.name, title: attr.alias, minWidth: '100px' })
|
const column = {
|
||||||
|
key: 'c_' + attr.id,
|
||||||
|
field: attr.name,
|
||||||
|
title: attr.alias,
|
||||||
|
minWidth: '100px',
|
||||||
|
params: {
|
||||||
|
attr
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if (attr.is_reference) {
|
||||||
|
column.slots = {
|
||||||
|
default: 'reference_default'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
columns.push(column)
|
||||||
|
|
||||||
if (attr.value_type === '6') {
|
if (attr.value_type === '6') {
|
||||||
jsonAttr.push(attr.name)
|
jsonAttr.push(attr.name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
:key="attr.name"
|
:key="attr.name"
|
||||||
v-for="attr in group.attributes"
|
v-for="attr in group.attributes"
|
||||||
>
|
>
|
||||||
<ci-detail-attr-content :ci="ci" :attr="attr" @refresh="refresh" @updateCIByself="updateCIByself" />
|
<ci-detail-attr-content :ci="ci" :attr="attr" @refresh="refresh" @updateCIByself="updateCIByself" @refreshReferenceAttr="handleReferenceAttr" />
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</div>
|
</div>
|
||||||
|
@ -137,7 +137,7 @@ import _ from 'lodash'
|
||||||
import { Descriptions, DescriptionsItem } from 'element-ui'
|
import { Descriptions, DescriptionsItem } from 'element-ui'
|
||||||
import { getCITypeGroupById, getCITypes } from '@/modules/cmdb/api/CIType'
|
import { getCITypeGroupById, getCITypes } from '@/modules/cmdb/api/CIType'
|
||||||
import { getCIHistory, judgeItsmInstalled } from '@/modules/cmdb/api/history'
|
import { getCIHistory, judgeItsmInstalled } from '@/modules/cmdb/api/history'
|
||||||
import { getCIById } from '@/modules/cmdb/api/ci'
|
import { getCIById, searchCI } from '@/modules/cmdb/api/ci'
|
||||||
import CiDetailAttrContent from './ciDetailAttrContent.vue'
|
import CiDetailAttrContent from './ciDetailAttrContent.vue'
|
||||||
import CiDetailRelation from './ciDetailRelation.vue'
|
import CiDetailRelation from './ciDetailRelation.vue'
|
||||||
import TriggerTable from '../../operation_history/modules/triggerTable.vue'
|
import TriggerTable from '../../operation_history/modules/triggerTable.vue'
|
||||||
|
@ -244,9 +244,78 @@ export default {
|
||||||
getCITypeGroupById(this.typeId, { need_other: 1 })
|
getCITypeGroupById(this.typeId, { need_other: 1 })
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.attributeGroups = res
|
this.attributeGroups = res
|
||||||
|
|
||||||
|
this.handleReferenceAttr()
|
||||||
})
|
})
|
||||||
.catch((e) => {})
|
.catch((e) => {})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async handleReferenceAttr() {
|
||||||
|
const map = {}
|
||||||
|
this.attributeGroups.forEach((group) => {
|
||||||
|
group.attributes.forEach((attr) => {
|
||||||
|
if (attr?.is_reference && attr?.reference_type_id && this.ci[attr.name]) {
|
||||||
|
const ids = Array.isArray(this.ci[attr.name]) ? this.ci[attr.name] : this.ci[attr.name] ? [this.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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const newAttrGroups = _.cloneDeep(this.attributeGroups)
|
||||||
|
|
||||||
|
newAttrGroups.forEach((group) => {
|
||||||
|
group.attributes.forEach((attr) => {
|
||||||
|
if (attr?.is_reference && attr?.reference_type_id) {
|
||||||
|
attr.showAttrName = showAttrNameMap?.[attr?.reference_type_id] || ''
|
||||||
|
|
||||||
|
const referenceShowAttrNameMap = {}
|
||||||
|
const referenceCIIds = this.ci[attr.name];
|
||||||
|
(Array.isArray(referenceCIIds) ? referenceCIIds : referenceCIIds ? [referenceCIIds] : []).forEach((id) => {
|
||||||
|
referenceShowAttrNameMap[id] = ciNameMap?.[id]?.[attr.showAttrName] ?? id
|
||||||
|
})
|
||||||
|
attr.referenceShowAttrNameMap = referenceShowAttrNameMap
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$set(this, 'attributeGroups', newAttrGroups)
|
||||||
|
},
|
||||||
|
|
||||||
async getCI() {
|
async getCI() {
|
||||||
await getCIById(this.ciId)
|
await getCIById(this.ciId)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
|
|
@ -16,6 +16,29 @@
|
||||||
:key="attr.name + attr_idx"
|
:key="attr.name + attr_idx"
|
||||||
>
|
>
|
||||||
<a-form-item :label="attr.alias || attr.name" :colon="false">
|
<a-form-item :label="attr.alias || attr.name" :colon="false">
|
||||||
|
<CIReferenceAttr
|
||||||
|
v-if="attr.is_reference"
|
||||||
|
:referenceTypeId="attr.reference_type_id"
|
||||||
|
:isList="attr.is_list"
|
||||||
|
v-decorator="[
|
||||||
|
attr.name,
|
||||||
|
{
|
||||||
|
rules: [{ required: attr.is_required, message: $t('placeholder2') + `${attr.alias || attr.name}` }],
|
||||||
|
initialValue: attr.is_list ? [] : ''
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
<a-switch
|
||||||
|
v-else-if="attr.is_bool"
|
||||||
|
v-decorator="[
|
||||||
|
attr.name,
|
||||||
|
{
|
||||||
|
rules: [{ required: false }],
|
||||||
|
valuePropName: 'checked',
|
||||||
|
initialValue: attr.default ? Boolean(attr.default.default) : false
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
/>
|
||||||
<a-select
|
<a-select
|
||||||
:style="{ width: '100%' }"
|
:style="{ width: '100%' }"
|
||||||
v-decorator="[
|
v-decorator="[
|
||||||
|
@ -33,7 +56,7 @@
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
:placeholder="$t('placeholder2')"
|
:placeholder="$t('placeholder2')"
|
||||||
v-if="attr.is_choice"
|
v-else-if="attr.is_choice"
|
||||||
:mode="attr.is_list ? 'multiple' : 'default'"
|
:mode="attr.is_list ? 'multiple' : 'default'"
|
||||||
showSearch
|
showSearch
|
||||||
allowClear
|
allowClear
|
||||||
|
@ -133,10 +156,14 @@
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import JsonEditor from '../../../components/JsonEditor/jsonEditor.vue'
|
import JsonEditor from '../../../components/JsonEditor/jsonEditor.vue'
|
||||||
|
import CIReferenceAttr from '@/components/ciReferenceAttr/index.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CreateInstanceFormByGroup',
|
name: 'CreateInstanceFormByGroup',
|
||||||
components: { JsonEditor },
|
components: {
|
||||||
|
JsonEditor,
|
||||||
|
CIReferenceAttr
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
group: {
|
group: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -146,6 +173,10 @@ export default {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
|
ciTypeId: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
},
|
},
|
||||||
inject: ['getFieldType'],
|
inject: ['getFieldType'],
|
||||||
data() {
|
data() {
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { valueTypeMap } from '@/modules/cmdb/utils/const'
|
import { valueTypeMap } from '@/modules/cmdb/utils/const'
|
||||||
|
import { getPropertyType } from '@/modules/cmdb/utils/helper'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AllAttrDrawer',
|
name: 'AllAttrDrawer',
|
||||||
|
@ -84,12 +85,7 @@ export default {
|
||||||
})
|
})
|
||||||
|
|
||||||
otherAttrData.forEach((attr) => {
|
otherAttrData.forEach((attr) => {
|
||||||
if (attr.is_password) {
|
attr.value_type = getPropertyType(attr)
|
||||||
attr.value_type = '7'
|
|
||||||
}
|
|
||||||
if (attr.is_link) {
|
|
||||||
attr.value_type = '8'
|
|
||||||
}
|
|
||||||
|
|
||||||
attr.groupId = -1
|
attr.groupId = -1
|
||||||
attr.groupName = this.$t('other')
|
attr.groupName = this.$t('other')
|
||||||
|
|
|
@ -21,9 +21,7 @@
|
||||||
<div :class="{ 'attribute-card-name': true, 'attribute-card-name-default-show': property.default_show }">
|
<div :class="{ 'attribute-card-name': true, 'attribute-card-name-default-show': property.default_show }">
|
||||||
{{ property.alias || property.name }}
|
{{ property.alias || property.name }}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="property.is_password" class="attribute-card_value-type">{{ $t('cmdb.ciType.password') }}</div>
|
<div class="attribute-card_value-type">{{ valueTypeMap[getPropertyType(property)] }}</div>
|
||||||
<div v-else-if="property.is_link" class="attribute-card_value-type">{{ $t('cmdb.ciType.link') }}</div>
|
|
||||||
<div v-else class="attribute-card_value-type">{{ valueTypeMap[property.value_type] }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="attribute-card-trigger"
|
class="attribute-card-trigger"
|
||||||
|
@ -74,7 +72,9 @@
|
||||||
!isUnique &&
|
!isUnique &&
|
||||||
!['6'].includes(property.value_type) &&
|
!['6'].includes(property.value_type) &&
|
||||||
!property.is_password &&
|
!property.is_password &&
|
||||||
!property.is_list
|
!property.is_list &&
|
||||||
|
!property.is_reference &&
|
||||||
|
!property.is_bool
|
||||||
"
|
"
|
||||||
:title="$t(isShowId ? 'cmdb.ciType.cancelSetAsShow' : 'cmdb.ciType.setAsShow')"
|
:title="$t(isShowId ? 'cmdb.ciType.cancelSetAsShow' : 'cmdb.ciType.setAsShow')"
|
||||||
>
|
>
|
||||||
|
@ -101,6 +101,8 @@ import ValueTypeIcon from '@/components/CMDBValueTypeMapIcon'
|
||||||
import { valueTypeMap } from '../../utils/const'
|
import { valueTypeMap } from '../../utils/const'
|
||||||
import TriggerForm from './triggerForm.vue'
|
import TriggerForm from './triggerForm.vue'
|
||||||
import { updateCIType } from '@/modules/cmdb/api/CIType'
|
import { updateCIType } from '@/modules/cmdb/api/CIType'
|
||||||
|
import { getPropertyType } from '../../utils/helper'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AttributeCard',
|
name: 'AttributeCard',
|
||||||
inject: {
|
inject: {
|
||||||
|
@ -191,6 +193,7 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getPropertyType,
|
||||||
handleEdit() {
|
handleEdit() {
|
||||||
this.$emit('edit')
|
this.$emit('edit')
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
<template>
|
||||||
|
<a-form-item
|
||||||
|
:label="$t('cmdb.ciType.referenceModel')"
|
||||||
|
:extra="$t('cmdb.ciType.referenceModelTip1')"
|
||||||
|
:label-col="formItemLayout.labelCol"
|
||||||
|
:wrapper-col="formItemLayout.wrapperCol"
|
||||||
|
>
|
||||||
|
<a-select
|
||||||
|
allowClear
|
||||||
|
v-decorator="['reference_type_id', {
|
||||||
|
rules: [{ required: true, message: $t('cmdb.ciType.referenceModelTip') }],
|
||||||
|
initialValue: ''
|
||||||
|
}]"
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="title"
|
||||||
|
@dropdownVisibleChange="handleDropdownVisibleChange"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="(item) in options"
|
||||||
|
:key="item.value"
|
||||||
|
:title="item.label"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getCITypes } from '@/modules/cmdb/api/CIType'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ReferenceModelSelect',
|
||||||
|
props: {
|
||||||
|
form: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
isLazyRequire: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
formItemLayout: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isInit: false,
|
||||||
|
options: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (!this.isLazyRequire) {
|
||||||
|
this.getSelectOptions()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleDropdownVisibleChange(open) {
|
||||||
|
if (!this.isInit && open) {
|
||||||
|
this.getSelectOptions()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getSelectOptions() {
|
||||||
|
this.isInit = true
|
||||||
|
const res = await getCITypes()
|
||||||
|
|
||||||
|
this.options = res.ci_types.map((ciType) => {
|
||||||
|
return {
|
||||||
|
value: ciType.id,
|
||||||
|
label: ciType?.alias || ciType?.name || ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -60,11 +60,17 @@
|
||||||
v-decorator="['value_type', { rules: [{ required: true }] }]"
|
v-decorator="['value_type', { rules: [{ required: true }] }]"
|
||||||
@change="handleChangeValueType"
|
@change="handleChangeValueType"
|
||||||
>
|
>
|
||||||
<a-select-option :value="key" :key="key" v-for="(value, key) in valueTypeMap">{{ value }}</a-select-option>
|
<a-select-option :value="key" :key="key" v-for="(value, key) in valueTypeMap">
|
||||||
|
<ops-icon :type="getPropertyIcon({ value_type: key })" />
|
||||||
|
<span class="value-type-text">{{ value }}</span>
|
||||||
|
</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item></a-col
|
</a-form-item></a-col
|
||||||
>
|
>
|
||||||
<a-col :span="currentValueType === '6' ? 24 : 12">
|
<a-col
|
||||||
|
v-if="currentValueType !== '11'"
|
||||||
|
:span="currentValueType === '6' ? 24 : 12"
|
||||||
|
>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label-col="{ span: currentValueType === '6' ? 4 : 8 }"
|
:label-col="{ span: currentValueType === '6' ? 4 : 8 }"
|
||||||
:wrapper-col="{ span: currentValueType === '6' ? 18 : 12 }"
|
:wrapper-col="{ span: currentValueType === '6' ? 18 : 12 }"
|
||||||
|
@ -77,6 +83,10 @@
|
||||||
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
||||||
>
|
>
|
||||||
</a-input>
|
</a-input>
|
||||||
|
<a-switch
|
||||||
|
v-else-if="currentValueType === '10'"
|
||||||
|
v-decorator="['default_value', { rules: [{ required: false }], valuePropName: 'checked' }]"
|
||||||
|
/>
|
||||||
<a-select
|
<a-select
|
||||||
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
||||||
mode="tags"
|
mode="tags"
|
||||||
|
@ -95,12 +105,7 @@
|
||||||
</a-input-number>
|
</a-input-number>
|
||||||
<a-input
|
<a-input
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
v-else-if="
|
v-else-if="['2', '5', '7', '8', '9'].includes(currentValueType)"
|
||||||
currentValueType === '2' ||
|
|
||||||
currentValueType === '5' ||
|
|
||||||
currentValueType === '7' ||
|
|
||||||
currentValueType === '8'
|
|
||||||
"
|
|
||||||
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
||||||
>
|
>
|
||||||
</a-input>
|
</a-input>
|
||||||
|
@ -157,7 +162,18 @@
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|
||||||
<a-col :span="currentValueType === '2' ? 6 : 0" v-if="currentValueType !== '6'">
|
<a-col
|
||||||
|
v-if="currentValueType === '11'"
|
||||||
|
:span="12"
|
||||||
|
>
|
||||||
|
<ReferenceModelSelect
|
||||||
|
:form="form"
|
||||||
|
:isLazyRequire="false"
|
||||||
|
:formItemLayout="formItemLayout"
|
||||||
|
/>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
<!-- <a-col :span="currentValueType === '2' ? 6 : 0" v-if="currentValueType !== '6'">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:hidden="currentValueType === '2' ? false : true"
|
:hidden="currentValueType === '2' ? false : true"
|
||||||
:label-col="horizontalFormItemLayout.labelCol"
|
:label-col="horizontalFormItemLayout.labelCol"
|
||||||
|
@ -189,10 +205,10 @@
|
||||||
v-decorator="['is_index', { rules: [], valuePropName: 'checked' }]"
|
v-decorator="['is_index', { rules: [], valuePropName: 'checked' }]"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col> -->
|
||||||
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label-col="currentValueType === '2' ? { span: 8 } : horizontalFormItemLayout.labelCol"
|
:label-col="horizontalFormItemLayout.labelCol"
|
||||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||||
:label="$t('cmdb.ciType.unique')"
|
:label="$t('cmdb.ciType.unique')"
|
||||||
>
|
>
|
||||||
|
@ -206,7 +222,7 @@
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="6">
|
<a-col :span="6">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label-col="['2', '6', '7'].findIndex(i => currentValueType === i) === -1 ? { span: 8 } : horizontalFormItemLayout.labelCol"
|
:label-col="horizontalFormItemLayout.labelCol"
|
||||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||||
:label="$t('required')"
|
:label="$t('required')"
|
||||||
>
|
>
|
||||||
|
@ -219,7 +235,7 @@
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="6">
|
<a-col :span="6">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label-col="currentValueType === '2' ? { span: 12 } : horizontalFormItemLayout.labelCol"
|
:label-col="horizontalFormItemLayout.labelCol"
|
||||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||||
>
|
>
|
||||||
<template slot="label">
|
<template slot="label">
|
||||||
|
@ -228,8 +244,8 @@
|
||||||
>{{ $t('cmdb.ciType.defaultShow') }}
|
>{{ $t('cmdb.ciType.defaultShow') }}
|
||||||
<a-tooltip :title="$t('cmdb.ciType.defaultShowTips')">
|
<a-tooltip :title="$t('cmdb.ciType.defaultShowTips')">
|
||||||
<a-icon
|
<a-icon
|
||||||
style="position:absolute;top:2px;left:-17px;color:#2f54eb;"
|
style="position:absolute;top:2px;left:-17px;color:#A5A9BC;"
|
||||||
type="question-circle"
|
type="info-circle"
|
||||||
theme="filled"
|
theme="filled"
|
||||||
@click="
|
@click="
|
||||||
(e) => {
|
(e) => {
|
||||||
|
@ -250,7 +266,7 @@
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label-col="currentValueType === '2' ? horizontalFormItemLayout.labelCol : { span: 8 }"
|
:label-col="horizontalFormItemLayout.labelCol"
|
||||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||||
:label="$t('cmdb.ciType.isSortable')"
|
:label="$t('cmdb.ciType.isSortable')"
|
||||||
>
|
>
|
||||||
|
@ -263,7 +279,7 @@
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|
||||||
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
<a-col :span="6" v-if="!['6', '7', '10'].includes(currentValueType)">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label-col="currentValueType === '2' ? { span: 8 } : horizontalFormItemLayout.labelCol"
|
:label-col="currentValueType === '2' ? { span: 8 } : horizontalFormItemLayout.labelCol"
|
||||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||||
|
@ -274,8 +290,8 @@
|
||||||
>{{ $t('cmdb.ciType.list') }}
|
>{{ $t('cmdb.ciType.list') }}
|
||||||
<a-tooltip :title="$t('cmdb.ciType.listTips')">
|
<a-tooltip :title="$t('cmdb.ciType.listTips')">
|
||||||
<a-icon
|
<a-icon
|
||||||
style="position:absolute;top:3px;left:-17px;color:#2f54eb;"
|
style="position:absolute;top:3px;left:-17px;color:#A5A9BC;"
|
||||||
type="question-circle"
|
type="info-circle"
|
||||||
theme="filled"
|
theme="filled"
|
||||||
@click="
|
@click="
|
||||||
(e) => {
|
(e) => {
|
||||||
|
@ -297,7 +313,7 @@
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col span="6">
|
<a-col span="6">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label-col="['2', '6', '7'].findIndex(i => currentValueType === i) === -1 ? { span: 12 } : horizontalFormItemLayout.labelCol"
|
:label-col="horizontalFormItemLayout.labelCol"
|
||||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||||
>
|
>
|
||||||
<template slot="label">
|
<template slot="label">
|
||||||
|
@ -306,8 +322,8 @@
|
||||||
>{{ $t('cmdb.ciType.isDynamic') }}
|
>{{ $t('cmdb.ciType.isDynamic') }}
|
||||||
<a-tooltip :title="$t('cmdb.ciType.dynamicTips')">
|
<a-tooltip :title="$t('cmdb.ciType.dynamicTips')">
|
||||||
<a-icon
|
<a-icon
|
||||||
style="position:absolute;top:3px;left:-17px;color:#2f54eb;"
|
style="position:absolute;top:3px;left:-17px;color:#A5A9BC;"
|
||||||
type="question-circle"
|
type="info-circle"
|
||||||
theme="filled"
|
theme="filled"
|
||||||
@click="
|
@click="
|
||||||
(e) => {
|
(e) => {
|
||||||
|
@ -328,17 +344,22 @@
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-divider style="font-size:14px;margin-top:6px;">{{ $t('cmdb.ciType.advancedSettings') }}</a-divider>
|
<a-divider style="font-size:14px;margin-top:6px;">{{ $t('cmdb.ciType.advancedSettings') }}</a-divider>
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :span="24" v-if="!['6'].includes(currentValueType)">
|
<a-col :span="24">
|
||||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 12 }" :label="$t('cmdb.ciType.reg')">
|
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 12 }" :label="$t('cmdb.ciType.reg')">
|
||||||
<RegSelect :isShowErrorMsg="false" v-model="re_check" :limitedFormat="getLimitedFormat()" />
|
<RegSelect
|
||||||
|
:isShowErrorMsg="false"
|
||||||
|
:limitedFormat="getLimitedFormat()"
|
||||||
|
:disabled="['6', '10', '11'].includes(currentValueType)"
|
||||||
|
v-model="re_check"
|
||||||
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="24">
|
<a-col :span="24">
|
||||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.font')">
|
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.font')">
|
||||||
<FontArea ref="fontArea" />
|
<FontArea ref="fontArea" :fontColorDisabled="['8', '11'].includes(currentValueType)" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="24" v-if="!['6', '7'].includes(currentValueType)">
|
<a-col :span="24" v-if="!['6', '7', '10', '11'].includes(currentValueType)">
|
||||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.choiceValue')">
|
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.choiceValue')">
|
||||||
<PreValueArea
|
<PreValueArea
|
||||||
v-if="drawerVisible"
|
v-if="drawerVisible"
|
||||||
|
@ -349,7 +370,7 @@
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="24" v-if="!['6', '7'].includes(currentValueType)">
|
<a-col :span="24" v-if="!['6', '7', '10', '11'].includes(currentValueType)">
|
||||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
|
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
|
||||||
<template slot="label">
|
<template slot="label">
|
||||||
<span
|
<span
|
||||||
|
@ -357,8 +378,8 @@
|
||||||
>{{ $t('cmdb.ciType.computedAttribute') }}
|
>{{ $t('cmdb.ciType.computedAttribute') }}
|
||||||
<a-tooltip :title="$t('cmdb.ciType.computedAttributeTips')">
|
<a-tooltip :title="$t('cmdb.ciType.computedAttributeTips')">
|
||||||
<a-icon
|
<a-icon
|
||||||
style="position:absolute;top:3px;left:-17px;color:#2f54eb;"
|
style="position:absolute;top:3px;left:-17px;color:#A5A9BC;"
|
||||||
type="question-circle"
|
type="info-circle"
|
||||||
theme="filled"
|
theme="filled"
|
||||||
@click="
|
@click="
|
||||||
(e) => {
|
(e) => {
|
||||||
|
@ -415,14 +436,16 @@ import {
|
||||||
calcComputedAttribute,
|
calcComputedAttribute,
|
||||||
} from '@/modules/cmdb/api/CITypeAttr'
|
} from '@/modules/cmdb/api/CITypeAttr'
|
||||||
import { valueTypeMap } from '../../utils/const'
|
import { valueTypeMap } from '../../utils/const'
|
||||||
|
import { getPropertyType, getPropertyIcon } from '../../utils/helper'
|
||||||
import ComputedArea from './computedArea.vue'
|
import ComputedArea from './computedArea.vue'
|
||||||
import PreValueArea from './preValueArea.vue'
|
import PreValueArea from './preValueArea.vue'
|
||||||
import FontArea from './fontArea.vue'
|
import FontArea from './fontArea.vue'
|
||||||
import RegSelect from '@/components/RegexSelect'
|
import RegSelect from '@/components/RegexSelect'
|
||||||
|
import ReferenceModelSelect from './attributeEdit/referenceModelSelect.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AttributeEditForm',
|
name: 'AttributeEditForm',
|
||||||
components: { ComputedArea, PreValueArea, vueJsonEditor, FontArea, RegSelect },
|
components: { ComputedArea, PreValueArea, vueJsonEditor, FontArea, RegSelect, ReferenceModelSelect },
|
||||||
props: {
|
props: {
|
||||||
CITypeId: {
|
CITypeId: {
|
||||||
type: Number,
|
type: Number,
|
||||||
|
@ -467,7 +490,7 @@ export default {
|
||||||
return formLayout === 'horizontal'
|
return formLayout === 'horizontal'
|
||||||
? {
|
? {
|
||||||
labelCol: { span: 8 },
|
labelCol: { span: 8 },
|
||||||
wrapperCol: { span: 12 },
|
wrapperCol: { span: 15 },
|
||||||
}
|
}
|
||||||
: {}
|
: {}
|
||||||
},
|
},
|
||||||
|
@ -484,6 +507,7 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {},
|
mounted() {},
|
||||||
methods: {
|
methods: {
|
||||||
|
getPropertyIcon,
|
||||||
async handleCreate() {
|
async handleCreate() {
|
||||||
try {
|
try {
|
||||||
await canDefineComputed()
|
await canDefineComputed()
|
||||||
|
@ -516,9 +540,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (property === 'is_list') {
|
if (property === 'is_list') {
|
||||||
this.form.setFieldsValue({
|
this.handleSwitchIsList(checked)
|
||||||
default_value: checked ? [] : '',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if (checked && property === 'is_sortable') {
|
if (checked && property === 'is_sortable') {
|
||||||
this.$message.warning(this.$t('cmdb.ciType.addAttributeTips1'))
|
this.$message.warning(this.$t('cmdb.ciType.addAttributeTips1'))
|
||||||
|
@ -536,6 +558,26 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleSwitchIsList(checked) {
|
||||||
|
let defaultValue = checked ? [] : ''
|
||||||
|
|
||||||
|
switch (this.currentValueType) {
|
||||||
|
case '2':
|
||||||
|
case '9':
|
||||||
|
defaultValue = ''
|
||||||
|
break
|
||||||
|
case '10':
|
||||||
|
defaultValue = checked ? '' : false
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
this.form.setFieldsValue({
|
||||||
|
default_value: defaultValue,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
async handleEdit(record, attributes) {
|
async handleEdit(record, attributes) {
|
||||||
try {
|
try {
|
||||||
await canDefineComputed()
|
await canDefineComputed()
|
||||||
|
@ -544,12 +586,7 @@ export default {
|
||||||
this.canDefineComputed = false
|
this.canDefineComputed = false
|
||||||
}
|
}
|
||||||
const _record = _.cloneDeep(record)
|
const _record = _.cloneDeep(record)
|
||||||
if (_record.is_password) {
|
_record.value_type = getPropertyType(_record)
|
||||||
_record.value_type = '7'
|
|
||||||
}
|
|
||||||
if (_record.is_link) {
|
|
||||||
_record.value_type = '8'
|
|
||||||
}
|
|
||||||
this.drawerTitle = this.$t('cmdb.ciType.editAttribute')
|
this.drawerTitle = this.$t('cmdb.ciType.editAttribute')
|
||||||
this.drawerVisible = true
|
this.drawerVisible = true
|
||||||
this.record = _record
|
this.record = _record
|
||||||
|
@ -573,8 +610,13 @@ export default {
|
||||||
is_dynamic: _record.is_dynamic,
|
is_dynamic: _record.is_dynamic,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if (_record.value_type === '11') {
|
||||||
|
this.form.setFieldsValue({
|
||||||
|
reference_type_id: _record.reference_type_id
|
||||||
|
})
|
||||||
|
}
|
||||||
console.log(_record)
|
console.log(_record)
|
||||||
if (!['6'].includes(_record.value_type) && _record.re_check) {
|
if (!['6', '10', '11'].includes(_record.value_type) && _record.re_check) {
|
||||||
this.re_check = {
|
this.re_check = {
|
||||||
value: _record.re_check,
|
value: _record.re_check,
|
||||||
}
|
}
|
||||||
|
@ -583,7 +625,11 @@ export default {
|
||||||
}
|
}
|
||||||
if (_record.default) {
|
if (_record.default) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (_record.value_type === '0') {
|
if (_record.value_type === '10') {
|
||||||
|
this.form.setFieldsValue({
|
||||||
|
default_value: Boolean(_record.default.default),
|
||||||
|
})
|
||||||
|
} else if (_record.value_type === '0') {
|
||||||
if (_record.is_list) {
|
if (_record.is_list) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.form.setFieldsValue({
|
this.form.setFieldsValue({
|
||||||
|
@ -639,7 +685,7 @@ export default {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const _find = attributes.find((item) => item.id === _record.id)
|
const _find = attributes.find((item) => item.id === _record.id)
|
||||||
if (!['6', '7'].includes(_record.value_type)) {
|
if (!['6', '7', '10', '11'].includes(_record.value_type)) {
|
||||||
this.$refs.preValueArea.setData({
|
this.$refs.preValueArea.setData({
|
||||||
choice_value: (_find || {}).choice_value || [],
|
choice_value: (_find || {}).choice_value || [],
|
||||||
choice_web_hook: _record.choice_web_hook,
|
choice_web_hook: _record.choice_web_hook,
|
||||||
|
@ -672,7 +718,9 @@ export default {
|
||||||
delete values['default_show']
|
delete values['default_show']
|
||||||
delete values['is_required']
|
delete values['is_required']
|
||||||
const { default_value } = values
|
const { default_value } = values
|
||||||
if (values.value_type === '0' && default_value) {
|
if (values.value_type === '10') {
|
||||||
|
values.default = { default: values.is_list ? default_value : Boolean(default_value) }
|
||||||
|
} else if (values.value_type === '0' && default_value) {
|
||||||
if (values.is_list) {
|
if (values.is_list) {
|
||||||
values.default = { default: default_value || null }
|
values.default = { default: default_value || null }
|
||||||
} else {
|
} else {
|
||||||
|
@ -706,23 +754,42 @@ export default {
|
||||||
values = { ...values, ...computedAreaData }
|
values = { ...values, ...computedAreaData }
|
||||||
} else {
|
} else {
|
||||||
// If it is a non-computed attribute, check to see if there is a predefined value
|
// If it is a non-computed attribute, check to see if there is a predefined value
|
||||||
if (!['6', '7'].includes(values.value_type)) {
|
if (!['6', '7', '10', '11'].includes(values.value_type)) {
|
||||||
const preValueAreaData = this.$refs.preValueArea.getData()
|
const preValueAreaData = this.$refs.preValueArea.getData()
|
||||||
values = { ...values, ...preValueAreaData }
|
values = { ...values, ...preValueAreaData }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const fontOptions = this.$refs.fontArea.getData()
|
const fontOptions = this.$refs.fontArea.getData()
|
||||||
if (values.value_type === '7') {
|
|
||||||
values.value_type = '2'
|
if (!['6', '10', '11'].includes(values.value_type)) {
|
||||||
values.is_password = true
|
|
||||||
}
|
|
||||||
if (values.value_type === '8') {
|
|
||||||
values.value_type = '2'
|
|
||||||
values.is_link = true
|
|
||||||
}
|
|
||||||
if (values.value_type !== '6') {
|
|
||||||
values.re_check = this.re_check?.value ?? null
|
values.re_check = this.re_check?.value ?? null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重置数据类型
|
||||||
|
switch (values.value_type) {
|
||||||
|
case '7':
|
||||||
|
values.value_type = '2'
|
||||||
|
values.is_password = true
|
||||||
|
break
|
||||||
|
case '8':
|
||||||
|
values.value_type = '2'
|
||||||
|
values.is_link = true
|
||||||
|
break
|
||||||
|
case '9':
|
||||||
|
values.value_type = '2'
|
||||||
|
break
|
||||||
|
case '10':
|
||||||
|
values.value_type = '7'
|
||||||
|
values.is_bool = true
|
||||||
|
break
|
||||||
|
case '11':
|
||||||
|
values.value_type = '0'
|
||||||
|
values.is_reference = true
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
if (values.id) {
|
if (values.id) {
|
||||||
await this.updateAttribute(values.id, { ...values, option: { fontOptions } }, isCalcComputed)
|
await this.updateAttribute(values.id, { ...values, option: { fontOptions } }, isCalcComputed)
|
||||||
} else {
|
} else {
|
||||||
|
@ -806,6 +873,9 @@ export default {
|
||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
color: #a5a9bc;
|
color: #a5a9bc;
|
||||||
}
|
}
|
||||||
|
.value-type-text {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.attribute-edit-form {
|
.attribute-edit-form {
|
||||||
|
|
|
@ -17,21 +17,21 @@
|
||||||
<a-space style="margin-bottom: 10px">
|
<a-space style="margin-bottom: 10px">
|
||||||
<a-button @click="handleAddGroup" size="small" icon="plus">{{ $t('cmdb.ciType.group') }}</a-button>
|
<a-button @click="handleAddGroup" size="small" icon="plus">{{ $t('cmdb.ciType.group') }}</a-button>
|
||||||
<a-button @click="handleOpenUniqueConstraint" size="small">{{ $t('cmdb.ciType.uniqueConstraint') }}</a-button>
|
<a-button @click="handleOpenUniqueConstraint" size="small">{{ $t('cmdb.ciType.uniqueConstraint') }}</a-button>
|
||||||
<div>
|
<div class="ci-types-attributes-flex">
|
||||||
<a-tooltip
|
<a-tooltip
|
||||||
v-for="typeKey in Object.keys(valueTypeMap)"
|
v-for="item in valueTypeMap"
|
||||||
:key="typeKey"
|
:key="item.key"
|
||||||
:title="$t('cmdb.ciType.filterTips', { name: valueTypeMap[typeKey] })"
|
:title="$t('cmdb.ciType.filterTips', { name: item.value })"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@click="handleFilterType(typeKey)"
|
@click="handleFilterType(item.key)"
|
||||||
:class="{
|
:class="{
|
||||||
'ci-types-attributes-filter': true,
|
'ci-types-attributes-filter': true,
|
||||||
'ci-types-attributes-filter-selected': attrTypeFilter.includes(typeKey),
|
'ci-types-attributes-filter-selected': attrTypeFilter.includes(item.key),
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<ops-icon :type="getPropertyIcon({ value_type: typeKey })" />
|
<ops-icon :type="getPropertyIcon({ value_type: item.key })" />
|
||||||
{{ valueTypeMap[typeKey] }}
|
{{ item.value }}
|
||||||
</span>
|
</span>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
@ -201,7 +201,7 @@ import AttributeEditForm from './attributeEditForm.vue'
|
||||||
import NewCiTypeAttrModal from './newCiTypeAttrModal.vue'
|
import NewCiTypeAttrModal from './newCiTypeAttrModal.vue'
|
||||||
import UniqueConstraint from './uniqueConstraint.vue'
|
import UniqueConstraint from './uniqueConstraint.vue'
|
||||||
import { valueTypeMap } from '../../utils/const'
|
import { valueTypeMap } from '../../utils/const'
|
||||||
import { getPropertyIcon } from '../../utils/helper'
|
import { getPropertyIcon, getPropertyType } from '../../utils/helper'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AttributesTable',
|
name: 'AttributesTable',
|
||||||
|
@ -245,7 +245,12 @@ export default {
|
||||||
return this.$store.state.windowHeight
|
return this.$store.state.windowHeight
|
||||||
},
|
},
|
||||||
valueTypeMap() {
|
valueTypeMap() {
|
||||||
return valueTypeMap()
|
const map = valueTypeMap()
|
||||||
|
const keys = ['0', '1', '2', '9', '3', '4', '5', '6', '7', '8', '10', '11']
|
||||||
|
return keys.map((key) => ({
|
||||||
|
key,
|
||||||
|
value: map[key]
|
||||||
|
}))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
provide() {
|
provide() {
|
||||||
|
@ -598,23 +603,8 @@ export default {
|
||||||
if (!attrTypeFilter.length) {
|
if (!attrTypeFilter.length) {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
if (attrTypeFilter.includes('7') && attr.is_password) {
|
const valueType = getPropertyType(attr)
|
||||||
return true
|
return attrTypeFilter.includes(valueType)
|
||||||
}
|
|
||||||
if (attrTypeFilter.includes('8') && attr.is_link) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
attrTypeFilter.includes(attr.value_type) &&
|
|
||||||
attr.value_type === '2' &&
|
|
||||||
(attr.is_password || attr.is_link)
|
|
||||||
) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (attrTypeFilter.includes(attr.value_type)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -638,6 +628,12 @@ export default {
|
||||||
.ci-types-attributes {
|
.ci-types-attributes {
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
|
&-flex {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
.ci-types-attributes-filter {
|
.ci-types-attributes-filter {
|
||||||
color: @text-color_4;
|
color: @text-color_4;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
@ -46,16 +46,21 @@
|
||||||
v-decorator="['value_type', { rules: [{ required: true }], initialValue: '2' }]"
|
v-decorator="['value_type', { rules: [{ required: true }], initialValue: '2' }]"
|
||||||
@change="handleChangeValueType"
|
@change="handleChangeValueType"
|
||||||
>
|
>
|
||||||
<a-select-option :value="key" :key="key" v-for="(value, key) in valueTypeMap">
|
<a-select-option :value="item.key" :key="item.key" v-for="(item) in valueTypeMap">
|
||||||
{{ value }}
|
<ops-icon :type="getPropertyIcon({ value_type: item.key })" />
|
||||||
<span class="value-type-des" v-if="key === '3'">yyyy-mm-dd HH:MM:SS</span>
|
<span class="value-type-text">{{ item.value }}</span>
|
||||||
<span class="value-type-des" v-if="key === '4'">yyyy-mm-dd</span>
|
<span class="value-type-des" v-if="item.key === '2'">{{ $t('cmdb.ciType.shortTextTip') }}</span>
|
||||||
<span class="value-type-des" v-if="key === '5'">HH:MM:SS</span>
|
<span class="value-type-des" v-if="item.key === '3'">yyyy-mm-dd HH:MM:SS</span>
|
||||||
|
<span class="value-type-des" v-if="item.key === '4'">yyyy-mm-dd</span>
|
||||||
|
<span class="value-type-des" v-if="item.key === '5'">HH:MM:SS</span>
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="currentValueType === '6' ? 24 : 12">
|
<a-col
|
||||||
|
v-if="currentValueType !== '11'"
|
||||||
|
:span="currentValueType === '6' ? 24 : 12"
|
||||||
|
>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label-col="{ span: currentValueType === '6' ? 4 : 8 }"
|
:label-col="{ span: currentValueType === '6' ? 4 : 8 }"
|
||||||
:wrapper-col="{ span: currentValueType === '6' ? 18 : 15 }"
|
:wrapper-col="{ span: currentValueType === '6' ? 18 : 15 }"
|
||||||
|
@ -68,6 +73,10 @@
|
||||||
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
||||||
>
|
>
|
||||||
</a-input>
|
</a-input>
|
||||||
|
<a-switch
|
||||||
|
v-else-if="currentValueType === '10'"
|
||||||
|
v-decorator="['default_value', { rules: [{ required: false }], valuePropName: 'checked' }]"
|
||||||
|
/>
|
||||||
<a-input-number
|
<a-input-number
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
v-else-if="currentValueType === '1'"
|
v-else-if="currentValueType === '1'"
|
||||||
|
@ -86,12 +95,7 @@
|
||||||
</a-select>
|
</a-select>
|
||||||
<a-input
|
<a-input
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
v-else-if="
|
v-else-if="['2', '5', '7', '8', '9'].includes(currentValueType)"
|
||||||
currentValueType === '2' ||
|
|
||||||
currentValueType === '5' ||
|
|
||||||
currentValueType === '7' ||
|
|
||||||
currentValueType === '8'
|
|
||||||
"
|
|
||||||
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
||||||
>
|
>
|
||||||
</a-input>
|
</a-input>
|
||||||
|
@ -148,9 +152,19 @@
|
||||||
</template>
|
</template>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|
||||||
|
<a-col
|
||||||
|
v-if="currentValueType === '11'"
|
||||||
|
:span="12"
|
||||||
|
>
|
||||||
|
<ReferenceModelSelect
|
||||||
|
:form="form"
|
||||||
|
:formItemLayout="formItemLayout"
|
||||||
|
/>
|
||||||
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
|
||||||
<a-col :span="currentValueType === '2' ? 6 : 0" v-if="currentValueType !== '6'">
|
<!-- <a-col :span="currentValueType === '2' ? 6 : 0" v-if="currentValueType !== '6'">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:hidden="currentValueType === '2' ? false : true"
|
:hidden="currentValueType === '2' ? false : true"
|
||||||
:label-col="horizontalFormItemLayout.labelCol"
|
:label-col="horizontalFormItemLayout.labelCol"
|
||||||
|
@ -182,10 +196,10 @@
|
||||||
v-decorator="['is_index', { rules: [], valuePropName: 'checked', initialValue: true }]"
|
v-decorator="['is_index', { rules: [], valuePropName: 'checked', initialValue: true }]"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col> -->
|
||||||
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label-col="currentValueType === '2' ? { span: 8 } : horizontalFormItemLayout.labelCol"
|
:label-col="horizontalFormItemLayout.labelCol"
|
||||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||||
:label="$t('cmdb.ciType.unique')"
|
:label="$t('cmdb.ciType.unique')"
|
||||||
>
|
>
|
||||||
|
@ -199,7 +213,7 @@
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="6">
|
<a-col :span="6">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label-col="['2', '6', '7'].findIndex(i => currentValueType === i) === -1 ? { span: 8 } : horizontalFormItemLayout.labelCol"
|
:label-col="horizontalFormItemLayout.labelCol"
|
||||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||||
:label="$t('required')"
|
:label="$t('required')"
|
||||||
>
|
>
|
||||||
|
@ -212,7 +226,7 @@
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="6">
|
<a-col :span="6">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label-col="currentValueType === '2' ? { span: 12 } : horizontalFormItemLayout.labelCol"
|
:label-col="horizontalFormItemLayout.labelCol"
|
||||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||||
>
|
>
|
||||||
<template slot="label">
|
<template slot="label">
|
||||||
|
@ -221,8 +235,8 @@
|
||||||
>{{ $t('cmdb.ciType.defaultShow') }}
|
>{{ $t('cmdb.ciType.defaultShow') }}
|
||||||
<a-tooltip :title="$t('cmdb.ciType.defaultShowTips')">
|
<a-tooltip :title="$t('cmdb.ciType.defaultShowTips')">
|
||||||
<a-icon
|
<a-icon
|
||||||
style="position:absolute;top:2px;left:-17px;color:#2f54eb;"
|
style="position:absolute;top:2px;left:-17px;color:#A5A9BC;"
|
||||||
type="question-circle"
|
type="info-circle"
|
||||||
theme="filled"
|
theme="filled"
|
||||||
@click="
|
@click="
|
||||||
(e) => {
|
(e) => {
|
||||||
|
@ -243,7 +257,7 @@
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label-col="currentValueType === '2' ? horizontalFormItemLayout.labelCol : { span: 8 }"
|
:label-col="horizontalFormItemLayout.labelCol"
|
||||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||||
:label="$t('cmdb.ciType.isSortable')"
|
:label="$t('cmdb.ciType.isSortable')"
|
||||||
>
|
>
|
||||||
|
@ -256,7 +270,7 @@
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|
||||||
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
<a-col :span="6" v-if="!['6', '7', '10'].includes(currentValueType)">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label-col="currentValueType === '2' ? { span: 8 } : horizontalFormItemLayout.labelCol"
|
:label-col="currentValueType === '2' ? { span: 8 } : horizontalFormItemLayout.labelCol"
|
||||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||||
|
@ -264,11 +278,11 @@
|
||||||
<template slot="label">
|
<template slot="label">
|
||||||
<span
|
<span
|
||||||
style="position:relative;white-space:pre;"
|
style="position:relative;white-space:pre;"
|
||||||
>{{ $t('cmdb.ciType.list') }}
|
>
|
||||||
<a-tooltip :title="$t('cmdb.ciType.listTips')">
|
<a-tooltip :title="$t('cmdb.ciType.listTips')">
|
||||||
<a-icon
|
<a-icon
|
||||||
style="position:absolute;top:3px;left:-17px;color:#2f54eb;"
|
style="position:absolute;top:3px;left:-17px;color:#A5A9BC;"
|
||||||
type="question-circle"
|
type="info-circle"
|
||||||
theme="filled"
|
theme="filled"
|
||||||
@click="
|
@click="
|
||||||
(e) => {
|
(e) => {
|
||||||
|
@ -278,6 +292,7 @@
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
{{ $t('cmdb.ciType.list') }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<a-switch
|
<a-switch
|
||||||
|
@ -290,17 +305,17 @@
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col span="6">
|
<a-col span="6">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
:label-col="['2', '6', '7'].findIndex(i => currentValueType === i) === -1 ? { span: 12 } : horizontalFormItemLayout.labelCol"
|
:label-col="horizontalFormItemLayout.labelCol"
|
||||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||||
>
|
>
|
||||||
<template slot="label">
|
<template slot="label">
|
||||||
<span
|
<span
|
||||||
style="position:relative;white-space:pre;"
|
style="position:relative;white-space:pre;"
|
||||||
>{{ $t('cmdb.ciType.isDynamic') }}
|
>
|
||||||
<a-tooltip :title="$t('cmdb.ciType.dynamicTips')">
|
<a-tooltip :title="$t('cmdb.ciType.dynamicTips')">
|
||||||
<a-icon
|
<a-icon
|
||||||
style="position:absolute;top:3px;left:-17px;color:#2f54eb;"
|
style="position:absolute;top:3px;left:-17px;color:#A5A9BC;"
|
||||||
type="question-circle"
|
type="info-circle"
|
||||||
theme="filled"
|
theme="filled"
|
||||||
@click="
|
@click="
|
||||||
(e) => {
|
(e) => {
|
||||||
|
@ -310,6 +325,7 @@
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
{{ $t('cmdb.ciType.isDynamic') }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<a-switch
|
<a-switch
|
||||||
|
@ -321,17 +337,22 @@
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-divider style="font-size:14px;margin-top:6px;">{{ $t('cmdb.ciType.advancedSettings') }}</a-divider>
|
<a-divider style="font-size:14px;margin-top:6px;">{{ $t('cmdb.ciType.advancedSettings') }}</a-divider>
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :span="24" v-if="!['6'].includes(currentValueType)">
|
<a-col :span="24">
|
||||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 12 }" :label="$t('cmdb.ciType.reg')">
|
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 12 }" :label="$t('cmdb.ciType.reg')">
|
||||||
<RegSelect :isShowErrorMsg="false" v-model="re_check" :limitedFormat="getLimitedFormat()" />
|
<RegSelect
|
||||||
|
v-model="re_check"
|
||||||
|
:isShowErrorMsg="false"
|
||||||
|
:limitedFormat="getLimitedFormat()"
|
||||||
|
:disabled="['6', '10', '11'].includes(currentValueType)"
|
||||||
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="24">
|
<a-col :span="24">
|
||||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.font')">
|
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.font')">
|
||||||
<FontArea ref="fontArea" />
|
<FontArea ref="fontArea" :fontColorDisabled="['8', '11'].includes(currentValueType)" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="24" v-if="!['6', '7'].includes(currentValueType)">
|
<a-col :span="24" v-if="!['6', '7', '10', '11'].includes(currentValueType)">
|
||||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.choiceValue')">
|
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.choiceValue')">
|
||||||
<PreValueArea
|
<PreValueArea
|
||||||
ref="preValueArea"
|
ref="preValueArea"
|
||||||
|
@ -341,16 +362,16 @@
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="24" v-if="!['6', '7'].includes(currentValueType)">
|
<a-col :span="24" v-if="!['6', '7', '10', '11'].includes(currentValueType)">
|
||||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
|
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
|
||||||
<template slot="label">
|
<template slot="label">
|
||||||
<span
|
<span
|
||||||
style="position:relative;white-space:pre;"
|
style="position:relative;white-space:pre;"
|
||||||
>{{ $t('cmdb.ciType.computedAttribute') }}
|
>
|
||||||
<a-tooltip :title="$t('cmdb.ciType.computedAttributeTips')">
|
<a-tooltip :title="$t('cmdb.ciType.computedAttributeTips')">
|
||||||
<a-icon
|
<a-icon
|
||||||
style="position:absolute;top:3px;left:-17px;color:#2f54eb;"
|
style="position:absolute;top:3px;left:-17px;color:#A5A9BC;"
|
||||||
type="question-circle"
|
type="info-circle"
|
||||||
theme="filled"
|
theme="filled"
|
||||||
@click="
|
@click="
|
||||||
(e) => {
|
(e) => {
|
||||||
|
@ -360,6 +381,7 @@
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
{{ $t('cmdb.ciType.computedAttribute') }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<a-switch
|
<a-switch
|
||||||
|
@ -392,6 +414,8 @@ import ComputedArea from './computedArea.vue'
|
||||||
import PreValueArea from './preValueArea.vue'
|
import PreValueArea from './preValueArea.vue'
|
||||||
import FontArea from './fontArea.vue'
|
import FontArea from './fontArea.vue'
|
||||||
import RegSelect from '@/components/RegexSelect'
|
import RegSelect from '@/components/RegexSelect'
|
||||||
|
import { getPropertyIcon } from '../../utils/helper'
|
||||||
|
import ReferenceModelSelect from './attributeEdit/referenceModelSelect.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CreateNewAttribute',
|
name: 'CreateNewAttribute',
|
||||||
|
@ -401,6 +425,7 @@ export default {
|
||||||
vueJsonEditor,
|
vueJsonEditor,
|
||||||
FontArea,
|
FontArea,
|
||||||
RegSelect,
|
RegSelect,
|
||||||
|
ReferenceModelSelect,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
hasFooter: {
|
hasFooter: {
|
||||||
|
@ -437,13 +462,19 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
valueTypeMap() {
|
valueTypeMap() {
|
||||||
return valueTypeMap()
|
const map = valueTypeMap()
|
||||||
|
const keys = ['0', '1', '2', '9', '3', '4', '5', '6', '7', '8', '10', '11']
|
||||||
|
return keys.map((key) => ({
|
||||||
|
key,
|
||||||
|
value: map[key]
|
||||||
|
}))
|
||||||
},
|
},
|
||||||
canDefineScript() {
|
canDefineScript() {
|
||||||
return this.canDefineComputed
|
return this.canDefineComputed
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getPropertyIcon,
|
||||||
handleSubmit(isCloseModal = true) {
|
handleSubmit(isCloseModal = true) {
|
||||||
this.form.validateFields(async (err, values) => {
|
this.form.validateFields(async (err, values) => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
|
@ -456,7 +487,9 @@ export default {
|
||||||
const data = { is_required, default_show, is_dynamic }
|
const data = { is_required, default_show, is_dynamic }
|
||||||
delete values.is_required
|
delete values.is_required
|
||||||
delete values.default_show
|
delete values.default_show
|
||||||
if (values.value_type === '0' && default_value) {
|
if (values.value_type === '10') {
|
||||||
|
values.default = { default: values.is_list ? (default_value || null) : Boolean(default_value) }
|
||||||
|
} else if (values.value_type === '0' && default_value) {
|
||||||
if (values.is_list) {
|
if (values.is_list) {
|
||||||
values.default = { default: default_value || null }
|
values.default = { default: default_value || null }
|
||||||
} else {
|
} else {
|
||||||
|
@ -489,39 +522,48 @@ export default {
|
||||||
values = { ...values, ...computedAreaData }
|
values = { ...values, ...computedAreaData }
|
||||||
} else {
|
} else {
|
||||||
// If it is a non-computed attribute, check to see if there is a predefined value
|
// If it is a non-computed attribute, check to see if there is a predefined value
|
||||||
if (!['6', '7'].includes(values.value_type)) {
|
if (!['6', '7', '10', '11'].includes(values.value_type)) {
|
||||||
const preValueAreaData = this.$refs.preValueArea.getData()
|
const preValueAreaData = this.$refs.preValueArea.getData()
|
||||||
values = { ...values, ...preValueAreaData }
|
values = { ...values, ...preValueAreaData }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const fontOptions = this.$refs.fontArea.getData()
|
const fontOptions = this.$refs.fontArea.getData()
|
||||||
|
|
||||||
// is_index: except for text, the index is hidden, text index default is true
|
// 索引
|
||||||
// 5 types in the box, is_index=true
|
values.is_index = !['6', '7', '8', '9', '11'].includes(values.value_type)
|
||||||
// json, password, link is_index=false
|
|
||||||
if (['6', '7', '8'].includes(values.value_type)) {
|
// 重置数据类型
|
||||||
values.is_index = false
|
switch (values.value_type) {
|
||||||
} else if (values.value_type !== '2') {
|
case '7':
|
||||||
values.is_index = true
|
|
||||||
}
|
|
||||||
if (values.value_type === '7') {
|
|
||||||
values.value_type = '2'
|
values.value_type = '2'
|
||||||
values.is_password = true
|
values.is_password = true
|
||||||
}
|
break
|
||||||
if (values.value_type === '8') {
|
case '8':
|
||||||
values.value_type = '2'
|
values.value_type = '2'
|
||||||
values.is_link = true
|
values.is_link = true
|
||||||
|
break
|
||||||
|
case '9':
|
||||||
|
values.value_type = '2'
|
||||||
|
break
|
||||||
|
case '10':
|
||||||
|
values.value_type = '7'
|
||||||
|
values.is_bool = true
|
||||||
|
break
|
||||||
|
case '11':
|
||||||
|
values.value_type = '0'
|
||||||
|
values.is_reference = true
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
if (values.value_type !== '6') {
|
|
||||||
values.re_check = this.re_check?.value ?? null
|
|
||||||
}
|
|
||||||
const { attr_id } = await createAttribute({ ...values, option: { fontOptions } })
|
const { attr_id } = await createAttribute({ ...values, option: { fontOptions } })
|
||||||
|
|
||||||
this.form.resetFields()
|
this.form.resetFields()
|
||||||
this.currentValueType = '2'
|
if (this?.$refs?.preValueArea) {
|
||||||
if (!['6'].includes(values.value_type) && !values.is_password) {
|
|
||||||
this.$refs.preValueArea.valueList = []
|
this.$refs.preValueArea.valueList = []
|
||||||
}
|
}
|
||||||
|
this.currentValueType = '2'
|
||||||
this.$emit('done', attr_id, data, isCloseModal)
|
this.$emit('done', attr_id, data, isCloseModal)
|
||||||
} else {
|
} else {
|
||||||
throw new Error()
|
throw new Error()
|
||||||
|
@ -540,11 +582,12 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleChangeValueType(value) {
|
handleChangeValueType(value) {
|
||||||
this.currentValueType = value
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.form.setFieldsValue({
|
this.currentValueType = value
|
||||||
default_value: this.form.getFieldValue('is_list') || value === '0' ? [] : null,
|
if (['6', '10', '11'].includes(value)) {
|
||||||
})
|
this.re_check = {}
|
||||||
|
}
|
||||||
|
this.handleSwitchType({ valueType: value })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
onChange(checked, property) {
|
onChange(checked, property) {
|
||||||
|
@ -560,9 +603,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (property === 'is_list') {
|
if (property === 'is_list') {
|
||||||
this.form.setFieldsValue({
|
this.handleSwitchType({ checked })
|
||||||
default_value: checked ? [] : '',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if (checked && property === 'is_sortable') {
|
if (checked && property === 'is_sortable') {
|
||||||
this.$message.warning(this.$t('cmdb.ciType.addAttributeTips1'))
|
this.$message.warning(this.$t('cmdb.ciType.addAttributeTips1'))
|
||||||
|
@ -579,6 +620,33 @@ export default {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleSwitchType({
|
||||||
|
checked,
|
||||||
|
valueType
|
||||||
|
}) {
|
||||||
|
checked = checked ?? this.form.getFieldValue('is_list')
|
||||||
|
valueType = valueType ?? this.currentValueType
|
||||||
|
|
||||||
|
let defaultValue = checked || valueType === '0' ? [] : ''
|
||||||
|
|
||||||
|
switch (valueType) {
|
||||||
|
case '2':
|
||||||
|
case '9':
|
||||||
|
defaultValue = ''
|
||||||
|
break
|
||||||
|
case '10':
|
||||||
|
defaultValue = checked ? '' : false
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
this.form.setFieldsValue({
|
||||||
|
default_value: defaultValue,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
onJsonChange(value) {
|
onJsonChange(value) {
|
||||||
this.default_value_json_right = true
|
this.default_value_json_right = true
|
||||||
},
|
},
|
||||||
|
@ -629,6 +697,9 @@ export default {
|
||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
color: #a5a9bc;
|
color: #a5a9bc;
|
||||||
}
|
}
|
||||||
|
.value-type-text {
|
||||||
|
margin: 0 4px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.create-new-attribute {
|
.create-new-attribute {
|
||||||
|
|
|
@ -21,7 +21,13 @@
|
||||||
<a-icon type="underline" />
|
<a-icon type="underline" />
|
||||||
</div>
|
</div>
|
||||||
<div :style="{ width: '100px', marginLeft: '10px', display: 'inline-flex', alignItems: 'center' }">
|
<div :style="{ width: '100px', marginLeft: '10px', display: 'inline-flex', alignItems: 'center' }">
|
||||||
<a-icon type="font-colors" /><el-color-picker size="mini" v-model="fontOptions.color"> </el-color-picker>
|
<a-icon type="font-colors" />
|
||||||
|
<el-color-picker
|
||||||
|
size="mini"
|
||||||
|
:disabled="fontColorDisabled"
|
||||||
|
v-model="fontOptions.color"
|
||||||
|
>
|
||||||
|
</el-color-picker>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -30,6 +36,12 @@
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
export default {
|
export default {
|
||||||
name: 'FontArea',
|
name: 'FontArea',
|
||||||
|
props: {
|
||||||
|
fontColorDisabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
fontOptions: {
|
fontOptions: {
|
||||||
|
@ -57,7 +69,11 @@ export default {
|
||||||
if (flag) {
|
if (flag) {
|
||||||
return undefined
|
return undefined
|
||||||
} else {
|
} else {
|
||||||
return this.fontOptions
|
const fontOptions = _.cloneDeep(this.fontOptions)
|
||||||
|
if (this.fontColorDisabled) {
|
||||||
|
Reflect.deleteProperty(fontOptions, 'color')
|
||||||
|
}
|
||||||
|
return fontOptions
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setData({ fontOptions = {} }) {
|
setData({ fontOptions = {} }) {
|
||||||
|
|
|
@ -545,7 +545,7 @@ export default {
|
||||||
},
|
},
|
||||||
showIdSelectOptions() {
|
showIdSelectOptions() {
|
||||||
const _showIdSelectOptions = this.currentTypeAttrs.filter(
|
const _showIdSelectOptions = this.currentTypeAttrs.filter(
|
||||||
(item) => item.id !== this.unique_id && !['6'].includes(item.value_type) && !item.is_password && !item.is_list
|
(item) => item.id !== this.unique_id && !['6'].includes(item.value_type) && !item.is_password && !item.is_list && !item.is_bool && !item.is_reference
|
||||||
)
|
)
|
||||||
if (this.showIdFilterInput) {
|
if (this.showIdFilterInput) {
|
||||||
return _showIdSelectOptions.filter(
|
return _showIdSelectOptions.filter(
|
||||||
|
@ -898,6 +898,7 @@ export default {
|
||||||
this.loadCITypes()
|
this.loadCITypes()
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.drawerVisible = false
|
this.drawerVisible = false
|
||||||
|
this.isInherit = false
|
||||||
}, 1000)
|
}, 1000)
|
||||||
},
|
},
|
||||||
async updateCIType(CITypeId, data) {
|
async updateCIType(CITypeId, data) {
|
||||||
|
@ -916,6 +917,7 @@ export default {
|
||||||
this.loadCITypes()
|
this.loadCITypes()
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.drawerVisible = false
|
this.drawerVisible = false
|
||||||
|
this.isInherit = false
|
||||||
}, 1000)
|
}, 1000)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -47,9 +47,32 @@
|
||||||
>
|
>
|
||||||
<ops-icon class="text-group-icon" type="veops-text" />
|
<ops-icon class="text-group-icon" type="veops-text" />
|
||||||
</div>
|
</div>
|
||||||
|
<CIReferenceAttr
|
||||||
|
v-if="getAttr(rule.property).is_reference && (rule.exp === 'is' || rule.exp === '~is')"
|
||||||
|
class="select-filter"
|
||||||
|
:referenceTypeId="getAttr(rule.property).reference_type_id"
|
||||||
|
:value="rule.value"
|
||||||
|
:disabled="disabled"
|
||||||
|
@change="(value) => handleChange('value', value)"
|
||||||
|
/>
|
||||||
|
<a-select
|
||||||
|
v-else-if="getAttr(rule.property).is_bool && (rule.exp === 'is' || rule.exp === '~is')"
|
||||||
|
class="select-filter"
|
||||||
|
:disabled="disabled"
|
||||||
|
:placeholder="$t('placeholder2')"
|
||||||
|
:value="rule.value"
|
||||||
|
@change="(value) => handleChange('value', value)"
|
||||||
|
>
|
||||||
|
<a-select-option key="1">
|
||||||
|
true
|
||||||
|
</a-select-option>
|
||||||
|
<a-select-option key="0">
|
||||||
|
false
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
<div
|
<div
|
||||||
class="input-group"
|
class="input-group"
|
||||||
v-if="isChoiceByProperty(rule.property) && (rule.exp === 'is' || rule.exp === '~is')"
|
v-else-if="isChoiceByProperty(rule.property) && (rule.exp === 'is' || rule.exp === '~is')"
|
||||||
>
|
>
|
||||||
<treeselect
|
<treeselect
|
||||||
class="custom-treeselect"
|
class="custom-treeselect"
|
||||||
|
@ -148,9 +171,13 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { compareTypeList } from '../constants.js'
|
import { compareTypeList } from '../constants.js'
|
||||||
|
import CIReferenceAttr from '@/components/ciReferenceAttr/index.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ValueControls',
|
name: 'ValueControls',
|
||||||
|
components: {
|
||||||
|
CIReferenceAttr
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
rule: {
|
rule: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -215,7 +242,10 @@ export default {
|
||||||
...this.rule,
|
...this.rule,
|
||||||
[key]: value
|
[key]: value
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
|
getAttr(property) {
|
||||||
|
return this.attrList.find((item) => item.name === property) || {}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -270,4 +300,21 @@ export default {
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.select-filter {
|
||||||
|
height: 36px;
|
||||||
|
width: 136px;
|
||||||
|
|
||||||
|
/deep/ .ant-select-selection {
|
||||||
|
height: 36px;
|
||||||
|
background: #f7f8fa;
|
||||||
|
line-height: 36px;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
.ant-select-selection__rendered {
|
||||||
|
height: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -137,6 +137,7 @@ import {
|
||||||
getCITypeChildren,
|
getCITypeChildren,
|
||||||
getCITypeParent
|
getCITypeParent
|
||||||
} from '../../api/CITypeRelation.js'
|
} from '../../api/CITypeRelation.js'
|
||||||
|
import { getCITypeAttributesById } from '../../api/CITypeAttr'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'RelationAutoDiscovery',
|
name: 'RelationAutoDiscovery',
|
||||||
|
@ -169,7 +170,18 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
async getCITypeAttributes() {
|
async getCITypeAttributes() {
|
||||||
const res = await getCITypeAttributes(this.CITypeId)
|
const res = await getCITypeAttributes(this.CITypeId)
|
||||||
this.ciTypeADTAttributes = res.map((item) => {
|
const attr = await getCITypeAttributesById(this.CITypeId)
|
||||||
|
|
||||||
|
const filterAttr = res.filter((name) => {
|
||||||
|
const currentAttr = attr?.attributes?.find((item) => item?.name === name)
|
||||||
|
if (!currentAttr) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.filterAttributes(name)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.ciTypeADTAttributes = filterAttr.map((item) => {
|
||||||
return {
|
return {
|
||||||
id: item,
|
id: item,
|
||||||
value: item,
|
value: item,
|
||||||
|
@ -239,7 +251,7 @@ export default {
|
||||||
const peer_type_id = item.peer_type_id
|
const peer_type_id = item.peer_type_id
|
||||||
const attributes = this?.relationOptions?.find((option) => option?.value === peer_type_id)?.attributes
|
const attributes = this?.relationOptions?.find((option) => option?.value === peer_type_id)?.attributes
|
||||||
|
|
||||||
item.attributes = attributes
|
item.attributes = attributes.filter((attr) => this.filterAttributes(attr))
|
||||||
item.peer_attr_id = undefined
|
item.peer_attr_id = undefined
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -288,6 +300,15 @@ export default {
|
||||||
this.getCITypeRelations()
|
this.getCITypeRelations()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
filterAttributes(attr) {
|
||||||
|
// filter password/json/is_list/longText/bool/reference
|
||||||
|
if (attr?.value_type === '2' && !attr?.is_index) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return !attr?.is_password && !attr?.is_list && attr?.value_type !== '6' && !attr?.is_bool && !attr?.is_reference
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -598,8 +598,14 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
filterAttributes(attributes) {
|
filterAttributes(attributes) {
|
||||||
// filter password/json/is_list
|
// filter password/json/is_list/longText/bool/reference
|
||||||
return attributes.filter((attr) => !attr.is_password && !attr.is_list && attr.value_type !== '6')
|
return attributes.filter((attr) => {
|
||||||
|
if (attr.value_type === '2' && !attr.is_index) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return !attr.is_password && !attr.is_list && attr.value_type !== '6' && !attr.is_bool && !attr.is_reference
|
||||||
|
})
|
||||||
},
|
},
|
||||||
addTableAttr() {
|
addTableAttr() {
|
||||||
this.tableAttrList.push({
|
this.tableAttrList.push({
|
||||||
|
|
|
@ -471,10 +471,15 @@ export default {
|
||||||
this.dateForm = _.cloneDeep(this.defaultDateForm)
|
this.dateForm = _.cloneDeep(this.defaultDateForm)
|
||||||
this.notifies = _.cloneDeep(this.defaultNotify)
|
this.notifies = _.cloneDeep(this.defaultNotify)
|
||||||
this.category = 1
|
this.category = 1
|
||||||
this.triggerAction = '1'
|
|
||||||
this.filterExp = ''
|
this.filterExp = ''
|
||||||
this.selectedBot = undefined
|
this.selectedBot = undefined
|
||||||
|
if (this.$refs.noticeContent) {
|
||||||
|
this.$refs.noticeContent.destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
this.visible = false
|
this.visible = false
|
||||||
|
})
|
||||||
},
|
},
|
||||||
filterChange(value) {
|
filterChange(value) {
|
||||||
this.filterValue = value
|
this.filterValue = value
|
||||||
|
|
|
@ -364,8 +364,14 @@ export default {
|
||||||
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
},
|
},
|
||||||
filterAttributes(attributes) {
|
filterAttributes(attributes) {
|
||||||
// filter password/json/is_list
|
// filter password/json/is_list/longText/bool/reference
|
||||||
return attributes.filter((attr) => !attr.is_password && !attr.is_list && attr.value_type !== '6')
|
return attributes.filter((attr) => {
|
||||||
|
if (attr.value_type === '2' && !attr.is_index) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return !attr.is_password && !attr.is_list && attr.value_type !== '6' && !attr.is_bool && !attr.is_reference
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
addModalAttr() {
|
addModalAttr() {
|
||||||
|
|
|
@ -306,8 +306,14 @@ export default {
|
||||||
return _find?.alias ?? _find?.name ?? id
|
return _find?.alias ?? _find?.name ?? id
|
||||||
},
|
},
|
||||||
filterAttributes(attributes) {
|
filterAttributes(attributes) {
|
||||||
// filter password/json/is_list
|
// filter password/json/is_list/longText/bool/reference
|
||||||
return attributes.filter((attr) => !attr.is_password && !attr.is_list && attr.value_type !== '6')
|
return attributes.filter((attr) => {
|
||||||
|
if (attr.value_type === '2' && !attr.is_index) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return !attr.is_password && !attr.is_list && attr.value_type !== '6' && !attr.is_bool && !attr.is_reference
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
addTableAttr() {
|
addTableAttr() {
|
||||||
|
|
|
@ -53,8 +53,18 @@
|
||||||
:width="col.width"
|
:width="col.width"
|
||||||
:sortable="col.sortable"
|
:sortable="col.sortable"
|
||||||
>
|
>
|
||||||
<template #default="{row}" v-if="col.value_type === '6'">
|
<template v-if="col.is_reference" #default="{row}">
|
||||||
<span v-if="col.value_type === '6' && row[col.field]">{{ JSON.stringify(row[col.field]) }}</span>
|
<a
|
||||||
|
v-for="(id) in (col.is_list ? row[col.field] : [row[col.field]])"
|
||||||
|
:key="id"
|
||||||
|
:href="`/cmdb/cidetail/${col.reference_type_id}/${id}`"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{{ id }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
<template #default="{row}" v-else-if="col.value_type == '6'">
|
||||||
|
<span v-if="col.value_type == '6' && row[col.field]">{{ JSON.stringify(row[col.field]) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</vxe-table-column>
|
</vxe-table-column>
|
||||||
</vxe-table>
|
</vxe-table>
|
||||||
|
|
|
@ -101,8 +101,18 @@
|
||||||
:minWidth="100"
|
:minWidth="100"
|
||||||
:cell-type="col.value_type === '2' ? 'string' : 'auto'"
|
:cell-type="col.value_type === '2' ? 'string' : 'auto'"
|
||||||
>
|
>
|
||||||
<template v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice" #default="{row}">
|
<template v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice || col.is_reference" #default="{row}">
|
||||||
<span v-if="col.value_type === '6' && row[col.field]">{{ JSON.stringify(row[col.field]) }}</span>
|
<template v-if="col.is_reference && row[col.field]" >
|
||||||
|
<a
|
||||||
|
v-for="(ciId) in (col.is_list ? row[col.field] : [row[col.field]])"
|
||||||
|
:key="ciId"
|
||||||
|
:href="`/cmdb/cidetail/${col.reference_type_id}/${ciId}`"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{{ getReferenceAttrValue(ciId, col) }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
<span v-else-if="col.value_type === '6' && row[col.field]">{{ JSON.stringify(row[col.field]) }}</span>
|
||||||
<template v-else-if="col.is_link && row[col.field]">
|
<template v-else-if="col.is_link && row[col.field]">
|
||||||
<a
|
<a
|
||||||
v-for="(item, linkIndex) in (col.is_list ? row[col.field] : [row[col.field]])"
|
v-for="(item, linkIndex) in (col.is_list ? row[col.field] : [row[col.field]])"
|
||||||
|
@ -254,6 +264,8 @@ export default {
|
||||||
sortByTable: undefined,
|
sortByTable: undefined,
|
||||||
loading: false,
|
loading: false,
|
||||||
columnsGroup: [],
|
columnsGroup: [],
|
||||||
|
referenceShowAttrNameMap: {},
|
||||||
|
referenceCIIdMap: {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -433,12 +445,99 @@ export default {
|
||||||
await Promise.all(promises1).then(() => {
|
await Promise.all(promises1).then(() => {
|
||||||
this.columnsGroup = [..._commonColumnsGroup, ..._columnsGroup]
|
this.columnsGroup = [..._commonColumnsGroup, ..._columnsGroup]
|
||||||
this.instanceList = res['result']
|
this.instanceList = res['result']
|
||||||
|
this.handlePerference()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handlePerference() {
|
||||||
|
let needRequiredCIType = []
|
||||||
|
this.columnsGroup.forEach((group) => {
|
||||||
|
group.children.forEach((col) => {
|
||||||
|
if (col?.is_reference && col?.reference_type_id) {
|
||||||
|
needRequiredCIType.push(col)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
needRequiredCIType = _.uniq(needRequiredCIType)
|
||||||
|
|
||||||
|
if (!needRequiredCIType.length) {
|
||||||
|
this.referenceShowAttrNameMap = {}
|
||||||
|
this.referenceCIIdMap = {}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handleReferenceShowAttrName(needRequiredCIType)
|
||||||
|
this.handleReferenceCIIdMap(needRequiredCIType)
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleReferenceShowAttrName(needRequiredCIType) {
|
||||||
|
const res = await getCITypes({
|
||||||
|
type_ids: needRequiredCIType.map((col) => col.reference_type_id).join(',')
|
||||||
|
})
|
||||||
|
|
||||||
|
const map = {}
|
||||||
|
res.ci_types.forEach((ciType) => {
|
||||||
|
map[ciType.id] = ciType?.show_name || ciType?.unique_name || ''
|
||||||
|
})
|
||||||
|
|
||||||
|
this.referenceShowAttrNameMap = map
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleReferenceCIIdMap(needRequiredCIType) {
|
||||||
|
const map = {}
|
||||||
|
this.instanceList.forEach((row) => {
|
||||||
|
needRequiredCIType.forEach((col) => {
|
||||||
|
const ids = Array.isArray(row[col.field]) ? row[col.field] : row[col.field] ? [row[col.field]] : []
|
||||||
|
if (ids.length) {
|
||||||
|
if (!map?.[col.reference_type_id]) {
|
||||||
|
map[col.reference_type_id] = {}
|
||||||
|
}
|
||||||
|
ids.forEach((id) => {
|
||||||
|
map[col.reference_type_id][id] = {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!Object.keys(map).length) {
|
||||||
|
this.referenceCIIdMap = {}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const allRes = await Promise.all(
|
||||||
|
Object.keys(map).map((key) => {
|
||||||
|
return searchCI({
|
||||||
|
q: `_type:${key},_id:(${Object.keys(map[key]).join(';')})`,
|
||||||
|
count: 9999
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
allRes.forEach((res) => {
|
||||||
|
res.result.forEach((item) => {
|
||||||
|
if (map?.[item._type]?.[item._id]) {
|
||||||
|
map[item._type][item._id] = item
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.referenceCIIdMap = map
|
||||||
|
},
|
||||||
|
|
||||||
|
getReferenceAttrValue(id, col) {
|
||||||
|
const ci = this?.referenceCIIdMap?.[col?.reference_type_id]?.[id]
|
||||||
|
if (!ci) {
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
const attrName = this.referenceShowAttrNameMap?.[col.reference_type_id]
|
||||||
|
return ci?.[attrName] || id
|
||||||
|
},
|
||||||
|
|
||||||
getColumns(data, attrList) {
|
getColumns(data, attrList) {
|
||||||
const width = document.getElementById('resource_search').clientWidth - 50
|
const width = document.getElementById('resource_search').clientWidth - 50
|
||||||
return getCITableColumns(data, attrList, width).map((item) => {
|
return getCITableColumns(data, attrList, width).map((item) => {
|
||||||
|
|
|
@ -14,7 +14,7 @@ export default {
|
||||||
name: 'TreeViewsNode',
|
name: 'TreeViewsNode',
|
||||||
props: {
|
props: {
|
||||||
title: {
|
title: {
|
||||||
type: [String, Number],
|
type: [String, Number, Boolean],
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
treeKey: {
|
treeKey: {
|
||||||
|
|
Loading…
Reference in New Issue