mirror of
https://github.com/veops/cmdb.git
synced 2025-09-03 19:26:56 +08:00
Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ab8ccf7d1b | ||
|
ae1f0f6b4f | ||
|
ff47e0ade6 | ||
|
0dd272fb04 | ||
|
6bc5c1516d | ||
|
4a4b9e6ef0 | ||
|
6e3f9478b3 | ||
|
691051c254 | ||
|
8f066e95a6 | ||
|
75bca39bf6 | ||
|
3360e4d0fe | ||
|
521fcd0ba2 | ||
|
fc113425cb | ||
|
81a76a9632 | ||
|
9ec105ca37 | ||
|
1e1c92a3ef |
@@ -5,8 +5,8 @@ name = "pypi"
|
||||
|
||||
[packages]
|
||||
# Flask
|
||||
Flask = "==2.3.2"
|
||||
Werkzeug = ">=2.3.6"
|
||||
Flask = "==2.2.5"
|
||||
Werkzeug = "==2.2.3"
|
||||
click = ">=5.0"
|
||||
# Api
|
||||
Flask-RESTful = "==0.3.10"
|
||||
|
@@ -50,7 +50,7 @@ def add_user():
|
||||
|
||||
if is_admin:
|
||||
app = AppCache.get('acl') or App.create(name='acl')
|
||||
acl_admin = RoleCache.get('acl_admin') or RoleCRUD.add_role('acl_admin', app.id, True)
|
||||
acl_admin = RoleCache.get_by_name(app.id, 'acl_admin') or RoleCRUD.add_role('acl_admin', app.id, True)
|
||||
rid = RoleCache.get_by_name(None, username).id
|
||||
|
||||
RoleRelationCRUD.add(acl_admin, acl_admin.id, [rid], app.id)
|
||||
|
@@ -1,14 +1,13 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
|
||||
import click
|
||||
import copy
|
||||
import datetime
|
||||
import json
|
||||
import requests
|
||||
import time
|
||||
import uuid
|
||||
|
||||
import click
|
||||
import requests
|
||||
from flask import current_app
|
||||
from flask.cli import with_appcontext
|
||||
from flask_login import login_user
|
||||
@@ -115,6 +114,8 @@ def cmdb_init_acl():
|
||||
_app = AppCache.get('cmdb') or App.create(name='cmdb')
|
||||
app_id = _app.id
|
||||
|
||||
current_app.test_request_context().push()
|
||||
|
||||
# 1. add resource type
|
||||
for resource_type in ResourceTypeEnum.all():
|
||||
try:
|
||||
@@ -183,11 +184,19 @@ def cmdb_counter():
|
||||
UserCRUD.add(username='worker', password=uuid.uuid4().hex, email='worker@xxx.com')
|
||||
|
||||
login_user(UserCache.get('worker'))
|
||||
|
||||
i = 0
|
||||
while True:
|
||||
try:
|
||||
db.session.remove()
|
||||
|
||||
CMDBCounterCache.reset()
|
||||
|
||||
if i % 5 == 0:
|
||||
CMDBCounterCache.flush_adc_counter()
|
||||
i = 0
|
||||
|
||||
i += 1
|
||||
except:
|
||||
import traceback
|
||||
print(traceback.format_exc())
|
||||
|
@@ -89,6 +89,16 @@ def db_setup():
|
||||
"""
|
||||
db.create_all()
|
||||
|
||||
db.session.execute("set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,"
|
||||
"ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'")
|
||||
db.session.commit()
|
||||
|
||||
try:
|
||||
db.session.execute("set global tidb_enable_noop_functions='ON'")
|
||||
db.session.commit()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
@click.group()
|
||||
def translate():
|
||||
|
@@ -5,10 +5,14 @@ from __future__ import unicode_literals
|
||||
from flask import current_app
|
||||
|
||||
from api.extensions import cache
|
||||
from api.extensions import db
|
||||
from api.lib.cmdb.custom_dashboard import CustomDashboardManager
|
||||
from api.models.cmdb import Attribute
|
||||
from api.models.cmdb import CI
|
||||
from api.models.cmdb import CIType
|
||||
from api.models.cmdb import CITypeAttribute
|
||||
from api.models.cmdb import PreferenceShowAttributes
|
||||
from api.models.cmdb import PreferenceTreeView
|
||||
from api.models.cmdb import RelationType
|
||||
|
||||
|
||||
@@ -226,7 +230,9 @@ class CITypeAttributeCache(object):
|
||||
|
||||
|
||||
class CMDBCounterCache(object):
|
||||
KEY = 'CMDB::Counter'
|
||||
KEY = 'CMDB::Counter::dashboard'
|
||||
KEY2 = 'CMDB::Counter::adc'
|
||||
KEY3 = 'CMDB::Counter::sub'
|
||||
|
||||
@classmethod
|
||||
def get(cls):
|
||||
@@ -429,3 +435,47 @@ class CMDBCounterCache(object):
|
||||
return
|
||||
|
||||
return numfound
|
||||
|
||||
@classmethod
|
||||
def flush_adc_counter(cls):
|
||||
res = db.session.query(CI.type_id, CI.is_auto_discovery)
|
||||
result = dict()
|
||||
for i in res:
|
||||
result.setdefault(i.type_id, dict(total=0, auto_discovery=0))
|
||||
result[i.type_id]['total'] += 1
|
||||
if i.is_auto_discovery:
|
||||
result[i.type_id]['auto_discovery'] += 1
|
||||
|
||||
cache.set(cls.KEY2, result, timeout=0)
|
||||
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def get_adc_counter(cls):
|
||||
return cache.get(cls.KEY2) or cls.flush_adc_counter()
|
||||
|
||||
@classmethod
|
||||
def flush_sub_counter(cls):
|
||||
result = dict(type_id2users=dict())
|
||||
|
||||
types = db.session.query(PreferenceShowAttributes.type_id,
|
||||
PreferenceShowAttributes.uid, PreferenceShowAttributes.created_at).filter(
|
||||
PreferenceShowAttributes.deleted.is_(False)).group_by(
|
||||
PreferenceShowAttributes.uid, PreferenceShowAttributes.type_id)
|
||||
for i in types:
|
||||
result['type_id2users'].setdefault(i.type_id, []).append(i.uid)
|
||||
|
||||
types = PreferenceTreeView.get_by(to_dict=False)
|
||||
for i in types:
|
||||
|
||||
result['type_id2users'].setdefault(i.type_id, [])
|
||||
if i.uid not in result['type_id2users'][i.type_id]:
|
||||
result['type_id2users'][i.type_id].append(i.uid)
|
||||
|
||||
cache.set(cls.KEY3, result, timeout=0)
|
||||
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def get_sub_counter(cls):
|
||||
return cache.get(cls.KEY3) or cls.flush_sub_counter()
|
||||
|
@@ -5,7 +5,6 @@ import copy
|
||||
import datetime
|
||||
import json
|
||||
import threading
|
||||
|
||||
from flask import abort
|
||||
from flask import current_app
|
||||
from flask_login import current_user
|
||||
@@ -16,6 +15,7 @@ from api.extensions import rd
|
||||
from api.lib.cmdb.cache import AttributeCache
|
||||
from api.lib.cmdb.cache import CITypeAttributesCache
|
||||
from api.lib.cmdb.cache import CITypeCache
|
||||
from api.lib.cmdb.cache import CMDBCounterCache
|
||||
from api.lib.cmdb.ci_type import CITypeAttributeManager
|
||||
from api.lib.cmdb.ci_type import CITypeManager
|
||||
from api.lib.cmdb.ci_type import CITypeRelationManager
|
||||
@@ -218,15 +218,7 @@ class CIManager(object):
|
||||
|
||||
@classmethod
|
||||
def get_ad_statistics(cls):
|
||||
res = CI.get_by(to_dict=False)
|
||||
result = dict()
|
||||
for i in res:
|
||||
result.setdefault(i.type_id, dict(total=0, auto_discovery=0))
|
||||
result[i.type_id]['total'] += 1
|
||||
if i.is_auto_discovery:
|
||||
result[i.type_id]['auto_discovery'] += 1
|
||||
|
||||
return result
|
||||
return CMDBCounterCache.get_adc_counter()
|
||||
|
||||
@staticmethod
|
||||
def ci_is_exist(unique_key, unique_value, type_id):
|
||||
@@ -368,6 +360,8 @@ class CIManager(object):
|
||||
if attr.default and attr.default.get('default') == AttributeDefaultValueEnum.UPDATED_AT:
|
||||
ci_dict[attr.name] = now
|
||||
|
||||
value_manager = AttributeValueManager()
|
||||
|
||||
computed_attrs = []
|
||||
for _, attr in attrs:
|
||||
if attr.is_computed:
|
||||
@@ -378,7 +372,8 @@ class CIManager(object):
|
||||
elif attr.alias in ci_dict:
|
||||
password_dict[attr.id] = ci_dict.pop(attr.alias)
|
||||
|
||||
value_manager = AttributeValueManager()
|
||||
if attr.re_check and password_dict.get(attr.id):
|
||||
value_manager.check_re(attr.re_check, password_dict[attr.id])
|
||||
|
||||
if computed_attrs:
|
||||
value_manager.handle_ci_compute_attributes(ci_dict, computed_attrs, ci)
|
||||
@@ -437,6 +432,8 @@ class CIManager(object):
|
||||
if attr.default and attr.default.get('default') == AttributeDefaultValueEnum.UPDATED_AT:
|
||||
ci_dict[attr.name] = now
|
||||
|
||||
value_manager = AttributeValueManager()
|
||||
|
||||
password_dict = dict()
|
||||
computed_attrs = list()
|
||||
for _, attr in attrs:
|
||||
@@ -448,7 +445,8 @@ class CIManager(object):
|
||||
elif attr.alias in ci_dict:
|
||||
password_dict[attr.id] = ci_dict.pop(attr.alias)
|
||||
|
||||
value_manager = AttributeValueManager()
|
||||
if attr.re_check and password_dict.get(attr.id):
|
||||
value_manager.check_re(attr.re_check, password_dict[attr.id])
|
||||
|
||||
if computed_attrs:
|
||||
value_manager.handle_ci_compute_attributes(ci_dict, computed_attrs, ci)
|
||||
|
@@ -1,7 +1,6 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import copy
|
||||
|
||||
import toposort
|
||||
from flask import abort
|
||||
from flask import current_app
|
||||
@@ -46,6 +45,7 @@ from api.models.cmdb import CITypeRelation
|
||||
from api.models.cmdb import CITypeTrigger
|
||||
from api.models.cmdb import CITypeUniqueConstraint
|
||||
from api.models.cmdb import CustomDashboard
|
||||
from api.models.cmdb import PreferenceCITypeOrder
|
||||
from api.models.cmdb import PreferenceRelationView
|
||||
from api.models.cmdb import PreferenceSearchOption
|
||||
from api.models.cmdb import PreferenceShowAttributes
|
||||
@@ -75,12 +75,13 @@ class CITypeManager(object):
|
||||
return CIType.get_by_id(ci_type.id)
|
||||
|
||||
@staticmethod
|
||||
def get_ci_types(type_name=None):
|
||||
def get_ci_types(type_name=None, like=True):
|
||||
resources = None
|
||||
if current_app.config.get('USE_ACL') and not is_app_admin('cmdb'):
|
||||
resources = set([i.get('name') for i in ACLManager().get_resources(ResourceTypeEnum.CI_TYPE)])
|
||||
|
||||
ci_types = CIType.get_by() if type_name is None else CIType.get_by_like(name=type_name)
|
||||
ci_types = CIType.get_by() if type_name is None else (
|
||||
CIType.get_by_like(name=type_name) if like else CIType.get_by(name=type_name))
|
||||
res = list()
|
||||
for type_dict in ci_types:
|
||||
attr = AttributeCache.get(type_dict["unique_id"])
|
||||
@@ -222,7 +223,7 @@ class CITypeManager(object):
|
||||
|
||||
for table in [PreferenceTreeView, PreferenceShowAttributes, PreferenceSearchOption, CustomDashboard,
|
||||
CITypeGroupItem, CITypeAttributeGroup, CITypeAttribute, CITypeUniqueConstraint, CITypeTrigger,
|
||||
AutoDiscoveryCIType, CIFilterPerms]:
|
||||
AutoDiscoveryCIType, CIFilterPerms, PreferenceCITypeOrder]:
|
||||
for item in table.get_by(type_id=type_id, to_dict=False):
|
||||
item.soft_delete(commit=False)
|
||||
|
||||
@@ -1274,7 +1275,7 @@ class CITypeTemplateManager(object):
|
||||
from api.lib.common_setting.upload_file import CommonFileCRUD
|
||||
|
||||
tpt = dict(
|
||||
ci_types=CITypeManager.get_ci_types(type_name=ci_type.name),
|
||||
ci_types=CITypeManager.get_ci_types(type_name=ci_type.name, like=False),
|
||||
ci_type_auto_discovery_rules=list(),
|
||||
type2attributes=dict(),
|
||||
type2attribute_group=dict(),
|
||||
|
@@ -114,6 +114,8 @@ class CIFilterPermsCRUD(DBMixin):
|
||||
|
||||
obj.soft_delete()
|
||||
|
||||
return obj
|
||||
|
||||
else:
|
||||
if not kwargs.get('ci_filter') and not kwargs.get('attr_filter'):
|
||||
return
|
||||
|
@@ -2,7 +2,6 @@
|
||||
|
||||
|
||||
import copy
|
||||
|
||||
import six
|
||||
import toposort
|
||||
from flask import abort
|
||||
@@ -14,6 +13,7 @@ from api.lib.cmdb.attribute import AttributeManager
|
||||
from api.lib.cmdb.cache import AttributeCache
|
||||
from api.lib.cmdb.cache import CITypeAttributesCache
|
||||
from api.lib.cmdb.cache import CITypeCache
|
||||
from api.lib.cmdb.cache import CMDBCounterCache
|
||||
from api.lib.cmdb.const import ConstraintEnum
|
||||
from api.lib.cmdb.const import PermEnum
|
||||
from api.lib.cmdb.const import ResourceTypeEnum
|
||||
@@ -24,6 +24,7 @@ from api.lib.exception import AbortException
|
||||
from api.lib.perm.acl.acl import ACLManager
|
||||
from api.models.cmdb import CITypeAttribute
|
||||
from api.models.cmdb import CITypeRelation
|
||||
from api.models.cmdb import PreferenceCITypeOrder
|
||||
from api.models.cmdb import PreferenceRelationView
|
||||
from api.models.cmdb import PreferenceSearchOption
|
||||
from api.models.cmdb import PreferenceShowAttributes
|
||||
@@ -38,13 +39,22 @@ class PreferenceManager(object):
|
||||
|
||||
@staticmethod
|
||||
def get_types(instance=False, tree=False):
|
||||
ci_type_order = sorted(PreferenceCITypeOrder.get_by(uid=current_user.uid, to_dict=False), key=lambda x: x.order)
|
||||
|
||||
types = db.session.query(PreferenceShowAttributes.type_id).filter(
|
||||
PreferenceShowAttributes.uid == current_user.uid).filter(
|
||||
PreferenceShowAttributes.deleted.is_(False)).group_by(
|
||||
PreferenceShowAttributes.type_id).all() if instance else []
|
||||
types = sorted(types, key=lambda x: {i.type_id: idx for idx, i in enumerate(
|
||||
ci_type_order) if not i.is_tree}.get(x.type_id, 1))
|
||||
|
||||
tree_types = PreferenceTreeView.get_by(uid=current_user.uid, to_dict=False) if tree else []
|
||||
type_ids = set([i.type_id for i in types + tree_types])
|
||||
tree_types = sorted(tree_types, key=lambda x: {i.type_id: idx for idx, i in enumerate(
|
||||
ci_type_order) if i.is_tree}.get(x.type_id, 1))
|
||||
|
||||
type_ids = [i.type_id for i in types + tree_types]
|
||||
if types and tree_types:
|
||||
type_ids = set(type_ids)
|
||||
|
||||
return [CITypeCache.get(type_id).to_dict() for type_id in type_ids]
|
||||
|
||||
@@ -59,32 +69,36 @@ class PreferenceManager(object):
|
||||
:param tree:
|
||||
:return:
|
||||
"""
|
||||
result = dict(self=dict(instance=[], tree=[], type_id2subs_time=dict()),
|
||||
type_id2users=dict())
|
||||
result = dict(self=dict(instance=[], tree=[], type_id2subs_time=dict()))
|
||||
|
||||
result.update(CMDBCounterCache.get_sub_counter())
|
||||
|
||||
ci_type_order = sorted(PreferenceCITypeOrder.get_by(uid=current_user.uid, to_dict=False), key=lambda x: x.order)
|
||||
if instance:
|
||||
types = db.session.query(PreferenceShowAttributes.type_id,
|
||||
PreferenceShowAttributes.uid, PreferenceShowAttributes.created_at).filter(
|
||||
PreferenceShowAttributes.deleted.is_(False)).group_by(
|
||||
PreferenceShowAttributes.deleted.is_(False)).filter(
|
||||
PreferenceShowAttributes.uid == current_user.uid).group_by(
|
||||
PreferenceShowAttributes.uid, PreferenceShowAttributes.type_id)
|
||||
for i in types:
|
||||
if i.uid == current_user.uid:
|
||||
result['self']['instance'].append(i.type_id)
|
||||
if str(i.created_at) > str(result['self']['type_id2subs_time'].get(i.type_id, "")):
|
||||
result['self']['type_id2subs_time'][i.type_id] = i.created_at
|
||||
result['self']['instance'].append(i.type_id)
|
||||
if str(i.created_at) > str(result['self']['type_id2subs_time'].get(i.type_id, "")):
|
||||
result['self']['type_id2subs_time'][i.type_id] = i.created_at
|
||||
|
||||
result['type_id2users'].setdefault(i.type_id, []).append(i.uid)
|
||||
instance_order = [i.type_id for i in ci_type_order if not i.is_tree]
|
||||
if len(instance_order) == len(result['self']['instance']):
|
||||
result['self']['instance'] = instance_order
|
||||
|
||||
if tree:
|
||||
types = PreferenceTreeView.get_by(to_dict=False)
|
||||
types = PreferenceTreeView.get_by(uid=current_user.uid, to_dict=False)
|
||||
for i in types:
|
||||
if i.uid == current_user.uid:
|
||||
result['self']['tree'].append(i.type_id)
|
||||
if str(i.created_at) > str(result['self']['type_id2subs_time'].get(i.type_id, "")):
|
||||
result['self']['type_id2subs_time'][i.type_id] = i.created_at
|
||||
result['self']['tree'].append(i.type_id)
|
||||
if str(i.created_at) > str(result['self']['type_id2subs_time'].get(i.type_id, "")):
|
||||
result['self']['type_id2subs_time'][i.type_id] = i.created_at
|
||||
|
||||
result['type_id2users'].setdefault(i.type_id, [])
|
||||
if i.uid not in result['type_id2users'][i.type_id]:
|
||||
result['type_id2users'][i.type_id].append(i.uid)
|
||||
tree_order = [i.type_id for i in ci_type_order if i.is_tree]
|
||||
if len(tree_order) == len(result['self']['tree']):
|
||||
result['self']['tree'] = tree_order
|
||||
|
||||
return result
|
||||
|
||||
@@ -151,9 +165,22 @@ class PreferenceManager(object):
|
||||
if i.attr_id not in attr_dict:
|
||||
i.soft_delete()
|
||||
|
||||
if not existed_all and attr_order:
|
||||
cls.add_ci_type_order_item(type_id, is_tree=False)
|
||||
|
||||
elif not PreferenceShowAttributes.get_by(type_id=type_id, uid=current_user.uid, to_dict=False):
|
||||
cls.delete_ci_type_order_item(type_id, is_tree=False)
|
||||
|
||||
@staticmethod
|
||||
def get_tree_view():
|
||||
ci_type_order = sorted(PreferenceCITypeOrder.get_by(uid=current_user.uid, is_tree=True, to_dict=False),
|
||||
key=lambda x: x.order)
|
||||
|
||||
res = PreferenceTreeView.get_by(uid=current_user.uid, to_dict=True)
|
||||
if ci_type_order:
|
||||
res = sorted(res, key=lambda x: {ii.type_id: idx for idx, ii in enumerate(
|
||||
ci_type_order)}.get(x['type_id'], 1))
|
||||
|
||||
for item in res:
|
||||
if item["levels"]:
|
||||
ci_type = CITypeCache.get(item['type_id']).to_dict()
|
||||
@@ -172,8 +199,8 @@ class PreferenceManager(object):
|
||||
|
||||
return res
|
||||
|
||||
@staticmethod
|
||||
def create_or_update_tree_view(type_id, levels):
|
||||
@classmethod
|
||||
def create_or_update_tree_view(cls, type_id, levels):
|
||||
attrs = CITypeAttributesCache.get(type_id)
|
||||
for idx, i in enumerate(levels):
|
||||
for attr in attrs:
|
||||
@@ -185,9 +212,12 @@ class PreferenceManager(object):
|
||||
if existed is not None:
|
||||
if not levels:
|
||||
existed.soft_delete()
|
||||
cls.delete_ci_type_order_item(type_id, is_tree=True)
|
||||
return existed
|
||||
return existed.update(levels=levels)
|
||||
elif levels:
|
||||
cls.add_ci_type_order_item(type_id, is_tree=True)
|
||||
|
||||
return PreferenceTreeView.create(levels=levels, type_id=type_id, uid=current_user.uid)
|
||||
|
||||
@staticmethod
|
||||
@@ -356,6 +386,9 @@ class PreferenceManager(object):
|
||||
for i in PreferenceTreeView.get_by(type_id=type_id, uid=uid, to_dict=False):
|
||||
i.soft_delete()
|
||||
|
||||
for i in PreferenceCITypeOrder.get_by(type_id=type_id, uid=uid, to_dict=False):
|
||||
i.soft_delete()
|
||||
|
||||
@staticmethod
|
||||
def can_edit_relation(parent_id, child_id):
|
||||
views = PreferenceRelationView.get_by(to_dict=False)
|
||||
@@ -381,3 +414,36 @@ class PreferenceManager(object):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def add_ci_type_order_item(type_id, is_tree=False):
|
||||
max_order = PreferenceCITypeOrder.get_by(
|
||||
uid=current_user.uid, is_tree=is_tree, only_query=True).order_by(PreferenceCITypeOrder.order.desc()).first()
|
||||
order = (max_order and max_order.order + 1) or 1
|
||||
|
||||
PreferenceCITypeOrder.create(type_id=type_id, is_tree=is_tree, uid=current_user.uid, order=order)
|
||||
|
||||
@staticmethod
|
||||
def delete_ci_type_order_item(type_id, is_tree=False):
|
||||
existed = PreferenceCITypeOrder.get_by(uid=current_user.uid, type_id=type_id, is_tree=is_tree,
|
||||
first=True, to_dict=False)
|
||||
|
||||
existed and existed.soft_delete()
|
||||
|
||||
@staticmethod
|
||||
def upsert_ci_type_order(type_ids, is_tree=False):
|
||||
for idx, type_id in enumerate(type_ids):
|
||||
order = idx + 1
|
||||
existed = PreferenceCITypeOrder.get_by(uid=current_user.uid, type_id=type_id, is_tree=is_tree,
|
||||
to_dict=False, first=True)
|
||||
if existed is not None:
|
||||
existed.update(order=order, flush=True)
|
||||
else:
|
||||
PreferenceCITypeOrder.create(uid=current_user.uid, type_id=type_id, is_tree=is_tree, order=order,
|
||||
flush=True)
|
||||
try:
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
current_app.logger.error("upsert citype order failed: {}".format(e))
|
||||
return abort(400, ErrFormat.unknown_error)
|
||||
|
@@ -5,10 +5,10 @@ from __future__ import unicode_literals
|
||||
|
||||
import copy
|
||||
import imp
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
import jinja2
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
from flask import abort
|
||||
from flask import current_app
|
||||
from jinja2schema import infer
|
||||
@@ -117,6 +117,11 @@ class AttributeValueManager(object):
|
||||
if type_attr and type_attr.is_required and not value and value != 0:
|
||||
return abort(400, ErrFormat.attribute_value_required.format(attr.alias))
|
||||
|
||||
@staticmethod
|
||||
def check_re(expr, value):
|
||||
if not re.compile(expr).match(str(value)):
|
||||
return abort(400, ErrFormat.attribute_value_invalid.format(value))
|
||||
|
||||
def _validate(self, attr, value, value_table, ci=None, type_id=None, ci_id=None, type_attr=None):
|
||||
ci = ci or {}
|
||||
v = self._deserialize_value(attr.value_type, value)
|
||||
@@ -130,6 +135,9 @@ class AttributeValueManager(object):
|
||||
if v == "" and attr.value_type not in (ValueTypeEnum.TEXT,):
|
||||
v = None
|
||||
|
||||
if attr.re_check and value:
|
||||
self.check_re(attr.re_check, value)
|
||||
|
||||
return v
|
||||
|
||||
@staticmethod
|
||||
|
@@ -2,7 +2,6 @@
|
||||
|
||||
|
||||
import datetime
|
||||
|
||||
from sqlalchemy.dialects.mysql import DOUBLE
|
||||
|
||||
from api.extensions import db
|
||||
@@ -94,6 +93,8 @@ class Attribute(Model):
|
||||
_choice_web_hook = db.Column('choice_web_hook', db.JSON)
|
||||
choice_other = db.Column(db.JSON)
|
||||
|
||||
re_check = db.Column(db.Text)
|
||||
|
||||
uid = db.Column(db.Integer, index=True)
|
||||
|
||||
option = db.Column(db.JSON)
|
||||
@@ -464,6 +465,15 @@ class PreferenceSearchOption(Model):
|
||||
option = db.Column(db.JSON)
|
||||
|
||||
|
||||
class PreferenceCITypeOrder(Model):
|
||||
__tablename__ = "c_pcto"
|
||||
|
||||
uid = db.Column(db.Integer, index=True, nullable=False)
|
||||
type_id = db.Column(db.Integer, db.ForeignKey('c_ci_types.id'))
|
||||
order = db.Column(db.SmallInteger, default=0)
|
||||
is_tree = db.Column(db.Boolean, default=False) # True is tree view, False is resource view
|
||||
|
||||
|
||||
# custom
|
||||
class CustomDashboard(Model):
|
||||
__tablename__ = "c_c_d"
|
||||
|
@@ -465,16 +465,16 @@ class CITypeGrantView(APIView):
|
||||
|
||||
acl.grant_resource_to_role_by_rid(type_name, rid, ResourceTypeEnum.CI_TYPE, perms, rebuild=False)
|
||||
|
||||
if request.values.get('ci_filter') or request.values.get('attr_filter'):
|
||||
CIFilterPermsCRUD().add(type_id=type_id, rid=rid, **request.values)
|
||||
else:
|
||||
resource = None
|
||||
if 'ci_filter' in request.values or 'attr_filter' in request.values:
|
||||
resource = CIFilterPermsCRUD().add(type_id=type_id, rid=rid, **request.values)
|
||||
|
||||
if not resource:
|
||||
from api.tasks.acl import role_rebuild
|
||||
from api.lib.perm.acl.const import ACL_QUEUE
|
||||
|
||||
app_id = AppCache.get('cmdb').id
|
||||
current_app.logger.info((rid, app_id))
|
||||
role_rebuild.apply_async(args=(rid, app_id), queue=ACL_QUEUE)
|
||||
current_app.logger.info('done')
|
||||
|
||||
return self.jsonify(code=200)
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
|
||||
from flask import abort
|
||||
from flask import current_app
|
||||
from flask import request
|
||||
|
||||
from api.lib.cmdb.ci_type import CITypeManager
|
||||
@@ -187,3 +188,15 @@ class PreferenceRelationRevokeView(APIView):
|
||||
acl.revoke_resource_from_role_by_rid(name, rid, ResourceTypeEnum.RELATION_VIEW, perms)
|
||||
|
||||
return self.jsonify(code=200)
|
||||
|
||||
|
||||
class PreferenceCITypeOrderView(APIView):
|
||||
url_prefix = ("/preference/ci_types/order",)
|
||||
|
||||
def post(self):
|
||||
type_ids = request.values.get("type_ids")
|
||||
is_tree = request.values.get("is_tree") in current_app.config.get('BOOL_TRUE')
|
||||
|
||||
PreferenceManager.upsert_ci_type_order(type_ids, is_tree)
|
||||
|
||||
return self.jsonify(type_ids=type_ids, is_tree=is_tree)
|
||||
|
@@ -8,7 +8,7 @@ elasticsearch==7.17.9
|
||||
email-validator==1.3.1
|
||||
environs==4.2.0
|
||||
flasgger==0.9.5
|
||||
Flask==2.3.2
|
||||
Flask==2.2.5
|
||||
Flask-Bcrypt==1.0.1
|
||||
flask-babel==4.0.0
|
||||
Flask-Caching==2.0.2
|
||||
@@ -46,7 +46,7 @@ supervisor==4.0.3
|
||||
timeout-decorator==0.5.0
|
||||
toposort==1.10
|
||||
treelib==1.6.1
|
||||
Werkzeug>=2.3.6
|
||||
Werkzeug==2.2.3
|
||||
WTForms==3.0.0
|
||||
shamir~=17.12.0
|
||||
pycryptodomex>=3.19.0
|
||||
|
@@ -13,7 +13,7 @@ const getAntdSerials = (color) => {
|
||||
|
||||
const themePluginOption = {
|
||||
fileName: 'css/theme-colors-[contenthash:8].css',
|
||||
matchColors: getAntdSerials('#1890ff'), // 主色系列
|
||||
matchColors: getAntdSerials('#2f54eb'), // 主色系列
|
||||
// 改变样式选择器,解决样式覆盖问题
|
||||
changeSelector (selector) {
|
||||
switch (selector) {
|
||||
|
2
cmdb-ui/src/components/Pager/index.js
Normal file
2
cmdb-ui/src/components/Pager/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import Pager from './index.vue'
|
||||
export default Pager
|
137
cmdb-ui/src/components/Pager/index.vue
Normal file
137
cmdb-ui/src/components/Pager/index.vue
Normal file
@@ -0,0 +1,137 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-row class="row" type="flex" justify="end">
|
||||
<a-col>
|
||||
<a-space align="end">
|
||||
<a-button
|
||||
class="left-button"
|
||||
size="small"
|
||||
:disabled="prevIsDisabled"
|
||||
@click="prevPage"
|
||||
><a-icon
|
||||
type="left"
|
||||
/></a-button>
|
||||
<a-button class="page-button" size="small">{{ currentPage }}</a-button>
|
||||
<a-button
|
||||
class="right-button"
|
||||
size="small"
|
||||
:disabled="nextIsDisabled"
|
||||
@click="nextPage"
|
||||
><a-icon
|
||||
type="right"
|
||||
/></a-button>
|
||||
<a-dropdown
|
||||
class="dropdown"
|
||||
size="small"
|
||||
placement="topCenter"
|
||||
:trigger="['click']"
|
||||
:disabled="dropdownIsDisabled"
|
||||
>
|
||||
<a-menu slot="overlay">
|
||||
<a-menu-item v-for="(size, index) in pageSizes" :key="index" @click="handleItemClick(size)">
|
||||
{{ `${size}${$t('itemsPerPage')}` }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
<a-button size="small">{{ `${pageSize}${$t('itemsPerPage')}` }}<a-icon type="down" /> </a-button>
|
||||
</a-dropdown>
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Pager',
|
||||
props: {
|
||||
currentPage: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
pageSize: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
pageSizes: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dropdownIsDisabled: false,
|
||||
prevIsDisabled: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
nextIsDisabled() {
|
||||
return this.isLoading || this.total < this.pageSize
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
isLoading: {
|
||||
immediate: true,
|
||||
handler: function(val) {
|
||||
if (val) {
|
||||
this.dropdownIsDisabled = true
|
||||
this.prevIsDisabled = true
|
||||
} else {
|
||||
this.dropdownIsDisabled = false
|
||||
if (this.currentPage === 1) {
|
||||
this.prevIsDisabled = true
|
||||
} else {
|
||||
this.prevIsDisabled = false
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
currentPage: {
|
||||
immediate: true,
|
||||
handler: function(val) {
|
||||
if (val === 1) {
|
||||
this.prevIsDisabled = true
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleItemClick(size) {
|
||||
this.$emit('showSizeChange', size)
|
||||
},
|
||||
nextPage() {
|
||||
const pageNum = this.currentPage + 1
|
||||
this.$emit('change', pageNum)
|
||||
},
|
||||
prevPage() {
|
||||
const pageNum = this.currentPage - 1
|
||||
this.$emit('change', pageNum)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.row {
|
||||
margin-top: 5px;
|
||||
.left-button {
|
||||
padding: 0;
|
||||
width: 24px;
|
||||
}
|
||||
.right-button {
|
||||
padding: 0;
|
||||
width: 24px;
|
||||
}
|
||||
.page-button {
|
||||
padding: 0;
|
||||
width: 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
19
cmdb-ui/src/components/RegexSelect/constants.js
Normal file
19
cmdb-ui/src/components/RegexSelect/constants.js
Normal file
@@ -0,0 +1,19 @@
|
||||
/* eslint-disable no-useless-escape */
|
||||
|
||||
import i18n from '@/lang'
|
||||
export const regList = () => {
|
||||
return [
|
||||
{ id: 'letter', label: i18n.t('regexSelect.letter'), value: '^[A-Za-z]+$', message: '请输入字母' },
|
||||
{ id: 'number', label: i18n.t('regexSelect.number'), value: '^-?(?!0\\d+)\\d+(\\.\\d+)?$', message: '请输入数字' },
|
||||
{ id: 'letterAndNumber', label: i18n.t('regexSelect.letterAndNumber'), value: '^[A-Za-z0-9.]+$', message: '请输入字母和数字' },
|
||||
{ id: 'phone', label: i18n.t('regexSelect.phone'), value: '^1[3-9]\\d{9}$', message: '请输入正确手机号码' },
|
||||
{ id: 'landline', label: i18n.t('regexSelect.landline'), value: '^(?:(?:\\d{3}-)?\\d{8}|^(?:\\d{4}-)?\\d{7,8})(?:-\\d+)?$', message: '请输入正确座机' },
|
||||
{ id: 'zipCode', label: i18n.t('regexSelect.zipCode'), value: '^(0[1-7]|1[0-356]|2[0-7]|3[0-6]|4[0-7]|5[1-7]|6[1-7]|7[0-5]|8[013-6])\\d{4}$', message: '请输入正确邮政编码' },
|
||||
{ id: 'IDCard', label: i18n.t('regexSelect.IDCard'), value: '(^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)', message: '请输入正确身份证号' },
|
||||
{ id: 'ip', label: i18n.t('regexSelect.ip'), value: '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$', message: '请输入正确IP地址' },
|
||||
{ id: 'email', label: i18n.t('regexSelect.email'), value: '^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\.\\w+([-.]\\w+)*$', message: '请输入正确邮箱' },
|
||||
{ id: 'link', label: i18n.t('regexSelect.link'), value: '^(https:\/\/www\.|http:\/\/www\.|https:\/\/|http:\/\/)?[a-zA-Z0-9]{2,}(\.[a-zA-Z0-9]{2,})(\.[a-zA-Z0-9]{2,})?$', message: '请输入链接' },
|
||||
{ id: 'monetaryAmount', label: i18n.t('regexSelect.monetaryAmount'), value: '^-?\\d+(,\\d{3})*(\.\\d{1,2})?$', message: '请输入货币金额' },
|
||||
{ id: 'custom', label: i18n.t('regexSelect.custom'), value: '', message: '' }
|
||||
]
|
||||
}
|
2
cmdb-ui/src/components/RegexSelect/index.js
Normal file
2
cmdb-ui/src/components/RegexSelect/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import RegexSelect from './regexSelect.vue'
|
||||
export default RegexSelect
|
208
cmdb-ui/src/components/RegexSelect/regexSelect.vue
Normal file
208
cmdb-ui/src/components/RegexSelect/regexSelect.vue
Normal file
@@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<a-popover
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
ref="regexSelect"
|
||||
overlayClassName="regex-select-wrapper"
|
||||
:overlayStyle="{ '--overlay-width': `${width}px` }"
|
||||
@visibleChange="visibleChange"
|
||||
>
|
||||
<div class="regex-select" slot="content">
|
||||
<div class="regex-select-left">
|
||||
<div class="regex-select-left-header">{{ $t('regexSelect.limitedFormat') }}</div>
|
||||
<div
|
||||
@click="
|
||||
() => {
|
||||
current = reg
|
||||
testInput = ''
|
||||
showMessage = false
|
||||
}
|
||||
"
|
||||
:class="{
|
||||
'regex-select-left-reg': true,
|
||||
'regex-select-left-reg-selected': current && current.label === reg.label,
|
||||
}"
|
||||
v-for="(reg, index) in regList"
|
||||
:key="reg.label"
|
||||
>
|
||||
<a-divider :style="{ margin: '2px -12px', width: 'calc(100% + 24px)' }" v-if="index === regList.length - 1" />
|
||||
{{ reg.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="regex-select-right">
|
||||
<template v-if="current">
|
||||
<div class="regex-select-right-header">{{ $t('regexSelect.regExp') }}</div>
|
||||
<div
|
||||
v-if="current.label !== $t('regexSelect.custom')"
|
||||
:style="{ color: '#000', fontSize: '12px', margin: '12px 0' }"
|
||||
>
|
||||
{{ current.value }}
|
||||
</div>
|
||||
<a-input
|
||||
:style="{ margin: '12px 0' }"
|
||||
size="small"
|
||||
v-else
|
||||
v-model="current.value"
|
||||
@change="
|
||||
() => {
|
||||
this.$emit('change', current)
|
||||
}
|
||||
"
|
||||
/>
|
||||
<template v-if="isShowErrorMsg">
|
||||
<div class="regex-select-right-header">{{ $t('regexSelect.errMsg') }}</div>
|
||||
<a-input :style="{ margin: '12px 0' }" size="small" v-model="current.message" />
|
||||
</template>
|
||||
<div class="regex-select-right-header">{{ $t('regexSelect.test') }}</div>
|
||||
<a-input v-model="testInput" :style="{ margin: '12px 0 4px' }" size="small" @change="validate" />
|
||||
<span :style="{ color: 'red', fontSize: '12px' }" v-if="showMessage">{{
|
||||
locale === 'zh' ? current.message || '错误' : $t('regexSelect.error')
|
||||
}}</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<a-input ref="regInput" :placeholder="$t('regexSelect.placeholder')" :value="current.label" @change="changeLabel">
|
||||
</a-input>
|
||||
</a-popover>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import { regList } from './constants'
|
||||
export default {
|
||||
name: 'RegexSelect',
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change',
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
isShowErrorMsg: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
limitedFormat: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showMessage: false,
|
||||
width: 370,
|
||||
testInput: '',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['locale']),
|
||||
regList() {
|
||||
if (this.limitedFormat.length) {
|
||||
return regList().filter((item) => this.limitedFormat.includes(item.id))
|
||||
}
|
||||
return regList()
|
||||
},
|
||||
current: {
|
||||
get() {
|
||||
if (this.value?.value && !this.value?.label) {
|
||||
const _find = this.regList.find((reg) => reg.value === this.value?.value)
|
||||
return { ...this.value, label: _find?.label ?? this.$t('regexSelect.custom') }
|
||||
}
|
||||
return this.value ?? {}
|
||||
},
|
||||
set(val) {
|
||||
this.showMessage = false
|
||||
this.$emit('change', val)
|
||||
return val
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
const regInput = this.$refs.regInput.$refs.input
|
||||
this.width = regInput.offsetWidth || 370
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
validate(e) {
|
||||
const reg = RegExp(this.current.value, 'g')
|
||||
this.showMessage = !reg.test(e.target.value)
|
||||
},
|
||||
changeLabel(e) {
|
||||
this.current = {}
|
||||
},
|
||||
visibleChange(visible) {
|
||||
if (visible) {
|
||||
this.$nextTick(() => {
|
||||
this.testInput = ''
|
||||
this.showMessage = false
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import '~@/style/static.less';
|
||||
.regex-select {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
display: flex;
|
||||
.regex-select-left {
|
||||
width: 40%;
|
||||
height: 100%;
|
||||
border: 1px solid #cacdd9;
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
&-reg {
|
||||
padding-left: 2px;
|
||||
cursor: pointer;
|
||||
&-selected,
|
||||
&:hover {
|
||||
color: #custom_colors[color_1];
|
||||
}
|
||||
}
|
||||
}
|
||||
&-right {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
border: 1px solid #cacdd9;
|
||||
border-radius: 4px;
|
||||
margin-left: 8px;
|
||||
padding: 12px;
|
||||
}
|
||||
&-left,
|
||||
&-right {
|
||||
&-header {
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
color: #000000;
|
||||
border-left: 2px solid #custom_colors[color_1];
|
||||
padding-left: 6px;
|
||||
margin-left: -6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
.regex-select-wrapper {
|
||||
.ant-popover-arrow {
|
||||
display: none;
|
||||
}
|
||||
.ant-popover-inner-content {
|
||||
padding: 0;
|
||||
min-width: 370px;
|
||||
width: var(--overlay-width);
|
||||
}
|
||||
}
|
||||
.regex-select-wrapper.ant-popover-placement-bottom .ant-popover-content {
|
||||
margin-top: -8px;
|
||||
}
|
||||
.regex-select-wrapper.ant-popover-placement-top .ant-popover-content {
|
||||
margin-bottom: -8px;
|
||||
}
|
||||
</style>
|
@@ -119,7 +119,8 @@ export default {
|
||||
border-radius: 4px;
|
||||
color: @layout-header-font-color;
|
||||
height: @layout-header-height;
|
||||
line-height: @layout-header-height;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
&:hover {
|
||||
background: linear-gradient(0deg, rgba(0, 80, 201, 0.2) 0%, rgba(174, 207, 255, 0.06) 86.76%);
|
||||
color: @layout-header-font-selected-color;
|
||||
|
@@ -71,8 +71,6 @@ export default {
|
||||
title: this.$t('tip'),
|
||||
content: this.$t('topMenu.confirmLogout'),
|
||||
onOk() {
|
||||
// localStorage.removeItem('ops_cityps_currentId')
|
||||
localStorage.clear()
|
||||
return that.Logout()
|
||||
},
|
||||
onCancel() {},
|
||||
|
@@ -14,7 +14,7 @@
|
||||
*/
|
||||
|
||||
export default {
|
||||
primaryColor: '#1890ff', // primary color of ant design
|
||||
primaryColor: '#2f54eb', // primary color of ant design
|
||||
navTheme: 'dark', // theme for nav menu
|
||||
layout: 'sidemenu', // nav menu position: sidemenu or topmenu
|
||||
contentWidth: 'Fixed', // layout of content: Fluid or Fixed, only works when layout is topmenu
|
||||
|
@@ -145,6 +145,26 @@ export default {
|
||||
sizeLimit: 'The image size cannot exceed 2MB!',
|
||||
nodata: 'There are currently no custom icons available. Click here to upload'
|
||||
},
|
||||
regexSelect: {
|
||||
limitedFormat: 'Limited Format',
|
||||
regExp: 'RegExp',
|
||||
errMsg: 'Error Message',
|
||||
test: 'Test',
|
||||
placeholder: 'Please Select RegExp',
|
||||
error: 'Error',
|
||||
letter: 'letter',
|
||||
number: 'number',
|
||||
letterAndNumber: 'letter&number',
|
||||
phone: 'phone',
|
||||
landline: 'landline',
|
||||
zipCode: 'zip code',
|
||||
IDCard: 'ID card',
|
||||
ip: 'IP',
|
||||
email: 'email',
|
||||
link: 'link',
|
||||
monetaryAmount: 'monetary amount',
|
||||
custom: 'custom',
|
||||
},
|
||||
cmdb: cmdb_en,
|
||||
cs: cs_en,
|
||||
acl: acl_en,
|
||||
|
@@ -145,6 +145,26 @@ export default {
|
||||
sizeLimit: '图片大小不可超过2MB!',
|
||||
nodata: '暂无自定义图标,点击此处上传'
|
||||
},
|
||||
regexSelect: {
|
||||
limitedFormat: '限定格式',
|
||||
regExp: '正则表达式',
|
||||
errMsg: '错误时提示',
|
||||
test: '测试',
|
||||
placeholder: '请选择正则表达式',
|
||||
error: '错误',
|
||||
letter: '字母',
|
||||
number: '数字',
|
||||
letterAndNumber: '字母和数字',
|
||||
phone: '手机号码',
|
||||
landline: '座机',
|
||||
zipCode: '邮政编码',
|
||||
IDCard: '身份证号',
|
||||
ip: 'IP地址',
|
||||
email: '邮箱',
|
||||
link: '链接',
|
||||
monetaryAmount: '货币金额',
|
||||
custom: '自定义',
|
||||
},
|
||||
cmdb: cmdb_zh,
|
||||
cs: cs_zh,
|
||||
acl: acl_zh,
|
||||
|
@@ -1,116 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-row class="row" type="flex" justify="end">
|
||||
<a-col>
|
||||
<a-space align="end">
|
||||
<a-button class="left-button" size="small" :disabled="prevIsDisabled" @click="prevPage"><a-icon type="left" /></a-button>
|
||||
<a-button class="page-button" size="small">{{ currentPage }}</a-button>
|
||||
<a-button class="right-button" size="small" :disabled="nextIsDisabled" @click="nextPage"><a-icon type="right" /></a-button>
|
||||
<a-dropdown class="dropdown" size="small" placement="topCenter" :trigger="['click']" :disabled="dropdownIsDisabled">
|
||||
<a-menu slot="overlay">
|
||||
<a-menu-item v-for="(size,index) in pageSizes" :key="index" @click="handleItemClick(size)">
|
||||
{{ size }}{{ $t('itemsPerPage') }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
<a-button size="small"> {{ pageSize }}{{ $t('itemsPerPage') }}<a-icon type="down" /> </a-button>
|
||||
</a-dropdown>
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
currentPage: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
pageSize: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
pageSizes: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dropdownIsDisabled: false,
|
||||
prevIsDisabled: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
nextIsDisabled() {
|
||||
return this.isLoading || this.total < this.pageSize
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isLoading: {
|
||||
immediate: true,
|
||||
handler: function (val) {
|
||||
if (val === true) {
|
||||
this.dropdownIsDisabled = true
|
||||
this.prevIsDisabled = true
|
||||
} else {
|
||||
this.dropdownIsDisabled = false
|
||||
if (this.currentPage === 1) {
|
||||
this.prevIsDisabled = true
|
||||
} else {
|
||||
this.prevIsDisabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
currentPage: {
|
||||
immediate: true,
|
||||
handler: function (val) {
|
||||
if (val === 1) {
|
||||
this.prevIsDisabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleItemClick(size) {
|
||||
this.$emit('showSizeChange', size)
|
||||
},
|
||||
nextPage() {
|
||||
const pageNum = this.currentPage + 1
|
||||
this.$emit('change', pageNum)
|
||||
},
|
||||
prevPage() {
|
||||
const pageNum = this.currentPage - 1
|
||||
this.$emit('change', pageNum)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.row{
|
||||
margin-top: 5px;
|
||||
.left-button{
|
||||
padding: 0;
|
||||
width: 24px;
|
||||
}
|
||||
.right-button{
|
||||
padding: 0;
|
||||
width: 24px;
|
||||
}
|
||||
.page-button{
|
||||
padding: 0;
|
||||
width: 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -79,7 +79,7 @@
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import Pager from './pager.vue'
|
||||
import Pager from '@/components/Pager'
|
||||
import SearchForm from './searchForm.vue'
|
||||
import { searchPermissonHistory } from '@/modules/acl/api/history'
|
||||
import debounce from 'lodash/debounce'
|
||||
|
@@ -62,7 +62,7 @@
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import Pager from './pager.vue'
|
||||
import Pager from '@/components/Pager'
|
||||
import SearchForm from './searchForm.vue'
|
||||
import { searchResourceHistory } from '@/modules/acl/api/history'
|
||||
export default {
|
||||
|
@@ -57,7 +57,7 @@
|
||||
</a-tag>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="operate" :title="$t('batchOperate')">
|
||||
<vxe-column field="operate" :title="$t('acl.batchOperate')">
|
||||
<template #default="{row}">
|
||||
<a-button size="small" type="danger" @click="handleClearAll(row)">
|
||||
{{ $t('clear') }}
|
||||
|
@@ -56,7 +56,7 @@
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import Pager from './pager.vue'
|
||||
import Pager from '@/components/Pager'
|
||||
import SearchForm from './searchForm.vue'
|
||||
import { searchResourceHistory } from '@/modules/acl/api/history'
|
||||
export default {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<CustomDrawer
|
||||
width="800px"
|
||||
placement="left"
|
||||
|
@@ -76,7 +76,7 @@
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import Pager from './pager.vue'
|
||||
import Pager from '@/components/Pager'
|
||||
import SearchForm from './searchForm.vue'
|
||||
import { searchRoleHistory } from '@/modules/acl/api/history'
|
||||
export default {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<CustomDrawer
|
||||
@close="handleClose"
|
||||
width="500"
|
||||
|
@@ -55,7 +55,7 @@
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import Pager from './pager.vue'
|
||||
import Pager from '@/components/Pager'
|
||||
import SearchForm from './searchForm.vue'
|
||||
import { searchTriggerHistory } from '@/modules/acl/api/history'
|
||||
export default {
|
||||
|
@@ -81,7 +81,7 @@
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import debounce from 'lodash/debounce'
|
||||
import Pager from '../../module/pager.vue'
|
||||
import Pager from '@/components/Pager'
|
||||
import SearchForm from '../../module/searchForm.vue'
|
||||
import { searchApp } from '@/modules/acl/api/app'
|
||||
import { searchPermissonHistory } from '@/modules/acl/api/history'
|
||||
|
@@ -64,7 +64,7 @@
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import Pager from '../../module/pager.vue'
|
||||
import Pager from '@/components/Pager'
|
||||
import SearchForm from '../../module/searchForm.vue'
|
||||
import { searchResourceHistory } from '@/modules/acl/api/history'
|
||||
import { searchUser } from '@/modules/acl/api/user'
|
||||
|
@@ -58,7 +58,7 @@
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import Pager from '../../module/pager.vue'
|
||||
import Pager from '@/components/Pager'
|
||||
import SearchForm from '../../module/searchForm.vue'
|
||||
import { searchResourceHistory } from '@/modules/acl/api/history'
|
||||
import { searchUser } from '@/modules/acl/api/user'
|
||||
|
@@ -76,7 +76,7 @@
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import Pager from '../../module/pager.vue'
|
||||
import Pager from '@/components/Pager'
|
||||
import SearchForm from '../../module/searchForm.vue'
|
||||
import { searchRoleHistory } from '@/modules/acl/api/history'
|
||||
import { searchApp } from '@/modules/acl/api/app'
|
||||
|
@@ -57,7 +57,7 @@
|
||||
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import Pager from '../../module/pager.vue'
|
||||
import Pager from '@/components/Pager'
|
||||
import SearchForm from '../../module/searchForm.vue'
|
||||
import { searchTriggerHistory } from '@/modules/acl/api/history'
|
||||
import { getTriggers } from '@/modules/acl/api/trigger'
|
||||
|
@@ -57,17 +57,20 @@
|
||||
</template>
|
||||
</vxe-table-column>
|
||||
</ops-table>
|
||||
<vxe-pager
|
||||
<a-pagination
|
||||
size="small"
|
||||
:layouts="['Total', 'PrevPage', 'JumpNumber', 'NextPage', 'Sizes']"
|
||||
:current-page.sync="tablePage.currentPage"
|
||||
:page-size.sync="tablePage.pageSize"
|
||||
show-size-changer
|
||||
show-quick-jumper
|
||||
:current="tablePage.currentPage"
|
||||
:total="tablePage.total"
|
||||
:page-sizes="pageSizeOptions"
|
||||
@page-change="handlePageChange"
|
||||
:style="{ marginTop: '10px' }"
|
||||
>
|
||||
</vxe-pager>
|
||||
:show-total="(total, range) => `当前展示 ${range[0]}-${range[1]} 条数据, 共 ${total} 条`"
|
||||
:page-size="tablePage.pageSize"
|
||||
:default-current="1"
|
||||
:page-size-options="pageSizeOptions"
|
||||
@change="pageOrSizeChange"
|
||||
@showSizeChange="pageOrSizeChange"
|
||||
:style="{ marginTop: '10px', textAlign: 'right' }"
|
||||
/>
|
||||
</a-spin>
|
||||
|
||||
<resourceTypeForm ref="resourceTypeForm" :handleOk="handleOk"> </resourceTypeForm>
|
||||
@@ -89,7 +92,7 @@ export default {
|
||||
loading: false,
|
||||
groups: [],
|
||||
id2perms: {},
|
||||
pageSizeOptions: [10, 25, 50, 100],
|
||||
pageSizeOptions: ['20', '50', '100', '200'],
|
||||
tablePage: {
|
||||
total: 0,
|
||||
currentPage: 1,
|
||||
@@ -176,7 +179,7 @@ export default {
|
||||
this.handleOk()
|
||||
})
|
||||
},
|
||||
handlePageChange({ currentPage, pageSize }) {
|
||||
pageOrSizeChange(currentPage, pageSize) {
|
||||
this.tablePage.currentPage = currentPage
|
||||
this.tablePage.pageSize = pageSize
|
||||
this.searchData()
|
||||
|
@@ -77,7 +77,7 @@
|
||||
<!-- 2 -->
|
||||
|
||||
<vxe-table-column field="name" :title="$t('acl.resourceName')" :min-widh="150" fixed="left" show-overflow>
|
||||
<template #title="{row}">
|
||||
<template #title="{ row }">
|
||||
{{ row.isGroup ? $t('acl.groupName') : $t('acl.resourceName') }}
|
||||
</template>
|
||||
</vxe-table-column>
|
||||
@@ -86,10 +86,12 @@
|
||||
<vxe-table-column field="user" :title="$t('acl.creator')" :min-widh="100"> </vxe-table-column>
|
||||
|
||||
<!-- 4 -->
|
||||
<vxe-table-column field="created_at" :title="$t('created_at')" :min-widh="220" align="center"> </vxe-table-column>
|
||||
<vxe-table-column field="created_at" :title="$t('created_at')" :min-widh="220" align="center">
|
||||
</vxe-table-column>
|
||||
|
||||
<!-- 5 -->
|
||||
<vxe-table-column field="updated_at" :title="$t('updated_at')" :min-widh="220" fixed="center"> </vxe-table-column>
|
||||
<vxe-table-column field="updated_at" :title="$t('updated_at')" :min-widh="220" fixed="center">
|
||||
</vxe-table-column>
|
||||
|
||||
<!-- 6 -->
|
||||
|
||||
@@ -99,8 +101,9 @@
|
||||
:min-widh="200"
|
||||
fixed="right"
|
||||
align="center"
|
||||
show-overflow>
|
||||
<template #default="{row}">
|
||||
show-overflow
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<span v-show="isGroup">
|
||||
<a @click="handleDisplayMember(row)">{{ $t('acl.member') }}</a>
|
||||
<a-divider type="vertical" />
|
||||
@@ -117,27 +120,36 @@
|
||||
</a>
|
||||
</a-tooltip>
|
||||
<a-divider type="vertical" />
|
||||
<a-popconfirm :title="$t('confirmDelete')" @confirm="handleDelete(row)" @cancel="cancel" :okText="$t('yes')" :cancelText="$t('no')">
|
||||
<a-popconfirm
|
||||
:title="$t('confirmDelete')"
|
||||
@confirm="handleDelete(row)"
|
||||
@cancel="cancel"
|
||||
:okText="$t('yes')"
|
||||
:cancelText="$t('no')"
|
||||
>
|
||||
<a style="color: red"><a-icon type="delete"/></a>
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</vxe-table-column>
|
||||
</ops-table>
|
||||
<vxe-pager
|
||||
<a-pagination
|
||||
size="small"
|
||||
:layouts="['Total', 'PrevPage', 'JumpNumber', 'NextPage', 'Sizes']"
|
||||
:current-page.sync="tablePage.currentPage"
|
||||
:page-size.sync="tablePage.pageSize"
|
||||
show-size-changer
|
||||
show-quick-jumper
|
||||
:current="tablePage.currentPage"
|
||||
:total="tablePage.total"
|
||||
:page-sizes="pageSizeOptions"
|
||||
@page-change="handlePageChange"
|
||||
:style="{ marginTop: '10px' }"
|
||||
>
|
||||
</vxe-pager>
|
||||
:show-total="(total, range) => `当前展示 ${range[0]}-${range[1]} 条数据, 共 ${total} 条`"
|
||||
:page-size="tablePage.pageSize"
|
||||
:default-current="1"
|
||||
:page-size-options="pageSizeOptions"
|
||||
@change="pageOrSizeChange"
|
||||
@showSizeChange="pageOrSizeChange"
|
||||
:style="{ marginTop: '10px', textAlign: 'right' }"
|
||||
/>
|
||||
</a-spin>
|
||||
</div>
|
||||
<div v-else style="text-align: center;margin-top:20%">
|
||||
<a-icon style="font-size:50px; margin-bottom: 20px; color: orange" type="info-circle" />
|
||||
<div v-else style="text-align: center; margin-top: 20%">
|
||||
<a-icon style="font-size: 50px; margin-bottom: 20px; color: orange" type="info-circle" />
|
||||
<h3>{{ $t('acl.addTypeTips') }}</h3>
|
||||
</div>
|
||||
<resourceForm ref="resourceForm" @fresh="handleOk"> </resourceForm>
|
||||
@@ -191,7 +203,7 @@ export default {
|
||||
isGroup: false,
|
||||
allResourceTypes: [],
|
||||
currentType: { id: 0 },
|
||||
pageSizeOptions: [10, 25, 50, 100],
|
||||
pageSizeOptions: ['20', '50', '100', '200'],
|
||||
searchName: '',
|
||||
selectedRows: [],
|
||||
}
|
||||
@@ -291,7 +303,7 @@ export default {
|
||||
}
|
||||
},
|
||||
cancel() {},
|
||||
handlePageChange({ currentPage, pageSize }) {
|
||||
pageOrSizeChange(currentPage, pageSize) {
|
||||
this.tablePage.currentPage = currentPage
|
||||
this.tablePage.pageSize = pageSize
|
||||
this.searchData()
|
||||
@@ -302,7 +314,6 @@ export default {
|
||||
.getVxetableRef()
|
||||
.getCheckboxRecords()
|
||||
.concat(this.$refs.xTable.getVxetableRef().getCheckboxReserveRecords())
|
||||
console.log(this.selectedRows)
|
||||
},
|
||||
onSelectRangeEnd({ records }) {
|
||||
this.selectedRows = records
|
||||
|
@@ -42,13 +42,13 @@
|
||||
|
||||
<!-- 2 -->
|
||||
<vxe-table-column field="is_app_admin" :title="$t('admin')" :min-width="100" align="center">
|
||||
<template #default="{row}">
|
||||
<template #default="{ row }">
|
||||
<a-icon type="check" v-if="row.is_app_admin" />
|
||||
</template>
|
||||
</vxe-table-column>
|
||||
|
||||
<vxe-table-column field="id" :title="$t('acl.inheritedFrom')" :min-width="150">
|
||||
<template #default="{row}">
|
||||
<template #default="{ row }">
|
||||
<a-tag color="cyan" v-for="role in id2parents[row.id]" :key="role.id">{{ role.name }}</a-tag>
|
||||
</template>
|
||||
</vxe-table-column>
|
||||
@@ -69,13 +69,13 @@
|
||||
}
|
||||
"
|
||||
>
|
||||
<template #default="{row}">
|
||||
<template #default="{ row }">
|
||||
{{ row.uid ? $t('no') : $t('yes') }}
|
||||
</template>
|
||||
</vxe-table-column>
|
||||
|
||||
<vxe-table-column field="action" :title="$t('operation')" :width="120" fixed="right">
|
||||
<template #default="{row}">
|
||||
<template #default="{ row }">
|
||||
<a-space>
|
||||
<a-tooltip :title="$t('acl.resourceList')">
|
||||
<a
|
||||
@@ -104,17 +104,20 @@
|
||||
</template>
|
||||
</vxe-table-column>
|
||||
</ops-table>
|
||||
<vxe-pager
|
||||
<a-pagination
|
||||
size="small"
|
||||
:layouts="['Total', 'PrevPage', 'JumpNumber', 'NextPage', 'Sizes']"
|
||||
:current-page.sync="tablePage.currentPage"
|
||||
:page-size.sync="tablePage.pageSize"
|
||||
show-size-changer
|
||||
show-quick-jumper
|
||||
:current="tablePage.currentPage"
|
||||
:total="tablePage.total"
|
||||
:page-sizes="pageSizeOptions"
|
||||
@page-change="handlePageChange"
|
||||
:style="{ marginTop: '10px' }"
|
||||
>
|
||||
</vxe-pager>
|
||||
:show-total="(total, range) => `当前展示 ${range[0]}-${range[1]} 条数据, 共 ${total} 条`"
|
||||
:page-size="tablePage.pageSize"
|
||||
:default-current="1"
|
||||
:page-size-options="pageSizeOptions"
|
||||
@change="pageOrSizeChange"
|
||||
@showSizeChange="pageOrSizeChange"
|
||||
:style="{ marginTop: '10px', textAlign: 'right' }"
|
||||
/>
|
||||
</a-spin>
|
||||
|
||||
<roleForm ref="roleForm" :allRoles="allRoles" :id2parents="id2parents" :handleOk="handleOk"></roleForm>
|
||||
@@ -149,7 +152,7 @@ export default {
|
||||
tableData: [],
|
||||
allRoles: [],
|
||||
id2parents: {},
|
||||
pageSizeOptions: [10, 25, 50, 100],
|
||||
pageSizeOptions: ['20', '50', '100', '200'],
|
||||
searchName: '',
|
||||
filterTableValue: { user_role: 1, user_only: 0 },
|
||||
}
|
||||
@@ -254,7 +257,7 @@ export default {
|
||||
cancel(e) {
|
||||
return false
|
||||
},
|
||||
handlePageChange({ currentPage, pageSize }) {
|
||||
pageOrSizeChange(currentPage, pageSize) {
|
||||
this.tablePage.currentPage = currentPage
|
||||
this.tablePage.pageSize = pageSize
|
||||
this.loadData()
|
||||
|
@@ -114,3 +114,12 @@ export function revokeRelationView(rid, data) {
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// preference citype order
|
||||
export function preferenceCitypeOrder(data) {
|
||||
return axios({
|
||||
url: `/v0.1/preference/ci_types/order`,
|
||||
method: 'POST',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
@@ -174,7 +174,8 @@ const cmdb_en = {
|
||||
date: 'Date',
|
||||
time: 'Time',
|
||||
json: 'JSON',
|
||||
event: 'Event'
|
||||
event: 'Event',
|
||||
reg: 'Regex'
|
||||
},
|
||||
components: {
|
||||
unselectAttributes: 'Unselected',
|
||||
@@ -366,12 +367,12 @@ const cmdb_en = {
|
||||
ad: {
|
||||
upload: 'Import',
|
||||
download: 'Export',
|
||||
accpet: 'Accept',
|
||||
accpetBy: 'Accept By',
|
||||
accept: 'Accept',
|
||||
acceptBy: 'Accept By',
|
||||
acceptTime: 'Accept Time',
|
||||
confirmAccept: 'Confirm Accept?',
|
||||
accpetSuccess: 'Accept successfully',
|
||||
isAccpet: 'Is accept',
|
||||
acceptSuccess: 'Accept successfully',
|
||||
isAccept: 'Is accept',
|
||||
deleteADC: 'Confirm to delete this data?',
|
||||
batchDelete: 'Confirm to delete this data?',
|
||||
agent: 'Built-in & Plug-ins',
|
||||
|
@@ -174,7 +174,8 @@ const cmdb_zh = {
|
||||
date: '日期',
|
||||
time: '时间',
|
||||
json: 'JSON',
|
||||
event: '事件'
|
||||
event: '事件',
|
||||
reg: '正则校验'
|
||||
},
|
||||
components: {
|
||||
unselectAttributes: '未选属性',
|
||||
@@ -366,12 +367,12 @@ const cmdb_zh = {
|
||||
ad: {
|
||||
upload: '规则导入',
|
||||
download: '规则导出',
|
||||
accpet: '入库',
|
||||
accpetBy: '入库人',
|
||||
accept: '入库',
|
||||
acceptBy: '入库人',
|
||||
acceptTime: '入库时间',
|
||||
confirmAccept: '确认入库?',
|
||||
accpetSuccess: '入库成功',
|
||||
isAccpet: '是否入库',
|
||||
acceptSuccess: '入库成功',
|
||||
isAccept: '是否入库',
|
||||
deleteADC: '确认删除该条数据?',
|
||||
batchDelete: '确认删除这些数据?',
|
||||
agent: '内置 & 插件',
|
||||
|
@@ -138,7 +138,7 @@ const genCmdbRoutes = async () => {
|
||||
const [preference, relation] = await Promise.all([getPreference(), getRelationView()])
|
||||
|
||||
preference.forEach(item => {
|
||||
routes.children[2].children.unshift({
|
||||
routes.children[2].children.push({
|
||||
path: `/cmdb/instances/types/${item.id}`,
|
||||
component: () => import(`../views/ci/index`),
|
||||
name: `cmdb_${item.id}`,
|
||||
|
@@ -101,7 +101,6 @@
|
||||
:cell-type="col.value_type === '2' ? 'string' : 'auto'"
|
||||
:fixed="col.is_fixed ? 'left' : ''"
|
||||
>
|
||||
<!-- <template #edit="{row}"><a-input v-model="row[col.field]"></a-input></template> -->
|
||||
<template #header>
|
||||
<span class="vxe-handle">
|
||||
<OpsMoveIcon
|
||||
@@ -110,7 +109,7 @@
|
||||
<span>{{ col.title }}</span>
|
||||
</span>
|
||||
</template>
|
||||
<template v-if="col.is_choice || col.is_password || col.is_list" #edit="{ row }">
|
||||
<template v-if="col.is_choice || col.is_password" #edit="{ row }">
|
||||
<vxe-input v-if="col.is_password" v-model="passwordValue[col.field]" />
|
||||
<a-select
|
||||
:getPopupContainer="(trigger) => trigger.parentElement"
|
||||
@@ -147,18 +146,6 @@
|
||||
</span>
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-select
|
||||
:getPopupContainer="(trigger) => trigger.parentElement"
|
||||
:style="{ width: '100%', height: '32px' }"
|
||||
v-model="row[col.field]"
|
||||
:placeholder="$t('placeholder2')"
|
||||
v-else-if="col.is_list"
|
||||
:showArrow="false"
|
||||
mode="tags"
|
||||
class="ci-table-edit-select"
|
||||
allowClear
|
||||
>
|
||||
</a-select>
|
||||
</template>
|
||||
<template
|
||||
v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice"
|
||||
@@ -293,8 +280,6 @@
|
||||
</a-pagination>
|
||||
</div>
|
||||
<create-instance-form ref="create" @reload="reloadData" @submit="batchUpdate" />
|
||||
<!-- <EditAttrsDrawer ref="editAttrsDrawer" @refresh="refreshAfterEditAttrs" /> -->
|
||||
<!-- <batch-update-relation :typeId="typeId" ref="batchUpdateRelation" @submit="batchUpdateRelation" /> -->
|
||||
<JsonEditor ref="jsonEditor" @jsonEditorOk="jsonEditorOk" />
|
||||
<BatchDownload ref="batchDownload" @batchDownload="batchDownload" />
|
||||
<MetadataDrawer ref="metadataDrawer" />
|
||||
@@ -471,11 +456,6 @@ export default {
|
||||
const regSort = /(?<=sort=).+/g
|
||||
|
||||
const exp = expression.match(regQ) ? expression.match(regQ)[0] : null
|
||||
// if (exp) {
|
||||
// exp = exp.replace(/(\:)/g, '$1*')
|
||||
// exp = exp.replace(/(\,)/g, '*$1')
|
||||
// }
|
||||
// If the sorting is done by clicking on the table, the table will prevail.
|
||||
let sort
|
||||
if (sortByTable) {
|
||||
sort = sortByTable
|
||||
@@ -484,7 +464,6 @@ export default {
|
||||
}
|
||||
const res = await searchCI({
|
||||
q: `_type:${this.typeId}${exp ? `,${exp}` : ''}${fuzzySearch ? `,*${fuzzySearch}*` : ''}`,
|
||||
// q: `${this.mergeQ(queryParams)}${exp ? `,${exp}` : ''}${fuzzySearch ? `,*${fuzzySearch}*` : ''}`,
|
||||
count: this.pageSize,
|
||||
page: this.currentPage,
|
||||
sort,
|
||||
@@ -533,55 +512,17 @@ export default {
|
||||
this.$refs['xTable'].getVxetableRef().setCheckboxRow(rows, true)
|
||||
}
|
||||
},
|
||||
// mergeQ(params) {
|
||||
// let q = `_type:${this.typeId}`
|
||||
// Object.keys(params).forEach((key) => {
|
||||
// if (!['pageNo', 'pageSize', 'sortField', 'sortOrder'].includes(key) && params[key] + '' !== '') {
|
||||
// if (typeof params[key] === 'object' && params[key] && params[key].length > 1) {
|
||||
// q += `,${key}:(${params[key].join(';')})`
|
||||
// } else if (params[key]) {
|
||||
// q += `,${key}:*${params[key]}*`
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// return q
|
||||
// },
|
||||
|
||||
async loadPreferenceAttrList() {
|
||||
const subscribed = await getSubscribeAttributes(this.typeId)
|
||||
this.preferenceAttrList = subscribed.attributes // All columns that have been subscribed
|
||||
},
|
||||
|
||||
onSelectChange() {
|
||||
// const current = records.map((i) => i.ci_id || i._id)
|
||||
|
||||
// const cached = new Set(this.selectedRowKeys)
|
||||
// if (checked) {
|
||||
// current.forEach((i) => {
|
||||
// cached.add(i)
|
||||
// })
|
||||
// } else {
|
||||
// if (row) {
|
||||
// cached.delete(row.ci_id || row._id)
|
||||
// } else {
|
||||
// this.instanceList.map((row) => {
|
||||
// cached.delete(row.ci_id || row._id)
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
const xTable = this.$refs.xTable.getVxetableRef()
|
||||
const records = [...xTable.getCheckboxRecords(), ...xTable.getCheckboxReserveRecords()]
|
||||
this.selectedRowKeys = records.map((i) => i.ci_id || i._id)
|
||||
},
|
||||
onSelectRangeEnd({ records }) {
|
||||
// const current = records.map((i) => i.ci_id || i._id)
|
||||
// const cached = new Set(this.selectedRowKeys)
|
||||
// current.forEach((i) => {
|
||||
// cached.add(i)
|
||||
// })
|
||||
this.selectedRowKeys = records.map((i) => i.ci_id || i._id)
|
||||
|
||||
// this.setSelectRows()
|
||||
},
|
||||
reloadData() {
|
||||
this.loadTableData()
|
||||
@@ -623,7 +564,7 @@ export default {
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
$table.revertData(row)
|
||||
this.loadTableData()
|
||||
})
|
||||
}
|
||||
this.columns.forEach((col) => {
|
||||
@@ -694,12 +635,22 @@ export default {
|
||||
}
|
||||
})
|
||||
this.$refs.create.visible = false
|
||||
const key = 'updatable'
|
||||
let errorMsg = ''
|
||||
for (let i = 0; i < this.selectedRowKeys.length; i++) {
|
||||
await updateCI(this.selectedRowKeys[i], payload, false)
|
||||
.then(() => {
|
||||
successNum += 1
|
||||
})
|
||||
.catch(() => {
|
||||
.catch((error) => {
|
||||
errorMsg = errorMsg + '\n' + `${this.selectedRowKeys[i]}:${error.response?.data?.message ?? ''}`
|
||||
this.$notification.warning({
|
||||
key,
|
||||
message: this.$t('warning'),
|
||||
description: errorMsg,
|
||||
duration: 0,
|
||||
style: { whiteSpace: 'break-spaces' },
|
||||
})
|
||||
errorNum += 1
|
||||
})
|
||||
.finally(() => {
|
||||
|
@@ -24,7 +24,9 @@
|
||||
/>
|
||||
</template>
|
||||
<template v-if="parentsType && parentsType.length">
|
||||
<a-divider style="font-size:14px;margin:14px 0;font-weight:700;">{{ $t('cmdb.menu.citypeRelation') }}</a-divider>
|
||||
<a-divider style="font-size:14px;margin:14px 0;font-weight:700;">{{
|
||||
$t('cmdb.menu.citypeRelation')
|
||||
}}</a-divider>
|
||||
<a-form>
|
||||
<a-row :gutter="24" align="top" type="flex">
|
||||
<a-col :span="12" v-for="item in parentsType" :key="item.id">
|
||||
@@ -40,7 +42,11 @@
|
||||
{{ attr.alias || attr.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-input :placeholder="$t('cmdb.ci.tips1')" v-model="parentsForm[item.name].value" style="width: 50%" />
|
||||
<a-input
|
||||
:placeholder="$t('cmdb.ci.tips1')"
|
||||
v-model="parentsForm[item.name].value"
|
||||
style="width: 50%"
|
||||
/>
|
||||
</a-input-group>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
@@ -60,7 +60,7 @@
|
||||
</span>
|
||||
</template>
|
||||
<template v-else-if="attr.is_list">
|
||||
<span> {{ ci[attr.name].join(',') }}</span>
|
||||
<span> {{ ci[attr.name] && Array.isArray(ci[attr.name]) ? ci[attr.name].join(',') : ci[attr.name] }}</span>
|
||||
</template>
|
||||
<template v-else>{{ getName(ci[attr.name]) }}</template>
|
||||
</span>
|
||||
@@ -105,23 +105,6 @@
|
||||
</span>
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-select
|
||||
:style="{ width: '100%' }"
|
||||
v-decorator="[
|
||||
attr.name,
|
||||
{
|
||||
rules: [{ required: attr.is_required }],
|
||||
},
|
||||
]"
|
||||
:placeholder="$t('placeholder2')"
|
||||
v-else-if="attr.is_list"
|
||||
mode="tags"
|
||||
showSearch
|
||||
allowClear
|
||||
size="small"
|
||||
:getPopupContainer="(trigger) => trigger.parentElement"
|
||||
>
|
||||
</a-select>
|
||||
<a-input-number
|
||||
size="small"
|
||||
v-decorator="[
|
||||
@@ -131,7 +114,7 @@
|
||||
},
|
||||
]"
|
||||
style="width: 100%"
|
||||
v-else-if="attr.value_type === '0' || attr.value_type === '1'"
|
||||
v-else-if="(attr.value_type === '0' || attr.value_type === '1') && !attr.is_list"
|
||||
/>
|
||||
<a-date-picker
|
||||
size="small"
|
||||
@@ -144,22 +127,9 @@
|
||||
style="width: 100%"
|
||||
:format="attr.value_type === '4' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
|
||||
:valueFormat="attr.value_type === '4' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
|
||||
v-else-if="attr.value_type === '4' || attr.value_type === '3'"
|
||||
v-else-if="(attr.value_type === '4' || attr.value_type === '3') && !attr.is_list"
|
||||
:showTime="attr.value_type === '4' ? false : { format: 'HH:mm:ss' }"
|
||||
/>
|
||||
<!-- <a-input
|
||||
size="small"
|
||||
@focus="(e) => handleFocusInput(e, attr)"
|
||||
v-decorator="[
|
||||
attr.name,
|
||||
{
|
||||
validateTrigger: ['submit'],
|
||||
rules: [{ required: attr.is_required }],
|
||||
},
|
||||
]"
|
||||
style="width: 100%"
|
||||
v-else-if="attr.value_type === '6'"
|
||||
/> -->
|
||||
<a-input
|
||||
size="small"
|
||||
v-decorator="[
|
||||
@@ -241,7 +211,9 @@ export default {
|
||||
this.$nextTick(async () => {
|
||||
if (this.attr.is_list && !this.attr.is_choice) {
|
||||
this.form.setFieldsValue({
|
||||
[`${this.attr.name}`]: this.ci[this.attr.name] || null,
|
||||
[`${this.attr.name}`]: Array.isArray(this.ci[this.attr.name])
|
||||
? this.ci[this.attr.name].join(',')
|
||||
: this.ci[this.attr.name],
|
||||
})
|
||||
return
|
||||
}
|
||||
|
@@ -22,7 +22,12 @@
|
||||
attr.name,
|
||||
{
|
||||
rules: [{ required: attr.is_required, message: $t('placeholder2') + `${attr.alias || attr.name}` }],
|
||||
initialValue: attr.default && attr.default.default ? attr.default.default : attr.is_list ? [] : null,
|
||||
initialValue:
|
||||
attr.default && attr.default.default
|
||||
? attr.is_list
|
||||
? attr.default.default.split(',')
|
||||
: attr.default.default
|
||||
: null,
|
||||
},
|
||||
]"
|
||||
:placeholder="$t('placeholder2')"
|
||||
@@ -53,19 +58,18 @@
|
||||
</span>
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-select
|
||||
<a-input
|
||||
v-else-if="attr.is_list"
|
||||
mode="tags"
|
||||
:style="{ width: '100%' }"
|
||||
v-decorator="[
|
||||
attr.name,
|
||||
{
|
||||
rules: [{ required: attr.is_required, message: $t('placeholder2') + `${attr.alias || attr.name}` }],
|
||||
initialValue: attr.default && attr.default.default ? attr.default.default : attr.is_list ? [] : null,
|
||||
initialValue: attr.default && attr.default.default ? attr.default.default : '',
|
||||
},
|
||||
]"
|
||||
>
|
||||
</a-select>
|
||||
</a-input>
|
||||
<a-input-number
|
||||
v-decorator="[
|
||||
attr.name,
|
||||
|
@@ -1,103 +0,0 @@
|
||||
<template>
|
||||
<CustomDrawer
|
||||
:visible="visible"
|
||||
width="600"
|
||||
@close="
|
||||
() => {
|
||||
visible = false
|
||||
}
|
||||
"
|
||||
:title="$t('cmdb.ci.attributeSettings')"
|
||||
>
|
||||
<CustomTransfer
|
||||
ref="customTransfer"
|
||||
:dataSource="attrList"
|
||||
:showSearch="true"
|
||||
:listStyle="{
|
||||
width: '230px',
|
||||
height: '500px',
|
||||
}"
|
||||
:titles="[$t('cmdb.components.unselectAttributes'), $t('cmdb.components.selectAttributes')]"
|
||||
:render="item => item.title"
|
||||
:targetKeys="selectedAttrList"
|
||||
@change="handleChange"
|
||||
@selectChange="selectChange"
|
||||
>
|
||||
<span slot="notFoundContent">{{ $t('noData') }}</span>
|
||||
</CustomTransfer>
|
||||
<div class="custom-drawer-bottom-action">
|
||||
<a-button @click="handleSubmit" type="primary">{{ $t('confirm') }}</a-button>
|
||||
</div>
|
||||
</CustomDrawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { subscribeCIType, getSubscribeAttributes } from '@/modules/cmdb/api/preference'
|
||||
import { getCITypeAttributesByName } from '@/modules/cmdb/api/CITypeAttr'
|
||||
export default {
|
||||
name: 'EditAttrsDrawer',
|
||||
data() {
|
||||
return {
|
||||
attrList: [],
|
||||
typeId: null,
|
||||
visible: false,
|
||||
selectedAttrList: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open(typeId) {
|
||||
this.typeId = typeId
|
||||
this.getAttrs()
|
||||
},
|
||||
getAttrs() {
|
||||
getCITypeAttributesByName(this.typeId).then(res => {
|
||||
const attributes = res.attributes
|
||||
getSubscribeAttributes(this.typeId).then(_res => {
|
||||
const attrList = []
|
||||
const selectedAttrList = []
|
||||
const subAttributes = _res.attributes
|
||||
this.instanceSubscribed = _res.is_subscribed
|
||||
subAttributes.forEach(item => {
|
||||
selectedAttrList.push(item.id.toString())
|
||||
})
|
||||
|
||||
attributes.forEach(item => {
|
||||
const data = {
|
||||
key: item.id.toString(),
|
||||
title: item.alias || item.name,
|
||||
}
|
||||
attrList.push(data)
|
||||
})
|
||||
|
||||
this.attrList = attrList
|
||||
this.selectedAttrList = selectedAttrList
|
||||
this.visible = true
|
||||
})
|
||||
})
|
||||
},
|
||||
handleChange(targetKeys, direction, moveKeys) {
|
||||
this.selectedAttrList = targetKeys
|
||||
},
|
||||
handleSubmit() {
|
||||
const that = this
|
||||
if (this.selectedAttrList.length) {
|
||||
subscribeCIType(this.typeId, this.selectedAttrList).then(res => {
|
||||
this.$message.success(this.$t('cmdb.components.subSuccess'))
|
||||
this.visible = false
|
||||
this.$emit('refresh')
|
||||
})
|
||||
} else {
|
||||
this.$confirm({
|
||||
title: that.$t('warning'),
|
||||
content: that.$t('cmdb.ci.tips4'),
|
||||
})
|
||||
}
|
||||
},
|
||||
selectChange(sourceSelectedKeys, targetSelectedKeys) {
|
||||
this.$refs.customTransfer.dbClick(sourceSelectedKeys, targetSelectedKeys, 'title', 'key')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
@@ -1 +0,0 @@
|
||||
editAttrsDrawer 这个文件似乎也没用了
|
@@ -13,7 +13,11 @@
|
||||
<a-form :form="form" :layout="formLayout">
|
||||
<a-divider style="font-size:14px;margin-top:6px;">{{ $t('cmdb.ciType.basicConfig') }}</a-divider>
|
||||
<a-col :span="12">
|
||||
<a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" :label="$t('cmdb.ciType.AttributeName')">
|
||||
<a-form-item
|
||||
:label-col="formItemLayout.labelCol"
|
||||
:wrapper-col="formItemLayout.wrapperCol"
|
||||
:label="$t('cmdb.ciType.AttributeName')"
|
||||
>
|
||||
<a-input
|
||||
:disabled="true"
|
||||
name="name"
|
||||
@@ -35,12 +39,20 @@
|
||||
</a-col>
|
||||
<a-col
|
||||
:span="12"
|
||||
><a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" :label="$t('alias')">
|
||||
><a-form-item
|
||||
:label-col="formItemLayout.labelCol"
|
||||
:wrapper-col="formItemLayout.wrapperCol"
|
||||
:label="$t('alias')"
|
||||
>
|
||||
<a-input name="alias" v-decorator="['alias', { rules: [] }]" /> </a-form-item
|
||||
></a-col>
|
||||
<a-col
|
||||
:span="12"
|
||||
><a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" :label="$t('cmdb.ciType.DataType')">
|
||||
><a-form-item
|
||||
:label-col="formItemLayout.labelCol"
|
||||
:wrapper-col="formItemLayout.wrapperCol"
|
||||
:label="$t('cmdb.ciType.DataType')"
|
||||
>
|
||||
<a-select
|
||||
:disabled="true"
|
||||
name="value_type"
|
||||
@@ -59,13 +71,12 @@
|
||||
:label="$t('cmdb.ciType.defaultValue')"
|
||||
>
|
||||
<template>
|
||||
<a-select
|
||||
<a-input
|
||||
v-if="form.getFieldValue('is_list')"
|
||||
mode="tags"
|
||||
:style="{ width: '100%' }"
|
||||
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
||||
>
|
||||
</a-select>
|
||||
</a-input>
|
||||
<a-select
|
||||
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
||||
mode="tags"
|
||||
@@ -160,7 +171,11 @@
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
||||
<a-form-item :label-col="{ span: 8 }" :wrapper-col="horizontalFormItemLayout.wrapperCol" :label="$t('cmdb.ciType.unique')">
|
||||
<a-form-item
|
||||
:label-col="{ span: 8 }"
|
||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||
:label="$t('cmdb.ciType.unique')"
|
||||
>
|
||||
<a-switch
|
||||
:disabled="isShowComputedArea"
|
||||
@change="onChange"
|
||||
@@ -282,6 +297,11 @@
|
||||
</a-col>
|
||||
<a-divider style="font-size:14px;margin-top:6px;">{{ $t('cmdb.ciType.advancedSettings') }}</a-divider>
|
||||
<a-row>
|
||||
<a-col :span="24" v-if="!['6'].includes(currentValueType)">
|
||||
<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()" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.font')">
|
||||
<FontArea ref="fontArea" />
|
||||
@@ -303,11 +323,7 @@
|
||||
<span
|
||||
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
|
||||
style="position:absolute;top:3px;left:-17px;color:#2f54eb;"
|
||||
type="question-circle"
|
||||
@@ -355,6 +371,8 @@ import _ from 'lodash'
|
||||
import moment from 'moment'
|
||||
import vueJsonEditor from 'vue-json-editor'
|
||||
import {
|
||||
// createAttribute,
|
||||
// createCITypeAttributes,
|
||||
updateAttributeById,
|
||||
updateCITypeAttributesById,
|
||||
canDefineComputed,
|
||||
@@ -364,10 +382,11 @@ import { valueTypeMap } from '../../utils/const'
|
||||
import ComputedArea from './computedArea.vue'
|
||||
import PreValueArea from './preValueArea.vue'
|
||||
import FontArea from './fontArea.vue'
|
||||
import RegSelect from '@/components/RegexSelect'
|
||||
|
||||
export default {
|
||||
name: 'AttributeEditForm',
|
||||
components: { ComputedArea, PreValueArea, vueJsonEditor, FontArea },
|
||||
components: { ComputedArea, PreValueArea, vueJsonEditor, FontArea, RegSelect },
|
||||
props: {
|
||||
CITypeId: {
|
||||
type: Number,
|
||||
@@ -395,6 +414,7 @@ export default {
|
||||
isShowComputedArea: false,
|
||||
|
||||
defaultForDatetime: '',
|
||||
re_check: {},
|
||||
}
|
||||
},
|
||||
|
||||
@@ -517,15 +537,30 @@ export default {
|
||||
})
|
||||
}
|
||||
console.log(_record)
|
||||
if (!['6'].includes(_record.value_type) && _record.re_check) {
|
||||
this.re_check = {
|
||||
value: _record.re_check,
|
||||
}
|
||||
} else {
|
||||
this.re_check = {}
|
||||
}
|
||||
if (_record.default) {
|
||||
this.$nextTick(() => {
|
||||
if (_record.value_type === '0') {
|
||||
this.form.setFieldsValue({
|
||||
default_value: _record.default.default ? [_record.default.default] : [],
|
||||
})
|
||||
if (_record.is_list) {
|
||||
this.$nextTick(() => {
|
||||
this.form.setFieldsValue({
|
||||
default_value: _record.default.default ? _record.default.default : '',
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.form.setFieldsValue({
|
||||
default_value: _record.default.default ? [_record.default.default] : [],
|
||||
})
|
||||
}
|
||||
} else if (_record.value_type === '6') {
|
||||
this.default_value_json = _record?.default?.default || null
|
||||
} else if (_record.value_type === '3' || _record.value_type === '4') {
|
||||
} else if ((_record.value_type === '3' || _record.value_type === '4') && !_record.is_list) {
|
||||
if (_record?.default?.default === '$created_at' || _record?.default?.default === '$updated_at') {
|
||||
this.defaultForDatetime = _record.default.default
|
||||
this.form.setFieldsValue({
|
||||
@@ -584,6 +619,9 @@ export default {
|
||||
await this.form.validateFields(async (err, values) => {
|
||||
if (!err) {
|
||||
console.log('Received values of form: ', values)
|
||||
// if (values.choice_value) {
|
||||
// values.choice_value = values.choice_value.split('\n')
|
||||
// }
|
||||
|
||||
if (this.record.is_required !== values.is_required || this.record.default_show !== values.default_show) {
|
||||
console.log('changed is_required')
|
||||
@@ -598,7 +636,11 @@ export default {
|
||||
delete values['is_required']
|
||||
const { default_value } = values
|
||||
if (values.value_type === '0' && default_value) {
|
||||
values.default = { default: default_value[0] || null }
|
||||
if (values.is_list) {
|
||||
values.default = { default: default_value || null }
|
||||
} else {
|
||||
values.default = { default: default_value[0] || null }
|
||||
}
|
||||
} else if (values.value_type === '6') {
|
||||
if (this.default_value_json_right) {
|
||||
values.default = { default: this.default_value_json }
|
||||
@@ -606,13 +648,13 @@ export default {
|
||||
values.default = { default: null }
|
||||
}
|
||||
} else if (default_value || default_value === 0) {
|
||||
if (values.value_type === '3') {
|
||||
if (values.value_type === '3' && !values.is_list) {
|
||||
if (default_value === '$created_at' || default_value === '$updated_at') {
|
||||
values.default = { default: default_value }
|
||||
} else {
|
||||
values.default = { default: moment(default_value).format('YYYY-MM-DD HH:mm:ss') }
|
||||
}
|
||||
} else if (values.value_type === '4') {
|
||||
} else if (values.value_type === '4' && !values.is_list) {
|
||||
values.default = { default: moment(default_value).format('YYYY-MM-DD') }
|
||||
} else {
|
||||
values.default = { default: default_value }
|
||||
@@ -641,6 +683,9 @@ export default {
|
||||
values.value_type = '2'
|
||||
values.is_link = true
|
||||
}
|
||||
if (values.value_type !== '6') {
|
||||
values.re_check = this.re_check?.value ?? null
|
||||
}
|
||||
if (values.id) {
|
||||
await this.updateAttribute(values.id, { ...values, option: { fontOptions } }, isCalcComputed)
|
||||
} else {
|
||||
@@ -698,6 +743,21 @@ export default {
|
||||
async handleCalcComputed() {
|
||||
await this.handleSubmit(true)
|
||||
},
|
||||
getLimitedFormat() {
|
||||
if (['0'].includes(this.currentValueType)) {
|
||||
return ['number', 'phone', 'landline', 'zipCode', 'IDCard', 'monetaryAmount', 'custom']
|
||||
}
|
||||
if (['1'].includes(this.currentValueType)) {
|
||||
return ['number', 'monetaryAmount', 'custom']
|
||||
}
|
||||
if (['3', '4', '5'].includes(this.currentValueType)) {
|
||||
return ['custom']
|
||||
}
|
||||
if (this.currentValueType === '8') {
|
||||
return ['link', 'custom']
|
||||
}
|
||||
return []
|
||||
},
|
||||
},
|
||||
watch: {},
|
||||
}
|
||||
|
@@ -21,7 +21,10 @@
|
||||
message: $t('cmdb.ciType.attributeNameTips'),
|
||||
pattern: RegExp('^(?!\\d)[a-zA-Z_0-9]+$'),
|
||||
},
|
||||
{ message: $t('cmdb.ciType.buildinAttribute'), pattern: RegExp('^(?!(id|_id|ci_id|type|_type|ci_type)$).*$') },
|
||||
{
|
||||
message: $t('cmdb.ciType.buildinAttribute'),
|
||||
pattern: RegExp('^(?!(id|_id|ci_id|type|_type|ci_type)$).*$'),
|
||||
},
|
||||
],
|
||||
},
|
||||
]"
|
||||
@@ -59,13 +62,12 @@
|
||||
:label="$t('cmdb.ciType.defaultValue')"
|
||||
>
|
||||
<template>
|
||||
<a-select
|
||||
<a-input
|
||||
v-if="form.getFieldValue('is_list')"
|
||||
mode="tags"
|
||||
:style="{ width: '100%' }"
|
||||
v-decorator="['default_value', { rules: [{ required: false }] }]"
|
||||
>
|
||||
</a-select>
|
||||
</a-input>
|
||||
<a-input-number
|
||||
style="width: 100%"
|
||||
v-else-if="currentValueType === '1'"
|
||||
@@ -162,7 +164,11 @@
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6" v-if="currentValueType !== '6' && currentValueType !== '7'">
|
||||
<a-form-item :label-col="{ span: 8 }" :wrapper-col="horizontalFormItemLayout.wrapperCol" :label="$t('cmdb.ciType.unique')">
|
||||
<a-form-item
|
||||
:label-col="{ span: 8 }"
|
||||
:wrapper-col="horizontalFormItemLayout.wrapperCol"
|
||||
:label="$t('cmdb.ciType.unique')"
|
||||
>
|
||||
<a-switch
|
||||
:disabled="isShowComputedArea"
|
||||
@change="onChange"
|
||||
@@ -280,6 +286,11 @@
|
||||
</a-col>
|
||||
<a-divider style="font-size:14px;margin-top:6px;">{{ $t('cmdb.ciType.advancedSettings') }}</a-divider>
|
||||
<a-row>
|
||||
<a-col :span="24" v-if="!['6'].includes(currentValueType)">
|
||||
<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()" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }" :label="$t('cmdb.ciType.font')">
|
||||
<FontArea ref="fontArea" />
|
||||
@@ -296,11 +307,7 @@
|
||||
<span
|
||||
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
|
||||
style="position:absolute;top:3px;left:-17px;color:#2f54eb;"
|
||||
type="question-circle"
|
||||
@@ -340,6 +347,7 @@ import { valueTypeMap } from '../../utils/const'
|
||||
import ComputedArea from './computedArea.vue'
|
||||
import PreValueArea from './preValueArea.vue'
|
||||
import FontArea from './fontArea.vue'
|
||||
import RegSelect from '@/components/RegexSelect'
|
||||
|
||||
export default {
|
||||
name: 'CreateNewAttribute',
|
||||
@@ -348,6 +356,7 @@ export default {
|
||||
PreValueArea,
|
||||
vueJsonEditor,
|
||||
FontArea,
|
||||
RegSelect,
|
||||
},
|
||||
props: {
|
||||
hasFooter: {
|
||||
@@ -374,6 +383,8 @@ export default {
|
||||
isShowComputedArea: false,
|
||||
|
||||
defaultForDatetime: '',
|
||||
|
||||
re_check: {},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -397,8 +408,12 @@ export default {
|
||||
const data = { is_required, default_show }
|
||||
delete values.is_required
|
||||
delete values.default_show
|
||||
if (values.value_type === '0' && default_value && default_value.length) {
|
||||
values.default = { default: default_value[0] }
|
||||
if (values.value_type === '0' && default_value) {
|
||||
if (values.is_list) {
|
||||
values.default = { default: default_value || null }
|
||||
} else {
|
||||
values.default = { default: default_value[0] || null }
|
||||
}
|
||||
} else if (values.value_type === '6') {
|
||||
if (this.default_value_json_right) {
|
||||
values.default = { default: this.default_value_json }
|
||||
@@ -406,13 +421,13 @@ export default {
|
||||
values.default = { default: null }
|
||||
}
|
||||
} else if (default_value || default_value === 0) {
|
||||
if (values.value_type === '3') {
|
||||
if (values.value_type === '3' && !values.is_list) {
|
||||
if (default_value === '$created_at' || default_value === '$updated_at') {
|
||||
values.default = { default: default_value }
|
||||
} else {
|
||||
values.default = { default: moment(default_value).format('YYYY-MM-DD HH:mm:ss') }
|
||||
}
|
||||
} else if (values.value_type === '4') {
|
||||
} else if (values.value_type === '4' && !values.is_list) {
|
||||
values.default = { default: moment(default_value).format('YYYY-MM-DD') }
|
||||
} else {
|
||||
values.default = { default: default_value }
|
||||
@@ -449,6 +464,9 @@ export default {
|
||||
values.value_type = '2'
|
||||
values.is_link = true
|
||||
}
|
||||
if (values.value_type !== '6') {
|
||||
values.re_check = this.re_check?.value ?? null
|
||||
}
|
||||
const { attr_id } = await createAttribute({ ...values, option: { fontOptions } })
|
||||
|
||||
this.form.resetFields()
|
||||
@@ -539,6 +557,21 @@ export default {
|
||||
default_value: key,
|
||||
})
|
||||
},
|
||||
getLimitedFormat() {
|
||||
if (['0'].includes(this.currentValueType)) {
|
||||
return ['number', 'phone', 'landline', 'zipCode', 'IDCard', 'monetaryAmount', 'custom']
|
||||
}
|
||||
if (['1'].includes(this.currentValueType)) {
|
||||
return ['number', 'monetaryAmount', 'custom']
|
||||
}
|
||||
if (['3', '4', '5'].includes(this.currentValueType)) {
|
||||
return ['custom']
|
||||
}
|
||||
if (this.currentValueType === '8') {
|
||||
return ['link', 'custom']
|
||||
}
|
||||
return []
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
@@ -37,7 +37,7 @@
|
||||
>{{ $t('cmdb.ciType.attributeLibray') }}</a
|
||||
>
|
||||
<a-dropdown v-if="permissions.includes('admin') || permissions.includes('cmdb_admin')">
|
||||
<a><ops-icon type="ops-menu" /></a>
|
||||
<a><ops-icon type="ops-menu"/></a>
|
||||
<a-menu slot="overlay">
|
||||
<a-menu-item key="0">
|
||||
<a-upload
|
||||
@@ -48,12 +48,15 @@
|
||||
action="/api/v0.1/ci_types/template/import/file"
|
||||
@change="changeUploadFile"
|
||||
>
|
||||
<a><a-icon type="upload" /></a><a> {{ $t('upload') }}</a>
|
||||
<a><a-icon type="upload"/></a><a> {{ $t('upload') }}</a>
|
||||
</a-upload>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="1">
|
||||
<a-space>
|
||||
<a href="/api/v0.1/ci_types/template/export/file"><a-icon type="download" /> {{ $t('download') }}</a>
|
||||
<a
|
||||
href="/api/v0.1/ci_types/template/export/file"
|
||||
><a-icon type="download" /> {{ $t('download') }}</a
|
||||
>
|
||||
</a-space>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
@@ -63,9 +66,11 @@
|
||||
<draggable class="ci-types-left-content" :list="CITypeGroups" @end="handleChangeGroups" filter=".undraggable">
|
||||
<div v-for="g in CITypeGroups" :key="g.id || g.name">
|
||||
<div
|
||||
:class="`${currentGId === g.id && !currentCId ? 'selected' : ''} ci-types-left-group ${
|
||||
g.id === -1 ? 'undraggable' : ''
|
||||
}`"
|
||||
:class="
|
||||
`${currentGId === g.id && !currentCId ? 'selected' : ''} ci-types-left-group ${
|
||||
g.id === -1 ? 'undraggable' : ''
|
||||
}`
|
||||
"
|
||||
@click="handleClickGroup(g.id)"
|
||||
>
|
||||
<div>
|
||||
@@ -78,16 +83,16 @@
|
||||
<a-space>
|
||||
<a-tooltip>
|
||||
<template slot="title">{{ $t('cmdb.ciType.addCITypeInGroup') }}</template>
|
||||
<a><a-icon type="plus" @click="handleCreate(g)" /></a>
|
||||
<a><a-icon type="plus" @click="handleCreate(g)"/></a>
|
||||
</a-tooltip>
|
||||
<template v-if="g.id !== -1">
|
||||
<a-tooltip>
|
||||
<template slot="title">{{ $t('cmdb.ciType.editGroup') }}</template>
|
||||
<a><a-icon type="edit" @click="handleEditGroup(g)" /></a>
|
||||
<a><a-icon type="edit" @click="handleEditGroup(g)"/></a>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template slot="title">{{ $t('cmdb.ciType.deleteGroup') }}</template>
|
||||
<a style="color: red"><a-icon type="delete" @click="handleDeleteGroup(g)" /></a>
|
||||
<a style="color: red"><a-icon type="delete" @click="handleDeleteGroup(g)"/></a>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</a-space>
|
||||
@@ -130,14 +135,15 @@
|
||||
</div>
|
||||
<span class="ci-types-left-detail-title">{{ ci.alias || ci.name }}</span>
|
||||
<a-space class="ci-types-left-detail-action">
|
||||
<a><a-icon type="user-add" @click="(e) => handlePerm(e, ci)" /></a>
|
||||
<a><a-icon type="edit" @click="(e) => handleEdit(e, ci)" /></a>
|
||||
<a><a-icon type="user-add" @click="(e) => handlePerm(e, ci)"/></a>
|
||||
<a><a-icon type="edit" @click="(e) => handleEdit(e, ci)"/></a>
|
||||
<a
|
||||
v-if="permissions.includes('admin') || permissions.includes('cmdb_admin')"
|
||||
@click="(e) => handleDownloadCiType(e, ci)">
|
||||
<a-icon type="download"/>
|
||||
@click="(e) => handleDownloadCiType(e, ci)"
|
||||
>
|
||||
<a-icon type="download" />
|
||||
</a>
|
||||
<a style="color: red" @click="(e) => handleDelete(e, ci)"><a-icon type="delete" /></a>
|
||||
<a style="color: red" @click="(e) => handleDelete(e, ci)"><a-icon type="delete"/></a>
|
||||
</a-space>
|
||||
</div>
|
||||
</draggable>
|
||||
@@ -242,6 +248,11 @@
|
||||
:filter-method="filterOption"
|
||||
v-decorator="['unique_key', { rules: [{ required: true, message: $t('cmdb.ciType.uniqueKeySelect') }] }]"
|
||||
:placeholder="$t('placeholder2')"
|
||||
@visible-change="
|
||||
() => {
|
||||
filterInput = ''
|
||||
}
|
||||
"
|
||||
>
|
||||
<el-option
|
||||
:key="item.id"
|
||||
@@ -549,6 +560,7 @@ export default {
|
||||
})
|
||||
},
|
||||
onClose() {
|
||||
this.filterInput = ''
|
||||
this.form.resetFields()
|
||||
this.drawerVisible = false
|
||||
},
|
||||
@@ -739,7 +751,7 @@ export default {
|
||||
const x = new XMLHttpRequest()
|
||||
x.open('GET', `/api/v0.1/ci_types/${ci.id}/template/export`, true)
|
||||
x.responseType = 'blob'
|
||||
x.onload = function (e) {
|
||||
x.onload = function(e) {
|
||||
const url = window.URL.createObjectURL(x.response)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
|
@@ -79,7 +79,7 @@
|
||||
<vxe-column
|
||||
align="center"
|
||||
field="is_accept"
|
||||
:title="$t('cmdb.ad.isAccpet')"
|
||||
:title="$t('cmdb.ad.isAccept')"
|
||||
v-bind="columns.length ? { width: '100px' } : { minWidth: '100px' }"
|
||||
:filters="[
|
||||
{ label: $t('yes'), value: true },
|
||||
@@ -92,7 +92,7 @@
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
field="accept_by"
|
||||
:title="$t('cmdb.ad.accpetBy')"
|
||||
:title="$t('cmdb.ad.acceptBy')"
|
||||
v-bind="columns.length ? { width: '80px' } : { minWidth: '80px' }"
|
||||
:filters="[]"
|
||||
></vxe-column>
|
||||
@@ -186,8 +186,8 @@ export default {
|
||||
this.clickSidebar(Number(_currentType))
|
||||
return
|
||||
}
|
||||
if (res && res.length) {
|
||||
this.clickSidebar(res[0].id)
|
||||
if (res && res.length && res[0].ci_types && res[0].ci_types.length) {
|
||||
this.clickSidebar(res[0].ci_types[0].id)
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -246,7 +246,7 @@ export default {
|
||||
content: that.$t('cmdb.ad.confirmAccept'),
|
||||
onOk() {
|
||||
updateADCAccept(row.id).then(() => {
|
||||
that.$message.success(that.$t('cmdb.ad.accpetSuccess'))
|
||||
that.$message.success(that.$t('cmdb.ad.acceptSuccess'))
|
||||
that.getAdc(false)
|
||||
})
|
||||
},
|
||||
|
@@ -102,7 +102,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import Pager from './pager.vue'
|
||||
import Pager from '@/components/Pager'
|
||||
import SearchForm from './searchForm.vue'
|
||||
import { getCIHistoryTable, getUsers } from '@/modules/cmdb/api/history'
|
||||
import { getCITypes } from '@/modules/cmdb/api/CIType'
|
||||
|
@@ -1,116 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-row class="row" type="flex" justify="end">
|
||||
<a-col>
|
||||
<a-space align="end">
|
||||
<a-button class="left-button" size="small" :disabled="prevIsDisabled" @click="prevPage"><a-icon type="left" /></a-button>
|
||||
<a-button class="page-button" size="small" >{{ currentPage }}</a-button>
|
||||
<a-button class="right-button" size="small" :disabled="nextIsDisabled" @click="nextPage"><a-icon type="right" /></a-button>
|
||||
<a-dropdown class="dropdown" placement="topCenter" :trigger="['click']" :disabled="dropdownIsDisabled">
|
||||
<a-menu slot="overlay">
|
||||
<a-menu-item v-for="(size,index) in pageSizes" :key="index" @click="handleItemClick(size)">
|
||||
{{ size }}{{ $t('cmdb.history.itemsPerPage') }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
<a-button size="small"> {{ pageSize }}{{ $t('cmdb.history.itemsPerPage') }} <a-icon type="down" /> </a-button>
|
||||
</a-dropdown>
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
currentPage: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
pageSize: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
pageSizes: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dropdownIsDisabled: false,
|
||||
prevIsDisabled: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
nextIsDisabled() {
|
||||
return this.isLoading || this.total < this.pageSize
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isLoading: {
|
||||
immediate: true,
|
||||
handler: function (val) {
|
||||
if (val === true) {
|
||||
this.dropdownIsDisabled = true
|
||||
this.prevIsDisabled = true
|
||||
} else {
|
||||
this.dropdownIsDisabled = false
|
||||
if (this.currentPage === 1) {
|
||||
this.prevIsDisabled = true
|
||||
} else {
|
||||
this.prevIsDisabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
currentPage: {
|
||||
immediate: true,
|
||||
handler: function (val) {
|
||||
if (val === 1) {
|
||||
this.prevIsDisabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleItemClick(size) {
|
||||
this.$emit('showSizeChange', size)
|
||||
},
|
||||
nextPage() {
|
||||
const pageNum = this.currentPage + 1
|
||||
this.$emit('change', pageNum)
|
||||
},
|
||||
prevPage() {
|
||||
const pageNum = this.currentPage - 1
|
||||
this.$emit('change', pageNum)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.row{
|
||||
margin-top: 5px;
|
||||
.left-button{
|
||||
padding: 0;
|
||||
width: 24px;
|
||||
}
|
||||
.right-button{
|
||||
padding: 0;
|
||||
width: 24px;
|
||||
}
|
||||
.page-button{
|
||||
padding: 0;
|
||||
width: 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -134,7 +134,7 @@
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import SearchForm from './searchForm'
|
||||
import Pager from './pager.vue'
|
||||
import Pager from '@/components/Pager'
|
||||
import { getCITypes } from '@/modules/cmdb/api/CIType'
|
||||
import { getRelationTable, getUsers } from '@/modules/cmdb/api/history'
|
||||
import { getRelationTypes } from '@/modules/cmdb/api/relationType'
|
||||
|
@@ -5,7 +5,7 @@
|
||||
<span class="cmdb-preference-left-card-title">{{ $t('cmdb.preference.mySub') }}</span>
|
||||
<span
|
||||
class="cmdb-preference-left-card-content"
|
||||
><ops-icon type="cmdb-ci" :style="{ marginRight: '5px' }" />{{ $t('cmdb.menu.ciTable') }}:
|
||||
><ops-icon type="cmdb-ci" :style="{ marginRight: '5px' }"/>{{ $t('cmdb.menu.ciTable') }}:
|
||||
<a-badge
|
||||
showZero
|
||||
:count="self.instance.length"
|
||||
@@ -16,11 +16,10 @@
|
||||
height: '23px',
|
||||
fontSize: '14px',
|
||||
}"
|
||||
/></span
|
||||
>
|
||||
/></span>
|
||||
<span
|
||||
class="cmdb-preference-left-card-content"
|
||||
><ops-icon type="cmdb-tree" :style="{ marginRight: '5px' }" />{{ $t('cmdb.menu.ciTree') }}:
|
||||
><ops-icon type="cmdb-tree" :style="{ marginRight: '5px' }"/>{{ $t('cmdb.menu.ciTree') }}:
|
||||
<a-badge
|
||||
showZero
|
||||
:count="self.tree.length"
|
||||
@@ -31,57 +30,67 @@
|
||||
height: '23px',
|
||||
fontSize: '14px',
|
||||
}"
|
||||
/></span
|
||||
>
|
||||
/></span>
|
||||
</div>
|
||||
<div class="cmdb-preference-group" v-for="(group, index) in myPreferences" :key="group.name">
|
||||
<div class="cmdb-preference-group-title">
|
||||
<span> <ops-icon :style="{ marginRight: '10px' }" :type="group.icon" />{{ group.name }} </span>
|
||||
</div>
|
||||
<div class="cmdb-preference-group-content" v-for="ciType in group.ci_types" :key="ciType.id">
|
||||
<div
|
||||
:class="{
|
||||
'cmdb-preference-avatar': true,
|
||||
'cmdb-preference-avatar-noicon': !ciType.icon,
|
||||
'cmdb-preference-avatar-noicon-is_subscribed': !ciType.icon && ciType.is_subscribed,
|
||||
}"
|
||||
:style="{ width: '30px', height: '30px', marginRight: '10px' }"
|
||||
>
|
||||
<template v-if="ciType.icon">
|
||||
<img
|
||||
v-if="ciType.icon.split('$$')[2]"
|
||||
:src="`/api/common-setting/v1/file/${ciType.icon.split('$$')[3]}`"
|
||||
:style="{ maxHeight: '30px', maxWidth: '30px' }"
|
||||
/>
|
||||
<ops-icon
|
||||
v-else
|
||||
:style="{
|
||||
color: ciType.icon.split('$$')[1],
|
||||
fontSize: '14px',
|
||||
}"
|
||||
:type="ciType.icon.split('$$')[0]"
|
||||
/>
|
||||
</template>
|
||||
<span v-else :style="{ fontSize: '20px' }">{{ ciType.name[0].toUpperCase() }}</span>
|
||||
<draggable
|
||||
v-model="group.ci_types"
|
||||
:animation="300"
|
||||
@change="
|
||||
(e) => {
|
||||
orderChange(e, group)
|
||||
}
|
||||
"
|
||||
>
|
||||
<div class="cmdb-preference-group-content" v-for="ciType in group.ci_types" :key="ciType.id">
|
||||
<OpsMoveIcon class="cmdb-preference-move-icon" />
|
||||
<div
|
||||
:class="{
|
||||
'cmdb-preference-avatar': true,
|
||||
'cmdb-preference-avatar-noicon': !ciType.icon,
|
||||
'cmdb-preference-avatar-noicon-is_subscribed': !ciType.icon && ciType.is_subscribed,
|
||||
}"
|
||||
:style="{ width: '30px', height: '30px', marginRight: '10px' }"
|
||||
>
|
||||
<template v-if="ciType.icon">
|
||||
<img
|
||||
v-if="ciType.icon.split('$$')[2]"
|
||||
:src="`/api/common-setting/v1/file/${ciType.icon.split('$$')[3]}`"
|
||||
:style="{ maxHeight: '30px', maxWidth: '30px' }"
|
||||
/>
|
||||
<ops-icon
|
||||
v-else
|
||||
:style="{
|
||||
color: ciType.icon.split('$$')[1],
|
||||
fontSize: '14px',
|
||||
}"
|
||||
:type="ciType.icon.split('$$')[0]"
|
||||
/>
|
||||
</template>
|
||||
<span v-else :style="{ fontSize: '20px' }">{{ ciType.name[0].toUpperCase() }}</span>
|
||||
</div>
|
||||
<span class="cmdb-preference-group-content-title">{{ ciType.alias || ciType.name }}</span>
|
||||
<span class="cmdb-preference-group-content-action">
|
||||
<a-tooltip :title="$t('cmdb.preference.cancelSub')">
|
||||
<span
|
||||
@click="unsubscribe(ciType, group.type)"
|
||||
><ops-icon type="cmdb-preference-cancel-subscribe" />
|
||||
</span>
|
||||
</a-tooltip>
|
||||
<a-divider type="vertical" :style="{ margin: '0 3px' }" />
|
||||
<a-tooltip :title="$t('cmdb.preference.editSub')">
|
||||
<span
|
||||
@click="openSubscribeSetting(ciType, `${index + 1}`)"
|
||||
><ops-icon
|
||||
type="cmdb-preference-subscribe"
|
||||
/></span>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
<span class="cmdb-preference-group-content-title">{{ ciType.alias || ciType.name }}</span>
|
||||
<span class="cmdb-preference-group-content-action">
|
||||
<a-tooltip :title="$t('cmdb.preference.cancelSub')">
|
||||
<span
|
||||
@click="unsubscribe(ciType, group.type)"
|
||||
><ops-icon type="cmdb-preference-cancel-subscribe" />
|
||||
</span>
|
||||
</a-tooltip>
|
||||
<a-divider type="vertical" :style="{ margin: '0 3px' }" />
|
||||
<a-tooltip :title="$t('cmdb.preference.editSub')">
|
||||
<span
|
||||
@click="openSubscribeSetting(ciType, `${index + 1}`)"
|
||||
><ops-icon
|
||||
type="cmdb-preference-subscribe"
|
||||
/></span>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</draggable>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cmdb-preference-right">
|
||||
@@ -124,19 +133,12 @@
|
||||
>
|
||||
</div>
|
||||
<div class="cmdb-preference-colleague">
|
||||
<template v-if="type_id2users[item.id] && type_id2users[item.id].length">
|
||||
<span
|
||||
>{{ type_id2users[item.id].length > 99 ? '99+' : type_id2users[item.id].length
|
||||
}}{{ $t('cmdb.preference.peopleSub') }}</span
|
||||
>
|
||||
<span class="cmdb-preference-colleague-name">
|
||||
<span v-for="uid in type_id2users[item.id].slice(0, 4)" :key="uid">
|
||||
{{ getNameByUid(uid) }}
|
||||
</span>
|
||||
<span class="cmdb-preference-colleague-ellipsis" v-if="type_id2users[item.id].length > 4">...</span>
|
||||
</span>
|
||||
</template>
|
||||
<span v-else :style="{ marginLeft: 'auto' }">{{ $t('cmdb.preference.noSub') }}</span>
|
||||
<span
|
||||
v-if="type_id2users[item.id] && type_id2users[item.id].length"
|
||||
>{{ type_id2users[item.id].length > 99 ? '99+' : type_id2users[item.id].length
|
||||
}}{{ $t('cmdb.preference.peopleSub') }}</span
|
||||
>
|
||||
<span v-else>{{ $t('cmdb.preference.noSub') }}</span>
|
||||
</div>
|
||||
<div class="cmdb-preference-progress">
|
||||
<div class="cmdb-preference-progress-info">
|
||||
@@ -190,15 +192,23 @@ import router, { resetRouter } from '@/router'
|
||||
import store from '@/store'
|
||||
import { mapState } from 'vuex'
|
||||
import moment from 'moment'
|
||||
import draggable from 'vuedraggable'
|
||||
import { getCITypeGroups } from '../../api/ciTypeGroup'
|
||||
import { getPreference, getPreference2, subscribeCIType, subscribeTreeView } from '@/modules/cmdb/api/preference'
|
||||
import {
|
||||
getPreference,
|
||||
getPreference2,
|
||||
subscribeCIType,
|
||||
subscribeTreeView,
|
||||
preferenceCitypeOrder,
|
||||
} from '@/modules/cmdb/api/preference'
|
||||
import CollapseTransition from '@/components/CollapseTransition'
|
||||
import SubscribeSetting from '../../components/subscribeSetting/subscribeSetting'
|
||||
import { getCIAdcStatistics } from '../../api/ci'
|
||||
import { ops_move_icon as OpsMoveIcon } from '@/core/icons'
|
||||
|
||||
export default {
|
||||
name: 'Preference',
|
||||
components: { CollapseTransition, SubscribeSetting },
|
||||
components: { CollapseTransition, SubscribeSetting, draggable, OpsMoveIcon },
|
||||
data() {
|
||||
return {
|
||||
citypeData: [],
|
||||
@@ -214,7 +224,6 @@ export default {
|
||||
computed: {
|
||||
...mapState({
|
||||
windowHeight: (state) => state.windowHeight,
|
||||
allUsers: (state) => state.user.allUsers,
|
||||
}),
|
||||
},
|
||||
mounted() {
|
||||
@@ -277,10 +286,6 @@ export default {
|
||||
}, 300)
|
||||
}
|
||||
},
|
||||
getNameByUid(uid) {
|
||||
const _find = this.allUsers.find((item) => item.uid === uid)
|
||||
return _find?.username[0].toUpperCase() || 'A'
|
||||
},
|
||||
getsubscribedDays(item) {
|
||||
const subscribedTime = this.self.type_id2subs_time[item.id]
|
||||
moment.duration(moment().diff(moment(subscribedTime)))
|
||||
@@ -351,6 +356,17 @@ export default {
|
||||
this.expandKeys.push(group.id)
|
||||
}
|
||||
},
|
||||
orderChange(e, group) {
|
||||
preferenceCitypeOrder({ type_ids: group.ci_types.map((type) => type.id), is_tree: group.type !== 'ci' })
|
||||
.then(() => {
|
||||
if (group.type === 'ci') {
|
||||
this.resetRoute()
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.getCITypes(false)
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -426,7 +442,7 @@ export default {
|
||||
align-items: center;
|
||||
height: 45px;
|
||||
padding: 0 8px;
|
||||
cursor: default;
|
||||
cursor: move;
|
||||
justify-content: flex-start;
|
||||
&:hover {
|
||||
background: #ffffff;
|
||||
@@ -437,6 +453,15 @@ export default {
|
||||
white-space: nowrap;
|
||||
margin-left: auto;
|
||||
}
|
||||
.cmdb-preference-move-icon {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
.cmdb-preference-move-icon {
|
||||
width: 14px;
|
||||
height: 20px;
|
||||
cursor: move;
|
||||
visibility: hidden;
|
||||
}
|
||||
.cmdb-preference-group-content-title {
|
||||
flex: 1;
|
||||
|
@@ -58,13 +58,9 @@
|
||||
/>
|
||||
<div class="relation-views-right-bar">
|
||||
<a-space>
|
||||
<a-button
|
||||
v-if="isLeaf"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="$refs.create.handleOpen(true, 'create')"
|
||||
>{{ $t('create') }}</a-button
|
||||
>
|
||||
<a-button v-if="isLeaf" type="primary" size="small" @click="$refs.create.handleOpen(true, 'create')">{{
|
||||
$t('create')
|
||||
}}</a-button>
|
||||
|
||||
<div class="ops-list-batch-action" v-if="isLeaf && isShowBatchIcon">
|
||||
<template v-if="selectedRowKeys.length">
|
||||
@@ -135,7 +131,7 @@
|
||||
{{ col.title }}</span
|
||||
>
|
||||
</template>
|
||||
<template v-if="col.is_choice || col.is_password || col.is_list" #edit="{ row }">
|
||||
<template v-if="col.is_choice || col.is_password" #edit="{ row }">
|
||||
<vxe-input v-if="col.is_password" v-model="passwordValue[col.field]" />
|
||||
<a-select
|
||||
:getPopupContainer="(trigger) => trigger.parentElement"
|
||||
@@ -172,18 +168,6 @@
|
||||
</span>
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-select
|
||||
:getPopupContainer="(trigger) => trigger.parentElement"
|
||||
:style="{ width: '100%', height: '32px' }"
|
||||
v-model="row[col.field]"
|
||||
:placeholder="$t('placeholder2')"
|
||||
v-else-if="col.is_list"
|
||||
:showArrow="false"
|
||||
mode="tags"
|
||||
class="ci-table-edit-select"
|
||||
allowClear
|
||||
>
|
||||
</a-select>
|
||||
</template>
|
||||
<template
|
||||
v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice"
|
||||
@@ -364,7 +348,7 @@ import {
|
||||
} from '@/modules/cmdb/api/CIRelation'
|
||||
|
||||
import { getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
|
||||
import { searchCI2, updateCI, deleteCI, searchCI } from '@/modules/cmdb/api/ci'
|
||||
import { searchCI2, updateCI, deleteCI } from '@/modules/cmdb/api/ci'
|
||||
import { getCITypes } from '../../api/CIType'
|
||||
import { roleHasPermissionToGrant } from '@/modules/acl/api/permission'
|
||||
import { searchResourceType } from '@/modules/acl/api/resource'
|
||||
@@ -1018,11 +1002,7 @@ export default {
|
||||
|
||||
this.$confirm({
|
||||
title: that.$t('warning'),
|
||||
content: (h) => (
|
||||
<div>
|
||||
{that.$t('confirmDelete2', { name: Object.values(firstCIObj)[0] })}
|
||||
</div>
|
||||
),
|
||||
content: (h) => <div>{that.$t('confirmDelete2', { name: Object.values(firstCIObj)[0] })}</div>,
|
||||
onOk() {
|
||||
deleteCIRelationView(_tempTreeParent[0], _tempTree[0], { ancestor_ids }).then((res) => {
|
||||
that.$message.success(that.$t('deleteSuccess'))
|
||||
@@ -1048,7 +1028,7 @@ export default {
|
||||
title: that.$t('warning'),
|
||||
content: (h) => (
|
||||
<div>
|
||||
{that.$t('cmdb.serviceTreedeleteRelationConfirm', { name: currentShowType.alias || currentShowType.name })}
|
||||
{that.$t('cmdb.serviceTree.deleteRelationConfirm', { name: currentShowType.alias || currentShowType.name })}
|
||||
</div>
|
||||
),
|
||||
onOk() {
|
||||
|
@@ -32,32 +32,24 @@
|
||||
>
|
||||
<template #one>
|
||||
<div class="tree-views-left" :style="{ height: `${windowHeight - 115}px` }">
|
||||
<a-collapse
|
||||
:activeKey="current"
|
||||
accordion
|
||||
@change="handleChangeCi"
|
||||
:bordered="false"
|
||||
:destroyInactivePanel="true"
|
||||
<draggable
|
||||
v-model="subscribeTreeViewCiTypes"
|
||||
:animation="300"
|
||||
@change="
|
||||
(e) => {
|
||||
orderChange(e, subscribeTreeViewCiTypes)
|
||||
}
|
||||
"
|
||||
>
|
||||
<a-collapse-panel
|
||||
v-for="ciType in subscribeTreeViewCiTypes"
|
||||
:key="String(ciType.type_id)"
|
||||
:showArrow="false"
|
||||
:style="{
|
||||
borderRadius: '4px',
|
||||
marginBottom: '5px',
|
||||
border: 0,
|
||||
overflow: 'hidden',
|
||||
width: '100%',
|
||||
}"
|
||||
>
|
||||
<div v-for="ciType in subscribeTreeViewCiTypes" :key="ciType.type_id">
|
||||
<div
|
||||
slot="header"
|
||||
@click="handleChangeCi(ciType.type_id)"
|
||||
:class="{
|
||||
'custom-header': true,
|
||||
'custom-header-selected': Number(ciType.type_id) === Number(typeId),
|
||||
'custom-header-selected': Number(ciType.type_id) === Number(typeId) && !treeKeys.length,
|
||||
}"
|
||||
>
|
||||
<OpsMoveIcon class="move-icon" />
|
||||
<span class="tree-views-left-header-icon">
|
||||
<template v-if="ciType.icon">
|
||||
<img
|
||||
@@ -95,6 +87,7 @@
|
||||
:tree-data="treeData"
|
||||
:load-data="onLoadData"
|
||||
:expandedKeys="expandedKeys"
|
||||
v-if="Number(ciType.type_id) === Number(typeId)"
|
||||
>
|
||||
<a-icon slot="switcherIcon" type="down" />
|
||||
<template #title="{ key: treeKey, title, isLeaf }">
|
||||
@@ -107,8 +100,8 @@
|
||||
/>
|
||||
</template>
|
||||
</a-tree>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
</div>
|
||||
</draggable>
|
||||
</div>
|
||||
</template>
|
||||
<template #two>
|
||||
@@ -189,7 +182,7 @@
|
||||
{{ col.title }}</span
|
||||
>
|
||||
</template>
|
||||
<template v-if="col.is_choice || col.is_password || col.is_list" #edit="{ row }">
|
||||
<template v-if="col.is_choice || col.is_password" #edit="{ row }">
|
||||
<vxe-input v-if="col.is_password" v-model="passwordValue[col.field]" />
|
||||
<a-select
|
||||
:getPopupContainer="(trigger) => trigger.parentElement"
|
||||
@@ -226,18 +219,6 @@
|
||||
</span>
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-select
|
||||
:getPopupContainer="(trigger) => trigger.parentElement"
|
||||
:style="{ width: '100%', height: '32px' }"
|
||||
v-model="row[col.field]"
|
||||
:placeholder="$t('placeholder2')"
|
||||
v-else-if="col.is_list"
|
||||
:showArrow="false"
|
||||
mode="tags"
|
||||
class="ci-table-edit-select"
|
||||
allowClear
|
||||
>
|
||||
</a-select>
|
||||
</template>
|
||||
<template
|
||||
v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice"
|
||||
@@ -407,7 +388,13 @@
|
||||
/* eslint-disable no-useless-escape */
|
||||
import _ from 'lodash'
|
||||
import Sortable from 'sortablejs'
|
||||
import { getSubscribeTreeView, getSubscribeAttributes, subscribeTreeView } from '@/modules/cmdb/api/preference'
|
||||
import draggable from 'vuedraggable'
|
||||
import {
|
||||
getSubscribeTreeView,
|
||||
getSubscribeAttributes,
|
||||
subscribeTreeView,
|
||||
preferenceCitypeOrder,
|
||||
} from '@/modules/cmdb/api/preference'
|
||||
import { searchCI, updateCI, deleteCI } from '@/modules/cmdb/api/ci'
|
||||
import { getCITypes } from '@/modules/cmdb/api/CIType'
|
||||
import { getCITableColumns } from '../../utils/helper'
|
||||
@@ -444,6 +431,7 @@ export default {
|
||||
PreferenceSearch,
|
||||
MetadataDrawer,
|
||||
OpsMoveIcon,
|
||||
draggable,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -463,7 +451,6 @@ export default {
|
||||
pageSize: 50,
|
||||
currentPage: 1,
|
||||
totalNumber: 0,
|
||||
current: '', // 当前页面的type_id
|
||||
currentAttrList: [],
|
||||
trigger: false,
|
||||
newLoad: true,
|
||||
@@ -571,7 +558,6 @@ export default {
|
||||
this.subscribeTreeViewCiTypes = res
|
||||
if (this.subscribeTreeViewCiTypes.length) {
|
||||
this.typeId = this.$route.params.typeId || this.subscribeTreeViewCiTypes[0].type_id
|
||||
this.current = `${this.typeId}`
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
||||
@@ -600,7 +586,6 @@ export default {
|
||||
async loadCurrentView() {
|
||||
if (this.subscribeTreeViewCiTypes.length) {
|
||||
this.typeId = this.$route.params.typeId || this.subscribeTreeViewCiTypes[0].type_id
|
||||
this.current = String(this.typeId)
|
||||
this.selectedRowKeys = []
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
||||
this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
||||
@@ -746,9 +731,14 @@ export default {
|
||||
name: 'cmdb_tree_views_item',
|
||||
params: { typeId: Number(value) },
|
||||
})
|
||||
this.typeId = Number(value)
|
||||
} else {
|
||||
this.newLoad = true
|
||||
this.initPage()
|
||||
this.typeId = null
|
||||
this.$nextTick(() => {
|
||||
this.typeId = Number(value)
|
||||
this.newLoad = true
|
||||
this.initPage()
|
||||
})
|
||||
}
|
||||
this.isSetDataNodes = []
|
||||
},
|
||||
@@ -1136,12 +1126,22 @@ export default {
|
||||
}
|
||||
})
|
||||
this.$refs.create.visible = false
|
||||
const key = 'updatable'
|
||||
let errorMsg = ''
|
||||
for (let i = 0; i < this.selectedRowKeys.length; i++) {
|
||||
await updateCI(this.selectedRowKeys[i], payload, false)
|
||||
.then(() => {
|
||||
successNum += 1
|
||||
})
|
||||
.catch(() => {
|
||||
.catch((error) => {
|
||||
errorMsg = errorMsg + '\n' + `${this.selectedRowKeys[i]}:${error.response?.data?.message ?? ''}`
|
||||
this.$notification.warning({
|
||||
key,
|
||||
message: this.$t('warning'),
|
||||
description: errorMsg,
|
||||
duration: 0,
|
||||
style: { whiteSpace: 'break-spaces' },
|
||||
})
|
||||
errorNum += 1
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -1209,6 +1209,13 @@ export default {
|
||||
this.$message.error(this.$t('cmdb.ci.copyFailed'))
|
||||
})
|
||||
},
|
||||
orderChange(e, subscribeTreeViewCiTypes) {
|
||||
preferenceCitypeOrder({ type_ids: subscribeTreeViewCiTypes.map((type) => type.type_id), is_tree: true }).catch(
|
||||
() => {
|
||||
this.getTreeViews()
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -1230,65 +1237,68 @@ export default {
|
||||
&:hover {
|
||||
overflow: auto;
|
||||
}
|
||||
.ant-collapse-borderless {
|
||||
background-color: #fff;
|
||||
}
|
||||
.ant-collapse-item:has(.custom-header-selected):not(:has(.ant-tree-treenode-selected)) > .ant-collapse-header,
|
||||
.ant-collapse-item-active:not(:has(.ant-tree-treenode-selected)) > .ant-collapse-header {
|
||||
background-color: #d6e4ff;
|
||||
}
|
||||
.ant-collapse-header {
|
||||
padding: 8px 12px 4px;
|
||||
.custom-header {
|
||||
width: 100%;
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding: 8px 0 8px 12px;
|
||||
cursor: move;
|
||||
border-radius: 2px;
|
||||
position: relative;
|
||||
&:hover {
|
||||
background-color: #f0f5ff;
|
||||
> .actions,
|
||||
> .move-icon {
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
&:hover > .custom-header > .actions {
|
||||
display: inherit;
|
||||
.move-icon {
|
||||
width: 14px;
|
||||
height: 20px;
|
||||
cursor: move;
|
||||
position: absolute;
|
||||
display: none;
|
||||
left: 0;
|
||||
}
|
||||
.custom-header {
|
||||
width: 100%;
|
||||
.tree-views-left-header-icon {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
.tree-views-left-header-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0px 1px 2px rgba(47, 84, 235, 0.2);
|
||||
margin-right: 6px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.tree-views-left-header-name {
|
||||
flex: 1;
|
||||
font-weight: bold;
|
||||
margin-left: 5px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.actions {
|
||||
display: none;
|
||||
margin-left: auto;
|
||||
}
|
||||
.action {
|
||||
display: inline-block;
|
||||
width: 22px;
|
||||
text-align: center;
|
||||
border-radius: 5px;
|
||||
&:hover {
|
||||
background-color: #cacaca;
|
||||
}
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0px 1px 2px rgba(47, 84, 235, 0.2);
|
||||
margin-right: 6px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.tree-views-left-header-name {
|
||||
flex: 1;
|
||||
font-weight: bold;
|
||||
margin-left: 5px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.actions {
|
||||
display: none;
|
||||
margin-left: auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
.action {
|
||||
display: inline-block;
|
||||
width: 22px;
|
||||
text-align: center;
|
||||
border-radius: 5px;
|
||||
&:hover {
|
||||
background-color: #cacaca;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-collapse > .ant-collapse-item > .ant-collapse-header {
|
||||
white-space: nowrap;
|
||||
.custom-header-selected {
|
||||
background-color: #d3e3fd !important;
|
||||
}
|
||||
.ant-tree li {
|
||||
padding: 2px 0;
|
||||
|
@@ -12,13 +12,13 @@
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(47, 122, 235, 0.2);
|
||||
background-color: @scrollbar-color;
|
||||
background-clip: padding-box;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: rgba(47, 122, 235, 0.2);
|
||||
background-color: @scrollbar-color;
|
||||
}
|
||||
|
||||
@import '~ant-design-vue/dist/antd.less';
|
||||
@@ -35,7 +35,7 @@ body {
|
||||
}
|
||||
|
||||
.ant-layout {
|
||||
background-color: #f0f5ff;
|
||||
background-color: #custom_colors() [color_2];
|
||||
}
|
||||
|
||||
.layout.ant-layout {
|
||||
@@ -99,12 +99,8 @@ body {
|
||||
height: @layout-header-icon-height;
|
||||
line-height: @layout-header-icon-height;
|
||||
display: inline-flex;
|
||||
align-items: flex-end;
|
||||
align-items: center;
|
||||
margin-right: 10px;
|
||||
&:hover {
|
||||
background: linear-gradient(0deg, rgba(0, 80, 201, 0.2) 0%, rgba(174, 207, 255, 0.06) 86.76%);
|
||||
color: @layout-header-font-selected-color;
|
||||
}
|
||||
}
|
||||
|
||||
.topmenu {
|
||||
@@ -192,12 +188,6 @@ body {
|
||||
color: @layout-header-font-color;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(0deg, rgba(0, 80, 201, 0.2) 0%, rgba(174, 207, 255, 0.06) 86.76%);
|
||||
color: @layout-header-font-selected-color;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin-right: 5px;
|
||||
color: @layout-header-font-color;
|
||||
@@ -349,8 +339,6 @@ body {
|
||||
}
|
||||
|
||||
&.light {
|
||||
background-color: #225686;
|
||||
|
||||
.header-index-wide {
|
||||
.header-index-left {
|
||||
.logo {
|
||||
@@ -425,7 +413,6 @@ body {
|
||||
min-height: 100vh;
|
||||
|
||||
.ant-layout-sider-children {
|
||||
background: #225686; //浅色系左边菜单栏 深色系需删除
|
||||
overflow-y: hidden;
|
||||
> .ant-menu {
|
||||
height: calc(100vh - 40px);
|
||||
@@ -519,7 +506,7 @@ body {
|
||||
.ops-side-bar.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected {
|
||||
// background-image: url('../assets/sidebar_selected.png') !important;
|
||||
// background-repeat: no-repeat !important;
|
||||
background: #3e4a71;
|
||||
background: @layout-sidebar-selected-color;
|
||||
// background-size: 228px 38px;
|
||||
// background-position-x: -10px;
|
||||
// background-position-y: center;
|
||||
@@ -546,13 +533,13 @@ body {
|
||||
border-right-color: transparent;
|
||||
// background: @layout-background-light-color;
|
||||
// background: url('../assets/sidebar_background.png');
|
||||
background: #1d264c;
|
||||
background: @layout-sidebar-color;
|
||||
// background-position-x: center;
|
||||
// background-position-y: center;
|
||||
background-repeat: no-repeat !important;
|
||||
background-size: cover;
|
||||
.ant-menu-inline.ant-menu-sub {
|
||||
background-color: #000c37;
|
||||
background-color: @layout-sidebar-sub-color;
|
||||
}
|
||||
.ant-menu-submenu-content .ant-menu-item,
|
||||
.ant-menu-item {
|
||||
@@ -560,7 +547,7 @@ body {
|
||||
> a {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
color: @layout-sidebar-font-color;
|
||||
}
|
||||
&:hover {
|
||||
// background: #0000000a;
|
||||
@@ -578,7 +565,7 @@ body {
|
||||
white-space: nowrap;
|
||||
}
|
||||
a:hover {
|
||||
color: #fff;
|
||||
color: @layout-sidebar-font-color;
|
||||
font-weight: 600;
|
||||
}
|
||||
&:hover .custom-menu-extra-ellipsis {
|
||||
@@ -614,7 +601,7 @@ body {
|
||||
.ant-menu-item-selected {
|
||||
a,
|
||||
a:hover {
|
||||
color: #fff;
|
||||
color: @layout-sidebar-font-color;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
@@ -624,20 +611,20 @@ body {
|
||||
}
|
||||
|
||||
.ant-menu-submenu {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
color: @layout-sidebar-font-color;
|
||||
}
|
||||
.ant-menu-submenu-title:hover {
|
||||
color: #fff;
|
||||
background: #0000000a;
|
||||
color: @layout-sidebar-font-color;
|
||||
background: @layout-sidebar-selected-color;
|
||||
font-weight: 600;
|
||||
.ant-menu-submenu-arrow::before,
|
||||
.ant-menu-submenu-arrow::after {
|
||||
background: #fff;
|
||||
background-image: linear-gradient(to right, #2e2e2e, #2e2e2e);
|
||||
background: @layout-sidebar-arrow-color;
|
||||
}
|
||||
}
|
||||
.ant-menu-submenu-selected {
|
||||
> .ant-menu-submenu-title {
|
||||
color: #fff;
|
||||
color: @layout-sidebar-font-color;
|
||||
font-weight: 800;
|
||||
}
|
||||
}
|
||||
@@ -650,7 +637,7 @@ body {
|
||||
padding-left: 0 !important;
|
||||
> a {
|
||||
padding-left: 10px;
|
||||
color: rgba(255, 255, 255, 0.6) !important;
|
||||
color: @layout-sidebar-disabled-font-color !important;
|
||||
font-size: 12px;
|
||||
}
|
||||
&:hover {
|
||||
@@ -659,8 +646,11 @@ body {
|
||||
}
|
||||
.ant-menu-submenu-arrow::after,
|
||||
.ant-menu-submenu-arrow::before {
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
background-image: linear-gradient(to right, rgba(255, 255, 255, 0.6), rgba(255, 255, 255, 0.6)) !important;
|
||||
background: @layout-sidebar-arrow-color;
|
||||
}
|
||||
|
||||
.ant-menu-item.ant-menu-item-active:hover {
|
||||
background: @layout-sidebar-selected-color;
|
||||
}
|
||||
}
|
||||
// 侧边栏折叠时
|
||||
@@ -668,7 +658,7 @@ body {
|
||||
.ant-menu-submenu.ant-menu-submenu-placement-rightTop {
|
||||
> .ant-menu {
|
||||
// background: url('../assets/sidebar_background.png');
|
||||
background: #1d264c;
|
||||
background: @layout-sidebar-color;
|
||||
background-position-x: center;
|
||||
background-position-y: center;
|
||||
background-repeat: no-repeat !important;
|
||||
@@ -830,14 +820,21 @@ body {
|
||||
.el-input__inner {
|
||||
border-radius: 2px !important;
|
||||
}
|
||||
.el-input__inner:hover {
|
||||
border-color: #4596de !important;
|
||||
|
||||
.el-input__inner:hover,
|
||||
.el-select .el-input.is-focus .el-input__inner,
|
||||
.el-select .el-input__inner:focus,
|
||||
.el-button.is-plain:focus,
|
||||
.el-button.is-plain:hover,
|
||||
.el-input.is-active .el-input__inner,
|
||||
.el-input__inner:focus {
|
||||
border-color: #custom_colors() [color_1] !important;
|
||||
}
|
||||
.el-select .el-input.is-focus .el-input__inner {
|
||||
border-color: #4596de !important;
|
||||
}
|
||||
.el-select-dropdown__item.selected {
|
||||
color: #4596de !important;
|
||||
.el-button--text,
|
||||
.el-select-dropdown__item.selected,
|
||||
.el-button.is-plain:focus,
|
||||
.el-button.is-plain:hover {
|
||||
color: #custom_colors() [color_1] !important;
|
||||
}
|
||||
|
||||
.ant-tabs-nav .ant-tabs-tab {
|
||||
@@ -897,7 +894,7 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.custom-vue-treeselect__control(@bgColor:#f0f5ff,@border:none) {
|
||||
.custom-vue-treeselect__control(@bgColor:#custom_colors()[color_2],@border:none) {
|
||||
background-color: @bgColor;
|
||||
border: @border;
|
||||
}
|
||||
@@ -938,29 +935,29 @@ body {
|
||||
.vue-treeselect__option--highlight,
|
||||
.vue-treeselect__option--selected {
|
||||
color: #custom_colors[color_1];
|
||||
background-color: #f0f5ff !important;
|
||||
background-color: #custom_colors() [color_2] !important;
|
||||
}
|
||||
.vue-treeselect__checkbox--checked,
|
||||
.vue-treeselect__checkbox--indeterminate {
|
||||
border-color: #2f54eb !important;
|
||||
background: #2f54eb !important;
|
||||
border-color: #custom_colors() [color_1] !important;
|
||||
background: #custom_colors() [color_1] !important;
|
||||
}
|
||||
.vue-treeselect__label-container:hover {
|
||||
.vue-treeselect__checkbox--checked,
|
||||
.vue-treeselect__checkbox--indeterminate {
|
||||
border-color: #2f54eb !important;
|
||||
background: #2f54eb !important;
|
||||
border-color: #custom_colors() [color_1] !important;
|
||||
background: #custom_colors() [color_1] !important;
|
||||
}
|
||||
}
|
||||
.vue-treeselect__multi-value-item {
|
||||
background: #f0f5ff !important;
|
||||
color: #2f54eb !important;
|
||||
background: #custom_colors() [color_2] !important;
|
||||
color: #custom_colors() [color_1] !important;
|
||||
}
|
||||
.vue-treeselect__value-remove {
|
||||
color: #2f54eb !important;
|
||||
color: #custom_colors() [color_1] !important;
|
||||
}
|
||||
.vue-treeselect__label-container:hover .vue-treeselect__checkbox--unchecked {
|
||||
border-color: #2f54eb !important;
|
||||
border-color: #custom_colors() [color_1] !important;
|
||||
}
|
||||
|
||||
//表格样式
|
||||
@@ -970,7 +967,7 @@ body {
|
||||
border: none !important;
|
||||
}
|
||||
.vxe-table--header-wrapper {
|
||||
background-color: #f0f5ff !important;
|
||||
background-color: #custom_colors() [color_2] !important;
|
||||
}
|
||||
.vxe-header--row .vxe-header--column:hover {
|
||||
background: #2f54eb1f !important;
|
||||
@@ -994,7 +991,7 @@ body {
|
||||
border: none !important;
|
||||
}
|
||||
.vxe-table--header-wrapper {
|
||||
background-color: #f0f5ff !important;
|
||||
background-color: #custom_colors() [color_2] !important;
|
||||
}
|
||||
// .vxe-table--header-wrapper.body--wrapper {
|
||||
// border-radius: 8px !important;
|
||||
@@ -1088,8 +1085,34 @@ body {
|
||||
.vxe-table--render-default .vxe-cell--checkbox:not(.is--disabled):hover .vxe-checkbox--icon,
|
||||
.is--filter-active .vxe-cell--filter .vxe-filter--btn,
|
||||
.vxe-table .vxe-sort--asc-btn.sort--active,
|
||||
.vxe-table .vxe-sort--desc-btn.sort--active {
|
||||
color: #2f54eb !important;
|
||||
.vxe-table .vxe-sort--desc-btn.sort--active,
|
||||
.vxe-select-option.is--selected,
|
||||
.vxe-loading > .vxe-loading--chunk,
|
||||
.vxe-loading > .vxe-loading--warpper,
|
||||
.vxe-pager .vxe-pager--jump-next:not(.is--disabled).is--active,
|
||||
.vxe-pager .vxe-pager--jump-next:not(.is--disabled):focus,
|
||||
.vxe-pager .vxe-pager--jump-prev:not(.is--disabled).is--active,
|
||||
.vxe-pager .vxe-pager--jump-prev:not(.is--disabled):focus,
|
||||
.vxe-pager .vxe-pager--next-btn:not(.is--disabled).is--active,
|
||||
.vxe-pager .vxe-pager--next-btn:not(.is--disabled):focus,
|
||||
.vxe-pager .vxe-pager--num-btn:not(.is--disabled).is--active,
|
||||
.vxe-pager .vxe-pager--num-btn:not(.is--disabled):focus,
|
||||
.vxe-pager .vxe-pager--prev-btn:not(.is--disabled).is--active,
|
||||
.vxe-pager .vxe-pager--prev-btn:not(.is--disabled):focus,
|
||||
.vxe-button.type--text:not(.is--disabled):hover,
|
||||
.vxe-table--filter-footer > button:hover {
|
||||
color: #custom_colors() [color_1] !important;
|
||||
}
|
||||
|
||||
.vxe-cell .vxe-default-input:focus,
|
||||
.vxe-cell .vxe-default-select:focus,
|
||||
.vxe-cell .vxe-default-textarea:focus,
|
||||
.vxe-table--filter-wrapper .vxe-default-input:focus,
|
||||
.vxe-table--filter-wrapper .vxe-default-select:focus,
|
||||
.vxe-table--filter-wrapper .vxe-default-textarea:focus,
|
||||
.vxe-select.is--active:not(.is--filter) > .vxe-input .vxe-input--inner,
|
||||
.vxe-input:not(.is--disabled).is--active .vxe-input--inner {
|
||||
border-color: #custom_colors() [color_1] !important;
|
||||
}
|
||||
|
||||
//批量操作
|
||||
@@ -1107,7 +1130,7 @@ body {
|
||||
}
|
||||
}
|
||||
> span:last-child {
|
||||
color: rgba(47, 84, 235, 0.55);
|
||||
color: #custom_colors[color_1];
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
@@ -1117,7 +1140,7 @@ body {
|
||||
.ant-tabs-card-bar {
|
||||
margin: 0;
|
||||
.ant-tabs-nav-container {
|
||||
background-color: #custom_colors[color_2];
|
||||
background-color: #fff;
|
||||
.ant-tabs-tab {
|
||||
border: none;
|
||||
border-top-left-radius: 4px;
|
||||
@@ -1125,9 +1148,9 @@ body {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
.ant-tabs-tab-active {
|
||||
background: #fff !important;
|
||||
.ant-tabs-tab-active {
|
||||
background: #custom_colors[color_2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1218,7 +1241,7 @@ body {
|
||||
|
||||
.el-tabs__header {
|
||||
border-bottom: none;
|
||||
background-color: #f0f5ff;
|
||||
background-color: #custom_colors[color_2];
|
||||
border-radius: 8px 8px 0px 0px;
|
||||
}
|
||||
|
||||
@@ -1303,6 +1326,15 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
// json editor
|
||||
.jsoneditor-vue {
|
||||
div.jsoneditor {
|
||||
border: none;
|
||||
}
|
||||
div.jsoneditor-menu {
|
||||
border-bottom-color: #custom_colors[color_1];
|
||||
}
|
||||
}
|
||||
// .ant-menu.ant-menu-light {
|
||||
// &.ops-menu {
|
||||
// background-color: white;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
@border-radius-base: 2px; // 组件/浮层圆角
|
||||
@primary-color: #2f54eb; // 全局主色
|
||||
@scrollbar-color: rgba(47, 122, 235, 0.2);
|
||||
|
||||
// @layout-header-background: #1a3652;
|
||||
@layout-header-background: #fff;
|
||||
@layout-header-height: 40px;
|
||||
@layout-header-icon-height: 34px;
|
||||
@@ -15,13 +15,20 @@
|
||||
@layout-background-light-color: #fafafa;
|
||||
@layout-background-light-color-light: #f0f0f0;
|
||||
|
||||
@layout-sidebar-color: #1d264c; //bg
|
||||
@layout-sidebar-sub-color: #000c37; //bg
|
||||
@layout-sidebar-selected-color: #3e4a71; //selected bg
|
||||
@layout-sidebar-arrow-color: rgba(255, 255, 255, 0.6);
|
||||
@layout-sidebar-font-color: #fff;
|
||||
@layout-sidebar-disabled-font-color: rgba(255, 255, 255, 0.6);
|
||||
|
||||
#custom_colors() {
|
||||
color_1: #2f54eb;
|
||||
color_2: #f0f5ff;
|
||||
color_3: #D2E2FF;
|
||||
color_1: #2f54eb; //primary color
|
||||
color_2: #f0f5ff; //light background color
|
||||
color_3: #d2e2ff;
|
||||
}
|
||||
|
||||
.ops_display_wrapper(@backgroundColor:#f0f5ff) {
|
||||
.ops_display_wrapper(@backgroundColor:#custom_colors()[color_2]) {
|
||||
cursor: pointer;
|
||||
padding: 5px 8px;
|
||||
background-color: @backgroundColor;
|
||||
|
@@ -76,7 +76,8 @@ const AppDeviceEnquire = {
|
||||
const mixinPermissions = {
|
||||
computed: {
|
||||
...mapState({
|
||||
detailPermissions: state => state.user.detailPermissions
|
||||
detailPermissions: state => state.user.detailPermissions,
|
||||
roles: state => state.user.roles
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
@@ -85,7 +86,7 @@ const mixinPermissions = {
|
||||
hasDetailPermission(appName, resourceName, perms = []) {
|
||||
const appNamePer = this.detailPermissions[`${appName}`]
|
||||
const _findResourcePermissions = appNamePer.find(item => item.name === resourceName)
|
||||
return _findResourcePermissions.permissions.some(item => perms.includes(item))
|
||||
return this.roles?.permissions.includes('acl_admin') || this.roles?.permissions.includes('backend_admin') || _findResourcePermissions?.permissions.some(item => perms.includes(item))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -60,34 +60,6 @@
|
||||
<vxe-column field="mobile" :title="$t('cs.companyStructure.mobile')" min-width="80"></vxe-column>
|
||||
<vxe-column field="position_name" :title="$t('cs.companyStructure.positionName')" min-width="80"></vxe-column>
|
||||
<vxe-column field="department_name" :title="$t('cs.companyStructure.departmentName')" min-width="80"></vxe-column>
|
||||
<vxe-column field="current_company" v-if="useDFC" :title="$t('cs.companyStructure.currentCompany')" min-width="120"></vxe-column>
|
||||
<vxe-column field="dfc_entry_date" v-if="useDFC" :title="$t('cs.companyStructure.dfcEntryDate')" min-width="120"></vxe-column>
|
||||
<vxe-column field="entry_date" :title="$t('cs.companyStructure.entryDate')" min-width="120"></vxe-column>
|
||||
<vxe-column field="is_internship" :title="$t('cs.companyStructure.isInternship')" min-width="120"></vxe-column>
|
||||
<vxe-column field="leave_date" :title="$t('cs.companyStructure.leaveDate')" min-width="120"></vxe-column>
|
||||
<vxe-column field="id_card" :title="$t('cs.companyStructure.idCard')" min-width="120"></vxe-column>
|
||||
<vxe-column field="nation" :title="$t('cs.companyStructure.nation')" min-width="80"></vxe-column>
|
||||
<vxe-column field="id_place" :title="$t('cs.companyStructure.idPlace')" min-width="80"></vxe-column>
|
||||
<vxe-column field="party" :title="$t('cs.companyStructure.party')" min-width="80"></vxe-column>
|
||||
<vxe-column field="household_registration_type" :title="$t('cs.companyStructure.householdRegistrationType')" min-width="80"></vxe-column>
|
||||
<vxe-column field="hometown" :title="$t('cs.companyStructure.homewtown')" min-width="80"></vxe-column>
|
||||
<vxe-column field="marry" :title="$t('cs.companyStructure.marry')" min-width="80"></vxe-column>
|
||||
<vxe-column field="max_degree" :title="$t('cs.companyStructure.maxDegree')" min-width="80"></vxe-column>
|
||||
<vxe-column field="emergency_person" :title="$t('cs.companyStructure.emergencyPerson')" min-width="120"></vxe-column>
|
||||
<vxe-column field="emergency_phone" :title="$t('cs.companyStructure.emergencyPhone')" min-width="120"></vxe-column>
|
||||
<vxe-column field="bank_card_number" :title="$t('cs.companyStructure.bankCardNumber')" min-width="120"></vxe-column>
|
||||
<vxe-column field="bank_card_name" :title="$t('cs.companyStructure.bankCardName')" min-width="80"></vxe-column>
|
||||
<vxe-column field="opening_bank" :title="$t('cs.companyStructure.openingBank')" min-width="80"></vxe-column>
|
||||
<vxe-column field="account_opening_location" :title="$t('cs.companyStructure.accountOpeningLocation')" min-width="120"></vxe-column>
|
||||
<vxe-column field="school" :title="$t('cs.companyStructure.school')" min-width="80"></vxe-column>
|
||||
<vxe-column field="major" :title="$t('cs.companyStructure.major')" min-width="80"></vxe-column>
|
||||
<vxe-column field="education" :title="$t('cs.companyStructure.education')" min-width="80"></vxe-column>
|
||||
<vxe-column field="graduation_year" :title="$t('cs.companyStructure.graduationYear')" min-width="120"></vxe-column>
|
||||
<vxe-column field="birth_date" :title="$t('cs.companyStructure.birthDate')" min-width="120"></vxe-column>
|
||||
<vxe-column field="birth_place" :title="$t('cs.companyStructure.birthPlace')" min-width="120"></vxe-column>
|
||||
<vxe-column field="nationality_region" :title="$t('cs.companyStructure.nationalityRegion')" min-width="120"></vxe-column>
|
||||
<vxe-column field="first_entry_date" :title="$t('cs.companyStructure.firstEntryDate')" min-width="120"></vxe-column>
|
||||
<vxe-column field="estimated_departure_date" :title="$t('cs.companyStructure.estimatedDepartureDate')" min-width="120"></vxe-column>
|
||||
<vxe-column v-if="has_error" field="err" :title="$t('cs.companyStructure.importFailedReason')" min-width="120" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<span :style="{ color: '#D81E06' }">{{ row.err }}</span>
|
||||
@@ -303,98 +275,6 @@ export default {
|
||||
v: '部门',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '目前所属主体',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '初始入职日期',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '目前主体入职日期',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '正式/实习生',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '离职日期',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '身份证号码',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '民族',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '籍贯',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '组织关系',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '户籍类型',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '户口所在地',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '婚姻情况',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '最高学历',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '紧急联系人',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '紧急联系电话',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '卡号',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '银行',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '开户行',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '开户地',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '学校',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '专业',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '学历',
|
||||
t: 's',
|
||||
},
|
||||
{
|
||||
v: '毕业年份',
|
||||
t: 's',
|
||||
},
|
||||
],
|
||||
]
|
||||
data[1] = data[1].filter((item) => item['v'] !== '目前所属主体')
|
||||
|
@@ -372,7 +372,7 @@ export default {
|
||||
{ label: this.$t('cs.companyStructure.mobile'), value: 'mobile' },
|
||||
{ label: this.$t('cs.companyStructure.departmentName'), value: 'department_name' },
|
||||
{ label: this.$t('cs.companyStructure.positionName'), value: 'position_name' },
|
||||
{ label: this.$t('cs.companyStructure.departmentDirector'), value: 'direct_supervisor_id' },
|
||||
{ label: this.$t('cs.companyStructure.supervisor'), value: 'direct_supervisor_id' },
|
||||
]
|
||||
},
|
||||
sceneList () {
|
||||
|
@@ -18,7 +18,7 @@ module.exports = {
|
||||
// TODO 需要增加根据环境不开启主题需求
|
||||
new ThemeColorReplacer({
|
||||
fileName: 'css/theme-colors-[contenthash:8].css',
|
||||
matchColors: getAntdSerials('#1890ff'), // 主色系列
|
||||
matchColors: getAntdSerials('#2f54eb'), // 主色系列
|
||||
// 改变样式选择器,解决样式覆盖问题
|
||||
changeSelector(selector) {
|
||||
switch (selector) {
|
||||
@@ -83,11 +83,9 @@ module.exports = {
|
||||
less: {
|
||||
modifyVars: {
|
||||
/* less 变量覆盖,用于自定义 ant design 主题 */
|
||||
/*
|
||||
'primary-color': '#F5222D',
|
||||
'link-color': '#F5222D',
|
||||
'border-radius-base': '4px',
|
||||
*/
|
||||
'primary-color': '#2f54eb',
|
||||
// 'link-color': '#F5222D',
|
||||
// 'border-radius-base': '4px',
|
||||
},
|
||||
javascriptEnabled: true,
|
||||
},
|
||||
|
Reference in New Issue
Block a user