mirror of
https://github.com/veops/cmdb.git
synced 2025-09-07 22:07:02 +08:00
Compare commits
9 Commits
v2.4.13
...
dev_ui_241
Author | SHA1 | Date | |
---|---|---|---|
|
f194d26450 | ||
|
093098bbec | ||
|
28dca7f086 | ||
|
4a3c21eec4 | ||
|
5d28c28023 | ||
|
ba6edb3abe | ||
|
2f1d57cee1 | ||
|
4111c634d9 | ||
|
f1fababa3d |
@@ -1,14 +1,13 @@
|
|||||||
# -*- coding:utf-8 -*-
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
import click
|
||||||
import copy
|
import copy
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
|
import requests
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import click
|
|
||||||
import requests
|
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from flask.cli import with_appcontext
|
from flask.cli import with_appcontext
|
||||||
from flask_login import login_user
|
from flask_login import login_user
|
||||||
@@ -37,11 +36,14 @@ from api.lib.secrets.secrets import InnerKVManger
|
|||||||
from api.models.acl import App
|
from api.models.acl import App
|
||||||
from api.models.acl import ResourceType
|
from api.models.acl import ResourceType
|
||||||
from api.models.cmdb import Attribute
|
from api.models.cmdb import Attribute
|
||||||
|
from api.models.cmdb import AttributeHistory
|
||||||
from api.models.cmdb import CI
|
from api.models.cmdb import CI
|
||||||
from api.models.cmdb import CIRelation
|
from api.models.cmdb import CIRelation
|
||||||
from api.models.cmdb import CIType
|
from api.models.cmdb import CIType
|
||||||
from api.models.cmdb import CITypeTrigger
|
from api.models.cmdb import CITypeTrigger
|
||||||
|
from api.models.cmdb import OperationRecord
|
||||||
from api.models.cmdb import PreferenceRelationView
|
from api.models.cmdb import PreferenceRelationView
|
||||||
|
from api.tasks.cmdb import batch_ci_cache
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@@ -557,5 +559,20 @@ def cmdb_patch(version):
|
|||||||
existed.update(option=option, commit=False)
|
existed.update(option=option, commit=False)
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
if version >= "2.4.14": # update ci columns: updated_at and updated_by
|
||||||
|
ci_ids = []
|
||||||
|
for i in CI.get_by(only_query=True).filter(CI.updated_at.is_(None)):
|
||||||
|
hist = AttributeHistory.get_by(ci_id=i.id, only_query=True).order_by(AttributeHistory.id.desc()).first()
|
||||||
|
if hist is not None:
|
||||||
|
record = OperationRecord.get_by_id(hist.record_id)
|
||||||
|
if record is not None:
|
||||||
|
u = UserCache.get(record.uid)
|
||||||
|
i.update(updated_at=record.created_at, updated_by=u and u.nickname, flush=True)
|
||||||
|
ci_ids.append(i.id)
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
batch_ci_cache.apply_async(args=(ci_ids,))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("cmdb patch failed: {}".format(e))
|
print("cmdb patch failed: {}".format(e))
|
||||||
|
@@ -45,6 +45,7 @@ from api.lib.notify import notify_send
|
|||||||
from api.lib.perm.acl.acl import ACLManager
|
from api.lib.perm.acl.acl import ACLManager
|
||||||
from api.lib.perm.acl.acl import is_app_admin
|
from api.lib.perm.acl.acl import is_app_admin
|
||||||
from api.lib.perm.acl.acl import validate_permission
|
from api.lib.perm.acl.acl import validate_permission
|
||||||
|
from api.lib.perm.acl.cache import UserCache
|
||||||
from api.lib.secrets.inner import InnerCrypt
|
from api.lib.secrets.inner import InnerCrypt
|
||||||
from api.lib.secrets.vault import VaultClient
|
from api.lib.secrets.vault import VaultClient
|
||||||
from api.lib.utils import handle_arg_list
|
from api.lib.utils import handle_arg_list
|
||||||
@@ -206,6 +207,8 @@ class CIManager(object):
|
|||||||
res['_type'] = ci_type.id
|
res['_type'] = ci_type.id
|
||||||
res['ci_type_alias'] = ci_type.alias
|
res['ci_type_alias'] = ci_type.alias
|
||||||
res['_id'] = ci_id
|
res['_id'] = ci_id
|
||||||
|
res['_updated_at'] = str(ci.updated_at)
|
||||||
|
res['_updated_by'] = ci.updated_by
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@@ -581,6 +584,9 @@ class CIManager(object):
|
|||||||
else:
|
else:
|
||||||
ci_relation_add(ref_ci_dict, ci.id)
|
ci_relation_add(ref_ci_dict, ci.id)
|
||||||
|
|
||||||
|
u = UserCache.get(current_user.uid)
|
||||||
|
ci.update(updated_at=now, updated_by=u and u.nickname)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def update_unique_value(ci_id, unique_name, unique_value):
|
def update_unique_value(ci_id, unique_name, unique_value):
|
||||||
ci = CI.get_by_id(ci_id) or abort(404, ErrFormat.ci_not_found.format("id={}".format(ci_id)))
|
ci = CI.get_by_id(ci_id) or abort(404, ErrFormat.ci_not_found.format("id={}".format(ci_id)))
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
# -*- coding:utf-8 -*-
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
from flask_babel import lazy_gettext as _l
|
||||||
|
|
||||||
from api.lib.utils import BaseEnum
|
from api.lib.utils import BaseEnum
|
||||||
|
|
||||||
|
|
||||||
@@ -110,17 +112,23 @@ class ExecuteStatusEnum(BaseEnum):
|
|||||||
FAILED = '1'
|
FAILED = '1'
|
||||||
RUNNING = '2'
|
RUNNING = '2'
|
||||||
|
|
||||||
|
|
||||||
class RelationSourceEnum(BaseEnum):
|
class RelationSourceEnum(BaseEnum):
|
||||||
ATTRIBUTE_VALUES = "0"
|
ATTRIBUTE_VALUES = "0"
|
||||||
AUTO_DISCOVERY = "1"
|
AUTO_DISCOVERY = "1"
|
||||||
|
|
||||||
|
|
||||||
|
BUILTIN_ATTRIBUTES = {
|
||||||
|
"_updated_at": _l("Update Time"),
|
||||||
|
"_updated_by": _l("Updated By"),
|
||||||
|
}
|
||||||
|
|
||||||
CMDB_QUEUE = "one_cmdb_async"
|
CMDB_QUEUE = "one_cmdb_async"
|
||||||
REDIS_PREFIX_CI = "ONE_CMDB"
|
REDIS_PREFIX_CI = "ONE_CMDB"
|
||||||
REDIS_PREFIX_CI_RELATION = "CMDB_CI_RELATION"
|
REDIS_PREFIX_CI_RELATION = "CMDB_CI_RELATION"
|
||||||
REDIS_PREFIX_CI_RELATION2 = "CMDB_CI_RELATION2"
|
REDIS_PREFIX_CI_RELATION2 = "CMDB_CI_RELATION2"
|
||||||
|
|
||||||
BUILTIN_KEYWORDS = {'id', '_id', 'ci_id', 'type', '_type', 'ci_type', 'ticket_id'}
|
BUILTIN_KEYWORDS = {'id', '_id', 'ci_id', 'type', '_type', 'ci_type', 'ticket_id', *BUILTIN_ATTRIBUTES.keys()}
|
||||||
|
|
||||||
L_TYPE = None
|
L_TYPE = None
|
||||||
L_CI = None
|
L_CI = None
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
# -*- coding:utf-8 -*-
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
@@ -17,6 +16,7 @@ from api.lib.cmdb.cache import CITypeAttributesCache
|
|||||||
from api.lib.cmdb.cache import CITypeCache
|
from api.lib.cmdb.cache import CITypeCache
|
||||||
from api.lib.cmdb.cache import CMDBCounterCache
|
from api.lib.cmdb.cache import CMDBCounterCache
|
||||||
from api.lib.cmdb.ci_type import CITypeAttributeManager
|
from api.lib.cmdb.ci_type import CITypeAttributeManager
|
||||||
|
from api.lib.cmdb.const import BUILTIN_ATTRIBUTES
|
||||||
from api.lib.cmdb.const import ConstraintEnum
|
from api.lib.cmdb.const import ConstraintEnum
|
||||||
from api.lib.cmdb.const import PermEnum
|
from api.lib.cmdb.const import PermEnum
|
||||||
from api.lib.cmdb.const import ResourceTypeEnum
|
from api.lib.cmdb.const import ResourceTypeEnum
|
||||||
@@ -25,7 +25,6 @@ from api.lib.cmdb.perms import CIFilterPermsCRUD
|
|||||||
from api.lib.cmdb.resp_format import ErrFormat
|
from api.lib.cmdb.resp_format import ErrFormat
|
||||||
from api.lib.exception import AbortException
|
from api.lib.exception import AbortException
|
||||||
from api.lib.perm.acl.acl import ACLManager
|
from api.lib.perm.acl.acl import ACLManager
|
||||||
from api.models.cmdb import CITypeAttribute
|
|
||||||
from api.models.cmdb import CITypeGroup
|
from api.models.cmdb import CITypeGroup
|
||||||
from api.models.cmdb import CITypeGroupItem
|
from api.models.cmdb import CITypeGroupItem
|
||||||
from api.models.cmdb import CITypeRelation
|
from api.models.cmdb import CITypeRelation
|
||||||
@@ -137,17 +136,24 @@ class PreferenceManager(object):
|
|||||||
_type = CITypeCache.get(type_id)
|
_type = CITypeCache.get(type_id)
|
||||||
type_id = _type and _type.id
|
type_id = _type and _type.id
|
||||||
|
|
||||||
attrs = db.session.query(PreferenceShowAttributes, CITypeAttribute.order).join(
|
# attrs = db.session.query(PreferenceShowAttributes, CITypeAttribute.order).join(
|
||||||
CITypeAttribute, CITypeAttribute.attr_id == PreferenceShowAttributes.attr_id).filter(
|
# CITypeAttribute, CITypeAttribute.attr_id == PreferenceShowAttributes.attr_id).filter(
|
||||||
PreferenceShowAttributes.uid == current_user.uid).filter(
|
# PreferenceShowAttributes.uid == current_user.uid).filter(
|
||||||
PreferenceShowAttributes.type_id == type_id).filter(
|
# PreferenceShowAttributes.type_id == type_id).filter(
|
||||||
PreferenceShowAttributes.deleted.is_(False)).filter(CITypeAttribute.deleted.is_(False)).group_by(
|
# PreferenceShowAttributes.deleted.is_(False)).filter(CITypeAttribute.deleted.is_(False)).group_by(
|
||||||
CITypeAttribute.attr_id).all()
|
# CITypeAttribute.attr_id).all()
|
||||||
|
|
||||||
|
attrs = PreferenceShowAttributes.get_by(uid=current_user.uid, type_id=type_id, to_dict=False)
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
for i in sorted(attrs, key=lambda x: x.PreferenceShowAttributes.order):
|
for i in sorted(attrs, key=lambda x: x.order):
|
||||||
item = i.PreferenceShowAttributes.attr.to_dict()
|
if i.attr_id:
|
||||||
item.update(dict(is_fixed=i.PreferenceShowAttributes.is_fixed))
|
item = i.attr.to_dict()
|
||||||
|
elif i.builtin_attr:
|
||||||
|
item = dict(name=i.builtin_attr, alias=BUILTIN_ATTRIBUTES[i.builtin_attr])
|
||||||
|
else:
|
||||||
|
item = dict(name="", alias="")
|
||||||
|
item.update(dict(is_fixed=i.is_fixed))
|
||||||
result.append(item)
|
result.append(item)
|
||||||
|
|
||||||
is_subscribed = True
|
is_subscribed = True
|
||||||
@@ -156,10 +162,14 @@ class PreferenceManager(object):
|
|||||||
choice_web_hook_parse=False,
|
choice_web_hook_parse=False,
|
||||||
choice_other_parse=False)
|
choice_other_parse=False)
|
||||||
result = [i for i in result if i['default_show']]
|
result = [i for i in result if i['default_show']]
|
||||||
|
|
||||||
|
for i in BUILTIN_ATTRIBUTES:
|
||||||
|
result.append(dict(name=i, alias=BUILTIN_ATTRIBUTES[i]))
|
||||||
|
|
||||||
is_subscribed = False
|
is_subscribed = False
|
||||||
|
|
||||||
for i in result:
|
for i in result:
|
||||||
if i["is_choice"]:
|
if i.get("is_choice"):
|
||||||
i.update(dict(choice_value=AttributeManager.get_choice_values(
|
i.update(dict(choice_value=AttributeManager.get_choice_values(
|
||||||
i["id"], i["value_type"], i.get("choice_web_hook"), i.get("choice_other"))))
|
i["id"], i["value_type"], i.get("choice_web_hook"), i.get("choice_other"))))
|
||||||
|
|
||||||
@@ -173,24 +183,34 @@ class PreferenceManager(object):
|
|||||||
_attr, is_fixed = x
|
_attr, is_fixed = x
|
||||||
else:
|
else:
|
||||||
_attr, is_fixed = x, False
|
_attr, is_fixed = x, False
|
||||||
attr = AttributeCache.get(_attr) or abort(404, ErrFormat.attribute_not_found.format("id={}".format(_attr)))
|
|
||||||
|
if _attr in BUILTIN_ATTRIBUTES:
|
||||||
|
attr = None
|
||||||
|
builtin_attr = _attr
|
||||||
|
else:
|
||||||
|
attr = AttributeCache.get(_attr) or abort(
|
||||||
|
404, ErrFormat.attribute_not_found.format("id={}".format(_attr)))
|
||||||
|
builtin_attr = None
|
||||||
existed = PreferenceShowAttributes.get_by(type_id=type_id,
|
existed = PreferenceShowAttributes.get_by(type_id=type_id,
|
||||||
uid=current_user.uid,
|
uid=current_user.uid,
|
||||||
attr_id=attr.id,
|
attr_id=attr and attr.id,
|
||||||
|
builtin_attr=builtin_attr,
|
||||||
first=True,
|
first=True,
|
||||||
to_dict=False)
|
to_dict=False)
|
||||||
if existed is None:
|
if existed is None:
|
||||||
PreferenceShowAttributes.create(type_id=type_id,
|
PreferenceShowAttributes.create(type_id=type_id,
|
||||||
uid=current_user.uid,
|
uid=current_user.uid,
|
||||||
attr_id=attr.id,
|
attr_id=attr and attr.id,
|
||||||
|
builtin_attr=builtin_attr,
|
||||||
order=order,
|
order=order,
|
||||||
is_fixed=is_fixed)
|
is_fixed=is_fixed)
|
||||||
else:
|
else:
|
||||||
existed.update(order=order, is_fixed=is_fixed)
|
existed.update(order=order, is_fixed=is_fixed)
|
||||||
|
|
||||||
attr_dict = {int(i[0]) if isinstance(i, list) else int(i): j for i, j in attr_order}
|
attr_dict = {(int(i[0]) if i[0].isdigit() else i[0]) if isinstance(i, list) else
|
||||||
|
(int(i) if i.isdigit() else i): j for i, j in attr_order}
|
||||||
for i in existed_all:
|
for i in existed_all:
|
||||||
if i.attr_id not in attr_dict:
|
if (i.attr_id and i.attr_id not in attr_dict) or (i.builtin_attr and i.builtin_attr not in attr_dict):
|
||||||
i.soft_delete()
|
i.soft_delete()
|
||||||
|
|
||||||
if not existed_all and attr_order:
|
if not existed_all and attr_order:
|
||||||
@@ -384,7 +404,7 @@ class PreferenceManager(object):
|
|||||||
def add_search_option(**kwargs):
|
def add_search_option(**kwargs):
|
||||||
kwargs['uid'] = current_user.uid
|
kwargs['uid'] = current_user.uid
|
||||||
|
|
||||||
if kwargs['name'] in ('__recent__', '__favor__'):
|
if kwargs['name'] in ('__recent__', '__favor__', '__relation_favor__'):
|
||||||
if kwargs['name'] == '__recent__':
|
if kwargs['name'] == '__recent__':
|
||||||
for i in PreferenceSearchOption.get_by(
|
for i in PreferenceSearchOption.get_by(
|
||||||
only_query=True, name=kwargs['name'], uid=current_user.uid).order_by(
|
only_query=True, name=kwargs['name'], uid=current_user.uid).order_by(
|
||||||
|
@@ -15,6 +15,7 @@ from api.extensions import db
|
|||||||
from api.lib.cmdb.cache import AttributeCache
|
from api.lib.cmdb.cache import AttributeCache
|
||||||
from api.lib.cmdb.cache import CITypeCache
|
from api.lib.cmdb.cache import CITypeCache
|
||||||
from api.lib.cmdb.ci import CIManager
|
from api.lib.cmdb.ci import CIManager
|
||||||
|
from api.lib.cmdb.const import BUILTIN_ATTRIBUTES
|
||||||
from api.lib.cmdb.const import PermEnum
|
from api.lib.cmdb.const import PermEnum
|
||||||
from api.lib.cmdb.const import ResourceTypeEnum
|
from api.lib.cmdb.const import ResourceTypeEnum
|
||||||
from api.lib.cmdb.const import RetKey
|
from api.lib.cmdb.const import RetKey
|
||||||
@@ -304,14 +305,21 @@ class Search(object):
|
|||||||
(self.page - 1) * self.count, sort_type, self.count))
|
(self.page - 1) * self.count, sort_type, self.count))
|
||||||
|
|
||||||
def __sort_by_field(self, field, sort_type, query_sql):
|
def __sort_by_field(self, field, sort_type, query_sql):
|
||||||
attr = AttributeCache.get(field)
|
if field not in BUILTIN_ATTRIBUTES:
|
||||||
attr_id = attr.id
|
|
||||||
|
|
||||||
table_name = TableMap(attr=attr).table_name
|
attr = AttributeCache.get(field)
|
||||||
_v_query_sql = """SELECT {0}.ci_id, {1}.value
|
attr_id = attr.id
|
||||||
FROM ({2}) AS {0} INNER JOIN {1} ON {1}.ci_id = {0}.ci_id
|
|
||||||
WHERE {1}.attr_id = {3}""".format("ALIAS", table_name, query_sql, attr_id)
|
table_name = TableMap(attr=attr).table_name
|
||||||
new_table = _v_query_sql
|
_v_query_sql = """SELECT ALIAS.ci_id, {0}.value
|
||||||
|
FROM ({1}) AS ALIAS INNER JOIN {0} ON {0}.ci_id = ALIAS.ci_id
|
||||||
|
WHERE {0}.attr_id = {2}""".format(table_name, query_sql, attr_id)
|
||||||
|
new_table = _v_query_sql
|
||||||
|
else:
|
||||||
|
_v_query_sql = """SELECT c_cis.id AS ci_id, c_cis.{0} AS value
|
||||||
|
FROM c_cis INNER JOIN ({1}) AS ALIAS ON ALIAS.ci_id = c_cis.id""".format(
|
||||||
|
field[1:], query_sql)
|
||||||
|
new_table = _v_query_sql
|
||||||
|
|
||||||
if self.only_type_query or not self.type_id_list or self.multi_type_has_ci_filter:
|
if self.only_type_query or not self.type_id_list or self.multi_type_has_ci_filter:
|
||||||
return ("SELECT SQL_CALC_FOUND_ROWS DISTINCT C.ci_id FROM ({0}) AS C ORDER BY C.value {2} "
|
return ("SELECT SQL_CALC_FOUND_ROWS DISTINCT C.ci_id FROM ({0}) AS C ORDER BY C.value {2} "
|
||||||
|
@@ -71,7 +71,7 @@ class PermissionCRUD(object):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_all2(cls, resource_name, resource_type_name, app_id):
|
def get_all2(cls, resource_name, resource_type_name, app_id):
|
||||||
rt = ResourceType.get_by(name=resource_type_name, first=True, to_dict=False)
|
rt = ResourceType.get_by(name=resource_type_name, app_id=app_id, first=True, to_dict=False)
|
||||||
rt or abort(404, ErrFormat.resource_type_not_found.format(resource_type_name))
|
rt or abort(404, ErrFormat.resource_type_not_found.format(resource_type_name))
|
||||||
|
|
||||||
r = Resource.get_by(name=resource_name, resource_type_id=rt.id, app_id=app_id, first=True, to_dict=False)
|
r = Resource.get_by(name=resource_name, resource_type_id=rt.id, app_id=app_id, first=True, to_dict=False)
|
||||||
|
@@ -253,6 +253,7 @@ class CI(Model):
|
|||||||
status = db.Column(db.Enum(*CIStatusEnum.all(), name="status"))
|
status = db.Column(db.Enum(*CIStatusEnum.all(), name="status"))
|
||||||
heartbeat = db.Column(db.DateTime, default=lambda: datetime.datetime.now())
|
heartbeat = db.Column(db.DateTime, default=lambda: datetime.datetime.now())
|
||||||
is_auto_discovery = db.Column('a', db.Boolean, default=False)
|
is_auto_discovery = db.Column('a', db.Boolean, default=False)
|
||||||
|
updated_by = db.Column(db.String(64))
|
||||||
|
|
||||||
ci_type = db.relationship("CIType", backref="c_cis.type_id")
|
ci_type = db.relationship("CIType", backref="c_cis.type_id")
|
||||||
|
|
||||||
@@ -534,6 +535,7 @@ class CustomDashboard(Model):
|
|||||||
|
|
||||||
type_id = db.Column(db.Integer, db.ForeignKey('c_ci_types.id'))
|
type_id = db.Column(db.Integer, db.ForeignKey('c_ci_types.id'))
|
||||||
attr_id = db.Column(db.Integer, db.ForeignKey('c_attributes.id'))
|
attr_id = db.Column(db.Integer, db.ForeignKey('c_attributes.id'))
|
||||||
|
builtin_attr = db.Column(db.String(256), nullable=True)
|
||||||
level = db.Column(db.Integer)
|
level = db.Column(db.Integer)
|
||||||
|
|
||||||
options = db.Column(db.JSON)
|
options = db.Column(db.JSON)
|
||||||
|
@@ -11,38 +11,11 @@
|
|||||||
<span class="common-settings-btn-text">{{ $t('settings') }}</span>
|
<span class="common-settings-btn-text">{{ $t('settings') }}</span>
|
||||||
</span>
|
</span>
|
||||||
<a-popover
|
<a-popover
|
||||||
overlayClassName="lang-popover-wrap"
|
|
||||||
placement="bottomRight"
|
|
||||||
:getPopupContainer="(trigger) => trigger.parentNode"
|
|
||||||
>
|
|
||||||
<span class="locale">{{ languageList.find((lang) => lang.key === locale).title }}</span>
|
|
||||||
<div class="lang-menu" slot="content">
|
|
||||||
<a
|
|
||||||
v-for="(lang) in languageList"
|
|
||||||
:key="lang.key"
|
|
||||||
:class="['lang-menu-item', lang.key === locale ? 'lang-menu-item_active' : '']"
|
|
||||||
@click="changeLang(lang.key)"
|
|
||||||
>
|
|
||||||
{{ lang.title }}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</a-popover>
|
|
||||||
<a-popover
|
|
||||||
:overlayStyle="{ width: '130px' }"
|
|
||||||
placement="bottomRight"
|
placement="bottomRight"
|
||||||
overlayClassName="custom-user"
|
overlayClassName="custom-user"
|
||||||
>
|
>
|
||||||
<template slot="content">
|
<template slot="content">
|
||||||
<router-link :to="{ name: 'setting_person' }" :style="{ color: '#000000a6' }">
|
<UserPanel />
|
||||||
<div class="custom-user-item">
|
|
||||||
<a-icon type="user" :style="{ marginRight: '10px' }" />
|
|
||||||
<span>{{ $t('topMenu.personalCenter') }}</span>
|
|
||||||
</div>
|
|
||||||
</router-link>
|
|
||||||
<div @click="handleLogout" class="custom-user-item">
|
|
||||||
<a-icon type="logout" :style="{ marginRight: '10px' }" />
|
|
||||||
<span>{{ $t('topMenu.logout') }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
<span class="action ant-dropdown-link user-dropdown-menu user-info-wrap">
|
<span class="action ant-dropdown-link user-dropdown-menu user-info-wrap">
|
||||||
<a-avatar
|
<a-avatar
|
||||||
@@ -63,11 +36,13 @@
|
|||||||
import { mapState, mapActions, mapGetters, mapMutations } from 'vuex'
|
import { mapState, mapActions, mapGetters, mapMutations } from 'vuex'
|
||||||
import DocumentLink from './DocumentLink.vue'
|
import DocumentLink from './DocumentLink.vue'
|
||||||
import { setDocumentTitle, domTitle } from '@/utils/domUtil'
|
import { setDocumentTitle, domTitle } from '@/utils/domUtil'
|
||||||
|
import UserPanel from './userPanel.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'UserMenu',
|
name: 'UserMenu',
|
||||||
components: {
|
components: {
|
||||||
DocumentLink,
|
DocumentLink,
|
||||||
|
UserPanel
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
487
cmdb-ui/src/components/tools/userPanel.vue
Normal file
487
cmdb-ui/src/components/tools/userPanel.vue
Normal file
@@ -0,0 +1,487 @@
|
|||||||
|
<template>
|
||||||
|
<div class="user-panel">
|
||||||
|
<a-avatar
|
||||||
|
class="user-panel-avatar"
|
||||||
|
size="small"
|
||||||
|
icon="user"
|
||||||
|
:src="avatarSrc"
|
||||||
|
/>
|
||||||
|
<div class="user-panel-nickname">
|
||||||
|
{{ userInfo.nickname }}
|
||||||
|
</div>
|
||||||
|
<div class="user-panel-info">
|
||||||
|
<ops-icon
|
||||||
|
type="veops-company"
|
||||||
|
class="user-panel-info-icon"
|
||||||
|
/>
|
||||||
|
<div class="user-panel-info-text">
|
||||||
|
{{ companyName }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="user-panel-info">
|
||||||
|
<ops-icon
|
||||||
|
type="veops-emails"
|
||||||
|
class="user-panel-info-icon"
|
||||||
|
/>
|
||||||
|
<div class="user-panel-info-text">
|
||||||
|
{{ email }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="user-panel-btn">
|
||||||
|
<div
|
||||||
|
v-for="(item) in userBtnGroup"
|
||||||
|
:key="item.type"
|
||||||
|
class="user-panel-btn-item"
|
||||||
|
@click="clickBtnGroup(item.type)"
|
||||||
|
>
|
||||||
|
<ops-icon
|
||||||
|
:type="item.icon"
|
||||||
|
class="user-panel-btn-icon"
|
||||||
|
/>
|
||||||
|
<span class="user-panel-btn-title">
|
||||||
|
{{ $t(item.title) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="user-panel-row">
|
||||||
|
<div class="user-panel-row-label">
|
||||||
|
{{ $t('userPanel.switchLanguage') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="user-panel-lang">
|
||||||
|
<div
|
||||||
|
v-for="(lang, index) in languageList"
|
||||||
|
:key="index"
|
||||||
|
:class="['user-panel-lang-item', lang.key === locale ? 'user-panel-lang-item_active' : '']"
|
||||||
|
@click="changeLang(lang.key)"
|
||||||
|
>
|
||||||
|
{{ lang.title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="user-panel-row">
|
||||||
|
<div class="user-panel-row-label">
|
||||||
|
{{ $t('userPanel.bindAccount') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="user-panel-bind">
|
||||||
|
<a-tooltip
|
||||||
|
v-for="(item) in bindList"
|
||||||
|
:key="item.type"
|
||||||
|
:title="$t(item.title)"
|
||||||
|
>
|
||||||
|
<ops-icon
|
||||||
|
class="user-panel-bind-item"
|
||||||
|
:type="userInfo.notice_info && userInfo.notice_info[item.type] ? item.existedIcon : item.icon"
|
||||||
|
@click="handleBindInfo(item.type)"
|
||||||
|
/>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="user-panel-account">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in accountActions"
|
||||||
|
:key="index"
|
||||||
|
class="user-panel-account-item"
|
||||||
|
@click="handleLogout"
|
||||||
|
>
|
||||||
|
<ops-icon class="user-panel-account-icon" :type="item.icon" />
|
||||||
|
<span class="user-panel-account-title">
|
||||||
|
{{ $t(item.title) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions, mapState, mapMutations } from 'vuex'
|
||||||
|
import { setDocumentTitle, domTitle } from '@/utils/domUtil'
|
||||||
|
import {
|
||||||
|
bindPlatformByUid,
|
||||||
|
unbindPlatformByUid,
|
||||||
|
} from '@/api/employee'
|
||||||
|
import { getCompanyInfo } from '@/api/company'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'UserPanel',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
userBtnGroup: [
|
||||||
|
{
|
||||||
|
icon: 'veops-personal',
|
||||||
|
title: 'userPanel.myProfile',
|
||||||
|
type: 'myProfile'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'a-veops-account1',
|
||||||
|
title: 'userPanel.accountPassword',
|
||||||
|
type: 'accountPassword'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
languageList: [
|
||||||
|
{
|
||||||
|
title: '简中',
|
||||||
|
key: 'zh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'EN',
|
||||||
|
key: 'en'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bindList: [
|
||||||
|
{
|
||||||
|
type: 'wechatApp',
|
||||||
|
icon: 'qiyeweixin',
|
||||||
|
existedIcon: 'wechatApp',
|
||||||
|
title: 'wechat'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'feishuApp',
|
||||||
|
icon: 'ops-setting-notice-feishu-selected',
|
||||||
|
existedIcon: 'feishuApp',
|
||||||
|
title: 'feishu'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'dingdingApp',
|
||||||
|
icon: 'ops-setting-notice-dingding-selected',
|
||||||
|
existedIcon: 'dingdingApp',
|
||||||
|
title: 'dingding'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
accountActions: [
|
||||||
|
{
|
||||||
|
icon: 'veops-switch',
|
||||||
|
title: 'userPanel.switchAccount'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'veops-sign_out',
|
||||||
|
title: 'userPanel.logout'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
hoverBindAccountList: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
email: (state) => state.user.email,
|
||||||
|
locale: (state) => state.locale,
|
||||||
|
userInfo: (state) => state.user,
|
||||||
|
companyName: (state) => state.company.name
|
||||||
|
}),
|
||||||
|
avatarSrc() {
|
||||||
|
const avatar = this.userInfo.avatar
|
||||||
|
if (!avatar) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return avatar.startsWith('https') ? avatar : `/api/common-setting/v1/file/${avatar}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.companyName === undefined) {
|
||||||
|
this.getCompanyInfo()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(['Logout', 'GetInfo']),
|
||||||
|
...mapMutations(['SET_LOCALE', 'SET_COMPANY_NAME']),
|
||||||
|
async getCompanyInfo() {
|
||||||
|
const res = await getCompanyInfo()
|
||||||
|
const name = res?.info?.name || ''
|
||||||
|
this.SET_COMPANY_NAME(name)
|
||||||
|
},
|
||||||
|
|
||||||
|
changeLang(lang) {
|
||||||
|
this.SET_LOCALE(lang)
|
||||||
|
this.$i18n.locale = lang
|
||||||
|
this.$nextTick(() => {
|
||||||
|
setDocumentTitle(`${this.$t(this.$route.meta.title)} - ${domTitle}`)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleBindInfo(platform) {
|
||||||
|
const isBind = this?.userInfo?.notice_info?.[platform]
|
||||||
|
const uid = this?.userInfo?.uid
|
||||||
|
|
||||||
|
if (isBind) {
|
||||||
|
this.$confirm({
|
||||||
|
title: this.$t('warning'),
|
||||||
|
content: this.$t('cs.person.confirmUnbind'),
|
||||||
|
onOk: () => {
|
||||||
|
unbindPlatformByUid(platform, uid)
|
||||||
|
.then(() => {
|
||||||
|
this.$message.success(this.$t('cs.person.unbindSuccess'))
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.GetInfo()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
bindPlatformByUid(platform, uid)
|
||||||
|
.then(() => {
|
||||||
|
this.$message.success(this.$t('cs.person.bindSuccess'))
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.GetInfo()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleLogout() {
|
||||||
|
this.$confirm({
|
||||||
|
title: this.$t('tip'),
|
||||||
|
content: this.$t('topMenu.confirmLogout'),
|
||||||
|
onOk: () => {
|
||||||
|
this.Logout()
|
||||||
|
},
|
||||||
|
onCancel() {},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
clickBtnGroup(type) {
|
||||||
|
switch (type) {
|
||||||
|
case 'myProfile':
|
||||||
|
if (this.$route.name === 'setting_person') {
|
||||||
|
this.$bus.$emit('changeSettingPersonCurrent', '1')
|
||||||
|
} else {
|
||||||
|
this.$router.push({
|
||||||
|
name: 'setting_person',
|
||||||
|
query: {
|
||||||
|
current: '1'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'accountPassword':
|
||||||
|
if (this.$route.name === 'setting_person') {
|
||||||
|
this.$bus.$emit('changeSettingPersonCurrent', '2')
|
||||||
|
} else {
|
||||||
|
this.$router.push({
|
||||||
|
name: 'setting_person',
|
||||||
|
query: {
|
||||||
|
current: '2'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleBindAccountMouse(type, isHover) {
|
||||||
|
const index = this.hoverBindAccountList.findIndex((item) => item === type)
|
||||||
|
if (isHover && index === -1) {
|
||||||
|
this.hoverBindAccountList.push(type)
|
||||||
|
} else if (!isHover && index !== -1) {
|
||||||
|
this.hoverBindAccountList.splice(index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.user-panel {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
width: 350px;
|
||||||
|
padding: 0 20px;
|
||||||
|
|
||||||
|
&-avatar {
|
||||||
|
width: 62px;
|
||||||
|
height: 62px;
|
||||||
|
border-radius: 62px;
|
||||||
|
margin-top: 13px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #000000;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
font-size: 48px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-nickname {
|
||||||
|
color: #1D2129;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 700;
|
||||||
|
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
text-wrap: nowrap;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 6px;
|
||||||
|
margin-top: 6px;
|
||||||
|
max-width: 100%;
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-text {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #4E5969;
|
||||||
|
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
text-wrap: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-btn {
|
||||||
|
width: 100%;
|
||||||
|
height: 72px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 11px;
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
font-size: 22px;
|
||||||
|
color: #CACDD9;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #1D2129;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-item {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #F7F8FA;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #EBEFF8;
|
||||||
|
|
||||||
|
.user-panel-btn-icon {
|
||||||
|
color: #2F54EB;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-panel-btn-title {
|
||||||
|
color: #2F54EB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-row {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 22px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&-label {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #4E5969;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-lang {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 28px;
|
||||||
|
width: 108px;
|
||||||
|
border-radius: 28px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&-item {
|
||||||
|
flex: 1;
|
||||||
|
height: 28px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #F7F8FA;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
border-right: solid 1px #E4E7ED;
|
||||||
|
}
|
||||||
|
|
||||||
|
&_active {
|
||||||
|
background-color: #EBEFF8;
|
||||||
|
color: #2F54EB;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #2F54EB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-bind {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 22px;
|
||||||
|
|
||||||
|
&-item {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-account {
|
||||||
|
margin-top: 22px;
|
||||||
|
padding-top: 13px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
border-top: solid 1px #F0F1F5;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #CACDD9;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #86909C;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.user-panel-account-icon {
|
||||||
|
color: #2F54EB;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-panel-account-title {
|
||||||
|
color: #2F54EB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@@ -168,6 +168,15 @@ export default {
|
|||||||
monetaryAmount: 'monetary amount',
|
monetaryAmount: 'monetary amount',
|
||||||
custom: 'custom',
|
custom: 'custom',
|
||||||
},
|
},
|
||||||
|
userPanel: {
|
||||||
|
myProfile: 'My Profile',
|
||||||
|
accountPassword: 'Password',
|
||||||
|
notice: 'Notice',
|
||||||
|
switchLanguage: 'Switch Language',
|
||||||
|
bindAccount: 'Bind Account',
|
||||||
|
switchAccount: 'Switch Account',
|
||||||
|
logout: 'Logout'
|
||||||
|
},
|
||||||
cmdb: cmdb_en,
|
cmdb: cmdb_en,
|
||||||
cs: cs_en,
|
cs: cs_en,
|
||||||
acl: acl_en,
|
acl: acl_en,
|
||||||
|
@@ -168,6 +168,15 @@ export default {
|
|||||||
monetaryAmount: '货币金额',
|
monetaryAmount: '货币金额',
|
||||||
custom: '自定义',
|
custom: '自定义',
|
||||||
},
|
},
|
||||||
|
userPanel: {
|
||||||
|
myProfile: '个人中心',
|
||||||
|
accountPassword: '账号密码',
|
||||||
|
notice: '通知中心',
|
||||||
|
switchLanguage: '切换语言',
|
||||||
|
bindAccount: '绑定账号',
|
||||||
|
switchAccount: '切换账号',
|
||||||
|
logout: '退出账号'
|
||||||
|
},
|
||||||
cmdb: cmdb_zh,
|
cmdb: cmdb_zh,
|
||||||
cs: cs_zh,
|
cs: cs_zh,
|
||||||
acl: acl_zh,
|
acl: acl_zh,
|
||||||
|
11
cmdb-ui/src/store/global/company.js
Normal file
11
cmdb-ui/src/store/global/company.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
const company = {
|
||||||
|
state: {
|
||||||
|
name: undefined
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
SET_COMPANY_NAME: (state, name) => {
|
||||||
|
state.name = name
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
export default company
|
@@ -46,7 +46,8 @@ const user = {
|
|||||||
sex: '',
|
sex: '',
|
||||||
position_name: '',
|
position_name: '',
|
||||||
direct_supervisor_id: null,
|
direct_supervisor_id: null,
|
||||||
auth_enable: {}
|
auth_enable: {},
|
||||||
|
notice_info: {}
|
||||||
},
|
},
|
||||||
|
|
||||||
mutations: {
|
mutations: {
|
||||||
@@ -54,7 +55,7 @@ const user = {
|
|||||||
state.token = token
|
state.token = token
|
||||||
},
|
},
|
||||||
|
|
||||||
SET_USER_INFO: (state, { name, welcome, avatar, roles, info, uid, rid, username, mobile, department_id, employee_id, email, nickname, sex, position_name, direct_supervisor_id, annual_leave }) => {
|
SET_USER_INFO: (state, { name, welcome, avatar, roles, info, uid, rid, username, mobile, department_id, employee_id, email, nickname, sex, position_name, direct_supervisor_id, annual_leave, notice_info }) => {
|
||||||
state.name = name
|
state.name = name
|
||||||
state.welcome = welcome
|
state.welcome = welcome
|
||||||
state.avatar = avatar
|
state.avatar = avatar
|
||||||
@@ -73,6 +74,7 @@ const user = {
|
|||||||
state.position_name = position_name
|
state.position_name = position_name
|
||||||
state.direct_supervisor_id = direct_supervisor_id
|
state.direct_supervisor_id = direct_supervisor_id
|
||||||
state.annual_leave = annual_leave
|
state.annual_leave = annual_leave
|
||||||
|
state.notice_info = notice_info
|
||||||
},
|
},
|
||||||
|
|
||||||
LOAD_ALL_USERS: (state, users) => {
|
LOAD_ALL_USERS: (state, users) => {
|
||||||
@@ -160,7 +162,8 @@ const user = {
|
|||||||
sex: res.sex,
|
sex: res.sex,
|
||||||
position_name: res.position_name,
|
position_name: res.position_name,
|
||||||
direct_supervisor_id: res.direct_supervisor_id,
|
direct_supervisor_id: res.direct_supervisor_id,
|
||||||
annual_leave: res.annual_leave
|
annual_leave: res.annual_leave,
|
||||||
|
notice_info: res.notice_info
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
@@ -7,6 +7,7 @@ import user from './global/user'
|
|||||||
import routes from './global/routes'
|
import routes from './global/routes'
|
||||||
import notice from './global/notice'
|
import notice from './global/notice'
|
||||||
import getters from './global/getters'
|
import getters from './global/getters'
|
||||||
|
import company from './global/company'
|
||||||
import appConfig from '@/config/app'
|
import appConfig from '@/config/app'
|
||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
@@ -16,7 +17,8 @@ const store = new Vuex.Store({
|
|||||||
app,
|
app,
|
||||||
user,
|
user,
|
||||||
routes,
|
routes,
|
||||||
notice
|
notice,
|
||||||
|
company
|
||||||
},
|
},
|
||||||
state: {
|
state: {
|
||||||
windowWidth: 800,
|
windowWidth: 800,
|
||||||
|
@@ -860,20 +860,30 @@ body {
|
|||||||
.vue-treeselect__control {
|
.vue-treeselect__control {
|
||||||
border-radius: 2px !important;
|
border-radius: 2px !important;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
border-color: #e4e7ed;
|
||||||
|
.vue-treeselect__value-container{
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
.vue-treeselect__input-container{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.vue-treeselect__placeholder,
|
.vue-treeselect__placeholder,
|
||||||
.vue-treeselect__single-value {
|
.vue-treeselect__single-value {
|
||||||
line-height: 32px !important;
|
line-height: 28px !important;
|
||||||
}
|
}
|
||||||
.vue-treeselect__input {
|
.vue-treeselect__input {
|
||||||
height: 32px !important;
|
height: 28px !important;
|
||||||
line-height: 32px !important;
|
line-height: 28px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// vue-treeselect 多选样式
|
// vue-treeselect 多选样式
|
||||||
.ops-setting-treeselect.vue-treeselect--multi {
|
.ops-setting-treeselect.vue-treeselect--multi {
|
||||||
.vue-treeselect__control {
|
.vue-treeselect__control {
|
||||||
border-radius: 2px !important;
|
border-radius: 2px !important;
|
||||||
|
border-color: #e4e7ed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -47,6 +47,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { mapMutations } from 'vuex'
|
||||||
import { getCompanyInfo, postCompanyInfo, putCompanyInfo } from '@/api/company'
|
import { getCompanyInfo, postCompanyInfo, putCompanyInfo } from '@/api/company'
|
||||||
import SpanTitle from '../components/spanTitle.vue'
|
import SpanTitle from '../components/spanTitle.vue'
|
||||||
import { mixinPermissions } from '@/utils/mixin'
|
import { mixinPermissions } from '@/utils/mixin'
|
||||||
@@ -82,6 +83,7 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.infoData = res.info
|
this.infoData = res.info
|
||||||
this.getId = res.id
|
this.getId = res.id
|
||||||
|
this.SET_COMPANY_NAME(res?.info?.name || '')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -122,6 +124,7 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapMutations(['SET_COMPANY_NAME']),
|
||||||
async onSubmit() {
|
async onSubmit() {
|
||||||
this.$refs.infoData.validate(async (valid) => {
|
this.$refs.infoData.validate(async (valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
@@ -130,6 +133,7 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
await putCompanyInfo(this.getId, this.infoData)
|
await putCompanyInfo(this.getId, this.infoData)
|
||||||
}
|
}
|
||||||
|
this.SET_COMPANY_NAME(this.infoData.name || '')
|
||||||
this.$message.success(this.$t('saveSuccess'))
|
this.$message.success(this.$t('saveSuccess'))
|
||||||
} else {
|
} else {
|
||||||
this.$message.warning(this.$t('cs.companyInfo.checkInputCorrect'))
|
this.$message.warning(this.$t('cs.companyInfo.checkInputCorrect'))
|
||||||
|
@@ -1,393 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-modal
|
|
||||||
:visible="visible"
|
|
||||||
:title="$t('cs.companyStructure.batchImport')"
|
|
||||||
dialogClass="ops-modal setting-structure-upload"
|
|
||||||
:width="800"
|
|
||||||
@cancel="close"
|
|
||||||
>
|
|
||||||
<div class="setting-structure-upload-steps">
|
|
||||||
<div
|
|
||||||
:class="{ 'setting-structure-upload-step': true, selected: index + 1 <= currentStep }"
|
|
||||||
v-for="(step, index) in stepList"
|
|
||||||
:key="step.value"
|
|
||||||
>
|
|
||||||
<div :class="{ 'setting-structure-upload-step-icon': true }">
|
|
||||||
<ops-icon :type="step.icon" />
|
|
||||||
</div>
|
|
||||||
<span>{{ step.label }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<template v-if="currentStep === 1">
|
|
||||||
<a-upload :multiple="false" :customRequest="customRequest" accept=".xlsx" :showUploadList="false">
|
|
||||||
<a-button :style="{ marginBottom: '20px' }" type="primary"> <a-icon type="upload" />{{ $t('cs.companyStructure.selectFile') }}</a-button>
|
|
||||||
</a-upload>
|
|
||||||
<p><a @click="download">{{ $t('cs.companyStructure.clickDownloadImportTemplate') }}</a></p>
|
|
||||||
</template>
|
|
||||||
<div
|
|
||||||
:style="{
|
|
||||||
height: '60px',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
whiteSpace: 'pre-wrap',
|
|
||||||
}"
|
|
||||||
v-if="currentStep === 3"
|
|
||||||
>
|
|
||||||
{{ $t('cs.companyStructure.importSuccess', { allCount: allCount })
|
|
||||||
}}<span :style="{ color: '#2362FB' }"> {{ allCount - errorCount }} </span>{{ $t('cs.companyStructure.count') }},
|
|
||||||
{{ $t('cs.companyStructure.importFailed') }}<span :style="{ color: '#D81E06' }"> {{ errorCount }} </span
|
|
||||||
>{{ $t('cs.companyStructure.count') }}
|
|
||||||
</div>
|
|
||||||
<vxe-table
|
|
||||||
v-if="currentStep === 2 || has_error"
|
|
||||||
ref="employeeTable"
|
|
||||||
stripe
|
|
||||||
:data="importData"
|
|
||||||
show-overflow
|
|
||||||
show-header-overflow
|
|
||||||
highlight-hover-row
|
|
||||||
size="small"
|
|
||||||
class="ops-stripe-table"
|
|
||||||
:max-height="400"
|
|
||||||
:column-config="{ resizable: true }"
|
|
||||||
>
|
|
||||||
<vxe-column field="email" :title="$t('cs.companyStructure.email')" min-width="120" fixed="left"></vxe-column>
|
|
||||||
<vxe-column field="username" :title="$t('cs.companyStructure.username')" min-width="80" ></vxe-column>
|
|
||||||
<vxe-column field="nickname" :title="$t('cs.companyStructure.nickname')" min-width="80"></vxe-column>
|
|
||||||
<vxe-column field="password" :title="$t('cs.companyStructure.password')" min-width="80"></vxe-column>
|
|
||||||
<vxe-column field="sex" :title="$t('cs.companyStructure.sex')" min-width="60"></vxe-column>
|
|
||||||
<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 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>
|
|
||||||
</template>
|
|
||||||
</vxe-column>
|
|
||||||
</vxe-table>
|
|
||||||
<a-space slot="footer">
|
|
||||||
<a-button size="small" type="primary" ghost @click="close">{{ $t('cancel') }}</a-button>
|
|
||||||
<a-button v-if="currentStep !== 1" size="small" type="primary" ghost @click="goPre">{{ $t('cs.companyStructure.prevStep') }}</a-button>
|
|
||||||
<a-button v-if="currentStep !== 3" size="small" type="primary" @click="goNext">{{ $t('cs.companyStructure.nextStep') }}</a-button>
|
|
||||||
<a-button v-else size="small" type="primary" @click="close">{{ $t('cs.companyStructure.done') }}</a-button>
|
|
||||||
</a-space>
|
|
||||||
</a-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { downloadExcel, excel2Array } from '@/utils/download'
|
|
||||||
import { importEmployee } from '@/api/employee'
|
|
||||||
export default {
|
|
||||||
name: 'BatchUpload',
|
|
||||||
data() {
|
|
||||||
const stepList = [
|
|
||||||
{
|
|
||||||
value: 1,
|
|
||||||
label: this.$t('cs.companyStructure.uploadFile'),
|
|
||||||
icon: 'icon-shidi-tianjia',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 2,
|
|
||||||
label: this.$t('cs.companyStructure.confirmData'),
|
|
||||||
icon: 'icon-shidi-yunshangchuan',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 3,
|
|
||||||
label: this.$t('cs.companyStructure.uploadDone'),
|
|
||||||
icon: 'icon-shidi-queren',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
const common_importParamsList = [
|
|
||||||
'email',
|
|
||||||
'username',
|
|
||||||
'nickname',
|
|
||||||
'password',
|
|
||||||
'sex',
|
|
||||||
'mobile',
|
|
||||||
'position_name',
|
|
||||||
'department_name',
|
|
||||||
'entry_date',
|
|
||||||
'is_internship',
|
|
||||||
'leave_date',
|
|
||||||
'id_card',
|
|
||||||
'nation',
|
|
||||||
'id_place',
|
|
||||||
'party',
|
|
||||||
'household_registration_type',
|
|
||||||
'hometown',
|
|
||||||
'marry',
|
|
||||||
'max_degree',
|
|
||||||
'emergency_person',
|
|
||||||
'emergency_phone',
|
|
||||||
'bank_card_number',
|
|
||||||
'bank_card_name',
|
|
||||||
'opening_bank',
|
|
||||||
'account_opening_location',
|
|
||||||
'school',
|
|
||||||
'major',
|
|
||||||
'education',
|
|
||||||
'graduation_year',
|
|
||||||
]
|
|
||||||
return {
|
|
||||||
stepList,
|
|
||||||
common_importParamsList,
|
|
||||||
visible: false,
|
|
||||||
currentStep: 1,
|
|
||||||
importData: [],
|
|
||||||
has_error: false,
|
|
||||||
allCount: 0,
|
|
||||||
errorCount: 0,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
open() {
|
|
||||||
this.importData = []
|
|
||||||
this.has_error = false
|
|
||||||
this.errorCount = 0
|
|
||||||
this.visible = true
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
this.currentStep = 1
|
|
||||||
this.visible = false
|
|
||||||
},
|
|
||||||
async goNext() {
|
|
||||||
if (this.currentStep === 2) {
|
|
||||||
// 此处调用后端接口
|
|
||||||
this.allCount = this.importData.length
|
|
||||||
const importData = this.importData.map((item) => {
|
|
||||||
const { _X_ROW_KEY, ...rest } = item
|
|
||||||
const keyArr = Object.keys(rest)
|
|
||||||
keyArr.forEach((key) => {
|
|
||||||
if (rest[key]) {
|
|
||||||
rest[key] = rest[key] + ''
|
|
||||||
}
|
|
||||||
})
|
|
||||||
rest.educational_experience = [
|
|
||||||
{
|
|
||||||
school: rest.school,
|
|
||||||
major: rest.major,
|
|
||||||
education: rest.education,
|
|
||||||
graduation_year: rest.graduation_year,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
delete rest.school
|
|
||||||
delete rest.major
|
|
||||||
delete rest.education
|
|
||||||
delete rest.graduation_year
|
|
||||||
return rest
|
|
||||||
})
|
|
||||||
const res = await importEmployee({ employee_list: importData })
|
|
||||||
if (res.length) {
|
|
||||||
const errData = res.filter((item) => {
|
|
||||||
return item.err.length
|
|
||||||
})
|
|
||||||
console.log('err', errData)
|
|
||||||
this.has_error = true
|
|
||||||
this.errorCount = errData.length
|
|
||||||
this.currentStep += 1
|
|
||||||
this.importData = errData
|
|
||||||
this.$message.error(this.$t('cs.companyStructure.dataErr'))
|
|
||||||
} else {
|
|
||||||
this.currentStep += 1
|
|
||||||
this.$message.success(this.$t('cs.companyStructure.opSuccess'))
|
|
||||||
}
|
|
||||||
this.$emit('refresh')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
goPre() {
|
|
||||||
this.has_error = false
|
|
||||||
this.errorCount = 0
|
|
||||||
this.currentStep -= 1
|
|
||||||
},
|
|
||||||
download() {
|
|
||||||
const data = [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
v: '1、表头标“*”的红色字体为必填项\n2、邮箱、用户名不允许重复\n3、登录密码:密码由6-20位字母、数字组成\n4、部门:上下级部门间用"/"隔开,且从最上级部门开始,例如“深圳分公司/IT部/IT二部”。如出现相同的部门,则默认导入组织架构中顺序靠前的部门',
|
|
||||||
t: 's',
|
|
||||||
s: {
|
|
||||||
alignment: {
|
|
||||||
wrapText: true,
|
|
||||||
vertical: 'center',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
v: '*邮箱',
|
|
||||||
t: 's',
|
|
||||||
s: {
|
|
||||||
font: {
|
|
||||||
color: {
|
|
||||||
rgb: 'FF0000',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
v: '*用户名',
|
|
||||||
t: 's',
|
|
||||||
s: {
|
|
||||||
font: {
|
|
||||||
color: {
|
|
||||||
rgb: 'FF0000',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
v: '*姓名',
|
|
||||||
t: 's',
|
|
||||||
s: {
|
|
||||||
font: {
|
|
||||||
color: {
|
|
||||||
rgb: 'FF0000',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
v: '*密码',
|
|
||||||
t: 's',
|
|
||||||
s: {
|
|
||||||
font: {
|
|
||||||
color: {
|
|
||||||
rgb: 'FF0000',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
v: '性别',
|
|
||||||
t: 's',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
v: '手机号',
|
|
||||||
t: 's',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
v: '岗位',
|
|
||||||
t: 's',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
v: '部门',
|
|
||||||
t: 's',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
]
|
|
||||||
data[1] = data[1].filter((item) => item['v'] !== '目前所属主体')
|
|
||||||
data[1] = data[1].filter((item) => item['v'] !== '初始入职日期')
|
|
||||||
downloadExcel(data, this.$t('cs.companyStructure.downloadTemplateName'))
|
|
||||||
},
|
|
||||||
customRequest(data) {
|
|
||||||
this.fileList = [data.file]
|
|
||||||
excel2Array(data.file).then((res) => {
|
|
||||||
res = res.filter((item) => item.length)
|
|
||||||
this.importData = res.slice(2).map((item) => {
|
|
||||||
const obj = {}
|
|
||||||
// 格式化日期字段
|
|
||||||
item[8] = this.formatDate(item[8]) // 目前主体入职日期
|
|
||||||
item[10] = this.formatDate(item[10]) // 离职日期
|
|
||||||
item[28] = this.formatDate(item[28]) // 毕业年份
|
|
||||||
item.forEach((ele, index) => {
|
|
||||||
obj[this.common_importParamsList[index]] = ele
|
|
||||||
})
|
|
||||||
return obj
|
|
||||||
})
|
|
||||||
this.currentStep = 2
|
|
||||||
})
|
|
||||||
},
|
|
||||||
formatDate(numb) {
|
|
||||||
if (numb) {
|
|
||||||
const time = new Date((numb - 1) * 24 * 3600000 + 1)
|
|
||||||
time.setYear(time.getFullYear() - 70)
|
|
||||||
time.setMonth(time.getMonth())
|
|
||||||
time.setHours(time.getHours() - 8)
|
|
||||||
time.setMinutes(time.getMinutes())
|
|
||||||
time.setMilliseconds(time.getMilliseconds())
|
|
||||||
// return time.valueOf()
|
|
||||||
// 日期格式
|
|
||||||
const format = 'Y-m-d'
|
|
||||||
const year = time.getFullYear()
|
|
||||||
// 由于 getMonth 返回值会比正常月份小 1
|
|
||||||
let month = time.getMonth() + 1
|
|
||||||
let day = time.getDate()
|
|
||||||
month = month > 9 ? month : `0${month}`
|
|
||||||
day = day > 9 ? day : `0${day}`
|
|
||||||
const hash = {
|
|
||||||
Y: year,
|
|
||||||
m: month,
|
|
||||||
d: day,
|
|
||||||
}
|
|
||||||
return format.replace(/\w/g, (o) => {
|
|
||||||
return hash[o]
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less">
|
|
||||||
.setting-structure-upload {
|
|
||||||
.ant-modal-body {
|
|
||||||
padding: 24px 48px;
|
|
||||||
}
|
|
||||||
.setting-structure-upload-steps {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
.setting-structure-upload-step {
|
|
||||||
display: inline-block;
|
|
||||||
text-align: center;
|
|
||||||
position: relative;
|
|
||||||
.setting-structure-upload-step-icon {
|
|
||||||
width: 86px;
|
|
||||||
height: 86px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background-image: url('../../../assets/icon-bg.png');
|
|
||||||
margin-bottom: 20px;
|
|
||||||
> i {
|
|
||||||
font-size: 40px;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
> span {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.setting-structure-upload-step:not(:first-child)::before {
|
|
||||||
content: '';
|
|
||||||
height: 2px;
|
|
||||||
width: 223px;
|
|
||||||
position: absolute;
|
|
||||||
background-color: #e7ecf3;
|
|
||||||
left: -223px;
|
|
||||||
top: 43px;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
.selected.setting-structure-upload-step {
|
|
||||||
&:not(:first-child)::before {
|
|
||||||
background-color: #7eb0ff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.selected {
|
|
||||||
.setting-structure-upload-step-icon {
|
|
||||||
background-image: url('../../../assets/icon-bg-selected.png');
|
|
||||||
}
|
|
||||||
> span {
|
|
||||||
color: rgba(0, 0, 0, 0.8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@@ -10,10 +10,22 @@
|
|||||||
:body-style="{ height: `${windowHeight - 320}px`, overflow: 'hidden', overflowY: 'scroll' }"
|
:body-style="{ height: `${windowHeight - 320}px`, overflow: 'hidden', overflowY: 'scroll' }"
|
||||||
>
|
>
|
||||||
<a-form-model ref="employeeFormData" :model="employeeFormData" :rules="rules" :colon="false">
|
<a-form-model ref="employeeFormData" :model="employeeFormData" :rules="rules" :colon="false">
|
||||||
<a-form-model-item ref="email" :label="$t('cs.companyStructure.email')" prop="email" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='email')!==-1">
|
<a-form-model-item
|
||||||
<a-input v-model="employeeFormData.email" :placeholder="$t('cs.companyStructure.emailPlaceholder')"/>
|
ref="email"
|
||||||
|
:label="$t('cs.companyStructure.email')"
|
||||||
|
prop="email"
|
||||||
|
:style="formModalItemStyle"
|
||||||
|
v-if="attributes.findIndex((v) => v == 'email') !== -1"
|
||||||
|
>
|
||||||
|
<a-input v-model="employeeFormData.email" :placeholder="$t('cs.companyStructure.emailPlaceholder')" />
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
<a-form-model-item ref="username" :label="$t('cs.companyStructure.username')" prop="username" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='username')!==-1">
|
<a-form-model-item
|
||||||
|
ref="username"
|
||||||
|
:label="$t('cs.companyStructure.username')"
|
||||||
|
prop="username"
|
||||||
|
:style="formModalItemStyle"
|
||||||
|
v-if="attributes.findIndex((v) => v == 'username') !== -1"
|
||||||
|
>
|
||||||
<a-input v-model="employeeFormData.username" :placeholder="$t('cs.companyStructure.usernamePlaceholder')" />
|
<a-input v-model="employeeFormData.username" :placeholder="$t('cs.companyStructure.usernamePlaceholder')" />
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
<a-form-model-item
|
<a-form-model-item
|
||||||
@@ -23,31 +35,82 @@
|
|||||||
prop="password"
|
prop="password"
|
||||||
:style="formModalItemStyle"
|
:style="formModalItemStyle"
|
||||||
>
|
>
|
||||||
<a-input-password v-model="employeeFormData.password" :placeholder="$t('cs.companyStructure.passwordPlaceholder')" />
|
<a-input-password
|
||||||
|
v-model="employeeFormData.password"
|
||||||
|
:placeholder="$t('cs.companyStructure.passwordPlaceholder')"
|
||||||
|
/>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
<a-form-model-item ref="nickname" :label="$t('cs.companyStructure.nickname')" prop="nickname" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='nickname')!==-1">
|
<a-form-model-item
|
||||||
|
ref="nickname"
|
||||||
|
:label="$t('cs.companyStructure.nickname')"
|
||||||
|
prop="nickname"
|
||||||
|
:style="formModalItemStyle"
|
||||||
|
v-if="attributes.findIndex((v) => v == 'nickname') !== -1"
|
||||||
|
>
|
||||||
<a-input v-model="employeeFormData.nickname" :placeholder="$t('cs.companyStructure.nicknamePlaceholder')" />
|
<a-input v-model="employeeFormData.nickname" :placeholder="$t('cs.companyStructure.nicknamePlaceholder')" />
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
<a-form-model-item :label="$t('cs.companyStructure.sex')" prop="sex" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='sex')!==-1">
|
<a-form-model-item
|
||||||
|
:label="$t('cs.companyStructure.sex')"
|
||||||
|
prop="sex"
|
||||||
|
:style="formModalItemStyle"
|
||||||
|
v-if="attributes.findIndex((v) => v == 'sex') !== -1"
|
||||||
|
>
|
||||||
<a-select v-model="employeeFormData.sex" :placeholder="$t('cs.companyStructure.sexPlaceholder')">
|
<a-select v-model="employeeFormData.sex" :placeholder="$t('cs.companyStructure.sexPlaceholder')">
|
||||||
<a-select-option value="男"> {{ $t('cs.companyStructure.male') }} </a-select-option>
|
<a-select-option value="男"> {{ $t('cs.companyStructure.male') }} </a-select-option>
|
||||||
<a-select-option value="女"> {{ $t('cs.companyStructure.female') }} </a-select-option>
|
<a-select-option value="女"> {{ $t('cs.companyStructure.female') }} </a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
<a-form-model-item ref="mobile" :label="$t('cs.companyStructure.mobile')" prop="mobile" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='mobile')!==-1">
|
<a-form-model-item
|
||||||
|
ref="mobile"
|
||||||
|
:label="$t('cs.companyStructure.mobile')"
|
||||||
|
prop="mobile"
|
||||||
|
:style="formModalItemStyle"
|
||||||
|
v-if="attributes.findIndex((v) => v == 'mobile') !== -1"
|
||||||
|
>
|
||||||
<a-input v-model="employeeFormData.mobile" :placeholder="$t('cs.companyStructure.mobilePlaceholder')" />
|
<a-input v-model="employeeFormData.mobile" :placeholder="$t('cs.companyStructure.mobilePlaceholder')" />
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
<div :style="{ width: '361px', display: 'inline-block', margin: '0 7px' }" v-if="attributes.findIndex(v=>v=='department_id')!==-1">
|
<a-form-model-item
|
||||||
<div :style="{ height: '41px', lineHeight: '40px' }">{{ $t('cs.companyStructure.departmentName') }}</div>
|
ref="department_id"
|
||||||
<DepartmentTreeSelect v-model="employeeFormData.department_id" />
|
:label="$t('cs.companyStructure.departmentName')"
|
||||||
</div>
|
prop="department_id"
|
||||||
<a-form-model-item ref="position_name" :label="$t('cs.companyStructure.positionName')" prop="position_name" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='position_name')!==-1">
|
:style="formModalItemStyle"
|
||||||
<a-input v-model="employeeFormData.position_name" :placeholder="$t('cs.companyStructure.positionNamePlaceholder')" />
|
v-if="attributes.findIndex((v) => v == 'department_id') !== -1"
|
||||||
|
>
|
||||||
|
<DepartmentTreeSelect style="margin-top: 4px" v-model="employeeFormData.department_id" />
|
||||||
|
</a-form-model-item>
|
||||||
|
<a-form-model-item
|
||||||
|
ref="position_name"
|
||||||
|
:label="$t('cs.companyStructure.positionName')"
|
||||||
|
prop="position_name"
|
||||||
|
:style="formModalItemStyle"
|
||||||
|
v-if="attributes.findIndex((v) => v == 'position_name') !== -1"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
v-model="employeeFormData.position_name"
|
||||||
|
:placeholder="$t('cs.companyStructure.positionNamePlaceholder')"
|
||||||
|
/>
|
||||||
|
</a-form-model-item>
|
||||||
|
<a-form-model-item
|
||||||
|
ref="direct_supervisor_id"
|
||||||
|
:label="$t('cs.companyStructure.selectDirectSupervisor')"
|
||||||
|
prop="direct_supervisor_id"
|
||||||
|
:style="formModalItemStyle"
|
||||||
|
v-if="attributes.findIndex((v) => v == 'direct_supervisor_id') !== -1"
|
||||||
|
>
|
||||||
|
<EmployeeTreeSelect style="margin-top: 4px" v-model="employeeFormData.direct_supervisor_id" />
|
||||||
|
</a-form-model-item>
|
||||||
|
<a-form-model-item
|
||||||
|
ref="work_region"
|
||||||
|
:label="$t('cs.companyStructure.work_region')"
|
||||||
|
prop="work_region"
|
||||||
|
:style="formModalItemStyle"
|
||||||
|
v-if="attributes.findIndex((v) => v == 'work_region') !== -1"
|
||||||
|
>
|
||||||
|
<a-select v-model="employeeFormData.work_region" :placeholder="$t('cs.companyStructure.workRegionPlaceholder')">
|
||||||
|
<a-select-option value="china_mainland"> {{ $t('cs.companyStructure.china_mainland') }} </a-select-option>
|
||||||
|
<a-select-option value="china_hk"> {{ $t('cs.companyStructure.china_hk') }} </a-select-option>
|
||||||
|
</a-select>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
<div :style="{ width: '361px', display: 'inline-block', margin: '0 7px' }" v-if="attributes.findIndex(v=>v=='direct_supervisor_id')!==-1">
|
|
||||||
<div :style="{ height: '41px', lineHeight: '40px' }">{{ $t('cs.companyStructure.selectDirectSupervisor') }}</div>
|
|
||||||
<EmployeeTreeSelect v-model="employeeFormData.direct_supervisor_id" />
|
|
||||||
</div>
|
|
||||||
</a-form-model>
|
</a-form-model>
|
||||||
<template slot="footer">
|
<template slot="footer">
|
||||||
<a-button key="back" @click="close"> {{ $t('cancel') }} </a-button>
|
<a-button key="back" @click="close"> {{ $t('cancel') }} </a-button>
|
||||||
@@ -75,7 +138,7 @@ export default {
|
|||||||
educational_experience: [],
|
educational_experience: [],
|
||||||
children_information: [],
|
children_information: [],
|
||||||
file_is_show: true,
|
file_is_show: true,
|
||||||
attributes: []
|
attributes: [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
@@ -85,7 +148,7 @@ export default {
|
|||||||
},
|
},
|
||||||
inject: ['provide_allTreeDepartment', 'provide_allFlatEmployees'],
|
inject: ['provide_allTreeDepartment', 'provide_allFlatEmployees'],
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
windowHeight: (state) => state.windowHeight,
|
windowHeight: (state) => state.windowHeight,
|
||||||
}),
|
}),
|
||||||
departemntTreeSelectOption() {
|
departemntTreeSelectOption() {
|
||||||
@@ -103,7 +166,12 @@ export default {
|
|||||||
rules() {
|
rules() {
|
||||||
return {
|
return {
|
||||||
email: [
|
email: [
|
||||||
{ required: true, whitespace: true, message: this.$t('cs.companyStructure.emailPlaceholder'), trigger: 'blur' },
|
{
|
||||||
|
required: true,
|
||||||
|
whitespace: true,
|
||||||
|
message: this.$t('cs.companyStructure.emailPlaceholder'),
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
pattern: /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/,
|
pattern: /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/,
|
||||||
message: this.$t('cs.companyStructure.emailFormatErr'),
|
message: this.$t('cs.companyStructure.emailFormatErr'),
|
||||||
@@ -112,12 +180,29 @@ export default {
|
|||||||
{ max: 50, message: this.$t('cs.person.inputStrCountLimit', { limit: 50 }) },
|
{ max: 50, message: this.$t('cs.person.inputStrCountLimit', { limit: 50 }) },
|
||||||
],
|
],
|
||||||
username: [
|
username: [
|
||||||
{ required: true, whitespace: true, message: this.$t('cs.companyStructure.usernamePlaceholder'), trigger: 'blur' },
|
{
|
||||||
|
required: true,
|
||||||
|
whitespace: true,
|
||||||
|
message: this.$t('cs.companyStructure.usernamePlaceholder'),
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
{ max: 20, message: this.$t('cs.person.inputStrCountLimit', { limit: 20 }) },
|
{ max: 20, message: this.$t('cs.person.inputStrCountLimit', { limit: 20 }) },
|
||||||
],
|
],
|
||||||
password: [{ required: true, whitespace: true, message: this.$t('cs.companyStructure.passwordPlaceholder'), trigger: 'blur' }],
|
password: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
whitespace: true,
|
||||||
|
message: this.$t('cs.companyStructure.passwordPlaceholder'),
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
],
|
||||||
nickname: [
|
nickname: [
|
||||||
{ required: true, whitespace: true, message: this.$t('cs.companyStructure.nicknamePlaceholder'), trigger: 'blur' },
|
{
|
||||||
|
required: true,
|
||||||
|
whitespace: true,
|
||||||
|
message: this.$t('cs.companyStructure.nicknamePlaceholder'),
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
{ max: 20, message: this.$t('cs.person.inputStrCountLimit', { limit: 20 }) },
|
{ max: 20, message: this.$t('cs.person.inputStrCountLimit', { limit: 20 }) },
|
||||||
],
|
],
|
||||||
mobile: [
|
mobile: [
|
||||||
@@ -128,7 +213,7 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
Bus.$off('getAttributes')
|
Bus.$off('getAttributes')
|
||||||
@@ -136,7 +221,8 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
async open(getData, type) {
|
async open(getData, type) {
|
||||||
// 提交时去掉school, major, education, graduation_year, name, gender, birthday, parental_leave_left
|
// 提交时去掉school, major, education, graduation_year, name, gender, birthday, parental_leave_left
|
||||||
const { school, major, education, graduation_year, name, gender, birthday, parental_leave_left, ...newGetData } = getData
|
const { school, major, education, graduation_year, name, gender, birthday, parental_leave_left, ...newGetData } =
|
||||||
|
getData
|
||||||
const _getData = _.cloneDeep(newGetData)
|
const _getData = _.cloneDeep(newGetData)
|
||||||
const { direct_supervisor_id } = newGetData
|
const { direct_supervisor_id } = newGetData
|
||||||
if (direct_supervisor_id) {
|
if (direct_supervisor_id) {
|
||||||
@@ -149,46 +235,54 @@ export default {
|
|||||||
// if (type !== 'add' && this.employeeFormData.educational_experience.length !== 0) {
|
// if (type !== 'add' && this.employeeFormData.educational_experience.length !== 0) {
|
||||||
// this.educational_experience = this.employeeFormData.educational_experience
|
// this.educational_experience = this.employeeFormData.educational_experience
|
||||||
// }
|
// }
|
||||||
this.children_information = this.formatChildrenInformationList() || [{
|
this.children_information = this.formatChildrenInformationList() || [
|
||||||
id: uuidv4(),
|
{
|
||||||
name: '',
|
id: uuidv4(),
|
||||||
gender: undefined,
|
name: '',
|
||||||
birthday: null,
|
gender: undefined,
|
||||||
parental_leave_left: 0
|
birthday: null,
|
||||||
}]
|
parental_leave_left: 0,
|
||||||
this.educational_experience = this.formatEducationalExperienceList() || [{
|
},
|
||||||
id: uuidv4(),
|
]
|
||||||
school: '',
|
this.educational_experience = this.formatEducationalExperienceList() || [
|
||||||
major: '',
|
{
|
||||||
education: undefined,
|
id: uuidv4(),
|
||||||
graduation_year: null
|
school: '',
|
||||||
}]
|
major: '',
|
||||||
|
education: undefined,
|
||||||
|
graduation_year: null,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
this.type = type
|
this.type = type
|
||||||
this.visible = true
|
this.visible = true
|
||||||
},
|
},
|
||||||
close() {
|
close() {
|
||||||
this.$refs.employeeFormData.resetFields()
|
this.$refs.employeeFormData.resetFields()
|
||||||
this.educational_experience = [{
|
this.educational_experience = [
|
||||||
school: '',
|
{
|
||||||
major: '',
|
school: '',
|
||||||
education: undefined,
|
major: '',
|
||||||
graduation_year: null
|
education: undefined,
|
||||||
}]
|
graduation_year: null,
|
||||||
this.children_information = [{
|
},
|
||||||
id: uuidv4(),
|
]
|
||||||
name: '',
|
this.children_information = [
|
||||||
gender: undefined,
|
{
|
||||||
birthday: null,
|
id: uuidv4(),
|
||||||
parental_leave_left: 0
|
name: '',
|
||||||
}]
|
gender: undefined,
|
||||||
|
birthday: null,
|
||||||
|
parental_leave_left: 0,
|
||||||
|
},
|
||||||
|
]
|
||||||
this.visible = false
|
this.visible = false
|
||||||
},
|
},
|
||||||
formatChildrenInformationList() {
|
formatChildrenInformationList() {
|
||||||
let arr = []
|
let arr = []
|
||||||
arr = this.employeeFormData.children_information ? this.employeeFormData.children_information : undefined
|
arr = this.employeeFormData.children_information ? this.employeeFormData.children_information : undefined
|
||||||
if (arr && arr.length) {
|
if (arr && arr.length) {
|
||||||
arr.forEach(item => {
|
arr.forEach((item) => {
|
||||||
item.id = uuidv4()
|
item.id = uuidv4()
|
||||||
})
|
})
|
||||||
return arr
|
return arr
|
||||||
@@ -199,7 +293,7 @@ export default {
|
|||||||
let arr = []
|
let arr = []
|
||||||
arr = this.employeeFormData.educational_experience ? this.employeeFormData.educational_experience : undefined
|
arr = this.employeeFormData.educational_experience ? this.employeeFormData.educational_experience : undefined
|
||||||
if (arr && arr.length) {
|
if (arr && arr.length) {
|
||||||
arr.forEach(item => {
|
arr.forEach((item) => {
|
||||||
item.id = uuidv4()
|
item.id = uuidv4()
|
||||||
})
|
})
|
||||||
return arr
|
return arr
|
||||||
@@ -212,12 +306,12 @@ export default {
|
|||||||
school: '',
|
school: '',
|
||||||
major: '',
|
major: '',
|
||||||
education: undefined,
|
education: undefined,
|
||||||
graduation_year: null
|
graduation_year: null,
|
||||||
}
|
}
|
||||||
this.educational_experience.push(newEducational_experience)
|
this.educational_experience.push(newEducational_experience)
|
||||||
},
|
},
|
||||||
removeEducation(removeId) {
|
removeEducation(removeId) {
|
||||||
const _idx = this.educational_experience.findIndex(item => item.id === removeId)
|
const _idx = this.educational_experience.findIndex((item) => item.id === removeId)
|
||||||
if (_idx !== -1) {
|
if (_idx !== -1) {
|
||||||
this.educational_experience.splice(_idx, 1)
|
this.educational_experience.splice(_idx, 1)
|
||||||
}
|
}
|
||||||
@@ -228,12 +322,12 @@ export default {
|
|||||||
name: '',
|
name: '',
|
||||||
gender: undefined,
|
gender: undefined,
|
||||||
birthday: null,
|
birthday: null,
|
||||||
parental_leave_left: 0
|
parental_leave_left: 0,
|
||||||
}
|
}
|
||||||
this.children_information.push(newChildrenInfo)
|
this.children_information.push(newChildrenInfo)
|
||||||
},
|
},
|
||||||
removeChildren(removeId) {
|
removeChildren(removeId) {
|
||||||
const _idx = this.children_information.findIndex(item => item.id === removeId)
|
const _idx = this.children_information.findIndex((item) => item.id === removeId)
|
||||||
if (_idx !== -1) {
|
if (_idx !== -1) {
|
||||||
this.children_information.splice(_idx, 1)
|
this.children_information.splice(_idx, 1)
|
||||||
}
|
}
|
||||||
@@ -254,10 +348,10 @@ export default {
|
|||||||
// }
|
// }
|
||||||
if (date !== null) {
|
if (date !== null) {
|
||||||
if (param === 'graduation_year') {
|
if (param === 'graduation_year') {
|
||||||
const _idx = this.educational_experience.findIndex(item => item.id === id)
|
const _idx = this.educational_experience.findIndex((item) => item.id === id)
|
||||||
this.educational_experience[_idx].graduation_year = moment(date).format('YYYY-MM')
|
this.educational_experience[_idx].graduation_year = moment(date).format('YYYY-MM')
|
||||||
} else if (param === 'birthday') {
|
} else if (param === 'birthday') {
|
||||||
const _idx = this.children_information.findIndex(item => item.id === id)
|
const _idx = this.children_information.findIndex((item) => item.id === id)
|
||||||
this.children_information[_idx].birthday = moment(date).format('YYYY-MM-DD')
|
this.children_information[_idx].birthday = moment(date).format('YYYY-MM-DD')
|
||||||
} else {
|
} else {
|
||||||
this.employeeFormData[param] = moment(date).format('YYYY-MM-DD')
|
this.employeeFormData[param] = moment(date).format('YYYY-MM-DD')
|
||||||
@@ -303,7 +397,7 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.el-date-picker {
|
.el-date-picker {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -16,17 +16,17 @@
|
|||||||
:key="group.id"
|
:key="group.id"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="ops-setting-structure-sidebar-group-header"
|
:class="{
|
||||||
:class="{ 'group-selected': groupIndex === activeGroupIndex }"
|
'ops-setting-structure-sidebar-group-header': true,
|
||||||
|
'group-selected': groupIndex === activeGroupIndex,
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
<div class="ops-setting-structure-sidebar-group-header-avatar">
|
<div class="ops-setting-structure-sidebar-group-header-avatar">
|
||||||
<a-icon :type="group.icon"/>
|
<a-icon :type="group.icon" />
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
class="ops-setting-structure-sidebar-group-header-title"
|
class="ops-setting-structure-sidebar-group-header-title"
|
||||||
@click="
|
@click="clickSelectGroup(groupIndex)"
|
||||||
clickSelectGroup(groupIndex)
|
|
||||||
"
|
|
||||||
:id="[group.id === 0 ? 'employee' : 'department']"
|
:id="[group.id === 0 ? 'employee' : 'department']"
|
||||||
>
|
>
|
||||||
{{ group.title }}
|
{{ group.title }}
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- 筛选框 -->
|
<!-- 筛选框 -->
|
||||||
<div class="Screening-box" v-if="activeGroupIndex === 1" style="background-color: rgb(240, 245, 255) ;">
|
<div class="Screening-box" v-if="activeGroupIndex === 1" style="background-color: rgb(240, 245, 255)">
|
||||||
<a-popover
|
<a-popover
|
||||||
@visibleChange="visibleChange"
|
@visibleChange="visibleChange"
|
||||||
trigger="click"
|
trigger="click"
|
||||||
@@ -122,16 +122,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<span :style="{ whiteSpace: 'nowrap' }">
|
<span :style="{ whiteSpace: 'nowrap' }">
|
||||||
<a-icon class="screening-box-scene-icon" type="filter"/>
|
<a-icon class="screening-box-scene-icon" type="filter" />
|
||||||
{{ getCurrentSceneLabel() }}
|
{{ getCurrentSceneLabel() }}
|
||||||
<a-icon class="screening-box-scene-icon" :type="displayTimeIcon"/>
|
<a-icon class="screening-box-scene-icon" :type="displayTimeIcon" />
|
||||||
</span>
|
</span>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</div>
|
</div>
|
||||||
<SearchForm
|
<SearchForm
|
||||||
ref="search"
|
ref="search"
|
||||||
:canSearchPreferenceAttrList="canSearchPreferenceAttrList"
|
:canSearchPreferenceAttrList="canSearchPreferenceAttrList"
|
||||||
@refresh="handleSearch"/>
|
@refresh="handleSearch"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a-space v-if="isEditable">
|
<a-space v-if="isEditable">
|
||||||
@@ -168,23 +169,24 @@
|
|||||||
<div>
|
<div>
|
||||||
<div :style="{ marginTop: '8px' }" class="ops-list-batch-action" v-show="!!selectedRowKeys.length">
|
<div :style="{ marginTop: '8px' }" class="ops-list-batch-action" v-show="!!selectedRowKeys.length">
|
||||||
<span @click="downloadEmployeeAll">{{ $t('cs.companyStructure.downloadAll') }}</span>
|
<span @click="downloadEmployeeAll">{{ $t('cs.companyStructure.downloadAll') }}</span>
|
||||||
<a-divider type="vertical"/>
|
<a-divider type="vertical" />
|
||||||
<span @click="exportSelectEvent">{{ $t('cs.companyStructure.downloadSelected') }}</span>
|
<span @click="exportSelectEvent">{{ $t('cs.companyStructure.downloadSelected') }}</span>
|
||||||
<a-divider type="vertical"/>
|
<a-divider type="vertical" />
|
||||||
<span @click="openBatchModal('department_id')">{{ $t('cs.companyStructure.editDepartment') }}</span>
|
<span @click="openBatchModal('department_id')">{{ $t('cs.companyStructure.editDepartment') }}</span>
|
||||||
<a-divider type="vertical"/>
|
<a-divider type="vertical" />
|
||||||
<span
|
<span @click="openBatchModal('direct_supervisor_id')">{{
|
||||||
@click="openBatchModal('direct_supervisor_id')">{{ $t('cs.companyStructure.editDirectSupervisor') }}</span>
|
$t('cs.companyStructure.editDirectSupervisor')
|
||||||
<a-divider type="vertical"/>
|
}}</span>
|
||||||
|
<a-divider type="vertical" />
|
||||||
<span @click="openBatchModal('position_name')">{{ $t('cs.companyStructure.editPosition') }}</span>
|
<span @click="openBatchModal('position_name')">{{ $t('cs.companyStructure.editPosition') }}</span>
|
||||||
<a-divider type="vertical"/>
|
<a-divider type="vertical" />
|
||||||
<span @click="openBatchModal('password')">{{ $t('cs.companyStructure.resetPassword') }}</span>
|
<span @click="openBatchModal('password')">{{ $t('cs.companyStructure.resetPassword') }}</span>
|
||||||
<a-divider type="vertical"/>
|
<a-divider type="vertical" />
|
||||||
<span @click="openBatchModal('block', null, 1)">{{ $t('cs.companyStructure.block') }}</span>
|
<span @click="openBatchModal('block', null, 1)">{{ $t('cs.companyStructure.block') }}</span>
|
||||||
<a-divider type="vertical"/>
|
<a-divider type="vertical" />
|
||||||
<span @click="openBatchModal('block', null, 0)">{{ $t('cs.companyStructure.recover') }}</span>
|
<span @click="openBatchModal('block', null, 0)">{{ $t('cs.companyStructure.recover') }}</span>
|
||||||
<a-divider type="vertical"/>
|
<a-divider type="vertical" />
|
||||||
<span>{{ $t('selectRows', {rows: selectedRowKeys.length}) }}</span>
|
<span>{{ $t('selectRows', { rows: selectedRowKeys.length }) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div>
|
<!-- <div>
|
||||||
@@ -195,11 +197,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 批量操作对话框 -->
|
<!-- 批量操作对话框 -->
|
||||||
<BatchModal ref="BatchModal" @refresh="updateAll"/>
|
<BatchModal ref="BatchModal" @refresh="updateAll" />
|
||||||
<!-- 部门表单对话框 -->
|
<!-- 部门表单对话框 -->
|
||||||
<DepartmentModal ref="DepartmentModal" @refresh="clickSelectGroup(1)"/>
|
<DepartmentModal ref="DepartmentModal" @refresh="clickSelectGroup(1)" />
|
||||||
<!-- 员工表单对话框 -->
|
<!-- 员工表单对话框 -->
|
||||||
<EmployeeModal ref="EmployeeModal" @refresh="updateAll"/>
|
<EmployeeModal ref="EmployeeModal" @refresh="updateAll" />
|
||||||
|
|
||||||
<!-- 表格展示 -->
|
<!-- 表格展示 -->
|
||||||
<EmployeeTable
|
<EmployeeTable
|
||||||
@@ -211,7 +213,7 @@
|
|||||||
@onSelectChange="onSelectChange"
|
@onSelectChange="onSelectChange"
|
||||||
@openEmployeeModal="openEmployeeModal"
|
@openEmployeeModal="openEmployeeModal"
|
||||||
@openBatchModal="openBatchModal"
|
@openBatchModal="openBatchModal"
|
||||||
@tranferAttributes="getAttributes"
|
@transferAttributes="getAttributes"
|
||||||
:isEditable="isEditable"
|
:isEditable="isEditable"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
>
|
>
|
||||||
@@ -225,7 +227,9 @@
|
|||||||
:page-size-options="pageSizeOptions"
|
:page-size-options="pageSizeOptions"
|
||||||
:current="tablePage.currentPage"
|
:current="tablePage.currentPage"
|
||||||
:total="tablePage.totalResult"
|
:total="tablePage.totalResult"
|
||||||
:show-total="(total, range) => $t('pagination.total', { range0: range[0], range1: range[1], total:total })"
|
:show-total="
|
||||||
|
(total, range) => $t('pagination.total', { range0: range[0], range1: range[1], total: total })
|
||||||
|
"
|
||||||
:page-size="tablePage.pageSize"
|
:page-size="tablePage.pageSize"
|
||||||
:default-current="1"
|
:default-current="1"
|
||||||
@change="pageOrSizeChange"
|
@change="pageOrSizeChange"
|
||||||
@@ -252,6 +256,9 @@
|
|||||||
clickSelectGroup(1)
|
clickSelectGroup(1)
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
|
@downloadTemplate="downloadTemplate"
|
||||||
|
@customRequest="customRequest"
|
||||||
|
@import="importEmployee"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -262,15 +269,22 @@ import SplitPane from '@/components/SplitPane'
|
|||||||
import CollapseTransition from '@/components/CollapseTransition'
|
import CollapseTransition from '@/components/CollapseTransition'
|
||||||
import Bus from './eventBus/bus'
|
import Bus from './eventBus/bus'
|
||||||
import CategroyTree from './CategoryTree'
|
import CategroyTree from './CategoryTree'
|
||||||
import BatchUpload from './BatchUpload'
|
import BatchUpload from '../components/BatchUpload.vue'
|
||||||
import BatchModal from './BatchModal.vue'
|
import BatchModal from './BatchModal.vue'
|
||||||
import EmployeeModal from './EmployeeModal.vue'
|
import EmployeeModal from './EmployeeModal.vue'
|
||||||
import DepartmentModal from './DepartmentModal.vue'
|
import DepartmentModal from './DepartmentModal.vue'
|
||||||
import EmployeeTable from '../components/employeeTable.vue'
|
import EmployeeTable from '../components/employeeTable.vue'
|
||||||
import { getDepartmentList, deleteDepartmentById, getAllDepartmentList, getAllDepAndEmployee } from '@/api/company'
|
import { getDepartmentList, deleteDepartmentById, getAllDepartmentList, getAllDepAndEmployee } from '@/api/company'
|
||||||
import { getEmployeeList, getEmployeeCount, downloadAllEmployee, getEmployeeListByFilter } from '@/api/employee'
|
import {
|
||||||
|
getEmployeeList,
|
||||||
|
getEmployeeCount,
|
||||||
|
downloadAllEmployee,
|
||||||
|
getEmployeeListByFilter,
|
||||||
|
importEmployee,
|
||||||
|
} from '@/api/employee'
|
||||||
import { mixinPermissions } from '@/utils/mixin'
|
import { mixinPermissions } from '@/utils/mixin'
|
||||||
import SearchForm from '../components/SearchForm.vue'
|
import SearchForm from '../components/SearchForm.vue'
|
||||||
|
import { downloadExcel, excel2Array } from '@/utils/download'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CompanyStructure',
|
name: 'CompanyStructure',
|
||||||
@@ -284,10 +298,22 @@ export default {
|
|||||||
EmployeeModal,
|
EmployeeModal,
|
||||||
DepartmentModal,
|
DepartmentModal,
|
||||||
EmployeeTable,
|
EmployeeTable,
|
||||||
SearchForm
|
SearchForm,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
const common_importParamsList = [
|
||||||
|
'email',
|
||||||
|
'username',
|
||||||
|
'nickname',
|
||||||
|
'password',
|
||||||
|
'sex',
|
||||||
|
'mobile',
|
||||||
|
'position_name',
|
||||||
|
'department_name',
|
||||||
|
'work_region',
|
||||||
|
]
|
||||||
return {
|
return {
|
||||||
|
common_importParamsList,
|
||||||
isActive: '',
|
isActive: '',
|
||||||
visible: true,
|
visible: true,
|
||||||
localStorageKey: 'itsm-company-strcutre',
|
localStorageKey: 'itsm-company-strcutre',
|
||||||
@@ -322,7 +348,7 @@ export default {
|
|||||||
attributes: [],
|
attributes: [],
|
||||||
pageSizeOptions: ['50', '100', '200', '9999'],
|
pageSizeOptions: ['50', '100', '200', '9999'],
|
||||||
expression: [],
|
expression: [],
|
||||||
loading: false
|
loading: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// created() {
|
// created() {
|
||||||
@@ -363,16 +389,26 @@ export default {
|
|||||||
value: 'sex',
|
value: 'sex',
|
||||||
is_choice: true,
|
is_choice: true,
|
||||||
choice_value: [
|
choice_value: [
|
||||||
{ label: this.$t('cs.companyStructure.male'), value: '男' },
|
{ label: this.$t('cs.companyStructure.male'), value: '男' },
|
||||||
{ label: this.$t('cs.companyStructure.female'), value: '女' }]
|
{ label: this.$t('cs.companyStructure.female'), value: '女' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{ label: this.$t('cs.companyStructure.mobile'), value: 'mobile' },
|
{ label: this.$t('cs.companyStructure.mobile'), value: 'mobile' },
|
||||||
{ label: this.$t('cs.companyStructure.departmentName'), value: 'department_name' },
|
{ label: this.$t('cs.companyStructure.departmentName'), value: 'department_name' },
|
||||||
{ label: this.$t('cs.companyStructure.positionName'), value: 'position_name' },
|
{ label: this.$t('cs.companyStructure.positionName'), value: 'position_name' },
|
||||||
{ label: this.$t('cs.companyStructure.supervisor'), value: 'direct_supervisor_id' },
|
{ label: this.$t('cs.companyStructure.supervisor'), value: 'direct_supervisor_id' },
|
||||||
|
{
|
||||||
|
label: this.$t('cs.companyStructure.work_region'),
|
||||||
|
value: 'work_region',
|
||||||
|
is_choice: true,
|
||||||
|
choice_value: [
|
||||||
|
{ label: this.$t('cs.companyStructure.china_mainland'), value: 'china_mainland' },
|
||||||
|
{ label: this.$t('cs.companyStructure.china_hk'), value: 'china_hk' },
|
||||||
|
],
|
||||||
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
sceneList () {
|
sceneList() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
label: this.$t('all'),
|
label: this.$t('all'),
|
||||||
@@ -388,7 +424,7 @@ export default {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
groupData () {
|
groupData() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: 0,
|
id: 0,
|
||||||
@@ -396,7 +432,7 @@ export default {
|
|||||||
icon: 'user',
|
icon: 'user',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
provide() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
@@ -426,11 +462,8 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.currentScene = 0
|
this.currentScene = 0
|
||||||
}
|
}
|
||||||
// console.log(this.currentScene)
|
this.updateCount()
|
||||||
// this.init()
|
this.clickSelectItem(0)
|
||||||
this.clickSelectGroup(0).then(val => {
|
|
||||||
this.clickSelectItem(0)
|
|
||||||
})
|
|
||||||
Bus.$on('updataAllIncludeEmployees', () => {
|
Bus.$on('updataAllIncludeEmployees', () => {
|
||||||
this.getAllFlatEmployees()
|
this.getAllFlatEmployees()
|
||||||
this.getAllDepAndEmployee()
|
this.getAllDepAndEmployee()
|
||||||
@@ -492,7 +525,7 @@ export default {
|
|||||||
setSearchPreferenceAttrList() {
|
setSearchPreferenceAttrList() {
|
||||||
this.canSearchPreferenceAttrList.forEach((item) => {
|
this.canSearchPreferenceAttrList.forEach((item) => {
|
||||||
if (!this.attributes.includes(item.value)) {
|
if (!this.attributes.includes(item.value)) {
|
||||||
this.canSearchPreferenceAttrList = this.canSearchPreferenceAttrList.filter(v => v.value !== item.value)
|
this.canSearchPreferenceAttrList = this.canSearchPreferenceAttrList.filter((v) => v.value !== item.value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -504,9 +537,6 @@ export default {
|
|||||||
this.$refs.ScreeningBoxScenePopover.$refs.tooltip.onVisibleChange(false)
|
this.$refs.ScreeningBoxScenePopover.$refs.tooltip.onVisibleChange(false)
|
||||||
}
|
}
|
||||||
document.getElementById('department').click()
|
document.getElementById('department').click()
|
||||||
// this.currentPage = 1
|
|
||||||
// this.updateTableData(1)
|
|
||||||
// this.departmentList = this.reqDepartmentList(-1)
|
|
||||||
},
|
},
|
||||||
clickHandler(event) {
|
clickHandler(event) {
|
||||||
this.isActive = event.target.innerText
|
this.isActive = event.target.innerText
|
||||||
@@ -544,37 +574,6 @@ export default {
|
|||||||
this.activeEmployeeCount = res1.employee_count
|
this.activeEmployeeCount = res1.employee_count
|
||||||
this.deactiveEmployeeCount = res2.employee_count
|
this.deactiveEmployeeCount = res2.employee_count
|
||||||
},
|
},
|
||||||
async updateTableData(currentPage = 1, pageSize = this.tablePage.pageSize) {
|
|
||||||
this.selectedRowKeys = []
|
|
||||||
let reqEmployeeData = null
|
|
||||||
if (this.activeGroupIndex === 0) {
|
|
||||||
reqEmployeeData = await getEmployeeList({
|
|
||||||
...this.tableFilterData,
|
|
||||||
block_status: this.block_status,
|
|
||||||
page: currentPage,
|
|
||||||
page_size: pageSize,
|
|
||||||
search: this.filterName,
|
|
||||||
order: this.tableSortData || 'direct_supervisor_id',
|
|
||||||
})
|
|
||||||
} else if (this.activeGroupIndex === 1) {
|
|
||||||
reqEmployeeData = await getEmployeeList({
|
|
||||||
...this.tableFilterData,
|
|
||||||
block_status: this.currentScene,
|
|
||||||
department_id: this.selectDepartment.id,
|
|
||||||
page: currentPage,
|
|
||||||
page_size: pageSize,
|
|
||||||
search: this.filterName,
|
|
||||||
order: this.tableSortData || 'direct_supervisor_id',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.tableData = this.FilterTableData(reqEmployeeData)
|
|
||||||
this.tablePage = {
|
|
||||||
...this.tablePage,
|
|
||||||
currentPage: reqEmployeeData.page,
|
|
||||||
pageSize: reqEmployeeData.page_size,
|
|
||||||
totalResult: reqEmployeeData.total,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async updateTableDataByFilter(currentPage = 1, pageSize = this.tablePage.pageSize) {
|
async updateTableDataByFilter(currentPage = 1, pageSize = this.tablePage.pageSize) {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
this.selectedRowKeys = []
|
this.selectedRowKeys = []
|
||||||
@@ -623,7 +622,8 @@ export default {
|
|||||||
let max_index = 0
|
let max_index = 0
|
||||||
educational_experience.forEach((item, index) => {
|
educational_experience.forEach((item, index) => {
|
||||||
if (index < educational_experience.length - 1) {
|
if (index < educational_experience.length - 1) {
|
||||||
max_index = item.graduation_year > educational_experience[index + 1].graduation_year ? index : index + 1
|
max_index =
|
||||||
|
item.graduation_year > educational_experience[index + 1].graduation_year ? index : index + 1
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
tableData[index].school = educational_experience[max_index].school
|
tableData[index].school = educational_experience[max_index].school
|
||||||
@@ -708,7 +708,7 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
block_status = this.currentScene
|
block_status = this.currentScene
|
||||||
}
|
}
|
||||||
downloadAllEmployee({ block_status: block_status }).then(res => {
|
downloadAllEmployee({ block_status: block_status }).then((res) => {
|
||||||
const content = res
|
const content = res
|
||||||
const blob = new Blob([content], { type: 'application/vnd.ms-excel' })
|
const blob = new Blob([content], { type: 'application/vnd.ms-excel' })
|
||||||
const url = window.URL.createObjectURL(blob)
|
const url = window.URL.createObjectURL(blob)
|
||||||
@@ -787,7 +787,8 @@ export default {
|
|||||||
},
|
},
|
||||||
// 请求部门数据
|
// 请求部门数据
|
||||||
async reqDepartmentList(departmentId) {
|
async reqDepartmentList(departmentId) {
|
||||||
const res = (await getDepartmentList({ department_parent_id: departmentId, block: this.currentScene })).departments
|
const res = (await getDepartmentList({ department_parent_id: departmentId, block: this.currentScene }))
|
||||||
|
.departments
|
||||||
return this.transformDepartmentData(res)
|
return this.transformDepartmentData(res)
|
||||||
},
|
},
|
||||||
openDepartmentModal(type) {
|
openDepartmentModal(type) {
|
||||||
@@ -828,10 +829,10 @@ export default {
|
|||||||
},
|
},
|
||||||
sortChangeEvent({ sortList }) {
|
sortChangeEvent({ sortList }) {
|
||||||
this.tableSortData = sortList
|
this.tableSortData = sortList
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
return `${item.order === 'asc' ? '' : '-'}${item.property}`
|
return `${item.order === 'asc' ? '' : '-'}${item.property}`
|
||||||
})
|
})
|
||||||
.join(',')
|
.join(',')
|
||||||
this.updateTableDataByFilter()
|
this.updateTableDataByFilter()
|
||||||
},
|
},
|
||||||
filterChangeEvent({ column, property, values, datas, filterList, $event }) {
|
filterChangeEvent({ column, property, values, datas, filterList, $event }) {
|
||||||
@@ -852,6 +853,137 @@ export default {
|
|||||||
exportSelectEvent() {
|
exportSelectEvent() {
|
||||||
Bus.$emit('reqExportSelectEvent')
|
Bus.$emit('reqExportSelectEvent')
|
||||||
},
|
},
|
||||||
|
downloadTemplate() {
|
||||||
|
const data = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
v: '1、表头标“*”的红色字体为必填项\n2、邮箱、用户名不允许重复\n3、登录密码:密码由6-20位字母、数字组成\n4、部门:上下级部门间用"/"隔开,且从最上级部门开始,例如“深圳分公司/IT部/IT二部”。如出现相同的部门,则默认导入组织架构中顺序靠前的部门',
|
||||||
|
t: 's',
|
||||||
|
s: {
|
||||||
|
alignment: {
|
||||||
|
wrapText: true,
|
||||||
|
vertical: 'center',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
v: '*邮箱',
|
||||||
|
t: 's',
|
||||||
|
s: {
|
||||||
|
font: {
|
||||||
|
color: {
|
||||||
|
rgb: 'FF0000',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
v: '*用户名',
|
||||||
|
t: 's',
|
||||||
|
s: {
|
||||||
|
font: {
|
||||||
|
color: {
|
||||||
|
rgb: 'FF0000',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
v: '*姓名',
|
||||||
|
t: 's',
|
||||||
|
s: {
|
||||||
|
font: {
|
||||||
|
color: {
|
||||||
|
rgb: 'FF0000',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
v: '*密码',
|
||||||
|
t: 's',
|
||||||
|
s: {
|
||||||
|
font: {
|
||||||
|
color: {
|
||||||
|
rgb: 'FF0000',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
v: '性别',
|
||||||
|
t: 's',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
v: '手机号',
|
||||||
|
t: 's',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
v: '部门',
|
||||||
|
t: 's',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
v: '岗位',
|
||||||
|
t: 's',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
v: '工作地区',
|
||||||
|
t: 's',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]
|
||||||
|
downloadExcel(data, this.$t('cs.companyStructure.downloadTemplateName'))
|
||||||
|
},
|
||||||
|
customRequest({ data }, callback) {
|
||||||
|
excel2Array(data.file).then((res) => {
|
||||||
|
res = res.filter((item) => item.length)
|
||||||
|
callback(
|
||||||
|
res.slice(2).map((item) => {
|
||||||
|
const obj = {}
|
||||||
|
item.forEach((ele, index) => {
|
||||||
|
obj[this.common_importParamsList[index]] = ele
|
||||||
|
})
|
||||||
|
return obj
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async importEmployee({ importData }, callback) {
|
||||||
|
this.allCount = importData.length
|
||||||
|
const _importData = importData.map((item) => {
|
||||||
|
const { _X_ROW_KEY, ...rest } = item
|
||||||
|
const keyArr = Object.keys(rest)
|
||||||
|
keyArr.forEach((key) => {
|
||||||
|
if (rest[key]) {
|
||||||
|
rest[key] = rest[key] + ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
rest.educational_experience = [
|
||||||
|
{
|
||||||
|
school: rest.school,
|
||||||
|
major: rest.major,
|
||||||
|
education: rest.education,
|
||||||
|
graduation_year: rest.graduation_year,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
delete rest.school
|
||||||
|
delete rest.major
|
||||||
|
delete rest.education
|
||||||
|
delete rest.graduation_year
|
||||||
|
const regionMap = {
|
||||||
|
中国大陆: 'china_mainland',
|
||||||
|
中国香港: 'china_hk',
|
||||||
|
'Chinese Mainland': 'china_mainland',
|
||||||
|
'HK China': 'china_hk',
|
||||||
|
}
|
||||||
|
rest.work_region = regionMap[rest.work_region] ?? res.work_region
|
||||||
|
return rest
|
||||||
|
})
|
||||||
|
const res = await importEmployee({ employee_list: _importData })
|
||||||
|
callback(res)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -1051,7 +1183,6 @@ export default {
|
|||||||
color: @primary-color;
|
color: @primary-color;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1068,7 +1199,6 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.ops-setting-structure-main-pagination {
|
.ops-setting-structure-main-pagination {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
243
cmdb-ui/src/views/setting/components/BatchUpload.vue
Normal file
243
cmdb-ui/src/views/setting/components/BatchUpload.vue
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
:visible="visible"
|
||||||
|
:title="$t('cs.companyStructure.batchImport')"
|
||||||
|
dialogClass="ops-modal setting-structure-upload"
|
||||||
|
:width="800"
|
||||||
|
@cancel="close"
|
||||||
|
>
|
||||||
|
<div class="setting-structure-upload-steps">
|
||||||
|
<div
|
||||||
|
:class="{ 'setting-structure-upload-step': true, selected: index + 1 <= currentStep }"
|
||||||
|
v-for="(step, index) in stepList"
|
||||||
|
:key="step.value"
|
||||||
|
>
|
||||||
|
<div :class="{ 'setting-structure-upload-step-icon': true }">
|
||||||
|
<ops-icon :type="step.icon" />
|
||||||
|
</div>
|
||||||
|
<span>{{ step.label }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template v-if="currentStep === 1">
|
||||||
|
<a-upload :multiple="false" :customRequest="customRequest" accept=".xlsx" :showUploadList="false">
|
||||||
|
<a-button :style="{ marginBottom: '20px' }" type="primary">
|
||||||
|
<a-icon type="upload" />{{ $t('cs.companyStructure.selectFile') }}</a-button
|
||||||
|
>
|
||||||
|
</a-upload>
|
||||||
|
<p>
|
||||||
|
<a @click="download">
|
||||||
|
<slot name="downloadTemplateText">{{ $t('cs.companyStructure.clickDownloadImportTemplate') }}</slot>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
height: '60px',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
whiteSpace: 'pre-wrap',
|
||||||
|
}"
|
||||||
|
v-if="currentStep === 3"
|
||||||
|
>
|
||||||
|
{{ $t('cs.companyStructure.importSuccess', { allCount: allCount })
|
||||||
|
}}<span :style="{ color: '#2362FB' }"> {{ allCount - errorCount }} </span>{{ $t('cs.companyStructure.count') }},
|
||||||
|
{{ $t('cs.companyStructure.importFailed') }}<span :style="{ color: '#D81E06' }"> {{ errorCount }} </span
|
||||||
|
>{{ $t('cs.companyStructure.count') }}
|
||||||
|
</div>
|
||||||
|
<slot>
|
||||||
|
<vxe-table
|
||||||
|
v-if="currentStep === 2 || has_error"
|
||||||
|
ref="employeeTable"
|
||||||
|
stripe
|
||||||
|
:data="importData"
|
||||||
|
show-overflow
|
||||||
|
show-header-overflow
|
||||||
|
highlight-hover-row
|
||||||
|
size="small"
|
||||||
|
class="ops-stripe-table"
|
||||||
|
:max-height="400"
|
||||||
|
:column-config="{ resizable: true }"
|
||||||
|
>
|
||||||
|
<vxe-column field="email" :title="$t('cs.companyStructure.email')" min-width="120" fixed="left"></vxe-column>
|
||||||
|
<vxe-column field="username" :title="$t('cs.companyStructure.username')" min-width="80"></vxe-column>
|
||||||
|
<vxe-column field="nickname" :title="$t('cs.companyStructure.nickname')" min-width="80"></vxe-column>
|
||||||
|
<vxe-column field="password" :title="$t('cs.companyStructure.password')" min-width="80"></vxe-column>
|
||||||
|
<vxe-column field="sex" :title="$t('cs.companyStructure.sex')" min-width="60"></vxe-column>
|
||||||
|
<vxe-column field="mobile" :title="$t('cs.companyStructure.mobile')" min-width="80"></vxe-column>
|
||||||
|
<vxe-column
|
||||||
|
field="department_name"
|
||||||
|
:title="$t('cs.companyStructure.departmentName')"
|
||||||
|
min-width="80"
|
||||||
|
></vxe-column>
|
||||||
|
<vxe-column field="position_name" :title="$t('cs.companyStructure.positionName')" min-width="80"></vxe-column>
|
||||||
|
<vxe-column field="work_region" :title="$t('cs.companyStructure.work_region')" min-width="80"></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>
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
</vxe-table>
|
||||||
|
</slot>
|
||||||
|
<a-space slot="footer">
|
||||||
|
<a-button size="small" type="primary" ghost @click="close">{{ $t('cancel') }}</a-button>
|
||||||
|
<a-button v-if="currentStep !== 1" size="small" type="primary" ghost @click="goPre">{{
|
||||||
|
$t('cs.companyStructure.prevStep')
|
||||||
|
}}</a-button>
|
||||||
|
<a-button v-if="currentStep !== 3" size="small" type="primary" @click="goNext">{{
|
||||||
|
$t('cs.companyStructure.nextStep')
|
||||||
|
}}</a-button>
|
||||||
|
<a-button v-else size="small" type="primary" @click="close">{{ $t('cs.companyStructure.done') }}</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'BatchUpload',
|
||||||
|
data() {
|
||||||
|
const stepList = [
|
||||||
|
{
|
||||||
|
value: 1,
|
||||||
|
label: this.$t('cs.companyStructure.uploadFile'),
|
||||||
|
icon: 'icon-shidi-tianjia',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 2,
|
||||||
|
label: this.$t('cs.companyStructure.confirmData'),
|
||||||
|
icon: 'icon-shidi-yunshangchuan',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 3,
|
||||||
|
label: this.$t('cs.companyStructure.uploadDone'),
|
||||||
|
icon: 'icon-shidi-queren',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return {
|
||||||
|
stepList,
|
||||||
|
visible: false,
|
||||||
|
currentStep: 1,
|
||||||
|
importData: [],
|
||||||
|
has_error: false,
|
||||||
|
allCount: 0,
|
||||||
|
errorCount: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open() {
|
||||||
|
this.importData = []
|
||||||
|
this.has_error = false
|
||||||
|
this.errorCount = 0
|
||||||
|
this.visible = true
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.currentStep = 1
|
||||||
|
this.visible = false
|
||||||
|
},
|
||||||
|
async goNext() {
|
||||||
|
if (this.currentStep === 2) {
|
||||||
|
this.allCount = this.importData.length
|
||||||
|
this.$emit('import', { importData: this.importData }, (res) => {
|
||||||
|
if (res.length) {
|
||||||
|
const errData = res.filter((item) => {
|
||||||
|
return item.err.length
|
||||||
|
})
|
||||||
|
console.log('err', errData)
|
||||||
|
this.has_error = true
|
||||||
|
this.errorCount = errData.length
|
||||||
|
this.currentStep += 1
|
||||||
|
this.importData = errData
|
||||||
|
this.$message.error(this.$t('cs.companyStructure.dataErr'))
|
||||||
|
} else {
|
||||||
|
this.currentStep += 1
|
||||||
|
this.$message.success(this.$t('cs.companyStructure.opSuccess'))
|
||||||
|
}
|
||||||
|
this.$emit('refresh')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
goPre() {
|
||||||
|
this.has_error = false
|
||||||
|
this.errorCount = 0
|
||||||
|
this.currentStep -= 1
|
||||||
|
},
|
||||||
|
download() {
|
||||||
|
this.$emit('downloadTemplate')
|
||||||
|
},
|
||||||
|
customRequest(data) {
|
||||||
|
this.fileList = [data.file]
|
||||||
|
this.$emit('customRequest', { data }, (importData) => {
|
||||||
|
this.importData = importData
|
||||||
|
this.currentStep = 2
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.setting-structure-upload {
|
||||||
|
.ant-modal-body {
|
||||||
|
padding: 24px 48px;
|
||||||
|
}
|
||||||
|
.setting-structure-upload-steps {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
.setting-structure-upload-step {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
.setting-structure-upload-step-icon {
|
||||||
|
width: 86px;
|
||||||
|
height: 86px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-image: url('../../../assets/icon-bg.png');
|
||||||
|
margin-bottom: 20px;
|
||||||
|
> i {
|
||||||
|
font-size: 40px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> span {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.setting-structure-upload-step:not(:first-child)::before {
|
||||||
|
content: '';
|
||||||
|
height: 2px;
|
||||||
|
width: 223px;
|
||||||
|
position: absolute;
|
||||||
|
background-color: #e7ecf3;
|
||||||
|
left: -223px;
|
||||||
|
top: 43px;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
.selected.setting-structure-upload-step {
|
||||||
|
&:not(:first-child)::before {
|
||||||
|
background-color: #7eb0ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.selected {
|
||||||
|
.setting-structure-upload-step-icon {
|
||||||
|
background-image: url('../../../assets/icon-bg-selected.png');
|
||||||
|
}
|
||||||
|
> span {
|
||||||
|
color: rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@@ -92,7 +92,7 @@
|
|||||||
<span>{{ $t('cs.companyStructure.sex') }}</span>
|
<span>{{ $t('cs.companyStructure.sex') }}</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template #default="{row}">
|
<template #default="{ row }">
|
||||||
<span v-if="row.sex === '男'">{{ $t('cs.companyStructure.male') }}</span>
|
<span v-if="row.sex === '男'">{{ $t('cs.companyStructure.male') }}</span>
|
||||||
<span v-if="row.sex === '女'">{{ $t('cs.companyStructure.female') }}</span>
|
<span v-if="row.sex === '女'">{{ $t('cs.companyStructure.female') }}</span>
|
||||||
</template>
|
</template>
|
||||||
@@ -175,6 +175,26 @@
|
|||||||
}}</span>
|
}}</span>
|
||||||
</template>
|
</template>
|
||||||
</vxe-column>
|
</vxe-column>
|
||||||
|
<vxe-column
|
||||||
|
field="work_region"
|
||||||
|
v-if="
|
||||||
|
checkedCols.findIndex((v) => v == 'work_region') !== -1 &&
|
||||||
|
attributes.findIndex((v) => v == 'work_region') !== -1
|
||||||
|
"
|
||||||
|
:title="$t('cs.companyStructure.work_region')"
|
||||||
|
min-width="120px"
|
||||||
|
key="work_region"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<span class="vxe-handle">
|
||||||
|
<OpsMoveIcon class="move-icon" />
|
||||||
|
<span>{{ $t('cs.companyStructure.work_region') }}</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ $t(`cs.companyStructure.${row.work_region}`) }}
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
<vxe-column
|
<vxe-column
|
||||||
field="control"
|
field="control"
|
||||||
width="100px"
|
width="100px"
|
||||||
@@ -197,7 +217,7 @@
|
|||||||
>
|
>
|
||||||
<template slot="content">
|
<template slot="content">
|
||||||
<div :style="{ maxHeight: `${windowHeight - 320}px`, overflowY: 'auto', width: '160px' }">
|
<div :style="{ maxHeight: `${windowHeight - 320}px`, overflowY: 'auto', width: '160px' }">
|
||||||
<a-checkbox-group v-model="unsbmitCheckedCols" :options="options" style="display: grid;">
|
<a-checkbox-group v-model="unsbmitCheckedCols" :options="options" style="display: grid">
|
||||||
</a-checkbox-group>
|
</a-checkbox-group>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -209,22 +229,24 @@
|
|||||||
justifyContent: 'flex-end',
|
justifyContent: 'flex-end',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<a-button :style="{ marginRight: '10px' }" size="small" @click="handleCancel">{{ $t('cancel') }}</a-button>
|
<a-button :style="{ marginRight: '10px' }" size="small" @click="handleCancel">{{
|
||||||
|
$t('cancel')
|
||||||
|
}}</a-button>
|
||||||
<a-button size="small" @click="handleSubmit" type="primary">{{ $t('confirm') }}</a-button>
|
<a-button size="small" @click="handleSubmit" type="primary">{{ $t('confirm') }}</a-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<a-icon type="control" style="cursor: pointer;" />
|
<a-icon type="control" style="cursor: pointer" />
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<a-space v-if="tableType === 'structure'">
|
<a-space v-if="tableType === 'structure'">
|
||||||
<a><a-icon type="edit" @click="openEmployeeModal(row, 'edit')"/></a>
|
<a><a-icon type="edit" @click="openEmployeeModal(row, 'edit')" /></a>
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
{{ $t('cs.companyStructure.resetPassword') }}
|
{{ $t('cs.companyStructure.resetPassword') }}
|
||||||
</template>
|
</template>
|
||||||
<a><a-icon type="reload" @click="openBatchModal('password', row)"/></a>
|
<a><a-icon type="reload" @click="openBatchModal('password', row)" /></a>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-tooltip v-if="!row.block">
|
<a-tooltip v-if="!row.block">
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
@@ -305,6 +327,7 @@ export default {
|
|||||||
{ label: this.$t('cs.companyStructure.departmentName'), value: 'department_name' },
|
{ label: this.$t('cs.companyStructure.departmentName'), value: 'department_name' },
|
||||||
{ label: this.$t('cs.companyStructure.positionName'), value: 'position_name' },
|
{ label: this.$t('cs.companyStructure.positionName'), value: 'position_name' },
|
||||||
{ label: this.$t('cs.companyStructure.supervisor'), value: 'direct_supervisor_id' },
|
{ label: this.$t('cs.companyStructure.supervisor'), value: 'direct_supervisor_id' },
|
||||||
|
{ label: this.$t('cs.companyStructure.work_region'), value: 'work_region' },
|
||||||
]
|
]
|
||||||
const checkedCols = JSON.parse(localStorage.getItem('setting-table-CheckedCols')) || [
|
const checkedCols = JSON.parse(localStorage.getItem('setting-table-CheckedCols')) || [
|
||||||
'nickname',
|
'nickname',
|
||||||
@@ -315,6 +338,7 @@ export default {
|
|||||||
'department_name',
|
'department_name',
|
||||||
'position_name',
|
'position_name',
|
||||||
'direct_supervisor_id',
|
'direct_supervisor_id',
|
||||||
|
'work_region',
|
||||||
]
|
]
|
||||||
return {
|
return {
|
||||||
filterRoleList: [],
|
filterRoleList: [],
|
||||||
@@ -442,7 +466,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Bus.$emit('getAttributes', this.attributes)
|
Bus.$emit('getAttributes', this.attributes)
|
||||||
this.$emit('tranferAttributes', this.attributes)
|
this.$emit('transferAttributes', this.attributes)
|
||||||
},
|
},
|
||||||
getIsInterInship(is_internship) {
|
getIsInterInship(is_internship) {
|
||||||
return this.internMap.filter((item) => item.id === is_internship)[0]['label']
|
return this.internMap.filter((item) => item.id === is_internship)[0]['label']
|
||||||
@@ -541,7 +565,7 @@ export default {
|
|||||||
useStyle: true, // 是否导出样式
|
useStyle: true, // 是否导出样式
|
||||||
isFooter: false, // 是否导出表尾(比如合计)
|
isFooter: false, // 是否导出表尾(比如合计)
|
||||||
// 过滤那个字段导出
|
// 过滤那个字段导出
|
||||||
columnFilterMethod: function(column, $columnIndex) {
|
columnFilterMethod: function (column, $columnIndex) {
|
||||||
return !(column.$columnIndex === 0)
|
return !(column.$columnIndex === 0)
|
||||||
// 0是复选框 不导出
|
// 0是复选框 不导出
|
||||||
},
|
},
|
||||||
|
@@ -19,7 +19,7 @@ const cs_en = {
|
|||||||
app: 'APP Authority',
|
app: 'APP Authority',
|
||||||
basic: 'Basic Settings',
|
basic: 'Basic Settings',
|
||||||
theme: 'Theme Settings',
|
theme: 'Theme Settings',
|
||||||
security: 'Security Settings'
|
security: 'Security Settings',
|
||||||
},
|
},
|
||||||
companyInfo: {
|
companyInfo: {
|
||||||
spanCompany: 'Description',
|
spanCompany: 'Description',
|
||||||
@@ -201,7 +201,11 @@ const cs_en = {
|
|||||||
createEmployee: 'Create Employee',
|
createEmployee: 'Create Employee',
|
||||||
editEmployee: 'Edit Employee',
|
editEmployee: 'Edit Employee',
|
||||||
role: 'Role',
|
role: 'Role',
|
||||||
selectDisplayColumn: 'Please select columns to display'
|
selectDisplayColumn: 'Please select columns to display',
|
||||||
|
work_region: 'Work Region',
|
||||||
|
workRegionPlaceholder: 'Please select work region',
|
||||||
|
china_mainland: 'Chinese Mainland',
|
||||||
|
china_hk: 'HK China',
|
||||||
},
|
},
|
||||||
auth: {
|
auth: {
|
||||||
basic: 'Basic',
|
basic: 'Basic',
|
||||||
@@ -220,7 +224,7 @@ const cs_en = {
|
|||||||
user: 'User',
|
user: 'User',
|
||||||
username: 'Username',
|
username: 'Username',
|
||||||
userPlaceholder: 'Please enter username',
|
userPlaceholder: 'Please enter username',
|
||||||
userHelp: 'User DN: cn={},ou=users,dc=xxx,dc=com {} will be replaced by username'
|
userHelp: 'User DN: cn={},ou=users,dc=xxx,dc=com {} will be replaced by username',
|
||||||
},
|
},
|
||||||
cas: {
|
cas: {
|
||||||
server: 'Server Address',
|
server: 'Server Address',
|
||||||
@@ -237,10 +241,11 @@ const cs_en = {
|
|||||||
validateRoutePlaceholder: 'Please enter validate route',
|
validateRoutePlaceholder: 'Please enter validate route',
|
||||||
afterLoginRoute: 'Redirect Route',
|
afterLoginRoute: 'Redirect Route',
|
||||||
afterLoginRoutePlaceholder: 'Please enter redirect route',
|
afterLoginRoutePlaceholder: 'Please enter redirect route',
|
||||||
userMap: 'User Attribute Mapping'
|
userMap: 'User Attribute Mapping',
|
||||||
},
|
},
|
||||||
autoRedirectLogin: 'Auto Redirect to Third-party Login Page',
|
autoRedirectLogin: 'Auto Redirect to Third-party Login Page',
|
||||||
autoRedirectLoginHelp: 'If disabled, a confirmation will be displayed to redirect to third-party login page. Click the Cancel button will go to the built-in login page',
|
autoRedirectLoginHelp:
|
||||||
|
'If disabled, a confirmation will be displayed to redirect to third-party login page. Click the Cancel button will go to the built-in login page',
|
||||||
usernameOrEmail: 'Username/Email',
|
usernameOrEmail: 'Username/Email',
|
||||||
usernameOrEmailPlaceholder: 'Please enter username/email',
|
usernameOrEmailPlaceholder: 'Please enter username/email',
|
||||||
password: 'Password',
|
password: 'Password',
|
||||||
@@ -257,7 +262,7 @@ const cs_en = {
|
|||||||
userInfo: 'User Info',
|
userInfo: 'User Info',
|
||||||
scopes: 'Scopes',
|
scopes: 'Scopes',
|
||||||
scopesPlaceholder: 'Please enter scopes',
|
scopesPlaceholder: 'Please enter scopes',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
duty: {
|
duty: {
|
||||||
basicSetting: 'Basic Settings',
|
basicSetting: 'Basic Settings',
|
||||||
@@ -274,13 +279,13 @@ const cs_en = {
|
|||||||
mainDutyPeople: 'Main Duty Person',
|
mainDutyPeople: 'Main Duty Person',
|
||||||
deputyDutyPeople: 'Deputy Duty Person',
|
deputyDutyPeople: 'Deputy Duty Person',
|
||||||
dutyRule: 'Duty Rule',
|
dutyRule: 'Duty Rule',
|
||||||
'一': 'Mon',
|
一: 'Mon',
|
||||||
'二': 'Tue',
|
二: 'Tue',
|
||||||
'三': 'Wed',
|
三: 'Wed',
|
||||||
'四': 'Thu',
|
四: 'Thu',
|
||||||
'五': 'Fri',
|
五: 'Fri',
|
||||||
'六': 'Sat',
|
六: 'Sat',
|
||||||
'日': 'Sun',
|
日: 'Sun',
|
||||||
searchPlaceholder: 'Please search',
|
searchPlaceholder: 'Please search',
|
||||||
dutyTable: 'Duty Schedule',
|
dutyTable: 'Duty Schedule',
|
||||||
dutyMember: 'Duty Member',
|
dutyMember: 'Duty Member',
|
||||||
@@ -304,7 +309,7 @@ const cs_en = {
|
|||||||
offDutyReceiverPlaceholder: 'Please select off-duty receiver',
|
offDutyReceiverPlaceholder: 'Please select off-duty receiver',
|
||||||
titleLimit: 'Please enter title (20 characters)',
|
titleLimit: 'Please enter title (20 characters)',
|
||||||
remarkLimit: 'Remark 150 characters max',
|
remarkLimit: 'Remark 150 characters max',
|
||||||
frequencyLimit: 'Please enter duty frequency (positive integer)'
|
frequencyLimit: 'Please enter duty frequency (positive integer)',
|
||||||
},
|
},
|
||||||
group: {
|
group: {
|
||||||
groupName: 'User Group',
|
groupName: 'User Group',
|
||||||
@@ -329,7 +334,7 @@ const cs_en = {
|
|||||||
moreThan: 'More Than',
|
moreThan: 'More Than',
|
||||||
lessThan: 'Less Than',
|
lessThan: 'Less Than',
|
||||||
operatorInPlaceholder: 'Separate by ;',
|
operatorInPlaceholder: 'Separate by ;',
|
||||||
selectEmployee: 'Select Employee'
|
selectEmployee: 'Select Employee',
|
||||||
},
|
},
|
||||||
notice: {
|
notice: {
|
||||||
corpid: 'Corp ID',
|
corpid: 'Corp ID',
|
||||||
@@ -368,7 +373,8 @@ const cs_en = {
|
|||||||
disableCreationOfRequestsViaEmail: 'Disable Creation of Requests Via Email',
|
disableCreationOfRequestsViaEmail: 'Disable Creation of Requests Via Email',
|
||||||
specifyAllowedEmails: 'Specify Allowed Emails/Domains, Separate Multiple Values By Comma',
|
specifyAllowedEmails: 'Specify Allowed Emails/Domains, Separate Multiple Values By Comma',
|
||||||
specifyAllowedEmailsExample: 'E.g. user@domain.com,*@domain.com',
|
specifyAllowedEmailsExample: 'E.g. user@domain.com,*@domain.com',
|
||||||
specifyAllowedEmailsLimit: 'Limit cannot apply to requests already in sessions, it will aggregate to its parent ticket',
|
specifyAllowedEmailsLimit:
|
||||||
|
'Limit cannot apply to requests already in sessions, it will aggregate to its parent ticket',
|
||||||
messageConfig: 'Message Settings',
|
messageConfig: 'Message Settings',
|
||||||
moveWrongMessagesToFolder: 'Move Messages to Wrong Folder',
|
moveWrongMessagesToFolder: 'Move Messages to Wrong Folder',
|
||||||
knowMore: 'Learn More',
|
knowMore: 'Learn More',
|
||||||
@@ -438,7 +444,7 @@ const cs_en = {
|
|||||||
myDepartmentAndSubordinateDepartments: 'My Department And Subordinate Departments',
|
myDepartmentAndSubordinateDepartments: 'My Department And Subordinate Departments',
|
||||||
test: 'Test',
|
test: 'Test',
|
||||||
selectApp: 'Select App',
|
selectApp: 'Select App',
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default cs_en
|
export default cs_en
|
||||||
|
@@ -19,7 +19,7 @@ const cs_zh = {
|
|||||||
app: '应用权限',
|
app: '应用权限',
|
||||||
basic: '基础设置',
|
basic: '基础设置',
|
||||||
theme: '主题配置',
|
theme: '主题配置',
|
||||||
security: '安全配置'
|
security: '安全配置',
|
||||||
},
|
},
|
||||||
companyInfo: {
|
companyInfo: {
|
||||||
spanCompany: '公司描述',
|
spanCompany: '公司描述',
|
||||||
@@ -201,7 +201,11 @@ const cs_zh = {
|
|||||||
createEmployee: '新建员工',
|
createEmployee: '新建员工',
|
||||||
editEmployee: '编辑员工',
|
editEmployee: '编辑员工',
|
||||||
role: '角色',
|
role: '角色',
|
||||||
selectDisplayColumn: '请选择需要展示的列'
|
selectDisplayColumn: '请选择需要展示的列',
|
||||||
|
work_region: '工作地区',
|
||||||
|
workRegionPlaceholder: '请选择工作地区',
|
||||||
|
china_mainland: '中国大陆',
|
||||||
|
china_hk: '中国香港',
|
||||||
},
|
},
|
||||||
auth: {
|
auth: {
|
||||||
basic: '基本',
|
basic: '基本',
|
||||||
@@ -220,7 +224,7 @@ const cs_zh = {
|
|||||||
user: '用户',
|
user: '用户',
|
||||||
username: '用户名称',
|
username: '用户名称',
|
||||||
userPlaceholder: '请输入用户名称',
|
userPlaceholder: '请输入用户名称',
|
||||||
userHelp: '用户dn: cn={},ou=users,dc=xxx,dc=com {}会替换成用户名'
|
userHelp: '用户dn: cn={},ou=users,dc=xxx,dc=com {}会替换成用户名',
|
||||||
},
|
},
|
||||||
cas: {
|
cas: {
|
||||||
server: '服务端地址',
|
server: '服务端地址',
|
||||||
@@ -237,7 +241,7 @@ const cs_zh = {
|
|||||||
validateRoutePlaceholder: '请输入验证路由',
|
validateRoutePlaceholder: '请输入验证路由',
|
||||||
afterLoginRoute: '重定向路由',
|
afterLoginRoute: '重定向路由',
|
||||||
afterLoginRoutePlaceholder: '请输入重定向路由',
|
afterLoginRoutePlaceholder: '请输入重定向路由',
|
||||||
userMap: '用户属性映射'
|
userMap: '用户属性映射',
|
||||||
},
|
},
|
||||||
autoRedirectLogin: '自动跳转到第三方登录页',
|
autoRedirectLogin: '自动跳转到第三方登录页',
|
||||||
autoRedirectLoginHelp: '如果关闭,则会弹出跳转到第三方登录页的确认,点取消按钮会进入系统内置的登录页',
|
autoRedirectLoginHelp: '如果关闭,则会弹出跳转到第三方登录页的确认,点取消按钮会进入系统内置的登录页',
|
||||||
@@ -257,7 +261,7 @@ const cs_zh = {
|
|||||||
userInfo: '用户信息',
|
userInfo: '用户信息',
|
||||||
scopes: '授权范围',
|
scopes: '授权范围',
|
||||||
scopesPlaceholder: '请输入授权范围',
|
scopesPlaceholder: '请输入授权范围',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
duty: {
|
duty: {
|
||||||
basicSetting: '基础设置',
|
basicSetting: '基础设置',
|
||||||
@@ -274,13 +278,13 @@ const cs_zh = {
|
|||||||
mainDutyPeople: '主值班人',
|
mainDutyPeople: '主值班人',
|
||||||
deputyDutyPeople: '副值班人',
|
deputyDutyPeople: '副值班人',
|
||||||
dutyRule: '排班规则',
|
dutyRule: '排班规则',
|
||||||
'一': '一',
|
一: '一',
|
||||||
'二': '二',
|
二: '二',
|
||||||
'三': '三',
|
三: '三',
|
||||||
'四': '四',
|
四: '四',
|
||||||
'五': '五',
|
五: '五',
|
||||||
'六': '六',
|
六: '六',
|
||||||
'日': '日',
|
日: '日',
|
||||||
searchPlaceholder: '请查找',
|
searchPlaceholder: '请查找',
|
||||||
dutyTable: '值班表',
|
dutyTable: '值班表',
|
||||||
dutyMember: '值班人员',
|
dutyMember: '值班人员',
|
||||||
@@ -304,7 +308,7 @@ const cs_zh = {
|
|||||||
offDutyReceiverPlaceholder: '请选择非值班时间接收人',
|
offDutyReceiverPlaceholder: '请选择非值班时间接收人',
|
||||||
titleLimit: '请输入标题(20个字符)',
|
titleLimit: '请输入标题(20个字符)',
|
||||||
remarkLimit: '备注150个字符以内',
|
remarkLimit: '备注150个字符以内',
|
||||||
frequencyLimit: '请输入值班频次(正整数)'
|
frequencyLimit: '请输入值班频次(正整数)',
|
||||||
},
|
},
|
||||||
group: {
|
group: {
|
||||||
groupName: '用户分组',
|
groupName: '用户分组',
|
||||||
@@ -329,7 +333,7 @@ const cs_zh = {
|
|||||||
moreThan: '大于',
|
moreThan: '大于',
|
||||||
lessThan: '小于',
|
lessThan: '小于',
|
||||||
operatorInPlaceholder: '以 ; 分隔',
|
operatorInPlaceholder: '以 ; 分隔',
|
||||||
selectEmployee: '选择员工'
|
selectEmployee: '选择员工',
|
||||||
},
|
},
|
||||||
notice: {
|
notice: {
|
||||||
corpid: '企业ID',
|
corpid: '企业ID',
|
||||||
@@ -438,6 +442,6 @@ const cs_zh = {
|
|||||||
myDepartmentAndSubordinateDepartments: '本部门及下属部门',
|
myDepartmentAndSubordinateDepartments: '本部门及下属部门',
|
||||||
test: '测试',
|
test: '测试',
|
||||||
selectApp: '选择应用',
|
selectApp: '选择应用',
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
export default cs_zh
|
export default cs_zh
|
||||||
|
@@ -2,27 +2,13 @@
|
|||||||
<div class="setting-person">
|
<div class="setting-person">
|
||||||
<div class="setting-person-left">
|
<div class="setting-person-left">
|
||||||
<div
|
<div
|
||||||
@click="
|
@click="clickSideItem('1')"
|
||||||
() => {
|
|
||||||
$refs.personForm.clearValidate()
|
|
||||||
$nextTick(() => {
|
|
||||||
current = '1'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
"
|
|
||||||
:class="{ 'setting-person-left-item': true, 'setting-person-left-item-selected': current === '1' }"
|
:class="{ 'setting-person-left-item': true, 'setting-person-left-item-selected': current === '1' }"
|
||||||
>
|
>
|
||||||
<ops-icon type="icon-shidi-yonghu" />{{ $t('cs.person.spanTitle') }}
|
<ops-icon type="icon-shidi-yonghu" />{{ $t('cs.person.spanTitle') }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@click="
|
@click="clickSideItem('2')"
|
||||||
() => {
|
|
||||||
$refs.personForm.clearValidate()
|
|
||||||
$nextTick(() => {
|
|
||||||
current = '2'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
"
|
|
||||||
:class="{ 'setting-person-left-item': true, 'setting-person-left-item-selected': current === '2' }"
|
:class="{ 'setting-person-left-item': true, 'setting-person-left-item-selected': current === '2' }"
|
||||||
>
|
>
|
||||||
<a-icon type="unlock" theme="filled" />{{ $t('cs.person.accountAndPassword') }}
|
<a-icon type="unlock" theme="filled" />{{ $t('cs.person.accountAndPassword') }}
|
||||||
@@ -240,7 +226,14 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.$bus.$off('changeSettingPersonCurrent', this.clickSideItemv)
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.$bus.$on('changeSettingPersonCurrent', this.clickSideItem)
|
||||||
|
if (this.$route?.query?.current) {
|
||||||
|
this.current = this.$route.query.current
|
||||||
|
}
|
||||||
this.getAllFlatEmployees()
|
this.getAllFlatEmployees()
|
||||||
this.getAllFlatDepartment()
|
this.getAllFlatDepartment()
|
||||||
this.getEmployeeByUid()
|
this.getEmployeeByUid()
|
||||||
@@ -249,6 +242,12 @@ export default {
|
|||||||
...mapActions(['GetInfo']),
|
...mapActions(['GetInfo']),
|
||||||
getDepartmentName,
|
getDepartmentName,
|
||||||
getDirectorName,
|
getDirectorName,
|
||||||
|
clickSideItem(type) {
|
||||||
|
this.$refs.personForm.clearValidate()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.current = type
|
||||||
|
})
|
||||||
|
},
|
||||||
getEmployeeByUid() {
|
getEmployeeByUid() {
|
||||||
getEmployeeByUid(this.uid).then((res) => {
|
getEmployeeByUid(this.uid).then((res) => {
|
||||||
this.form = { ...res }
|
this.form = { ...res }
|
||||||
|
Reference in New Issue
Block a user