feat(base-ui):i18n

This commit is contained in:
wang-liang0615 2024-01-02 16:39:41 +08:00
parent 70d674ac4f
commit 3401cf4a1e
50 changed files with 4755 additions and 3345 deletions

View File

@ -1,5 +1,5 @@
<template> <template>
<a-config-provider :locale="locale"> <a-config-provider :locale="antdLocale">
<div id="app" :class="{ 'ops-fullscreen': isOpsFullScreen, 'ops-only-topmenu': isOpsOnlyTopMenu }"> <div id="app" :class="{ 'ops-fullscreen': isOpsFullScreen, 'ops-only-topmenu': isOpsOnlyTopMenu }">
<router-view v-if="alive" /> <router-view v-if="alive" />
</div> </div>
@ -7,8 +7,9 @@
</template> </template>
<script> <script>
import { mapActions } from 'vuex' import { mapState, mapActions, mapMutations } from 'vuex'
import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN' import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN'
import enUS from 'ant-design-vue/lib/locale-provider/en_US'
import { AppDeviceEnquire } from '@/utils/mixin' import { AppDeviceEnquire } from '@/utils/mixin'
import { debounce } from './utils/util' import { debounce } from './utils/util'
@ -24,20 +25,28 @@ export default {
}, },
data() { data() {
return { return {
locale: zhCN,
alive: true, alive: true,
timer: null, timer: null,
} }
}, },
computed: { computed: {
...mapState(['locale']),
antdLocale() {
if (this.locale === 'zh') {
return zhCN
}
return enUS
},
isOpsFullScreen() { isOpsFullScreen() {
return this.$route.name === 'cmdb_screen' return ['cmdb_screen'].includes(this.$route.name)
}, },
isOpsOnlyTopMenu() { isOpsOnlyTopMenu() {
return ['fullscreen_index', 'setting_person'].includes(this.$route.name) return ['fullscreen_index', 'setting_person', 'notice_center'].includes(this.$route.name)
}, },
}, },
created() { created() {
this.SET_LOCALE(localStorage.getItem('ops_locale') || 'zh')
this.$i18n.locale = localStorage.getItem('ops_locale') || 'zh'
this.timer = setInterval(() => { this.timer = setInterval(() => {
this.setTime(new Date().getTime()) this.setTime(new Date().getTime())
}, 1000) }, 1000)
@ -184,6 +193,7 @@ export default {
}, },
methods: { methods: {
...mapActions(['setTime']), ...mapActions(['setTime']),
...mapMutations(['SET_LOCALE']),
reload() { reload() {
this.alive = false this.alive = false
this.$nextTick(() => { this.$nextTick(() => {

View File

@ -1,29 +1,37 @@
export const ruleTypeList = [ import i18n from '@/lang'
{ value: 'and', label: '与' },
{ value: 'or', label: '或' },
// { value: 'not', label: '非' },
]
export const expList = [ export const ruleTypeList = () => {
{ value: 'is', label: '等于' }, return [
{ value: '~is', label: '不等于' }, { value: 'and', label: i18n.t('cmdbFilterComp.and') },
{ value: 'contain', label: '包含' }, { value: 'or', label: i18n.t('cmdbFilterComp.or') },
{ value: '~contain', label: '不包含' }, // { value: 'not', label: '非' },
{ value: 'start_with', label: '以...开始' }, ]
{ value: '~start_with', label: '不以...开始' }, }
{ value: 'end_with', label: '以...结束' },
{ value: '~end_with', label: '不以...结束' },
{ value: '~value', label: '为空' }, // 为空的定义有点绕
{ value: 'value', label: '不为空' },
]
export const advancedExpList = [ export const expList = () => {
{ value: 'in', label: 'in查询' }, return [
{ value: '~in', label: '非in查询' }, { value: 'is', label: i18n.t('cmdbFilterComp.is') },
{ value: 'range', label: '范围' }, { value: '~is', label: i18n.t('cmdbFilterComp.~is') },
{ value: '~range', label: '范围外' }, { value: 'contain', label: i18n.t('cmdbFilterComp.contain') },
{ value: 'compare', label: '比较' }, { value: '~contain', label: i18n.t('cmdbFilterComp.~contain') },
] { value: 'start_with', label: i18n.t('cmdbFilterComp.start_with') },
{ value: '~start_with', label: i18n.t('cmdbFilterComp.~start_with') },
{ value: 'end_with', label: i18n.t('cmdbFilterComp.end_with') },
{ value: '~end_with', label: i18n.t('cmdbFilterComp.~end_with') },
{ value: '~value', label: i18n.t('cmdbFilterComp.~value') }, // 为空的定义有点绕
{ value: 'value', label: i18n.t('cmdbFilterComp.value') },
]
}
export const advancedExpList = () => {
return [
{ value: 'in', label: i18n.t('cmdbFilterComp.in') },
{ value: '~in', label: i18n.t('cmdbFilterComp.~in') },
{ value: 'range', label: i18n.t('cmdbFilterComp.range') },
{ value: '~range', label: i18n.t('cmdbFilterComp.~range') },
{ value: 'compare', label: i18n.t('cmdbFilterComp.compare') },
]
}
export const compareTypeList = [ export const compareTypeList = [
{ value: '1', label: '>' }, { value: '1', label: '>' },

View File

@ -1,293 +1,332 @@
<template> <template>
<div> <div>
<a-space :style="{ display: 'flex', marginBottom: '10px' }" v-for="(item, index) in ruleList" :key="item.id"> <a-space :style="{ display: 'flex', marginBottom: '10px' }" v-for="(item, index) in ruleList" :key="item.id">
<div :style="{ width: '50px', height: '24px', position: 'relative' }"> <div :style="{ width: '70px', height: '24px', position: 'relative' }">
<treeselect <treeselect
v-if="index" v-if="index"
class="custom-treeselect" class="custom-treeselect"
:style="{ width: '50px', '--custom-height': '24px', position: 'absolute', top: '-17px', left: 0 }" :style="{ width: '70px', '--custom-height': '24px', position: 'absolute', top: '-17px', left: 0 }"
v-model="item.type" v-model="item.type"
:multiple="false" :multiple="false"
:clearable="false" :clearable="false"
searchable searchable
:options="ruleTypeList" :options="ruleTypeList"
:normalizer=" :normalizer="
(node) => { (node) => {
return { return {
id: node.value, id: node.value,
label: node.label, label: node.label,
children: node.children, children: node.children,
} }
} }
" "
> >
</treeselect> </treeselect>
</div> </div>
<treeselect <treeselect
class="custom-treeselect" class="custom-treeselect"
:style="{ width: '130px', '--custom-height': '24px' }" :style="{ width: '130px', '--custom-height': '24px' }"
v-model="item.property" v-model="item.property"
:multiple="false" :multiple="false"
:clearable="false" :clearable="false"
searchable searchable
:options="canSearchPreferenceAttrList" :options="canSearchPreferenceAttrList"
:normalizer=" :normalizer="
(node) => { (node) => {
return { return {
id: node.name, id: node.name,
label: node.alias || node.name, label: node.alias || node.name,
children: node.children, children: node.children,
} }
} }
" "
appendToBody appendToBody
:zIndex="1050" :zIndex="1050"
> >
<div <div
:title="node.label" :title="node.label"
slot="option-label" slot="option-label"
slot-scope="{ node }" slot-scope="{ node }"
:style="{ width: '100%', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }" :style="{ width: '100%', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }"
> >
<ValueTypeMapIcon :attr="node.raw" /> <ValueTypeMapIcon :attr="node.raw" />
{{ node.label }} {{ node.label }}
</div> </div>
<div <div
:style="{ width: '100%', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }" :style="{ width: '100%', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }"
slot="value-label" slot="value-label"
slot-scope="{ node }" slot-scope="{ node }"
> >
<ValueTypeMapIcon :attr="node.raw" /> {{ node.label }} <ValueTypeMapIcon :attr="node.raw" /> {{ node.label }}
</div> </div>
</treeselect> </treeselect>
<treeselect <treeselect
class="custom-treeselect" class="custom-treeselect"
:style="{ width: '100px', '--custom-height': '24px' }" :style="{ width: '100px', '--custom-height': '24px' }"
v-model="item.exp" v-model="item.exp"
:multiple="false" :multiple="false"
:clearable="false" :clearable="false"
searchable searchable
:options="[...getExpListByProperty(item.property), ...advancedExpList]" :options="[...getExpListByProperty(item.property), ...advancedExpList]"
:normalizer=" :normalizer="
(node) => { (node) => {
return { return {
id: node.value, id: node.value,
label: node.label, label: node.label,
children: node.children, children: node.children,
} }
} }
" "
@select="(value) => handleChangeExp(value, item, index)" @select="(value) => handleChangeExp(value, item, index)"
appendToBody appendToBody
:zIndex="1050" :zIndex="1050"
> >
</treeselect> </treeselect>
<treeselect <treeselect
class="custom-treeselect" class="custom-treeselect"
:style="{ width: '175px', '--custom-height': '24px' }" :style="{ width: '175px', '--custom-height': '24px' }"
v-model="item.value" v-model="item.value"
:multiple="false" :multiple="false"
:clearable="false" :clearable="false"
searchable searchable
v-if="isChoiceByProperty(item.property) && (item.exp === 'is' || item.exp === '~is')" v-if="isChoiceByProperty(item.property) && (item.exp === 'is' || item.exp === '~is')"
:options="getChoiceValueByProperty(item.property)" :options="getChoiceValueByProperty(item.property)"
placeholder="请选择" :placeholder="$t('placeholder2')"
:normalizer=" :normalizer="
(node) => { (node) => {
return { return {
id: node[0], id: node[0],
label: node[0], label: node[0],
children: node.children, children: node.children,
} }
} }
" "
appendToBody appendToBody
:zIndex="1050" :zIndex="1050"
> >
<div <div
:title="node.label" :title="node.label"
slot="option-label" slot="option-label"
slot-scope="{ node }" slot-scope="{ node }"
:style="{ width: '100%', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }" :style="{ width: '100%', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }"
> >
{{ node.label }} {{ node.label }}
</div> </div>
</treeselect> </treeselect>
<a-input-group <a-input-group
size="small" size="small"
compact compact
v-else-if="item.exp === 'range' || item.exp === '~range'" v-else-if="item.exp === 'range' || item.exp === '~range'"
:style="{ width: '175px' }" :style="{ width: '175px' }"
> >
<a-input class="ops-input" size="small" v-model="item.min" :style="{ width: '78px' }" placeholder="最小值" /> <a-input
~ class="ops-input"
<a-input class="ops-input" size="small" v-model="item.max" :style="{ width: '78px' }" placeholder="最大值" /> size="small"
</a-input-group> v-model="item.min"
<a-input-group size="small" compact v-else-if="item.exp === 'compare'" :style="{ width: '175px' }"> :style="{ width: '78px' }"
<treeselect :placeholder="$t('min')"
class="custom-treeselect" />
:style="{ width: '60px', '--custom-height': '24px' }" ~
v-model="item.compareType" <a-input
:multiple="false" class="ops-input"
:clearable="false" size="small"
searchable v-model="item.max"
:options="compareTypeList" :style="{ width: '78px' }"
:normalizer=" :placeholder="$t('max')"
(node) => { />
return { </a-input-group>
id: node.value, <a-input-group size="small" compact v-else-if="item.exp === 'compare'" :style="{ width: '175px' }">
label: node.label, <treeselect
children: node.children, class="custom-treeselect"
} :style="{ width: '60px', '--custom-height': '24px' }"
} v-model="item.compareType"
" :multiple="false"
appendToBody :clearable="false"
:zIndex="1050" searchable
> :options="compareTypeList"
</treeselect> :normalizer="
<a-input class="ops-input" v-model="item.value" size="small" style="width: 113px" /> (node) => {
</a-input-group> return {
<a-input id: node.value,
v-else-if="item.exp !== 'value' && item.exp !== '~value'" label: node.label,
size="small" children: node.children,
v-model="item.value" }
:placeholder="item.exp === 'in' || item.exp === '~in' ? '以 ; 分隔' : ''" }
class="ops-input" "
></a-input> appendToBody
<div v-else :style="{ width: '175px' }"></div> :zIndex="1050"
<a-tooltip title="复制"> >
<a class="operation" @click="handleCopyRule(item)"><ops-icon type="icon-xianxing-copy"/></a> </treeselect>
</a-tooltip> <a-input class="ops-input" v-model="item.value" size="small" style="width: 113px" />
<a-tooltip title="删除"> </a-input-group>
<a class="operation" @click="handleDeleteRule(item)"><ops-icon type="icon-xianxing-delete"/></a> <a-input
</a-tooltip> v-else-if="item.exp !== 'value' && item.exp !== '~value'"
</a-space> size="small"
<div class="table-filter-add"> v-model="item.value"
<a @click="handleAddRule">+ 新增</a> :placeholder="item.exp === 'in' || item.exp === '~in' ? $t('cmdbFilterComp.split', { separator: ';' }) : ''"
</div> class="ops-input"
</div> :style="{ width: '175px' }"
</template> ></a-input>
<div v-else :style="{ width: '175px' }"></div>
<script> <a-tooltip :title="$t('copy')">
import _ from 'lodash' <a class="operation" @click="handleCopyRule(item)"><ops-icon type="icon-xianxing-copy"/></a>
import { v4 as uuidv4 } from 'uuid' </a-tooltip>
import { ruleTypeList, expList, advancedExpList, compareTypeList } from './constants' <a-tooltip :title="$t('delete')">
import ValueTypeMapIcon from '../CMDBValueTypeMapIcon' <a class="operation" @click="handleDeleteRule(item)"><ops-icon type="icon-xianxing-delete"/></a>
</a-tooltip>
export default { <a-tooltip :title="$t('cmdbFilterComp.addHere')" :needAddHere="needAddHere">
name: 'Expression', <a class="operation" @click="handleAddRuleAt(item)"><a-icon type="plus-circle"/></a>
components: { ValueTypeMapIcon }, </a-tooltip>
model: { </a-space>
prop: 'value', <div class="table-filter-add">
event: 'change', <a @click="handleAddRule">+ {{ $t('new') }}</a>
}, </div>
props: { </div>
value: { </template>
type: Array,
default: () => [], <script>
}, import _ from 'lodash'
canSearchPreferenceAttrList: { import { v4 as uuidv4 } from 'uuid'
type: Array, import { ruleTypeList, expList, advancedExpList, compareTypeList } from './constants'
required: true, import ValueTypeMapIcon from '../CMDBValueTypeMapIcon'
default: () => [],
}, export default {
}, name: 'Expression',
data() { components: { ValueTypeMapIcon },
return { model: {
ruleTypeList, prop: 'value',
expList, event: 'change',
advancedExpList, },
compareTypeList, props: {
} value: {
}, type: Array,
computed: { default: () => [],
ruleList: { },
get() { canSearchPreferenceAttrList: {
return this.value type: Array,
}, required: true,
set(val) { default: () => [],
this.$emit('change', val) },
return val needAddHere: {
}, type: Boolean,
}, default: false,
}, },
methods: { },
getExpListByProperty(property) { data() {
if (property) { return {
const _find = this.canSearchPreferenceAttrList.find((item) => item.name === property) compareTypeList,
if (_find && ['0', '1', '3', '4', '5'].includes(_find.value_type)) { }
return [ },
{ value: 'is', label: '等于' }, computed: {
{ value: '~is', label: '不等于' }, ruleList: {
{ value: '~value', label: '为空' }, // 为空的定义有点绕 get() {
{ value: 'value', label: '不为空' }, return this.value
] },
} set(val) {
return this.expList this.$emit('change', val)
} return val
return this.expList },
}, },
isChoiceByProperty(property) { ruleTypeList() {
const _find = this.canSearchPreferenceAttrList.find((item) => item.name === property) return ruleTypeList()
if (_find) { },
return _find.is_choice expList() {
} return expList()
return false },
}, advancedExpList() {
handleAddRule() { return advancedExpList()
this.ruleList.push({ },
id: uuidv4(), },
type: 'and', methods: {
property: this.canSearchPreferenceAttrList[0]?.name, getExpListByProperty(property) {
exp: 'is', if (property) {
value: null, const _find = this.canSearchPreferenceAttrList.find((item) => item.name === property)
}) if (_find && ['0', '1', '3', '4', '5'].includes(_find.value_type)) {
this.$emit('change', this.ruleList) return [
}, { value: 'is', label: this.$t('cmdbFilterComp.is') },
handleCopyRule(item) { { value: '~is', label: this.$t('cmdbFilterComp.~is') },
this.ruleList.push({ ...item, id: uuidv4() }) { value: '~value', label: this.$t('cmdbFilterComp.~value') }, // 为空的定义有点绕
this.$emit('change', this.ruleList) { value: 'value', label: this.$t('cmdbFilterComp.value') },
}, ]
handleDeleteRule(item) { }
const idx = this.ruleList.findIndex((r) => r.id === item.id) return this.expList
if (idx > -1) { }
this.ruleList.splice(idx, 1) return this.expList
} },
this.$emit('change', this.ruleList) isChoiceByProperty(property) {
}, const _find = this.canSearchPreferenceAttrList.find((item) => item.name === property)
getChoiceValueByProperty(property) { if (_find) {
const _find = this.canSearchPreferenceAttrList.find((item) => item.name === property) return _find.is_choice
if (_find) { }
return _find.choice_value return false
} },
return [] handleAddRule() {
}, this.ruleList.push({
handleChangeExp({ value }, item, index) { id: uuidv4(),
const _ruleList = _.cloneDeep(this.ruleList) type: 'and',
if (value === 'range') { property: this.canSearchPreferenceAttrList[0]?.name,
_ruleList[index] = { exp: 'is',
..._ruleList[index], value: null,
min: '', })
max: '', this.$emit('change', this.ruleList)
exp: value, },
} handleCopyRule(item) {
} else if (value === 'compare') { this.ruleList.push({ ...item, id: uuidv4() })
_ruleList[index] = { this.$emit('change', this.ruleList)
..._ruleList[index], },
compareType: '1', handleDeleteRule(item) {
exp: value, const idx = this.ruleList.findIndex((r) => r.id === item.id)
} if (idx > -1) {
} else { this.ruleList.splice(idx, 1)
_ruleList[index] = { }
..._ruleList[index], this.$emit('change', this.ruleList)
exp: value, },
} handleAddRuleAt(item) {
} const idx = this.ruleList.findIndex((r) => r.id === item.id)
this.ruleList = _ruleList if (idx > -1) {
this.$emit('change', this.ruleList) this.ruleList.splice(idx, 0, {
}, id: uuidv4(),
}, type: 'and',
} property: this.canSearchPreferenceAttrList[0]?.name,
</script> exp: 'is',
value: null,
<style></style> })
}
this.$emit('change', this.ruleList)
},
getChoiceValueByProperty(property) {
const _find = this.canSearchPreferenceAttrList.find((item) => item.name === property)
if (_find) {
return _find.choice_value
}
return []
},
handleChangeExp({ value }, item, index) {
const _ruleList = _.cloneDeep(this.ruleList)
if (value === 'range') {
_ruleList[index] = {
..._ruleList[index],
min: '',
max: '',
exp: value,
}
} else if (value === 'compare') {
_ruleList[index] = {
..._ruleList[index],
compareType: '1',
exp: value,
}
} else {
_ruleList[index] = {
..._ruleList[index],
exp: value,
}
}
this.ruleList = _ruleList
this.$emit('change', this.ruleList)
},
},
}
</script>
<style></style>

View File

@ -1,290 +1,296 @@
<template> <template>
<div> <div>
<a-popover <a-popover
v-if="isDropdown" v-if="isDropdown"
v-model="visible" v-model="visible"
trigger="click" trigger="click"
:placement="placement" :placement="placement"
overlayClassName="table-filter" overlayClassName="table-filter"
@visibleChange="visibleChange" @visibleChange="visibleChange"
> >
<slot name="popover_item"> <slot name="popover_item">
<a-button type="primary" ghost>条件过滤<a-icon type="filter"/></a-button> <a-button type="primary" ghost>{{ $t('cmdbFilterComp.conditionFilter') }}<a-icon type="filter"/></a-button>
</slot> </slot>
<template slot="content"> <template slot="content">
<Expression <Expression
v-model="ruleList" :needAddHere="needAddHere"
:canSearchPreferenceAttrList="canSearchPreferenceAttrList.filter((attr) => !attr.is_password)" v-model="ruleList"
/> :canSearchPreferenceAttrList="canSearchPreferenceAttrList.filter((attr) => !attr.is_password)"
<a-divider :style="{ margin: '10px 0' }" /> />
<div style="width:534px"> <a-divider :style="{ margin: '10px 0' }" />
<a-space :style="{ display: 'flex', justifyContent: 'flex-end' }"> <div style="width:554px">
<a-button type="primary" size="small" @click="handleSubmit">确定</a-button> <a-space :style="{ display: 'flex', justifyContent: 'flex-end' }">
<a-button size="small" @click="handleClear">清空</a-button> <a-button type="primary" size="small" @click="handleSubmit">{{ $t('confirm') }}</a-button>
</a-space> <a-button size="small" @click="handleClear">{{ $t('clear') }}</a-button>
</div> </a-space>
</template> </div>
</a-popover> </template>
<Expression </a-popover>
v-else <Expression
v-model="ruleList" :needAddHere="needAddHere"
:canSearchPreferenceAttrList="canSearchPreferenceAttrList.filter((attr) => !attr.is_password)" v-else
/> v-model="ruleList"
</div> :canSearchPreferenceAttrList="canSearchPreferenceAttrList.filter((attr) => !attr.is_password)"
</template> />
</div>
<script> </template>
import { v4 as uuidv4 } from 'uuid'
import Expression from './expression.vue' <script>
import { advancedExpList, compareTypeList } from './constants' import { v4 as uuidv4 } from 'uuid'
import Expression from './expression.vue'
export default { import { advancedExpList, compareTypeList } from './constants'
name: 'FilterComp',
components: { Expression }, export default {
props: { name: 'FilterComp',
canSearchPreferenceAttrList: { components: { Expression },
type: Array, props: {
required: true, canSearchPreferenceAttrList: {
default: () => [], type: Array,
}, required: true,
expression: { default: () => [],
type: String, },
default: '', expression: {
}, type: String,
regQ: { default: '',
type: String, },
default: '(?<=q=).+(?=&)|(?<=q=).+$', regQ: {
}, type: String,
placement: { default: '(?<=q=).+(?=&)|(?<=q=).+$',
type: String, },
default: 'bottomRight', placement: {
}, type: String,
isDropdown: { default: 'bottomRight',
type: Boolean, },
default: true, isDropdown: {
}, type: Boolean,
}, default: true,
data() { },
return { needAddHere: {
advancedExpList, type: Boolean,
compareTypeList, default: false,
visible: false, },
ruleList: [], },
filterExp: '', data() {
} return {
}, advancedExpList,
compareTypeList,
methods: { visible: false,
visibleChange(open, isInitOne = true) { ruleList: [],
// isInitOne 初始化exp为空时ruleList是否默认给一条 filterExp: '',
// const regQ = /(?<=q=).+(?=&)|(?<=q=).+$/g }
const exp = this.expression.match(new RegExp(this.regQ, 'g')) },
? this.expression.match(new RegExp(this.regQ, 'g'))[0]
: null methods: {
if (open && exp) { visibleChange(open, isInitOne = true) {
const expArray = exp.split(',').map((item) => { // isInitOne 初始化exp为空时ruleList是否默认给一条
let has_not = '' // const regQ = /(?<=q=).+(?=&)|(?<=q=).+$/g
const key = item.split(':')[0] const exp = this.expression.match(new RegExp(this.regQ, 'g'))
const val = item ? this.expression.match(new RegExp(this.regQ, 'g'))[0]
.split(':') : null
.slice(1) if (open && exp) {
.join(':') const expArray = exp.split(',').map((item) => {
let type, property, exp, value, min, max, compareType let has_not = ''
if (key.includes('-')) { const key = item.split(':')[0]
type = 'or' const val = item
if (key.includes('~')) { .split(':')
property = key.substring(2) .slice(1)
has_not = '~' .join(':')
} else { let type, property, exp, value, min, max, compareType
property = key.substring(1) if (key.includes('-')) {
} type = 'or'
} else { if (key.includes('~')) {
type = 'and' property = key.substring(2)
if (key.includes('~')) { has_not = '~'
property = key.substring(1) } else {
has_not = '~' property = key.substring(1)
} else { }
property = key } else {
} type = 'and'
} if (key.includes('~')) {
property = key.substring(1)
const in_reg = /(?<=\().+(?=\))/g has_not = '~'
const range_reg = /(?<=\[).+(?=\])/g } else {
const compare_reg = /(?<=>=|<=|>(?!=)|<(?!=)).+/ property = key
if (val === '*') { }
exp = has_not + 'value' }
value = ''
} else if (in_reg.test(val)) { const in_reg = /(?<=\().+(?=\))/g
exp = has_not + 'in' const range_reg = /(?<=\[).+(?=\])/g
value = val.match(in_reg)[0] const compare_reg = /(?<=>=|<=|>(?!=)|<(?!=)).+/
} else if (range_reg.test(val)) { if (val === '*') {
exp = has_not + 'range' exp = has_not + 'value'
value = val.match(range_reg)[0] value = ''
min = value.split('_TO_')[0] } else if (in_reg.test(val)) {
max = value.split('_TO_')[1] exp = has_not + 'in'
} else if (compare_reg.test(val)) { value = val.match(in_reg)[0]
exp = has_not + 'compare' } else if (range_reg.test(val)) {
value = val.match(compare_reg)[0] exp = has_not + 'range'
const _compareType = val.substring(0, val.match(compare_reg)['index']) value = val.match(range_reg)[0]
const idx = compareTypeList.findIndex((item) => item.label === _compareType) min = value.split('_TO_')[0]
compareType = compareTypeList[idx].value max = value.split('_TO_')[1]
} else if (!val.includes('*')) { } else if (compare_reg.test(val)) {
exp = has_not + 'is' exp = has_not + 'compare'
value = val value = val.match(compare_reg)[0]
} else { const _compareType = val.substring(0, val.match(compare_reg)['index'])
const resList = [ const idx = compareTypeList.findIndex((item) => item.label === _compareType)
['contain', /(?<=\*).*(?=\*)/g], compareType = compareTypeList[idx].value
['end_with', /(?<=\*).+/g], } else if (!val.includes('*')) {
['start_with', /.+(?=\*)/g], exp = has_not + 'is'
] value = val
for (let i = 0; i < 3; i++) { } else {
const reg = resList[i] const resList = [
if (reg[1].test(val)) { ['contain', /(?<=\*).*(?=\*)/g],
exp = has_not + reg[0] ['end_with', /(?<=\*).+/g],
value = val.match(reg[1])[0] ['start_with', /.+(?=\*)/g],
break ]
} for (let i = 0; i < 3; i++) {
} const reg = resList[i]
} if (reg[1].test(val)) {
return { exp = has_not + reg[0]
id: uuidv4(), value = val.match(reg[1])[0]
type, break
property, }
exp, }
value, }
min, return {
max, id: uuidv4(),
compareType, type,
} property,
}) exp,
this.ruleList = [...expArray] value,
} else if (open) { min,
const _canSearchPreferenceAttrList = this.canSearchPreferenceAttrList.filter((attr) => !attr.is_password) max,
this.ruleList = isInitOne compareType,
? [ }
{ })
id: uuidv4(), this.ruleList = [...expArray]
type: 'and', } else if (open) {
property: const _canSearchPreferenceAttrList = this.canSearchPreferenceAttrList.filter((attr) => !attr.is_password)
_canSearchPreferenceAttrList && _canSearchPreferenceAttrList.length this.ruleList = isInitOne
? _canSearchPreferenceAttrList[0].name ? [
: undefined, {
exp: 'is', id: uuidv4(),
value: null, type: 'and',
}, property:
] _canSearchPreferenceAttrList && _canSearchPreferenceAttrList.length
: [] ? _canSearchPreferenceAttrList[0].name
} : undefined,
}, exp: 'is',
handleClear() { value: null,
this.ruleList = [ },
{ ]
id: uuidv4(), : []
type: 'and', }
property: this.canSearchPreferenceAttrList[0].name, },
exp: 'is', handleClear() {
value: null, this.ruleList = [
}, {
] id: uuidv4(),
this.filterExp = '' type: 'and',
this.visible = false property: this.canSearchPreferenceAttrList[0].name,
this.$emit('setExpFromFilter', this.filterExp) exp: 'is',
}, value: null,
handleSubmit() { },
if (this.ruleList && this.ruleList.length) { ]
this.ruleList[0].type = 'and' // 增删后以防万一第一个不是and this.filterExp = ''
this.filterExp = '' this.visible = false
const expList = this.ruleList.map((rule) => { this.$emit('setExpFromFilter', this.filterExp)
let singleRuleExp = '' },
let _exp = rule.exp handleSubmit() {
if (rule.type === 'or') { if (this.ruleList && this.ruleList.length) {
singleRuleExp += '-' this.ruleList[0].type = 'and' // 增删后以防万一第一个不是and
} this.filterExp = ''
if (rule.exp.includes('~')) { const expList = this.ruleList.map((rule) => {
singleRuleExp += '~' let singleRuleExp = ''
_exp = rule.exp.split('~')[1] let _exp = rule.exp
} if (rule.type === 'or') {
singleRuleExp += `${rule.property}:` singleRuleExp += '-'
if (_exp === 'is') { }
singleRuleExp += `${rule.value ?? ''}` if (rule.exp.includes('~')) {
} singleRuleExp += '~'
if (_exp === 'contain') { _exp = rule.exp.split('~')[1]
singleRuleExp += `*${rule.value ?? ''}*` }
} singleRuleExp += `${rule.property}:`
if (_exp === 'start_with') { if (_exp === 'is') {
singleRuleExp += `${rule.value ?? ''}*` singleRuleExp += `${rule.value ?? ''}`
} }
if (_exp === 'end_with') { if (_exp === 'contain') {
singleRuleExp += `*${rule.value ?? ''}` singleRuleExp += `*${rule.value ?? ''}*`
} }
if (_exp === 'value') { if (_exp === 'start_with') {
singleRuleExp += `*` singleRuleExp += `${rule.value ?? ''}*`
} }
if (_exp === 'in') { if (_exp === 'end_with') {
singleRuleExp += `(${rule.value ?? ''})` singleRuleExp += `*${rule.value ?? ''}`
} }
if (_exp === 'range') { if (_exp === 'value') {
singleRuleExp += `[${rule.min}_TO_${rule.max}]` singleRuleExp += `*`
} }
if (_exp === 'compare') { if (_exp === 'in') {
const idx = compareTypeList.findIndex((item) => item.value === rule.compareType) singleRuleExp += `(${rule.value ?? ''})`
singleRuleExp += `${compareTypeList[idx].label}${rule.value ?? ''}` }
} if (_exp === 'range') {
return singleRuleExp singleRuleExp += `[${rule.min}_TO_${rule.max}]`
}) }
this.filterExp = expList.join(',') if (_exp === 'compare') {
this.$emit('setExpFromFilter', this.filterExp) const idx = compareTypeList.findIndex((item) => item.value === rule.compareType)
} else { singleRuleExp += `${compareTypeList[idx].label}${rule.value ?? ''}`
this.$emit('setExpFromFilter', '') }
} return singleRuleExp
this.visible = false })
}, this.filterExp = expList.join(',')
}, this.$emit('setExpFromFilter', this.filterExp)
} } else {
</script> this.$emit('setExpFromFilter', '')
}
<style lang="less" scoped> this.visible = false
.table-filter { },
.table-filter-add { },
margin-top: 10px; }
& > a { </script>
padding: 2px 8px;
&:hover { <style lang="less" scoped>
background-color: #f0faff; .table-filter {
border-radius: 5px; .table-filter-add {
} margin-top: 10px;
} & > a {
} padding: 2px 8px;
.table-filter-extra-icon { &:hover {
padding: 0px 2px; background-color: #f0faff;
&:hover { border-radius: 5px;
display: inline-block; }
border-radius: 5px; }
background-color: #f0faff; }
} .table-filter-extra-icon {
} padding: 0px 2px;
} &:hover {
</style> display: inline-block;
border-radius: 5px;
<style lang="less"> background-color: #f0faff;
.table-filter-extra-operation { }
.ant-popover-inner-content { }
padding: 3px 4px; }
.operation { </style>
cursor: pointer;
width: 90px; <style lang="less">
height: 30px; .table-filter-extra-operation {
line-height: 30px; .ant-popover-inner-content {
padding: 3px 4px; padding: 3px 4px;
border-radius: 5px; .operation {
transition: all 0.3s; cursor: pointer;
&:hover { width: 90px;
background-color: #f0faff; height: 30px;
} line-height: 30px;
> .anticon { padding: 3px 4px;
margin-right: 10px; border-radius: 5px;
} transition: all 0.3s;
} &:hover {
} background-color: #f0faff;
} }
</style> > .anticon {
margin-right: 10px;
}
}
}
}
</style>

View File

@ -1,8 +1,10 @@
export const iconTypeList = [ import i18n from '@/lang'
export const iconTypeList = () => [
// { value: '0', label: '常用' }, // { value: '0', label: '常用' },
{ value: '1', label: '线性' }, { value: '1', label: i18n.t('customIconSelect.outlined') },
{ value: '2', label: '实底' }, { value: '2', label: i18n.t('customIconSelect.filled') },
{ value: '3', label: '多色' } { value: '3', label: i18n.t('customIconSelect.multicolor') }
] ]
export const commonIconList = ['changyong-ubuntu', export const commonIconList = ['changyong-ubuntu',

View File

@ -16,7 +16,7 @@
{{ item.label }} {{ item.label }}
</div> </div>
<div :class="`${currentIconType === '4' ? 'selected' : ''}`" @click="handleChangeIconType('4')"> <div :class="`${currentIconType === '4' ? 'selected' : ''}`" @click="handleChangeIconType('4')">
自定义 {{ this.$t('customIconSelect.custom') }}
</div> </div>
<a-upload <a-upload
slot="description" slot="description"
@ -26,7 +26,7 @@
accept=".svg,.png,.jpg,.jpeg" accept=".svg,.png,.jpg,.jpeg"
v-if="currentIconType === '4'" v-if="currentIconType === '4'"
> >
<a-button icon="plus" size="small" type="primary">添加</a-button> <a-button icon="plus" size="small" type="primary">{{ $t('add') }}</a-button>
</a-upload> </a-upload>
</div> </div>
<div class="custom-icon-select-popover-content"> <div class="custom-icon-select-popover-content">
@ -55,11 +55,11 @@
@click="clickCustomIcon(icon)" @click="clickCustomIcon(icon)"
> >
<div class="custom-icon-select-popover-content-img-box"> <div class="custom-icon-select-popover-content-img-box">
<img :src="`/api/common-setting/v1/file/${icon.data.url}`" /> <img v-if="icon.data && icon.data.url" :src="`/api/common-setting/v1/file/${icon.data.url}`" />
<a-popconfirm <a-popconfirm
overlayClassName="custom-icon-select-confirm-popover" overlayClassName="custom-icon-select-confirm-popover"
:getPopupContainer="(trigger) => trigger.parentNode" :getPopupContainer="(trigger) => trigger.parentNode"
title="确认删除?" :title="$t('confirmDelete')"
@confirm="(e) => deleteIcon(e, icon)" @confirm="(e) => deleteIcon(e, icon)"
@cancel=" @cancel="
(e) => { (e) => {
@ -102,27 +102,27 @@
</template> </template>
<a-form class="custom-icon-select-form" :form="form" v-show="currentIconType === '4' && formVisible"> <a-form class="custom-icon-select-form" :form="form" v-show="currentIconType === '4' && formVisible">
<a-form-item <a-form-item
label="名称" :label="$t('name')"
:labelCol="{ span: 4 }" :labelCol="{ span: 4 }"
:wrapperCol="{ span: 16 }" :wrapperCol="{ span: 16 }"
><a-input ><a-input
v-decorator="['name', { rules: [{ required: true, message: '请输入名称' }] }]" v-decorator="['name', { rules: [{ required: true, message: $t('placeholder1') }] }]"
/></a-form-item> /></a-form-item>
<a-form-item label="预览" :labelCol="{ span: 4 }"> <a-form-item :label="$t('customIconSelect.preview')" :labelCol="{ span: 4 }">
<div class="custom-icon-select-form-img"> <div class="custom-icon-select-form-img">
<img :src="formImg" /> <img :src="formImg" />
</div> </div>
</a-form-item> </a-form-item>
<a-form-item label=" " :colon="false" :labelCol="{ span: 16 }"> <a-form-item label=" " :colon="false" :labelCol="{ span: 16 }">
<a-space> <a-space>
<a-button size="small" @click="handleCancel">取消</a-button> <a-button size="small" @click="handleCancel">{{ $t('cancel') }}</a-button>
<a-button size="small" type="primary" @click="handleOk">确定</a-button> <a-button size="small" type="primary" @click="handleOk">{{ $t('confirm') }}</a-button>
</a-space> </a-space>
</a-form-item> </a-form-item>
</a-form> </a-form>
</div> </div>
<div class="custom-icon-select-block" id="custom-icon-select-block" @click="showSelect"> <div class="custom-icon-select-block" :id="`custom-icon-select-block-${uuid}`" @click="showSelect">
<img v-if="value.id && value.url" :src="`/api/common-setting/v1/file/${value.url}`" /> <img v-if="value.id && value.url" :src="`/api/common-setting/v1/file/${value.url}`" />
<ops-icon <ops-icon
v-else v-else
@ -134,6 +134,7 @@
</template> </template>
<script> <script>
import { v4 as uuidv4 } from 'uuid'
import { ColorPicker } from 'element-ui' import { ColorPicker } from 'element-ui'
import { import {
iconTypeList, iconTypeList,
@ -166,7 +167,6 @@ export default {
data() { data() {
return { return {
form: this.$form.createForm(this), form: this.$form.createForm(this),
iconTypeList,
commonIconList, commonIconList,
linearIconList, linearIconList,
fillIconList, fillIconList,
@ -177,6 +177,7 @@ export default {
formVisible: false, formVisible: false,
formImg: null, formImg: null,
file: null, file: null,
uuid: uuidv4(),
} }
}, },
computed: { computed: {
@ -200,6 +201,9 @@ export default {
const splitFileName = this.file.name.split('.') const splitFileName = this.file.name.split('.')
return splitFileName.splice(0, splitFileName.length - 1).join('') return splitFileName.splice(0, splitFileName.length - 1).join('')
}, },
iconTypeList() {
return iconTypeList()
},
}, },
mounted() { mounted() {
document.addEventListener('click', this.eventListener) document.addEventListener('click', this.eventListener)
@ -217,7 +221,7 @@ export default {
eventListener(e) { eventListener(e) {
if (this.visible) { if (this.visible) {
const dom = document.getElementById(`custom-icon-select-popover`) const dom = document.getElementById(`custom-icon-select-popover`)
const dom_icon = document.getElementById(`custom-icon-select-block`) const dom_icon = document.getElementById(`custom-icon-select-block-${this.uuid}`)
e.stopPropagation() e.stopPropagation()
e.preventDefault() e.preventDefault()
if (dom) { if (dom) {
@ -249,12 +253,11 @@ export default {
color: '', color: '',
}) })
} else { } else {
this.$emit('change', { name: icon.data.name, id: icon.id, url: icon.data.url }) this.$emit('change', { name: icon.data.name, id: icon.id, url: icon?.data?.url })
} }
}, },
showSelect() { showSelect() {
this.visible = true this.visible = true
console.log(this.value)
if (!this.value.name) { if (!this.value.name) {
this.currentIconType = '3' this.currentIconType = '3'
return return
@ -278,7 +281,7 @@ export default {
beforeUpload(file) { beforeUpload(file) {
const isLt2M = file.size / 1024 / 1024 < 2 const isLt2M = file.size / 1024 / 1024 < 2
if (!isLt2M) { if (!isLt2M) {
this.$message.error('图片大小不可超过2MB!') this.$message.error(this.$t('customIconSelect.sizeLimit'))
return false return false
} }
@ -306,7 +309,7 @@ export default {
this.form.validateFields((err, values) => { this.form.validateFields((err, values) => {
if (!err) { if (!err) {
addFileData('ops-custom-icon', { data: { name: values.name, url: res.file_name } }).then(() => { addFileData('ops-custom-icon', { data: { name: values.name, url: res.file_name } }).then(() => {
this.$message.success('上传成功!') this.$message.success(this.$t('uploadSuccess'))
this.handleCancel() this.handleCancel()
this.getFileData() this.getFileData()
}) })
@ -318,7 +321,7 @@ export default {
e.stopPropagation() e.stopPropagation()
e.preventDefault() e.preventDefault()
deleteFileData('ops-custom-icon', icon.id).then(() => { deleteFileData('ops-custom-icon', icon.id).then(() => {
this.$message.success('删除成功!') this.$message.success(this.$t('deleteSuccess'))
this.handleCancel() this.handleCancel()
this.getFileData() this.getFileData()
}) })

View File

@ -6,17 +6,17 @@
:flat="true" :flat="true"
:multiple="true" :multiple="true"
:options="employeeTreeSelectOption" :options="employeeTreeSelectOption"
placeholder="请输入搜索内容" :placeholder="$t('placeholderSearch')"
v-model="treeValue" v-model="treeValue"
:max-height="height - 50" :max-height="height - 50"
noChildrenText="" noChildrenText=""
noOptionsText="" noOptionsText=""
:clearable="false" :clearable="false"
:always-open="true" :always-open="true"
:default-expand-level="1" :default-expand-level="showInternship ? 0 : 1"
:class="{ 'employee-transfer': true, 'employee-transfer-has-input': !!inputValue }" :class="{ 'employee-transfer': true, 'employee-transfer-has-input': !!inputValue }"
@search-change="changeInputValue" @search-change="changeInputValue"
noResultsText="暂无数据" :noResultsText="$t('noData')"
openDirection="below" openDirection="below"
> >
</treeselect> </treeselect>
@ -85,6 +85,10 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
showInternship: {
type: Boolean,
default: false,
},
}, },
data() { data() {
return { return {
@ -99,13 +103,22 @@ export default {
}, },
computed: { computed: {
employeeTreeSelectOption() { employeeTreeSelectOption() {
return formatOption( const formatOptions = formatOption(
this.allTreeDepAndEmp, this.allTreeDepAndEmp,
2, 2,
this.isDisabledAllCompany, this.isDisabledAllCompany,
this.uniqueKey || 'department_id', this.uniqueKey || 'department_id',
this.uniqueKey || 'employee_id' this.uniqueKey || 'employee_id'
) )
if (this.showInternship) {
formatOptions.push(
...[
{ id: -2, label: '全职' },
{ id: -3, label: '实习生' },
]
)
}
return formatOptions
}, },
allTreeDepAndEmp() { allTreeDepAndEmp() {
if (this.getDataBySelf) { if (this.getDataBySelf) {
@ -148,11 +161,15 @@ export default {
const department = [] const department = []
const user = [] const user = []
this.rightData.forEach((item) => { this.rightData.forEach((item) => {
const _split = item.split('-') if (item === -2 || item === -3) {
if (_split[0] === 'department') { department.push(item)
department.push(Number(_split[1]))
} else { } else {
user.push(Number(_split[1])) const _split = item.split('-')
if (_split[0] === 'department') {
department.push(Number(_split[1]))
} else {
user.push(Number(_split[1]))
}
} }
}) })
const _idx = department.findIndex((item) => item === 0) const _idx = department.findIndex((item) => item === 0)
@ -191,6 +208,12 @@ export default {
} }
}, },
getLabel(id) { getLabel(id) {
if (id === -2) {
return '全职'
}
if (id === -3) {
return '实习生'
}
const _split = id.split('-') const _split = id.split('-')
const type = _split[0] const type = _split[0]
const _id = Number(_split[1]) const _id = Number(_split[1])

View File

@ -161,6 +161,9 @@ export default {
} }
return null return null
}, },
renderI18n(title) {
return this.$t(`${title}`)
},
renderMenuItem(menu) { renderMenuItem(menu) {
const isShowDot = menu.path.substr(0, 22) === '/cmdb/instances/types/' const isShowDot = menu.path.substr(0, 22) === '/cmdb/instances/types/'
const isShowGrant = menu.path.substr(0, 20) === '/cmdb/relationviews/' const isShowGrant = menu.path.substr(0, 20) === '/cmdb/relationviews/'
@ -183,7 +186,7 @@ export default {
<tag {...{ props, attrs }}> <tag {...{ props, attrs }}>
{this.renderIcon({ icon: menu.meta.icon, customIcon: menu.meta.customIcon, name: menu.meta.name, typeId: menu.meta.typeId, routeName: menu.name, selectedIcon: menu.meta.selectedIcon, })} {this.renderIcon({ icon: menu.meta.icon, customIcon: menu.meta.customIcon, name: menu.meta.name, typeId: menu.meta.typeId, routeName: menu.name, selectedIcon: menu.meta.selectedIcon, })}
<span> <span>
<span class={menu.meta.title.length > 10 ? 'scroll' : ''}>{menu.meta.title}</span> <span class={this.renderI18n(menu.meta.title).length > 10 ? 'scroll' : ''}>{this.renderI18n(menu.meta.title)}</span>
{isShowDot && {isShowDot &&
<a-popover <a-popover
overlayClassName="custom-menu-extra-submenu" overlayClassName="custom-menu-extra-submenu"
@ -217,7 +220,7 @@ export default {
<SubMenu {...{ key: menu.path }}> <SubMenu {...{ key: menu.path }}>
<span slot="title"> <span slot="title">
{this.renderIcon({ icon: menu.meta.icon, selectedIcon: menu.meta.selectedIcon, routeName: menu.name })} {this.renderIcon({ icon: menu.meta.icon, selectedIcon: menu.meta.selectedIcon, routeName: menu.name })}
<span>{menu.meta.title}</span> <span>{this.renderI18n(menu.meta.title)}</span>
</span> </span>
{itemArr} {itemArr}
</SubMenu> </SubMenu>

View File

@ -3,9 +3,9 @@
<slot></slot> <slot></slot>
<template #empty> <template #empty>
<slot name="empty"> <slot name="empty">
<div> <div :style="{ paddingTop: '10px' }">
<img :style="{ width: '100px' }" :src="require('@/assets/data_empty.png')" /> <img :style="{ width: '100px', height: '90px' }" :src="require('@/assets/data_empty.png')" />
<div>暂无数据</div> <div>{{ $t('noData') }}</div>
</div> </div>
</slot> </slot>
</template> </template>

View File

@ -3,12 +3,12 @@
<a-switch <a-switch
class="role-transfer-switch" class="role-transfer-switch"
v-model="isUserRole" v-model="isUserRole"
checked-children="用户" :checked-children="$t('user')"
un-checked-children="虚拟" :un-checked-children="$t('visual')"
@change="loadRoles" @change="loadRoles"
/> />
<div class="role-transfer-left"> <div class="role-transfer-left">
<a-input placeholder="请输入搜索内容" v-model="searchValue" /> <a-input :placeholder="$t('placeholderSearch')" v-model="searchValue" />
<div v-for="item in filterAllRoles" :key="item.id" @click="handleSelectedLeft(item.id)"> <div v-for="item in filterAllRoles" :key="item.id" @click="handleSelectedLeft(item.id)">
<a-checkbox :checked="selectedLeft.includes(item.id)" /> <a-checkbox :checked="selectedLeft.includes(item.id)" />
<div :title="item.name" class="role-transfer-left-role">{{ item.name }}</div> <div :title="item.name" class="role-transfer-left-role">{{ item.name }}</div>

View File

@ -10,9 +10,10 @@
> >
<a-icon type="setting" /> <a-icon type="setting" />
</span> </span>
<span class="locale" @click="changeLang">{{ locale === 'zh' ? 'English' : '中文' }}</span>
<a-popover <a-popover
trigger="click" trigger="click"
:overlayStyle="{ width: '120px' }" :overlayStyle="{ width: '150px' }"
placement="bottomRight" placement="bottomRight"
overlayClassName="custom-user" overlayClassName="custom-user"
> >
@ -20,12 +21,12 @@
<router-link :to="{ name: 'setting_person' }" :style="{ color: '#000000a6' }"> <router-link :to="{ name: 'setting_person' }" :style="{ color: '#000000a6' }">
<div class="custom-user-item"> <div class="custom-user-item">
<a-icon type="user" :style="{ marginRight: '10px' }" /> <a-icon type="user" :style="{ marginRight: '10px' }" />
<span>个人中心</span> <span>{{ $t('topMenu.personalCenter') }}</span>
</div> </div>
</router-link> </router-link>
<div @click="handleLogout" class="custom-user-item"> <div @click="handleLogout" class="custom-user-item">
<a-icon type="logout" :style="{ marginRight: '10px' }" /> <a-icon type="logout" :style="{ marginRight: '10px' }" />
<span>退出登录</span> <span>{{ $t('topMenu.logout') }}</span>
</div> </div>
</template> </template>
<span class="action ant-dropdown-link user-dropdown-menu"> <span class="action ant-dropdown-link user-dropdown-menu">
@ -44,8 +45,9 @@
</template> </template>
<script> <script>
import { mapState, mapActions, mapGetters, mapMutations } from 'vuex'
import DocumentLink from './DocumentLink.vue' import DocumentLink from './DocumentLink.vue'
import { mapState, mapActions, mapGetters } from 'vuex' import { setDocumentTitle, domTitle } from '@/utils/domUtil'
export default { export default {
name: 'UserMenu', name: 'UserMenu',
@ -53,21 +55,24 @@ export default {
DocumentLink, DocumentLink,
}, },
computed: { computed: {
...mapState(['user']), ...mapState(['user', 'locale']),
hasBackendPermission() { hasBackendPermission() {
return this.user?.roles?.permissions.includes('acl_admin', 'backend_admin') || false return this.user?.detailPermissions?.backend?.length
}, },
}, },
methods: { methods: {
...mapActions(['Logout']), ...mapActions(['Logout']),
...mapGetters(['nickname', 'avatar']), ...mapGetters(['nickname', 'avatar']),
...mapMutations(['SET_LOCALE']),
handleLogout() { handleLogout() {
const that = this const that = this
this.$confirm({ this.$confirm({
title: '提示', title: '提示',
content: '确认注销登录 ?', content: '真的要注销登录吗 ?',
onOk() { onOk() {
// localStorage.removeItem('ops_cityps_currentId')
localStorage.clear()
return that.Logout() return that.Logout()
}, },
onCancel() {}, onCancel() {},
@ -76,9 +81,22 @@ export default {
handleClick() { handleClick() {
this.$router.push('/setting') this.$router.push('/setting')
}, },
changeLang() {
if (this.locale === 'zh') {
this.SET_LOCALE('en')
this.$i18n.locale = 'en'
} else {
this.SET_LOCALE('zh')
this.$i18n.locale = 'zh'
}
this.$nextTick(() => {
setDocumentTitle(`${this.$t(this.$route.meta.title)} - ${domTitle}`)
})
},
}, },
} }
</script> </script>
<style lang="less"> <style lang="less">
@import '~@/style/static.less'; @import '~@/style/static.less';
.color { .color {
@ -98,4 +116,11 @@ export default {
color: #000000a6; color: #000000a6;
} }
} }
.locale {
cursor: pointer;
&:hover {
color: #custom_colors[color_1];
}
}
</style> </style>

View File

@ -38,11 +38,18 @@ import CardTitle from '@/components/CardTitle'
import ElementUI from 'element-ui' import ElementUI from 'element-ui'
import Treeselect from '@riophae/vue-treeselect' import Treeselect from '@riophae/vue-treeselect'
import OpsTable from '@/components/OpsTable' import OpsTable from '@/components/OpsTable'
import VueI18n from 'vue-i18n'
import i18n from '@/lang'
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.prototype.$bus = EventBus Vue.prototype.$bus = EventBus
VXETable.setup({
i18n: (key, args) => i18n.t(key, args)
})
Vue.use(VXETable) Vue.use(VXETable)
VXETable.use(VXETablePluginExportXLSX) VXETable.use(VXETablePluginExportXLSX)
Vue.use(VueI18n)
Vue.config.productionTip = false Vue.config.productionTip = false
@ -75,4 +82,3 @@ Vue.component('CustomRadio', CustomRadio)
Vue.component('CardTitle', CardTitle) Vue.component('CardTitle', CardTitle)
Vue.component('Treeselect', Treeselect) Vue.component('Treeselect', Treeselect)
Vue.component('OpsTable', OpsTable) Vue.component('OpsTable', OpsTable)

View File

@ -7,6 +7,7 @@ import NProgress from 'nprogress'
import 'nprogress/nprogress.css' import 'nprogress/nprogress.css'
import { setDocumentTitle, domTitle } from '@/utils/domUtil' import { setDocumentTitle, domTitle } from '@/utils/domUtil'
import { ACCESS_TOKEN } from './store/global/mutation-types' import { ACCESS_TOKEN } from './store/global/mutation-types'
import i18n from '@/lang'
NProgress.configure({ showSpinner: false }) NProgress.configure({ showSpinner: false })
@ -17,7 +18,7 @@ const whitePath = ['/user/login', '/user/logout', '/user/register', '/api/sso/lo
// 登录页面处理处理 是否使用单点登录 // 登录页面处理处理 是否使用单点登录
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
NProgress.start() // start progress bar NProgress.start() // start progress bar
to.meta && (!!to.meta.title && setDocumentTitle(`${to.meta.title} - ${domTitle}`)) to.meta && (!!to.meta.title && setDocumentTitle(`${i18n.t(to.meta.title)} - ${domTitle}`))
const authed = store.state.authed const authed = store.state.authed
const auth_type = localStorage.getItem('ops_auth_type') const auth_type = localStorage.getItem('ops_auth_type')

140
cmdb-ui/src/lang/en.js Normal file
View File

@ -0,0 +1,140 @@
import cmdb_en from '@/modules/cmdb/lang/en.js'
import cs_en from '../views/setting/lang/en.js'
import acl_en from '@/modules/acl/lang/en.js'
export default {
screen: 'Big Screen',
dashboard: 'Dashboard',
admin: 'Admin',
user: 'User',
role: 'Role',
operation: 'Operation',
login: 'Login',
refresh: 'Refresh',
cancel: 'Cancel',
confirm: 'Confirm',
create: 'Create',
edit: 'Edit',
deleting: 'Deleting',
deletingTip: 'Deleting, total of {total}, {successNum} succeeded, {errorNum} failed',
grant: 'Grant',
login_at: 'Login At',
logout_at: 'Logout At',
createSuccess: 'Create Success',
editSuccess: 'edit Success',
warning: 'Warning',
export: 'Export',
placeholderSearch: 'Please Search',
success: 'Success',
fail: 'Fail',
browser: 'Browser',
status: 'Status',
type: 'Type',
description: 'Description',
new: 'New',
add: 'Add',
define: 'Define',
update: 'Update',
clear: 'Clear',
delete: 'Delete',
copy: 'Copy',
created_at: 'Created At',
updated_at: 'Updated At',
placeholder1: 'Please Input',
placeholder2: 'Please Select',
confirmDelete: 'Confirm delete?',
confirmDelete2: 'Confirm delete [{name}]?',
query: 'Query',
search: 'Search',
hide: 'Hide',
expand: 'Expand',
save: 'Save',
submit: 'Submit',
upload: 'Import',
download: 'Export',
name: 'Name',
alias: 'Alias',
desc: 'Description',
other: 'Other',
icon: 'Icon',
addSuccess: 'Added successfully',
uploadSuccess: 'Import successfully',
saveSuccess: 'Save successfully',
copySuccess: 'Copy successfully',
updateSuccess: 'Updated successfully',
deleteSuccess: 'Deleted successfully',
operateSuccess: 'The operation was successful',
noPermission: 'No Permission',
noData: 'No Data',
seconds: 'Seconds',
createdAt: 'Created At',
updatedAt: 'Updated At',
deletedAt: 'Deleted At',
required: 'required',
email: 'Email',
wechat: 'Wechat',
dingding: 'DingTalk',
feishu: 'Feishu',
bot: 'Robot',
checkAll: 'Select All',
loading: 'Loading...',
view: 'View',
reset: 'Reset',
yes: 'Yes',
no: 'No',
all: 'All',
selectRows: 'Selected: {rows} items',
itemsPerPage: '/page',
'星期一': 'Monday',
'星期二': 'Tuesday',
'星期三': 'Wednesday',
'星期四': 'Thursday',
'星期五': 'Friday',
'星期六': 'Saturday',
'星期日': 'Sunday',
hour: 'hour',
'items/page': '{items} items/page',
max: 'Max',
min: 'Min',
visual: 'Visual',
pagination: {
total: '{range0}-{range1} of {total} items'
},
topMenu: {
personalCenter: 'Personal Center',
logout: 'logout',
},
cmdbFilterComp: {
conditionFilter: 'Conditional filtering',
and: 'and',
or: 'or',
is: 'equal',
'~is': 'not equal',
contain: 'contain',
'~contain': 'not contain',
start_with: 'start_with',
'~start_with': 'not start_with',
end_with: 'end_with',
'~end_with': 'not end_with',
'~value': 'null',
value: 'not null',
in: 'in',
'~in': 'not in',
range: 'range',
'~range': 'out of range',
compare: 'compare',
addHere: 'Add Here',
split: 'split by {separator}'
},
customIconSelect: {
outlined: 'Outlined',
filled: 'Filled',
multicolor: 'Multicolor',
custom: 'Custom',
preview: 'Preview',
sizeLimit: 'The image size cannot exceed 2MB!'
},
cmdb: cmdb_en,
cs: cs_en,
acl: acl_en,
}

18
cmdb-ui/src/lang/index.js Normal file
View File

@ -0,0 +1,18 @@
import VueI18n from 'vue-i18n'
import zh from './zh'
import en from './en'
import Vue from 'vue'
import zhCN from 'vxe-table/lib/locale/lang/zh-CN'
import enUS from 'vxe-table/lib/locale/lang/en-US'
Vue.use(VueI18n)
const i18n = new VueI18n({
locale: 'zh', // 初始化中文
messages: {
'zh': { ...zh, ...zhCN },
'en': { ...en, ...enUS },
},
silentTranslationWarn: true
})
export default i18n

140
cmdb-ui/src/lang/zh.js Normal file
View File

@ -0,0 +1,140 @@
import cmdb_zh from '@/modules/cmdb/lang/zh.js'
import cs_zh from '../views/setting/lang/zh.js'
import acl_zh from '@/modules/acl/lang/zh.js'
export default {
screen: '大屏',
dashboard: '仪表盘',
admin: '管理员',
user: '用户',
role: '角色',
operation: '操作',
login: '登录',
refresh: '刷新',
cancel: '取消',
confirm: '确定',
create: '创建',
edit: '编辑',
deleting: '正在删除',
deletingTip: '正在删除,共{total}个,成功{successNum}个,失败{errorNum}个',
grant: '授权',
login_at: '登录时间',
logout_at: '登出时间',
createSuccess: '创建成功',
editSuccess: '修改成功',
warning: '警告',
export: '导出',
placeholderSearch: '请查找',
success: '成功',
fail: '失败',
browser: '浏览器',
status: '状态',
type: '类型',
description: '描述',
new: '新增',
add: '添加',
define: '定义',
update: '修改',
clear: '清空',
delete: '删除',
copy: '复制',
created_at: '创建日期',
updated_at: '更新日期',
placeholder1: '请输入',
placeholder2: '请选择',
confirmDelete: '确认删除?',
confirmDelete2: '确认删除【{name}】?',
query: '查询',
search: '搜索',
hide: '隐藏',
expand: '展开',
save: '保存',
submit: '提交',
upload: '导入',
download: '导出',
name: '名称',
alias: '别名',
desc: '描述',
other: '其他',
icon: '图标',
addSuccess: '新增成功',
uploadSuccess: '导入成功',
saveSuccess: '保存成功',
copySuccess: '复制成功',
updateSuccess: '更新成功',
deleteSuccess: '删除成功',
operateSuccess: '操作成功',
noPermission: '权限不足',
noData: '暂无数据',
seconds: '秒',
createdAt: '创建时间',
updatedAt: '更新时间',
deletedAt: '删除时间',
required: '必须',
email: '邮件',
wechat: '企业微信',
dingding: '钉钉',
feishu: '飞书',
bot: '机器人',
checkAll: '全选',
loading: '加载中...',
view: '查看',
reset: '重置',
yes: '是',
no: '否',
all: '全部',
selectRows: '选取:{rows} 项',
itemsPerPage: '/页',
'星期一': '星期一',
'星期二': '星期二',
'星期三': '星期三',
'星期四': '星期四',
'星期五': '星期五',
'星期六': '星期六',
'星期日': '星期日',
hour: '小时',
'items/page': '{items} 条/页',
max: '最大值',
min: '最小值',
visual: '虚拟',
pagination: {
total: '当前展示 {range0}-{range1} 条数据, 共 {total} 条'
},
topMenu: {
personalCenter: '个人中心',
logout: '退出登录',
},
cmdbFilterComp: {
conditionFilter: '条件过滤',
and: '与',
or: '或',
is: '等于',
'~is': '不等于',
contain: '包含',
'~contain': '不包含',
start_with: '以...开始',
'~start_with': '不以...开始',
end_with: '以...结束',
'~end_with': '不以...结束',
'~value': '为空',
value: '不为空',
in: 'in查询',
'~in': '非in查询',
range: '范围',
'~range': '范围外',
compare: '比较',
addHere: '在此处添加',
split: '以 {separator} 分隔'
},
customIconSelect: {
outlined: '线框',
filled: '实底',
multicolor: '多色',
custom: '自定义',
preview: '预览',
sizeLimit: '图片大小不可超过2MB'
},
cmdb: cmdb_zh,
cs: cs_zh,
acl: acl_zh,
}

View File

@ -10,6 +10,7 @@ import './guard' // guard permission control
import './utils/filter' // global filter import './utils/filter' // global filter
import Setting from './config/setting' import Setting from './config/setting'
import { Icon } from 'ant-design-vue' import { Icon } from 'ant-design-vue'
import i18n from './lang'
import iconFont from '../public/iconfont/iconfont' import iconFont from '../public/iconfont/iconfont'
@ -22,6 +23,7 @@ async function start() {
const _vue = new Vue({ const _vue = new Vue({
router, router,
store, store,
i18n,
created: bootstrap, created: bootstrap,
render: h => h(App) render: h => h(App)
}).$mount('#app') }).$mount('#app')

View File

@ -34,6 +34,7 @@ export const generatorDynamicRouter = async () => {
name: 'notice_center', name: 'notice_center',
component: BasicLayout, component: BasicLayout,
children: [{ children: [{
hidden: true,
path: '/noticecenter', path: '/noticecenter',
name: 'notice_center', name: 'notice_center',
meta: { title: '消息中心' }, meta: { title: '消息中心' },
@ -50,53 +51,53 @@ export const generatorDynamicRouter = async () => {
hidden: true, hidden: true,
path: '/setting/person', path: '/setting/person',
name: 'setting_person', name: 'setting_person',
meta: { title: '个人中心', }, meta: { title: 'cs.menu.person', },
component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/person/index') component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/person/index')
}, },
{ {
path: '/setting/companyinfo', path: '/setting/companyinfo',
name: 'company_info', name: 'company_info',
meta: { title: '公司信息', appName: 'backend', icon: 'ops-setting-companyInfo', selectedIcon: 'ops-setting-companyInfo-selected', permission: ['acl_admin', 'backend_admin'] }, meta: { title: 'cs.menu.companyInfo', appName: 'backend', icon: 'ops-setting-companyInfo', selectedIcon: 'ops-setting-companyInfo-selected', permission: ['公司信息', 'backend_admin'] },
component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/companyInfo/index') component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/companyInfo/index')
}, },
{ {
path: '/setting/companystructure', path: '/setting/companystructure',
name: 'company_structure', name: 'company_structure',
meta: { title: '公司架构', appName: 'backend', icon: 'ops-setting-companyStructure', selectedIcon: 'ops-setting-companyStructure-selected', permission: ['acl_admin', 'backend_admin'] }, meta: { title: 'cs.menu.companyStructure', appName: 'backend', icon: 'ops-setting-companyStructure', selectedIcon: 'ops-setting-companyStructure-selected', permission: ['公司架构', 'backend_admin'] },
component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/companyStructure/index') component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/companyStructure/index')
}, },
{ {
path: '/setting/notice', path: '/setting/notice',
name: 'notice', name: 'notice',
component: RouteView, component: RouteView,
meta: { title: '通知设置', appName: 'backend', icon: 'ops-setting-notice', selectedIcon: 'ops-setting-notice-selected', permission: ['通知设置', 'backend_admin'] }, meta: { title: 'cs.menu.notice', appName: 'backend', icon: 'ops-setting-notice', selectedIcon: 'ops-setting-notice-selected', permission: ['通知设置', 'backend_admin'] },
redirect: '/setting/notice/email', redirect: '/setting/notice/email',
children: [{ children: [{
path: '/setting/notice/email', path: '/setting/notice/email',
name: 'notice_email', name: 'notice_email',
meta: { title: '邮件设置', icon: 'ops-setting-notice-email', selectedIcon: 'ops-setting-notice-email-selected' }, meta: { title: 'cs.menu.email', icon: 'ops-setting-notice-email', selectedIcon: 'ops-setting-notice-email-selected' },
component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/notice/email/index') component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/notice/email/index')
}, { }, {
path: '/setting/notice/wx', path: '/setting/notice/wx',
name: 'notice_wx', name: 'notice_wx',
meta: { title: '企业微信', icon: 'ops-setting-notice-wx', selectedIcon: 'ops-setting-notice-wx-selected' }, meta: { title: 'cs.menu.wx', icon: 'ops-setting-notice-wx', selectedIcon: 'ops-setting-notice-wx-selected' },
component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/notice/wx') component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/notice/wx')
}, { }, {
path: '/setting/notice/dingding', path: '/setting/notice/dingding',
name: 'notice_dingding', name: 'notice_dingding',
meta: { title: '钉钉', icon: 'ops-setting-notice-dingding', selectedIcon: 'ops-setting-notice-dingding-selected' }, meta: { title: 'cs.menu.dingding', icon: 'ops-setting-notice-dingding', selectedIcon: 'ops-setting-notice-dingding-selected' },
component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/notice/dingding') component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/notice/dingding')
}, { }, {
path: '/setting/notice/feishu', path: '/setting/notice/feishu',
name: 'notice_feishu', name: 'notice_feishu',
meta: { title: '飞书', icon: 'ops-setting-notice-feishu', selectedIcon: 'ops-setting-notice-feishu-selected' }, meta: { title: 'cs.menu.feishu', icon: 'ops-setting-notice-feishu', selectedIcon: 'ops-setting-notice-feishu-selected' },
component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/notice/feishu') component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/notice/feishu')
}] }]
}, },
{ {
path: '/setting/auth', path: '/setting/auth',
name: 'company_auth', name: 'company_auth',
meta: { title: '认证设置', appName: 'backend', icon: 'ops-setting-auth', selectedIcon: 'ops-setting-auth-selected', permission: ['acl_admin'] }, meta: { title: 'cs.menu.auth', appName: 'backend', icon: 'ops-setting-auth', selectedIcon: 'ops-setting-auth-selected', permission: ['acl_admin'] },
component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/auth/index') component: () => import(/* webpackChunkName: "setting" */ '@/views/setting/auth/index')
}, },
] ]

View File

@ -24,6 +24,7 @@ const store = new Vuex.Store({
windowWidth: 800, windowWidth: 800,
windowHeight: 600, windowHeight: 600,
currentTime: 0, currentTime: 0,
locale: 'zh'
}, },
mutations: { mutations: {
SET_WINDOW_SIZE(state, { width, height }) { SET_WINDOW_SIZE(state, { width, height }) {
@ -33,6 +34,10 @@ const store = new Vuex.Store({
SET_TIME: (state, time) => { SET_TIME: (state, time) => {
state.currentTime = time state.currentTime = time
}, },
SET_LOCALE: (state, locale) => {
state.locale = locale
localStorage.setItem('ops_locale', locale)
}
}, },
actions: { actions: {
setWindowSize({ commit }) { setWindowSize({ commit }) {

View File

@ -1,7 +1,7 @@
<template> <template>
<a-form-model ref="form" :model="form" :label-col="labelCol" :wrapper-col="wrapperCol" :rules="rules"> <a-form-model ref="form" :model="form" :label-col="labelCol" :wrapper-col="wrapperCol" :rules="rules">
<SpanTitle>基本</SpanTitle> <SpanTitle>{{ $t('cs.auth.basic') }}</SpanTitle>
<a-form-model-item label="是否启用" prop="enable"> <a-form-model-item :label="$t('cs.auth.isEnable')" prop="enable">
<a-switch <a-switch
:checked="Boolean(form.enable)" :checked="Boolean(form.enable)"
@change=" @change="
@ -11,26 +11,26 @@
" "
/> />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="服务端地址" prop="cas_server" help="不包括url path例如https://xxx.com"> <a-form-model-item :label="$t('cs.auth.cas.server')" prop="cas_server" :help="$t('cs.auth.cas.serverHelp')">
<a-input v-model="form.cas_server" placeholder="请输入服务端地址" /> <a-input v-model="form.cas_server" :placeholder="$t('cs.auth.cas.serverPlaceholder')" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="验证服务端地址" prop="cas_validate_server" help="不包括url path例如https://xxx.com"> <a-form-model-item :label="$t('cs.auth.cas.validateServer')" prop="cas_validate_server" :help="$t('cs.auth.cas.validateServerHelp')">
<a-input v-model="form.cas_validate_server" placeholder="请输入验证服务端地址" /> <a-input v-model="form.cas_validate_server" :placeholder="$t('cs.auth.cas.validateServerPlaceholder')" />
</a-form-model-item> </a-form-model-item>
<SpanTitle>其他</SpanTitle> <SpanTitle>{{ $t('cs.auth.other') }}</SpanTitle>
<a-form-model-item label="登录路由" prop="cas_login_route"> <a-form-model-item :label="$t('cs.auth.cas.loginRoute')" prop="cas_login_route">
<a-input v-model="form.cas_login_route" placeholder="/cas/built-in/cas/login" /> <a-input v-model="form.cas_login_route" placeholder="/cas/built-in/cas/login" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="注销路由" prop="cas_logout_route"> <a-form-model-item :label="$t('cs.auth.cas.logoutRoute')" prop="cas_logout_route">
<a-input v-model="form.cas_logout_route" placeholder="/cas/built-in/cas/logout" /> <a-input v-model="form.cas_logout_route" placeholder="/cas/built-in/cas/logout" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="验证路由" prop="cas_validate_route"> <a-form-model-item :label="$t('cs.auth.cas.validateRoute')" prop="cas_validate_route">
<a-input v-model="form.cas_validate_route" placeholder="/cas/built-in/cas/serviceValidate" /> <a-input v-model="form.cas_validate_route" placeholder="/cas/built-in/cas/serviceValidate" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="重定向路由" prop="cas_after_login"> <a-form-model-item :label="$t('cs.auth.cas.afterLoginRoute')" prop="cas_after_login">
<a-input v-model="form.cas_after_login" placeholder="请输入重定向路由" /> <a-input v-model="form.cas_after_login" :placeholder="$t('cs.auth.cas.afterLoginRoutePlaceholder')" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="用户属性映射" prop="cas_user_map" :wrapper-col="{ span: 15 }"> <a-form-model-item :label="$t('cs.auth.cas.userMap')" prop="cas_user_map" :wrapper-col="{ span: 15 }">
<vue-json-editor <vue-json-editor
:style="{ '--custom-height': `${200}px` }" :style="{ '--custom-height': `${200}px` }"
v-model="form.cas_user_map" v-model="form.cas_user_map"
@ -73,16 +73,20 @@ export default {
labelCol: { span: 3 }, labelCol: { span: 3 },
wrapperCol: { span: 10 }, wrapperCol: { span: 10 },
form: _.cloneDeep(defaultForm), form: _.cloneDeep(defaultForm),
rules: {
enable: [{ required: true }],
cas_server: [{ required: true, message: '请输入服务端地址' }],
cas_login_route: [{ required: true, message: '请输入登录路由' }],
cas_logout_route: [{ required: true, message: '请输入注销路由' }],
cas_validate_route: [{ required: true, message: '请输入验证路由' }],
},
isJsonRight: true, isJsonRight: true,
} }
}, },
computed: {
rules() {
return {
enable: [{ required: true }],
cas_server: [{ required: true, message: this.$t('cs.auth.cas.serverPlaceholder') }],
cas_login_route: [{ required: true, message: this.$t('cs.auth.cas.loginRoutePlaceholder') }],
cas_logout_route: [{ required: true, message: this.$t('cs.auth.cas.logoutRoutePlaceholder') }],
cas_validate_route: [{ required: true, message: this.$t('cs.auth.cas.validateRoutePlaceholder') }],
}
}
},
methods: { methods: {
setData(data) { setData(data) {
if (data) { if (data) {

View File

@ -1,10 +1,10 @@
<template> <template>
<a-form-model ref="form" :model="form" :label-col="labelCol" :wrapper-col="wrapperCol" :rules="rules"> <a-form-model ref="form" :model="form" :label-col="labelCol" :wrapper-col="wrapperCol" :rules="rules">
<SpanTitle>基本</SpanTitle> <SpanTitle>{{ $t('cs.auth.basic') }}</SpanTitle>
<a-form-model-item <a-form-model-item
label="自动跳转到第三方登录页" :label="$t('cs.auth.autoRedirectLogin')"
prop="auto_redirect" prop="auto_redirect"
help="如果关闭,则会弹出跳转到第三方登录页的确认,点取消按钮会进入系统内置的登录页" :help="$t('cs.auth.autoRedirectLoginHelp')"
> >
<a-switch <a-switch
:checked="Boolean(form.auto_redirect)" :checked="Boolean(form.auto_redirect)"

View File

@ -15,12 +15,12 @@
<a-row> <a-row>
<a-col :offset="item.value === 'AuthCommonConfig' ? 5 : 3"> <a-col :offset="item.value === 'AuthCommonConfig' ? 5 : 3">
<a-space> <a-space>
<a-button :loading="loading" type="primary" @click="handleSave">保存</a-button> <a-button :loading="loading" type="primary" @click="handleSave">{{ $t('save') }}</a-button>
<template v-if="item.value === 'LDAP'"> <template v-if="item.value === 'LDAP'">
<a-button :loading="loading" ghost type="primary" @click="handleTest('connect')">测试连接</a-button> <a-button :loading="loading" ghost type="primary" @click="handleTest('connect')">{{ $t('cs.auth.testConnect') }}</a-button>
<a-button :loading="loading" ghost type="primary" @click="handleTest('login')">测试登录</a-button> <a-button :loading="loading" ghost type="primary" @click="handleTest('login')">{{ $t('cs.auth.testLogin') }}</a-button>
</template> </template>
<a-button :loading="loading" @click="handleReset">重置</a-button> <a-button :loading="loading" @click="handleReset">{{ $t('reset') }}</a-button>
</a-space> </a-space>
</a-col> </a-col>
</a-row> </a-row>
@ -42,7 +42,20 @@ export default {
name: 'Auth', name: 'Auth',
components: { LDAP, CAS, AuthCommonConfig, OAUTH2, LoginModal }, components: { LDAP, CAS, AuthCommonConfig, OAUTH2, LoginModal },
data() { data() {
const authList = [ return {
activeKey: 'LDAP',
dataTypeId: null,
loading: false,
enable_list: [],
}
},
mounted() {
this.changeActiveKey()
this.getAuthDataEnable()
},
computed: {
authList() {
return [
{ {
value: 'LDAP', value: 'LDAP',
label: 'LDAP', label: 'LDAP',
@ -61,21 +74,11 @@ export default {
}, },
{ {
value: 'AuthCommonConfig', value: 'AuthCommonConfig',
label: '通用', label: this.$t('cs.auth.common'),
}, },
] ]
return {
authList,
activeKey: 'LDAP',
dataTypeId: null,
loading: false,
enable_list: [],
} }
}, },
mounted() {
this.changeActiveKey()
this.getAuthDataEnable()
},
methods: { methods: {
getAuthDataEnable() { getAuthDataEnable() {
getAuthDataEnable().then((res) => { getAuthDataEnable().then((res) => {
@ -105,7 +108,7 @@ export default {
this.loading = false this.loading = false
}) })
} }
this.$message.success('保存成功') this.$message.success(this.$t('saveSuccess'))
this.changeActiveKey() this.changeActiveKey()
this.getAuthDataEnable() this.getAuthDataEnable()
}) })
@ -128,7 +131,7 @@ export default {
} }
testLDAP(type, { data: _data }) testLDAP(type, { data: _data })
.then((res) => { .then((res) => {
this.$message.success('测试成功') this.$message.success(this.$t('cs.auth.testSuccess'))
}) })
.finally(() => { .finally(() => {
this.loading = false this.loading = false

View File

@ -1,7 +1,7 @@
<template> <template>
<a-form-model ref="form" :model="form" :label-col="labelCol" :wrapper-col="wrapperCol" :rules="rules"> <a-form-model ref="form" :model="form" :label-col="labelCol" :wrapper-col="wrapperCol" :rules="rules">
<SpanTitle>基本</SpanTitle> <SpanTitle>{{ $t('cs.auth.basic') }}</SpanTitle>
<a-form-model-item label="是否启用" prop="enable"> <a-form-model-item :label="$t('cs.auth.isEnable')" prop="enable">
<a-switch <a-switch
:checked="Boolean(form.enable)" :checked="Boolean(form.enable)"
@change=" @change="
@ -12,22 +12,22 @@
/> />
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item
label="服务器地址" :label="$t('cs.auth.ldap.serverAddress')"
prop="ldap_server" prop="ldap_server"
help="例如: 192.168.1.6 或者 ldap://192.168.1.6 或者 ldap://192.168.1.6:389" :help="$t('cs.auth.ldap.serverAddressHelp')"
> >
<a-input v-model="form.ldap_server" placeholder="请输入服务器地址" /> <a-input v-model="form.ldap_server" :placeholder="$t('cs.auth.ldap.serverAddressPlaceholder')" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="" prop="ldap_domain"> <a-form-model-item :label="$t('cs.auth.ldap.domain')" prop="ldap_domain">
<a-input v-model="form.ldap_domain" placeholder="请输入域" /> <a-input v-model="form.ldap_domain" :placeholder="$t('cs.auth.ldap.domainPlaceholder')" />
</a-form-model-item> </a-form-model-item>
<SpanTitle>用户</SpanTitle> <SpanTitle>{{ $t('cs.auth.ldap.user') }}</SpanTitle>
<a-form-model-item <a-form-model-item
label="用户名称" :label="$t('cs.auth.ldap.username')"
prop="ldap_user_dn" prop="ldap_user_dn"
help="用户dn: cn={},ou=users,dc=xxx,dc=com {}会替换成用户名" :help="$t('cs.auth.ldap.userHelp')"
> >
<a-input v-model="form.ldap_user_dn" placeholder="请输入用户名称" /> <a-input v-model="form.ldap_user_dn" :placeholder="$t('cs.auth.ldap.userPlaceholder')" />
</a-form-model-item> </a-form-model-item>
</a-form-model> </a-form-model>
</template> </template>
@ -46,11 +46,15 @@ export default {
ldap_server: '', ldap_server: '',
ldap_domain: '', ldap_domain: '',
ldap_user_dn: 'cn={},ou=users,dc=xxx,dc=com', ldap_user_dn: 'cn={},ou=users,dc=xxx,dc=com',
}, }
rules: { }
},
computed: {
rules() {
return {
enable: [{ required: true }], enable: [{ required: true }],
ldap_server: [{ required: true, message: '请输入服务器地址' }], ldap_server: [{ required: true, message: this.$t('cs.auth.ldap.domainPlaceholder') }],
}, }
} }
}, },
methods: { methods: {

View File

@ -1,23 +1,23 @@
<template> <template>
<a-modal :visible="visible" @cancel="handleCancel" @ok="handleOK"> <a-modal :visible="visible" @cancel="handleCancel" @ok="handleOK">
<a-form :form="form" :label-col="{ span: 5 }" :wrapper-col="{ span: 12 }"> <a-form :form="form" :label-col="{ span: 5 }" :wrapper-col="{ span: 12 }">
<a-form-item label="用户名/邮箱"> <a-form-item :label="$t('cs.auth.usernameOrEmail')">
<a-input <a-input
v-decorator="[ v-decorator="[
'username', 'username',
{ {
rules: [{ required: true, message: '请输入用户名或邮箱' }], rules: [{ required: true, message: $t('cs.auth.usernameOrEmailPlaceholder') }],
validateTrigger: 'change', validateTrigger: 'change',
}, },
]" ]"
> >
</a-input> </a-input>
</a-form-item> </a-form-item>
<a-form-item label="密码"> <a-form-item :label="$t('cs.auth.password')">
<a-input <a-input
type="password" type="password"
autocomplete="false" autocomplete="false"
v-decorator="['password', { rules: [{ required: true, message: '请输入密码' }], validateTrigger: 'blur' }]" v-decorator="['password', { rules: [{ required: true, message: $t('cs.auth.passwordPlaceholder') }], validateTrigger: 'blur' }]"
> >
</a-input> </a-input>
</a-form-item> </a-form-item>
@ -25,32 +25,32 @@
</a-modal> </a-modal>
</template> </template>
<script> <script>
export default { export default {
name: 'LoginModal', name: 'LoginModal',
data() { data() {
return { return {
visible: false, visible: false,
form: this.$form.createForm(this), form: this.$form.createForm(this),
} }
},
methods: {
open() {
this.visible = true
}, },
methods: { handleCancel() {
open() { this.visible = false
this.visible = true
},
handleCancel() {
this.visible = false
},
handleOK() {
this.form.validateFields((err, values) => {
if (!err) {
this.$emit('handleOK', values)
this.handleCancel()
}
})
},
}, },
} handleOK() {
</script> this.form.validateFields((err, values) => {
if (!err) {
this.$emit('handleOK', values)
this.handleCancel()
}
})
},
},
}
</script>
<style></style> <style></style>

View File

@ -1,7 +1,7 @@
<template> <template>
<a-form-model ref="form" :model="form" :label-col="labelCol" :wrapper-col="wrapperCol" :rules="rules"> <a-form-model ref="form" :model="form" :label-col="labelCol" :wrapper-col="wrapperCol" :rules="rules">
<SpanTitle>基本</SpanTitle> <SpanTitle>{{ $t('cs.auth.basic') }}</SpanTitle>
<a-form-model-item label="是否启用" prop="enable"> <a-form-model-item :label="$t('cs.auth.isEnable')" prop="enable">
<a-switch <a-switch
:checked="Boolean(form.enable)" :checked="Boolean(form.enable)"
@change=" @change="
@ -11,20 +11,20 @@
" "
/> />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="客户端ID" prop="client_id"> <a-form-model-item :label="$t('cs.auth.oauth2.clientId')" prop="client_id">
<a-input v-model="form.client_id" placeholder="请输入客户端ID" /> <a-input v-model="form.client_id" :placeholder="$t('cs.auth.oauth2.clientIdPlaceholder')" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="客户端密钥" prop="client_secret"> <a-form-model-item :label="$t('cs.auth.oauth2.clientSecret')" prop="client_secret">
<a-input v-model="form.client_secret" placeholder="请输入客户端密钥" /> <a-input v-model="form.client_secret" :placeholder="$t('cs.auth.oauth2.clientSecretPlaceholder')" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="授权链接" prop="authorize_url"> <a-form-model-item :label="$t('cs.auth.oauth2.authorizeUrl')" prop="authorize_url">
<a-input v-model="form.authorize_url" placeholder="请输入授权链接" /> <a-input v-model="form.authorize_url" :placeholder="$t('cs.auth.oauth2.authorizeUrlPlaceholder')" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="令牌链接" prop="token_url"> <a-form-model-item :label="$t('cs.auth.oauth2.tokenUrl')" prop="token_url">
<a-input v-model="form.token_url" placeholder="请输入令牌链接" /> <a-input v-model="form.token_url" :placeholder="$t('cs.auth.oauth2.tokenUrlPlaceholder')" />
</a-form-model-item> </a-form-model-item>
<SpanTitle>其他</SpanTitle> <SpanTitle>其他</SpanTitle>
<a-form-model-item label="用户信息" prop="user_info" :wrapper-col="{ span: 15 }"> <a-form-model-item :label="$t('cs.auth.oauth2.userInfo')" prop="user_info" :wrapper-col="{ span: 15 }">
<vue-json-editor <vue-json-editor
:style="{ '--custom-height': `${200}px` }" :style="{ '--custom-height': `${200}px` }"
v-model="form.user_info" v-model="form.user_info"
@ -35,11 +35,11 @@
@has-error="onJsonError" @has-error="onJsonError"
/> />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="范围" prop="scopes"> <a-form-model-item :label="$t('cs.auth.oauth2.scopes')" prop="scopes">
<a-select mode="tags" v-model="form.scopes" placeholder="请输入范围" /> <a-select mode="tags" v-model="form.scopes" :placeholder="$t('cs.auth.oauth2.scopesPlaceholder')" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="重定向路由" prop="after_login"> <a-form-model-item :label="$t('cs.auth.cas.afterLoginRoute')" prop="after_login">
<a-input v-model="form.after_login" placeholder="请输入重定向路由" /> <a-input v-model="form.after_login" :placeholder="$t('cs.auth.cas.afterLoginRoutePlaceholder')" />
</a-form-model-item> </a-form-model-item>
</a-form-model> </a-form-model>
</template> </template>
@ -78,14 +78,18 @@ export default {
labelCol: { span: 3 }, labelCol: { span: 3 },
wrapperCol: { span: 10 }, wrapperCol: { span: 10 },
form: _.cloneDeep(defaultForm), form: _.cloneDeep(defaultForm),
rules: {
enable: [{ required: true }],
client_id: [{ required: true, message: '请输入客户端ID' }],
client_secret: [{ required: true, message: '请输入客户端密钥' }],
},
isJsonRight: true, isJsonRight: true,
} }
}, },
computed: {
rules() {
return {
enable: [{ required: true }],
client_id: [{ required: true, message: this.$t('cs.auth.oauth2.clientIdPlaceholder') }],
client_secret: [{ required: true, message: this.$t('cs.auth.oauth2.clientSecretPlaceholder') }],
}
}
},
methods: { methods: {
setData(data) { setData(data) {
if (data) { if (data) {

View File

@ -1,379 +1,384 @@
<template> <template>
<div class="ops-setting-companyinfo" :style="{ height: `${windowHeight - 64}px` }"> <div class="ops-setting-companyinfo" :style="{ height: `${windowHeight - 64}px` }">
<a-form-model ref="infoData" :model="infoData" :label-col="labelCol" :wrapper-col="wrapperCol" :rules="rule"> <a-form-model ref="infoData" :model="infoData" :label-col="labelCol" :wrapper-col="wrapperCol" :rules="rule">
<SpanTitle>公司描述</SpanTitle> <SpanTitle>{{ $t('cs.companyInfo.spanCompany') }}</SpanTitle>
<a-form-model-item label="名称" prop="name"> <a-form-model-item :label="$t('cs.companyInfo.name')" prop="name">
<a-input v-model="infoData.name" :disabled="!isEditable" /> <a-input v-model="infoData.name" :disabled="!isEditable"/>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="描述"> <a-form-model-item :label="$t('cs.companyInfo.description')">
<a-input v-model="infoData.description" type="textarea" :disabled="!isEditable" /> <a-input v-model="infoData.description" type="textarea" :disabled="!isEditable"/>
</a-form-model-item> </a-form-model-item>
<SpanTitle>公司地址</SpanTitle> <SpanTitle>{{ $t('cs.companyInfo.spanAddress') }}</SpanTitle>
<a-form-model-item label="国家/地区"> <a-form-model-item :label="$t('cs.companyInfo.country')">
<a-input v-model="infoData.country" :disabled="!isEditable" /> <a-input v-model="infoData.country" :disabled="!isEditable"/>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="城市"> <a-form-model-item :label="$t('cs.companyInfo.city')">
<a-input v-model="infoData.city" :disabled="!isEditable" /> <a-input v-model="infoData.city" :disabled="!isEditable"/>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="地址"> <a-form-model-item :label="$t('cs.companyInfo.address')">
<a-input v-model="infoData.address" :disabled="!isEditable" /> <a-input v-model="infoData.address" :disabled="!isEditable"/>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="邮编"> <a-form-model-item :label="$t('cs.companyInfo.postcode')">
<a-input v-model="infoData.postCode" :disabled="!isEditable" /> <a-input v-model="infoData.postCode" :disabled="!isEditable"/>
</a-form-model-item> </a-form-model-item>
<SpanTitle>联系方式</SpanTitle> <SpanTitle>{{ $t('cs.companyInfo.spanContract') }}</SpanTitle>
<a-form-model-item label="网站"> <a-form-model-item :label="$t('cs.companyInfo.website')">
<a-input v-model="infoData.website" :disabled="!isEditable" /> <a-input v-model="infoData.website" :disabled="!isEditable"/>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="电话号码" prop="phone"> <a-form-model-item :label="$t('cs.companyInfo.phone')" prop="phone">
<a-input v-model="infoData.phone" :disabled="!isEditable" /> <a-input v-model="infoData.phone" :disabled="!isEditable"/>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="传真号码" prop="faxCode"> <a-form-model-item :label="$t('cs.companyInfo.faxCode')" prop="faxCode">
<a-input v-model="infoData.faxCode" :disabled="!isEditable" /> <a-input v-model="infoData.faxCode" :disabled="!isEditable"/>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="电子邮箱" prop="email"> <a-form-model-item :label="$t('cs.companyInfo.email')" prop="email">
<a-input v-model="infoData.email" :disabled="!isEditable" /> <a-input v-model="infoData.email" :disabled="!isEditable"/>
</a-form-model-item> </a-form-model-item>
<SpanTitle>公司标识</SpanTitle> <SpanTitle>{{ $t('cs.companyInfo.spanLogo') }}</SpanTitle>
<a-form-model-item label="Messenger地址" prop="messenger"> <a-form-model-item :label="$t('cs.companyInfo.messenger')" prop="messenger">
<a-input v-model="infoData.messenger" :disabled="!isEditable" /> <a-input v-model="infoData.messenger" :disabled="!isEditable"/>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="部署域名" prop="domainName"> <a-form-model-item :label="$t('cs.companyInfo.domainName')" prop="domainName">
<a-input v-model="infoData.domainName" :disabled="!isEditable" /> <a-input v-model="infoData.domainName" :disabled="!isEditable"/>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="公司logo"> <a-form-model-item :label="$t('cs.companyInfo.logo')">
<a-space> <a-space>
<a-upload <a-upload
:disabled="!isEditable" :disabled="!isEditable"
name="avatar" name="avatar"
list-type="picture-card" list-type="picture-card"
class="avatar-uploader" class="avatar-uploader"
:show-upload-list="false" :show-upload-list="false"
:customRequest="customRequest" :customRequest="customRequest"
:before-upload="beforeUpload" :before-upload="beforeUpload"
:style="{ width: '400px', height: '80px' }" :style="{ width: '400px', height: '80px' }"
accept=".png,.jpg,.jpeg" accept=".png,.jpg,.jpeg"
> >
<div <div
class="ops-setting-companyinfo-upload-show" class="ops-setting-companyinfo-upload-show"
v-if="infoData.logoName" v-if="infoData.logoName"
:style="{ width: '400px', height: '80px' }" :style="{ width: '400px', height: '80px' }"
@click="eidtImageOption.type = 'Logo'" @click="eidtImageOption.type = 'Logo'"
> >
<img :src="`/api/common-setting/v1/file/${infoData.logoName}`" alt="avatar" /> <img :src="`/api/common-setting/v1/file/${infoData.logoName}`" alt="avatar"/>
<a-icon <a-icon
v-if="isEditable" v-if="isEditable"
type="minus-circle" type="minus-circle"
theme="filled" theme="filled"
class="delete-icon" class="delete-icon"
@click.stop="deleteLogo" @click.stop="deleteLogo"
/> />
</div> </div>
<div v-else @click="eidtImageOption.type = 'Logo'"> <div v-else @click="eidtImageOption.type = 'Logo'">
<a-icon type="plus" /> <a-icon type="plus"/>
<div class="ant-upload-text">上传</div> <div class="ant-upload-text">{{ $t('cs.companyInfo.upload') }}</div>
</div> </div>
</a-upload> </a-upload>
<a-upload <a-upload
:disabled="!isEditable" :disabled="!isEditable"
name="avatar" name="avatar"
list-type="picture-card" list-type="picture-card"
class="avatar-uploader" class="avatar-uploader"
:show-upload-list="false" :show-upload-list="false"
:customRequest="customRequest" :customRequest="customRequest"
:before-upload="beforeUpload" :before-upload="beforeUpload"
:style="{ width: '82px', height: '82px' }" :style="{ width: '82px', height: '82px' }"
accept=".png,.jpg,.jpeg" accept=".png,.jpg,.jpeg"
> >
<div <div
class="ops-setting-companyinfo-upload-show" class="ops-setting-companyinfo-upload-show"
v-if="infoData.smallLogoName" v-if="infoData.smallLogoName"
:style="{ width: '82px', height: '82px' }" :style="{ width: '82px', height: '82px' }"
@click="eidtImageOption.type = 'SmallLogo'" @click="eidtImageOption.type = 'SmallLogo'"
> >
<img :src="`/api/common-setting/v1/file/${infoData.smallLogoName}`" alt="avatar" /> <img :src="`/api/common-setting/v1/file/${infoData.smallLogoName}`" alt="avatar"/>
<a-icon <a-icon
v-if="isEditable" v-if="isEditable"
type="minus-circle" type="minus-circle"
theme="filled" theme="filled"
class="delete-icon" class="delete-icon"
@click.stop="deleteSmallLogo" @click.stop="deleteSmallLogo"
/> />
</div> </div>
<div v-else @click="eidtImageOption.type = 'SmallLogo'"> <div v-else @click="eidtImageOption.type = 'SmallLogo'">
<a-icon type="plus" /> <a-icon type="plus"/>
<div class="ant-upload-text">上传</div> <div class="ant-upload-text">{{ $t('cs.companyInfo.upload') }}</div>
</div> </div>
</a-upload> </a-upload>
</a-space> </a-space>
</a-form-model-item> </a-form-model-item>
<a-form-model-item :wrapper-col="{ span: 14, offset: 3 }" v-if="isEditable"> <a-form-model-item :wrapper-col="{ span: 14, offset: 3 }" v-if="isEditable">
<a-button type="primary" @click="onSubmit"> 保存 </a-button> <a-button type="primary" @click="onSubmit"> {{ $t('save') }}</a-button>
<a-button ghost type="primary" style="margin-left: 28px" @click="resetForm"> 重置 </a-button> <a-button ghost type="primary" style="margin-left: 28px" @click="resetForm"> {{ $t('reset') }}</a-button>
</a-form-model-item> </a-form-model-item>
</a-form-model> </a-form-model>
<edit-image <edit-image
v-if="showEditImage" v-if="showEditImage"
:show="showEditImage" :show="showEditImage"
:image="editImage" :image="editImage"
:title="eidtImageOption.title" :title="eidtImageOption.title"
:eidtImageOption="eidtImageOption" :eidtImageOption="eidtImageOption"
@save="submitImage" @save="submitImage"
@close="showEditImage = false" @close="showEditImage = false"
/> />
</div> </div>
</template> </template>
<script> <script>
import { getCompanyInfo, postCompanyInfo, putCompanyInfo } from '@/api/company' import { getCompanyInfo, postCompanyInfo, putCompanyInfo } from '@/api/company'
import { postImageFile } from '@/api/file' import { postImageFile } from '@/api/file'
import { mapMutations, mapState } from 'vuex' import { mapMutations, mapState } from 'vuex'
import SpanTitle from '../components/spanTitle.vue' import SpanTitle from '../components/spanTitle.vue'
import EditImage from '../components/EditImage.vue' import EditImage from '../components/EditImage.vue'
import { mixinPermissions } from '@/utils/mixin' import { mixinPermissions } from '@/utils/mixin'
export default {
name: 'CompanyInfo', export default {
mixins: [mixinPermissions], name: 'CompanyInfo',
components: { SpanTitle, EditImage }, mixins: [mixinPermissions],
data() { components: { SpanTitle, EditImage },
return { data() {
labelCol: { span: 3 }, return {
wrapperCol: { span: 10 }, labelCol: { span: 3 },
infoData: { wrapperCol: { span: 10 },
name: '', infoData: {
description: '', name: '',
address: '', description: '',
city: '', address: '',
postCode: '', city: '',
country: '', postCode: '',
website: '', country: '',
phone: '', website: '',
faxCode: '', phone: '',
email: '', faxCode: '',
logoName: '', email: '',
smallLogoName: '', logoName: '',
messenger: '', smallLogoName: '',
domainName: '', messenger: '',
}, domainName: '',
rule: { },
name: [{ required: true, whitespace: true, message: '请输入名称', trigger: 'blur' }], getId: -1,
phone: [ showEditImage: false,
{ editImage: null
required: false, }
whitespace: true, },
pattern: new RegExp('^([0-9]|-)+$', 'g'), async mounted() {
message: '请输入正确的电话号码', const res = await getCompanyInfo()
trigger: 'blur', if (!res.id) {
}, this.getId = -1
], } else {
faxCode: [ this.infoData = res.info
{ this.getId = res.id
required: false, }
whitespace: true, },
pattern: new RegExp('^([0-9]|-)+$', 'g'), computed: {
message: '请输入正确的传真号码', ...mapState({
trigger: 'blur', windowHeight: (state) => state.windowHeight,
}, }),
], isEditable() {
email: [ return this.hasDetailPermission('backend', '公司信息', ['update'])
{ },
required: false, rule() {
whitespace: true, return {
pattern: new RegExp('^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(.[a-zA-Z0-9-]+)*.[a-zA-Z0-9]{2,6}$', 'g'), name: [{ required: true, whitespace: true, message: this.$t('cs.companyInfo.nameValidate'), trigger: 'blur' }],
message: '请输入正确的邮箱地址', phone: [
trigger: 'blur', {
}, required: false,
], whitespace: true,
}, pattern: new RegExp('^([0-9]|-)+$', 'g'),
getId: -1, message: this.$t('cs.companyInfo.phoneValidate'),
showEditImage: false, trigger: 'blur',
editImage: null, },
eidtImageOption: { ],
type: 'Logo', faxCode: [
fixedNumber: [15, 4], {
title: '编辑企业logo', required: false,
previewWidth: '200px', whitespace: true,
previewHeight: '40px', pattern: new RegExp('^([0-9]|-)+$', 'g'),
autoCropWidth: 200, message: this.$t('cs.companyInfo.faxCodeValidate'),
autoCropHeight: 40, trigger: 'blur',
}, },
} ],
}, email: [
async mounted() { {
const res = await getCompanyInfo() required: false,
if (!res.id) { whitespace: true,
this.getId = -1 pattern: new RegExp('^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(.[a-zA-Z0-9-]+)*.[a-zA-Z0-9]{2,6}$', 'g'),
} else { message: this.$t('cs.companyInfo.emailValidate'),
this.infoData = res.info trigger: 'blur',
this.getId = res.id },
} ],
}, }
computed: { },
...mapState({ eidtImageOption () {
windowHeight: (state) => state.windowHeight, return {
}), type: 'Logo',
isEditable() { fixedNumber: [15, 4],
return this.hasDetailPermission('backend', '公司信息', ['update']) title: this.$t('cs.companyInfo.editCompanyLogo'),
}, previewWidth: '200px',
}, previewHeight: '40px',
methods: { autoCropWidth: 200,
...mapMutations(['SET_FILENAME', 'SET_SMALL_FILENAME']), autoCropHeight: 40,
deleteLogo() { }
this.infoData.logoName = '' }
}, },
deleteSmallLogo() { methods: {
this.infoData.smallLogoName = '' ...mapMutations(['SET_FILENAME', 'SET_SMALL_FILENAME']),
}, deleteLogo() {
async onSubmit() { this.infoData.logoName = ''
this.$refs.infoData.validate(async (valid) => { },
if (valid) { deleteSmallLogo() {
if (this.getId === -1) { this.infoData.smallLogoName = ''
await postCompanyInfo(this.infoData) },
} else { async onSubmit() {
await putCompanyInfo(this.getId, this.infoData) this.$refs.infoData.validate(async (valid) => {
} if (valid) {
this.SET_FILENAME(this.infoData.logoName) if (this.getId === -1) {
this.SET_SMALL_FILENAME(this.infoData.smallFileName) await postCompanyInfo(this.infoData)
this.$message.success('保存成功') } else {
} else { await putCompanyInfo(this.getId, this.infoData)
this.$message.warning('检查您的输入是否正确!') }
return false this.SET_FILENAME(this.infoData.logoName)
} this.SET_SMALL_FILENAME(this.infoData.smallFileName)
}) this.$message.success(this.$t('saveSuccess'))
}, } else {
resetForm() { this.$message.warning(this.$t('cs.companyInfo.checkInputCorrect'))
this.infoData = { return false
name: '', }
description: '', })
address: '', },
city: '', resetForm() {
postCode: '', this.infoData = {
country: '', name: '',
website: '', description: '',
phone: '', address: '',
faxCode: '', city: '',
email: '', postCode: '',
logoName: '', country: '',
smallLogoName: '', website: '',
messenger: '', phone: '',
domainName: '', faxCode: '',
} email: '',
}, logoName: '',
customRequest(file) { smallLogoName: '',
const reader = new FileReader() messenger: '',
var self = this domainName: '',
if (this.eidtImageOption.type === 'Logo') { }
this.eidtImageOption = { },
type: 'Logo', customRequest(file) {
fixedNumber: [20, 4], const reader = new FileReader()
title: '编辑企业logo', var self = this
previewWidth: '200px', if (this.eidtImageOption.type === 'Logo') {
previewHeight: '40px', this.eidtImageOption = {
autoCropWidth: 200, type: 'Logo',
autoCropHeight: 40, fixedNumber: [20, 4],
} title: this.$t('cs.companyInfo.editCompanyLogo'),
} else if (this.eidtImageOption.type === 'SmallLogo') { previewWidth: '200px',
this.eidtImageOption = { previewHeight: '40px',
type: 'SmallLogo', autoCropWidth: 200,
fixedNumber: [4, 4], autoCropHeight: 40,
title: '编辑企业logo缩略图', }
previewWidth: '80px', } else if (this.eidtImageOption.type === 'SmallLogo') {
previewHeight: '80px', this.eidtImageOption = {
autoCropWidth: 250, type: 'SmallLogo',
autoCropHeight: 250, fixedNumber: [4, 4],
} title: this.$t('cs.companyInfo.editCompanyLogoSmall'),
} previewWidth: '80px',
reader.onload = function(e) { previewHeight: '80px',
let result autoCropWidth: 250,
if (typeof e.target.result === 'object') { autoCropHeight: 250,
// 把Array Buffer转化为blob 如果是base64不需要 }
result = window.URL.createObjectURL(new Blob([e.target.result])) }
} else { reader.onload = function (e) {
result = e.target.result let result
} if (typeof e.target.result === 'object') {
// 把Array Buffer转化为blob 如果是base64不需要
self.editImage = result result = window.URL.createObjectURL(new Blob([e.target.result]))
self.showEditImage = true } else {
} result = e.target.result
reader.readAsDataURL(file.file) }
},
submitImage(file) { self.editImage = result
postImageFile(file).then((res) => { self.showEditImage = true
if (res.file_name) { }
if (this.eidtImageOption.type === 'Logo') { reader.readAsDataURL(file.file)
this.infoData.logoName = res.file_name },
} else if (this.eidtImageOption.type === 'SmallLogo') { submitImage(file) {
this.infoData.smallLogoName = res.file_name postImageFile(file).then((res) => {
} if (res.file_name) {
} else { if (this.eidtImageOption.type === 'Logo') {
} this.infoData.logoName = res.file_name
}) } else if (this.eidtImageOption.type === 'SmallLogo') {
}, this.infoData.smallLogoName = res.file_name
}
beforeUpload(file) { } else {
const isLt2M = file.size / 1024 / 1024 < 2 }
if (!isLt2M) { })
this.$message.error('图片大小不可超过2MB!') },
}
return isLt2M beforeUpload(file) {
}, const isLt2M = file.size / 1024 / 1024 < 2
}, if (!isLt2M) {
} this.$message.error(this.$t('cs.companyInfo.imageSizeLimit2MB'))
</script> }
return isLt2M
<style lang="less"> },
.ops-setting-companyinfo { },
padding-top: 15px; }
background-color: #fff; </script>
border-radius: 15px;
overflow: auto; <style lang="less">
margin-bottom: -24px; .ops-setting-companyinfo {
.ops-setting-companyinfo-upload-show { padding-top: 15px;
position: relative; background-color: #fff;
width: 290px; border-radius: 15px;
height: 100px; overflow: auto;
max-height: 100px; margin-bottom: -24px;
img { .ops-setting-companyinfo-upload-show {
width: 100%; position: relative;
height: 100%; width: 290px;
} height: 100px;
max-height: 100px;
.delete-icon { img {
display: none; width: 100%;
} height: 100%;
} }
.ant-upload:hover .delete-icon {
display: block; .delete-icon {
position: absolute; display: none;
top: 5px; }
right: 5px; }
color: rgb(247, 85, 85); .ant-upload:hover .delete-icon {
} display: block;
.ant-form-item { position: absolute;
margin-bottom: 10px; top: 5px;
} right: 5px;
.ant-form-item label { color: rgb(247, 85, 85);
padding-right: 10px; }
} .ant-form-item {
.avatar-uploader > .ant-upload { margin-bottom: 10px;
// max-width: 100px; }
max-height: 100px; .ant-form-item label {
} padding-right: 10px;
// .ant-upload.ant-upload-select-picture-card { }
// width: 100%; .avatar-uploader > .ant-upload {
// > .ant-upload { // max-width: 100px;
// padding: 0px; max-height: 100px;
.ant-upload-picture-card-wrapper { }
height: 100px; // .ant-upload.ant-upload-select-picture-card {
.ant-upload.ant-upload-select-picture-card { // width: 100%;
width: 100%; // > .ant-upload {
height: 100%; // padding: 0px;
margin: 0; .ant-upload-picture-card-wrapper {
> .ant-upload { height: 100px;
padding: 0px; .ant-upload.ant-upload-select-picture-card {
} width: 100%;
} height: 100%;
} margin: 0;
} > .ant-upload {
</style> padding: 0px;
}
}
}
}
</style>

View File

@ -10,54 +10,54 @@
> >
<a-form-model v-if="visible && batchProps.type === 'department_id'"> <a-form-model v-if="visible && batchProps.type === 'department_id'">
<div :style="{ width: '420px', display: 'inline-block', margin: '0 7px' }"> <div :style="{ width: '420px', display: 'inline-block', margin: '0 7px' }">
<div :style="{ height: '40px', lineHeight: '40px' }">选择部门:</div> <div :style="{ height: '40px', lineHeight: '40px' }">{{ $t('cs.companyStructure.selectDepartment') }}:</div>
<DepartmentTreeSelect v-model="batchForm.value"> </DepartmentTreeSelect> <DepartmentTreeSelect v-model="batchForm.value"> </DepartmentTreeSelect>
</div> </div>
</a-form-model> </a-form-model>
<a-form-model v-else-if="batchProps.type === 'direct_supervisor_id'" ref="ruleForm"> <a-form-model v-else-if="batchProps.type === 'direct_supervisor_id'" ref="ruleForm">
<div :style="{ width: '420px', display: 'inline-block', margin: '0 7px' }"> <div :style="{ width: '420px', display: 'inline-block', margin: '0 7px' }">
<div :style="{ height: '40px', lineHeight: '40px' }">选择上级:</div> <div :style="{ height: '40px', lineHeight: '40px' }">{{ $t('cs.companyStructure.selectDirectSupervisor') }}:</div>
<EmployeeTreeSelect v-model="batchForm.value" /> <EmployeeTreeSelect v-model="batchForm.value" />
</div> </div>
</a-form-model> </a-form-model>
<a-form-model v-else-if="batchProps.type === 'position_name'"> <a-form-model v-else-if="batchProps.type === 'position_name'">
<a-form-model-item label="编辑岗位"> <a-form-model-item :label="$t('cs.companyStructure.editPosition')">
<a-input v-model="batchForm.value" /> <a-input v-model="batchForm.value" />
</a-form-model-item> </a-form-model-item>
</a-form-model> </a-form-model>
<a-form-model v-else-if="batchProps.type === 'annual_leave'"> <a-form-model v-else-if="batchProps.type === 'annual_leave'">
<a-form-model-item label="编辑年假"> <a-form-model-item :label="$t('cs.companyStructure.editAnnualLeave')">
<a-input-number <a-input-number
:min="0" :min="0"
:step="1" :step="1"
:style="{ width: '100%' }" :style="{ width: '100%' }"
v-model="batchForm.value" v-model="batchForm.value"
placeholder="请输入年假" :placeholder="$t('cs.companyStructure.annualLeavePlaceholder')"
:formatter="(value) => `${value} `" :formatter="(value) => `${value} $t('cs.companyStructure.day')`"
/> />
</a-form-model-item> </a-form-model-item>
</a-form-model> </a-form-model>
<a-form-model v-else-if="batchProps.type === 'password'" ref="batchForm" :model="batchForm" :rules="rules"> <a-form-model v-else-if="batchProps.type === 'password'" ref="batchForm" :model="batchForm" :rules="rules">
<a-form-model-item label="重置密码" prop="password"> <a-form-model-item :label="$t('cs.companyStructure.resetPassword')" prop="password">
<a-input-password v-model="batchForm.value" /> <a-input-password v-model="batchForm.value" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="确认密码" prop="repeatPassword"> <a-form-model-item :label="$t('cs.companyStructure.confirmPassword')" prop="repeatPassword">
<a-input-password v-model="batchForm.confirmValue" /> <a-input-password v-model="batchForm.confirmValue" />
</a-form-model-item> </a-form-model-item>
</a-form-model> </a-form-model>
<a-form-model v-else-if="batchProps.type === 'block' && batchProps.state === 1"> <a-form-model v-else-if="batchProps.type === 'block' && batchProps.state === 1">
<a-icon type="info-circle" :style="{ color: '#FF9E58', fontSize: '16px', marginRight: '10px' }" /> <a-icon type="info-circle" :style="{ color: '#FF9E58', fontSize: '16px', marginRight: '10px' }" />
<span v-if="batchProps.selectedRowKeys.length > 1">这些用户将会被禁用是否继续?</span> <span v-if="batchProps.selectedRowKeys.length > 1">{{ $t('cs.companyStructure.batchBlockUserConfirm') }}</span>
<span v-else>该用户将会被禁用是否继续?</span> <span v-else>{{ $t('cs.companyStructure.blockUserConfirm') }}</span>
</a-form-model> </a-form-model>
<a-form-model v-else-if="batchProps.type === 'block' && batchProps.state === 0"> <a-form-model v-else-if="batchProps.type === 'block' && batchProps.state === 0">
<a-icon type="info-circle" :style="{ color: '#FF9E58', fontSize: '16px', marginRight: '10px' }" /> <a-icon type="info-circle" :style="{ color: '#FF9E58', fontSize: '16px', marginRight: '10px' }" />
<span v-if="batchProps.selectedRowKeys.length > 1">这些用户将会被恢复是否继续?</span> <span v-if="batchProps.selectedRowKeys.length > 1">{{ $t('cs.companyStructure.batchRecoverUserConfirm') }}</span>
<span v-else>该用户将会被恢复是否继续?</span> <span v-else>{{ $t('cs.companyStructure.recoverUserConfirm') }}</span>
</a-form-model> </a-form-model>
<template slot="footer"> <template slot="footer">
<a-button key="back" @click="close"> 取消 </a-button> <a-button key="back" @click="close"> {{ $t('cancel') }} </a-button>
<a-button key="submit" type="primary" @click="batchModalHandleOk"> 确定 </a-button> <a-button key="submit" type="primary" @click="batchModalHandleOk"> {{ $t('confirm') }} </a-button>
</template> </template>
</a-modal> </a-modal>
</template> </template>
@ -75,7 +75,7 @@ export default {
const validatePass = (rule, value, callback) => { const validatePass = (rule, value, callback) => {
console.log(this.batchForm) console.log(this.batchForm)
if (this.batchForm.value === '') { if (this.batchForm.value === '') {
callback(new Error('请输入密码')) callback(new Error(this.$t('cs.companyStructure.password_placeholder')))
} else { } else {
this.$refs.batchForm.validateField('repeatPassword') this.$refs.batchForm.validateField('repeatPassword')
callback() callback()
@ -84,9 +84,9 @@ export default {
const validatePass2 = (rule, value, callback) => { const validatePass2 = (rule, value, callback) => {
console.log(this.batchForm) console.log(this.batchForm)
if (this.batchForm.confirmValue === '') { if (this.batchForm.confirmValue === '') {
callback(new Error('请输入密码')) callback(new Error(this.$t('cs.companyStructure.passwordPlaceholder')))
} else if (this.batchForm.confirmValue !== this.batchForm.value) { } else if (this.batchForm.confirmValue !== this.batchForm.value) {
callback(new Error('两次密码不一致')) callback(new Error(this.$t('cs.person.thePasswordEnteredTwiceIsInconsistent')))
} else { } else {
callback() callback()
} }
@ -115,19 +115,19 @@ export default {
this.visible = true this.visible = true
this.batchProps = batchProps this.batchProps = batchProps
const { type, selectedRowKeys, state } = batchProps const { type, selectedRowKeys, state } = batchProps
this.title = '批量编辑' this.title = this.$t('cs.companyStructure.batchEdit')
if (type === 'department_id') { if (type === 'department_id') {
this.batchForm.value = null this.batchForm.value = null
} else if (type === 'direct_supervisor_id') { } else if (type === 'direct_supervisor_id') {
this.batchForm.value = undefined this.batchForm.value = undefined
} else if (type === 'password') { } else if (type === 'password') {
if (selectedRowKeys.length <= 1) { if (selectedRowKeys.length <= 1) {
this.title = '重置密码' this.title = this.$t('cs.companyStructure.resetPassword')
} }
} else if (type === 'block') { } else if (type === 'block') {
this.batchForm.value = state this.batchForm.value = state
if (selectedRowKeys.length <= 1) { if (selectedRowKeys.length <= 1) {
this.title = state ? '禁用' : '恢复' this.title = state ? this.$t('cs.companyStructure.block') : this.$t('cs.companyStructure.recover')
} }
} }
}, },
@ -163,7 +163,7 @@ export default {
}) })
if (res.length) { if (res.length) {
this.$notification.error({ this.$notification.error({
message: '操作失败', message: this.$t('cs.companyStructure.opFailed'),
description: res description: res
.map((item) => `${getDirectorName(this.allFlatEmployees, item.employee_id)}${item.err}`) .map((item) => `${getDirectorName(this.allFlatEmployees, item.employee_id)}${item.err}`)
.join('\n'), .join('\n'),
@ -175,7 +175,7 @@ export default {
}, },
}) })
} else { } else {
this.$message.success('操作成功') this.$message.success(this.$t('cs.companyStructure.opSuccess'))
} }
if (this.batchProps.type === 'department_id') { if (this.batchProps.type === 'department_id') {
Bus.$emit('clickSelectGroup', 1) Bus.$emit('clickSelectGroup', 1)

View File

@ -1,7 +1,7 @@
<template> <template>
<a-modal <a-modal
:visible="visible" :visible="visible"
title="批量导入" :title="$t('cs.companyStructure.batchImport')"
dialogClass="ops-modal setting-structure-upload" dialogClass="ops-modal setting-structure-upload"
:width="800" :width="800"
@cancel="close" @cancel="close"
@ -22,15 +22,17 @@
<a-upload :multiple="false" :customRequest="customRequest" accept=".xlsx" :showUploadList="false"> <a-upload :multiple="false" :customRequest="customRequest" accept=".xlsx" :showUploadList="false">
<a-button :style="{ marginBottom: '20px' }" type="primary"> <a-icon type="upload" />选择文件</a-button> <a-button :style="{ marginBottom: '20px' }" type="primary"> <a-icon type="upload" />选择文件</a-button>
</a-upload> </a-upload>
<p><a @click="download">点击下载员工导入模板</a></p> <p><a @click="download">{{ $t('cs.companyStructure.clickDownloadImportTemplate') }}</a></p>
</template> </template>
<div <div
:style="{ height: '60px', display: 'flex', justifyContent: 'center', alignItems: 'center' }" :style="{ height: '60px', display: 'flex', justifyContent: 'center', alignItems: 'center' }"
v-if="currentStep === 3" v-if="currentStep === 3"
> >
导入总数据{{ allCount }}, 导入成功 <span :style="{ color: '#2362FB' }">{{ allCount - errorCount }}</span> , 导入总数据{{ allCount }}, 导入成功 <span :style="{ color: '#2362FB' }">{{ allCount - errorCount }}</span> ,
导入失败<span :style="{ color: '#D81E06' }">{{ errorCount }}</span {{ $t('cs.companyStructure.importSuccess', {allCount: allCount}) }}<span :style="{ color: '#2362FB' }">{{ allCount - errorCount }}</span>
> {{ $t('cs.companyStructure.count')}},
{{ $t('cs.companyStructure.importError') }}<span :style="{ color: '#D81E06' }">{{ errorCount }}</span
>{{ $t('cs.companyStructure.count')}}
</div> </div>
<vxe-table <vxe-table
v-if="currentStep === 2 || has_error" v-if="currentStep === 2 || has_error"
@ -45,46 +47,53 @@
:max-height="400" :max-height="400"
:column-config="{ resizable: true }" :column-config="{ resizable: true }"
> >
<vxe-column field="email" title="邮箱" min-width="120" fixed="left"></vxe-column> <vxe-column field="email" :title="$t('cs.companyStructure.email')" min-width="120" fixed="left"></vxe-column>
<vxe-column field="username" title="用户名" min-width="80"></vxe-column> <vxe-column field="username" :title="$t('cs.companyStructure.username')" min-width="80" ></vxe-column>
<vxe-column field="nickname" title="姓名" min-width="80"></vxe-column> <vxe-column field="nickname" :title="$t('cs.companyStructure.nickname')" min-width="80"></vxe-column>
<vxe-column field="password" title="密码" min-width="80"></vxe-column> <vxe-column field="password" :title="$t('cs.companyStructure.password')" min-width="80"></vxe-column>
<vxe-column field="sex" title="性别" min-width="60"></vxe-column> <vxe-column field="sex" :title="$t('cs.companyStructure.sex')" min-width="60"></vxe-column>
<vxe-column field="mobile" title="手机号" min-width="80"></vxe-column> <vxe-column field="mobile" :title="$t('cs.companyStructure.mobile')" min-width="80"></vxe-column>
<vxe-column field="position_name" title="岗位" 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="部门" min-width="80"></vxe-column> <vxe-column field="department_name" :title="$t('cs.companyStructure.departmentName')" min-width="80"></vxe-column>
<vxe-column field="entry_date" title="目前主体入职日期" min-width="120"></vxe-column> <vxe-column field="current_company" v-if="useDFC" :title="$t('cs.companyStructure.currentCompany')" min-width="120"></vxe-column>
<vxe-column field="is_internship" title="正式/实习生" min-width="120"></vxe-column> <vxe-column field="dfc_entry_date" v-if="useDFC" :title="$t('cs.companyStructure.dfcEntryDate')" min-width="120"></vxe-column>
<vxe-column field="leave_date" title="离职日期" min-width="120"></vxe-column> <vxe-column field="entry_date" :title="$t('cs.companyStructure.entryDate')" min-width="120"></vxe-column>
<vxe-column field="id_card" title="身份证号码" min-width="120"></vxe-column> <vxe-column field="is_internship" :title="$t('cs.companyStructure.isInternship')" min-width="120"></vxe-column>
<vxe-column field="nation" title="民族" min-width="80"></vxe-column> <vxe-column field="leave_date" :title="$t('cs.companyStructure.leaveDate')" min-width="120"></vxe-column>
<vxe-column field="id_place" title="籍贯" min-width="80"></vxe-column> <vxe-column field="id_card" :title="$t('cs.companyStructure.idCard')" min-width="120"></vxe-column>
<vxe-column field="party" title="组织关系" min-width="80"></vxe-column> <vxe-column field="nation" :title="$t('cs.companyStructure.nation')" min-width="80"></vxe-column>
<vxe-column field="household_registration_type" title="户籍类型" min-width="80"></vxe-column> <vxe-column field="id_place" :title="$t('cs.companyStructure.idPlace')" min-width="80"></vxe-column>
<vxe-column field="hometown" title="户口所在地" min-width="80"></vxe-column> <vxe-column field="party" :title="$t('cs.companyStructure.party')" min-width="80"></vxe-column>
<vxe-column field="marry" title="婚姻情况" min-width="80"></vxe-column> <vxe-column field="household_registration_type" :title="$t('cs.companyStructure.householdRegistrationType')" min-width="80"></vxe-column>
<vxe-column field="max_degree" title="最高学历" min-width="80"></vxe-column> <vxe-column field="hometown" :title="$t('cs.companyStructure.homewtown')" min-width="80"></vxe-column>
<vxe-column field="emergency_person" title="紧急联系人" min-width="120"></vxe-column> <vxe-column field="marry" :title="$t('cs.companyStructure.marry')" min-width="80"></vxe-column>
<vxe-column field="emergency_phone" title="紧急联系电话" min-width="120"></vxe-column> <vxe-column field="max_degree" :title="$t('cs.companyStructure.maxDegree')" min-width="80"></vxe-column>
<vxe-column field="bank_card_number" title="卡号" min-width="120"></vxe-column> <vxe-column field="emergency_person" :title="$t('cs.companyStructure.emergencyPerson')" min-width="120"></vxe-column>
<vxe-column field="bank_card_name" title="银行" min-width="80"></vxe-column> <vxe-column field="emergency_phone" :title="$t('cs.companyStructure.emergencyPhone')" min-width="120"></vxe-column>
<vxe-column field="opening_bank" title="开户行" min-width="80"></vxe-column> <vxe-column field="bank_card_number" :title="$t('cs.companyStructure.bankCardNumber')" min-width="120"></vxe-column>
<vxe-column field="account_opening_location" title="开户地" min-width="120"></vxe-column> <vxe-column field="bank_card_name" :title="$t('cs.companyStructure.bankCardName')" min-width="80"></vxe-column>
<vxe-column field="school" title="学校" min-width="80"></vxe-column> <vxe-column field="opening_bank" :title="$t('cs.companyStructure.openingBank')" min-width="80"></vxe-column>
<vxe-column field="major" title="专业" min-width="80"></vxe-column> <vxe-column field="account_opening_location" :title="$t('cs.companyStructure.accountOpeningLocation')" min-width="120"></vxe-column>
<vxe-column field="education" title="学历" min-width="80"></vxe-column> <vxe-column field="school" :title="$t('cs.companyStructure.school')" min-width="80"></vxe-column>
<vxe-column field="graduation_year" title="毕业年份" min-width="120"></vxe-column> <vxe-column field="major" :title="$t('cs.companyStructure.major')" min-width="80"></vxe-column>
<vxe-column v-if="has_error" field="err" title="失败原因" min-width="120" fixed="right"> <vxe-column field="education" :title="$t('cs.companyStructure.education')" min-width="80"></vxe-column>
<vxe-column field="graduation_year" :title="$t('cs.companyStructure.graduationYear')" min-width="120"></vxe-column>
<vxe-column field="birth_date" :title="$t('cs.companyStructure.birthDate')" min-width="120"></vxe-column>
<vxe-column field="birth_place" :title="$t('cs.companyStructure.birthPlace')" min-width="120"></vxe-column>
<vxe-column field="nationality_region" :title="$t('cs.companyStructure.nationalityRegion')" min-width="120"></vxe-column>
<vxe-column field="first_entry_date" :title="$t('cs.companyStructure.firstEntryDate')" min-width="120"></vxe-column>
<vxe-column field="estimated_departure_date" :title="$t('cs.companyStructure.estimatedDepartureDate')" min-width="120"></vxe-column>
<vxe-column v-if="has_error" field="err" :title="$t('cs.companyStructure.importFailedReason')" min-width="120" fixed="right">
<template #default="{ row }"> <template #default="{ row }">
<span :style="{ color: '#D81E06' }">{{ row.err }}</span> <span :style="{ color: '#D81E06' }">{{ row.err }}</span>
</template> </template>
</vxe-column> </vxe-column>
</vxe-table> </vxe-table>
<a-space slot="footer"> <a-space slot="footer">
<a-button size="small" type="primary" ghost @click="close">取消</a-button> <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">上一步</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">下一步</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">完成</a-button> <a-button v-else size="small" type="primary" @click="close">{{ $t('cs.companyStructure.done') }}</a-button>
</a-space> </a-space>
</a-modal> </a-modal>
</template> </template>
@ -98,17 +107,17 @@ export default {
const stepList = [ const stepList = [
{ {
value: 1, value: 1,
label: '上传文件', label: this.$t('cs.companyStructure.uploadFile'),
icon: 'icon-shidi-tianjia', icon: 'icon-shidi-tianjia',
}, },
{ {
value: 2, value: 2,
label: '确认数据', label: this.$t('cs.companyStructure.confirmData'),
icon: 'icon-shidi-yunshangchuan', icon: 'icon-shidi-yunshangchuan',
}, },
{ {
value: 3, value: 3,
label: '上传完成', label: this.$t('cs.companyStructure.uploadDone'),
icon: 'icon-shidi-queren', icon: 'icon-shidi-queren',
}, },
] ]
@ -235,10 +244,10 @@ export default {
this.errorCount = errData.length this.errorCount = errData.length
this.currentStep += 1 this.currentStep += 1
this.importData = errData this.importData = errData
this.$message.error('数据存在错误') this.$message.error(this.$t('cs.companyStructure.dataErr'))
} else { } else {
this.currentStep += 1 this.currentStep += 1
this.$message.success('操作成功') this.$message.success(this.$t('cs.companyStructure.opSuccess'))
} }
this.$emit('refresh') this.$emit('refresh')
} }

View File

@ -3,7 +3,7 @@
destroyOnClose destroyOnClose
width="500px" width="500px"
v-model="visible" v-model="visible"
:title="type === 'add' ? '创建子部门' : '编辑部门'" :title="type === 'add' ? $t('cs.companyStructure.createSubDepartment') : $t('cs.companyStructure.editDepartment')"
layout="inline" layout="inline"
@cancel="close" @cancel="close"
> >
@ -14,10 +14,10 @@
:label-col="labelCol" :label-col="labelCol"
:wrapper-col="wrapperCol" :wrapper-col="wrapperCol"
> >
<a-form-model-item ref="title" label="部门名称" prop="department_name"> <a-form-model-item ref="title" :label="$t('cs.companyStructure.departmentLabel')" prop="department_name">
<a-input v-model="departmentFormData.department_name" placeholder="请输入部门名称" /> <a-input v-model="departmentFormData.department_name" :placeholder="$t('cs.companyStructure.departmentLabelPlaceholder')" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="上级部门" prop="department_parent_id"> <a-form-model-item :label="$t('cs.companyStructure.parentDepartment')" prop="department_parent_id">
<DepartmentTreeSelect v-model="departmentFormData.department_parent_id" /> <DepartmentTreeSelect v-model="departmentFormData.department_parent_id" />
<!-- <Treeselect <!-- <Treeselect
v-else v-else
@ -37,13 +37,13 @@
" "
/> --> /> -->
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="部门负责人" prop="department_director_id"> <a-form-model-item :label="$t('cs.companyStructure.departmentDirector')" prop="department_director_id">
<EmployeeTreeSelect v-model="departmentFormData.department_director_id" /> <EmployeeTreeSelect v-model="departmentFormData.department_director_id" />
</a-form-model-item> </a-form-model-item>
</a-form-model> </a-form-model>
<template slot="footer"> <template slot="footer">
<a-button key="back" @click="close"> 取消 </a-button> <a-button key="back" @click="close"> {{ $t('cancel') }} </a-button>
<a-button key="submit" type="primary" @click="departmentModalHandleOk"> 确定 </a-button> <a-button key="submit" type="primary" @click="departmentModalHandleOk"> {{ $t('confirm') }} </a-button>
</template> </template>
</a-modal> </a-modal>
</template> </template>
@ -67,10 +67,6 @@ export default {
department_parent_id: '', department_parent_id: '',
department_director_id: undefined, department_director_id: undefined,
}, },
rules: {
department_name: [{ required: true, message: '请输入部门名称' }],
department_parent_id: [{ required: true, message: '请选择上级部门' }],
},
currentDepartmentParentList: [], currentDepartmentParentList: [],
selectDepartment: {}, selectDepartment: {},
type: 'add', type: 'add',
@ -81,6 +77,12 @@ export default {
allFlatEmployees() { allFlatEmployees() {
return this.provide_allFlatEmployees() return this.provide_allFlatEmployees()
}, },
rules () {
return {
department_name: [{ required: true, message: this.$t('cs.companyStructure.departmentLabelPlaceholder') }],
department_parent_id: [{ required: true, message: this.$t('cs.companyStructure.parentDepartmentPlaceholder') }],
}
}
}, },
mounted() {}, mounted() {},
methods: { methods: {
@ -129,7 +131,7 @@ export default {
} else if (this.type === 'add') { } else if (this.type === 'add') {
await postDepartment(params) await postDepartment(params)
} }
this.$message.success('操作成功') this.$message.success(this.$t('cs.companyStructure.opSuccess'))
this.$emit('refresh') this.$emit('refresh')
Bus.$emit('updateAllIncludeDepartment') Bus.$emit('updateAllIncludeDepartment')
this.close() this.close()

View File

@ -10,349 +10,225 @@
: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 <a-form-model-item ref="email" :label="$t('cs.companyStructure.email')" prop="email" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='email')!==-1">
ref="email" <a-input v-model="employeeFormData.email" :placeholder="$t('cs.companyStructure.emailPlaceholder')"/>
label="邮箱"
prop="email"
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'email') !== -1"
>
<a-input v-model="employeeFormData.email" placeholder="请输入邮箱" />
</a-form-model-item> </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">
ref="username" <a-input v-model="employeeFormData.username" :placeholder="$t('cs.companyStructure.usernamePlaceholder')" />
label="用户名"
prop="username"
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'username') !== -1"
>
<a-input v-model="employeeFormData.username" placeholder="请输入用户名" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item
v-if="type === 'add'" v-if="type === 'add'"
ref="password" ref="password"
label="登录密码" :label="$t('cs.companyStructure.password')"
prop="password" prop="password"
:style="formModalItemStyle" :style="formModalItemStyle"
> >
<a-input-password v-model="employeeFormData.password" placeholder="请输入登录密码" /> <a-input-password v-model="employeeFormData.password" :placeholder="$t('cs.companyStructure.passwordPlaceholder')" />
</a-form-model-item> </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">
ref="nickname" <a-input v-model="employeeFormData.nickname" :placeholder="$t('cs.companyStructure.nicknamePlaceholder')" />
label="姓名"
prop="nickname"
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'nickname') !== -1"
>
<a-input v-model="employeeFormData.nickname" placeholder="请输入姓名" />
</a-form-model-item> </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">
label="性别" <a-select v-model="employeeFormData.sex" :placeholder="$t('cs.companyStructure.sexPlaceholder')">
prop="sex" <a-select-option value=""> {{ $t('cs.companyStructure.male') }} </a-select-option>
:style="formModalItemStyle" <a-select-option value=""> {{ $t('cs.companyStructure.female') }} </a-select-option>
v-if="attributes.findIndex((v) => v == 'sex') !== -1"
>
<a-select v-model="employeeFormData.sex" placeholder="请选择性别">
<a-select-option value=""> </a-select-option>
<a-select-option value=""> </a-select-option>
</a-select> </a-select>
</a-form-model-item> </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">
ref="mobile" <a-input v-model="employeeFormData.mobile" :placeholder="$t('cs.companyStructure.mobilePlaceholder')" />
label="手机号"
prop="mobile"
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'mobile') !== -1"
>
<a-input v-model="employeeFormData.mobile" placeholder="请输入手机号" />
</a-form-model-item> </a-form-model-item>
<div <div :style="{ width: '361px', display: 'inline-block', margin: '0 7px' }" v-if="attributes.findIndex(v=>v=='department_id')!==-1">
:style="{ width: '361px', display: 'inline-block', margin: '0 7px' }" <div :style="{ height: '41px', lineHeight: '40px' }">{{ $t('cs.companyStructure.departmentName') }}</div>
v-if="attributes.findIndex((v) => v == 'department_id') !== -1"
>
<div :style="{ height: '41px', lineHeight: '40px' }">部门</div>
<DepartmentTreeSelect v-model="employeeFormData.department_id" /> <DepartmentTreeSelect v-model="employeeFormData.department_id" />
</div> </div>
<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">
ref="position_name" <a-input v-model="employeeFormData.position_name" :placeholder="$t('cs.companyStructure.positionNamePlaceholder')" />
label="岗位"
prop="position_name"
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'position_name') !== -1"
>
<a-input v-model="employeeFormData.position_name" placeholder="请输入岗位" />
</a-form-model-item> </a-form-model-item>
<div <div :style="{ width: '361px', display: 'inline-block', margin: '0 7px' }" v-if="attributes.findIndex(v=>v=='direct_supervisor_id')!==-1">
:style="{ width: '361px', display: 'inline-block', margin: '0 7px' }" <div :style="{ height: '41px', lineHeight: '40px' }">{{ $t('cs.companyStructure.selectDirectSupervisor') }}</div>
v-if="attributes.findIndex((v) => v == 'direct_supervisor_id') !== -1"
>
<div :style="{ height: '41px', lineHeight: '40px' }">上级</div>
<EmployeeTreeSelect v-model="employeeFormData.direct_supervisor_id" /> <EmployeeTreeSelect v-model="employeeFormData.direct_supervisor_id" />
</div> </div>
<a-form-model-item <!-- <a-form-model-item :label="角色" prop="role" :style="formModalItemStyle">
ref="annual_leave" <a-select mode="multiple" v-model="employeeFormData.role" :placeholder="请选择角色">
label="年假" <a-select-option value="PM"> PM </a-select-option>
prop="annual_leave" <a-select-option value="Test"> Test </a-select-option>
:style="formModalItemStyle" <a-select-option value="Tevelop"> Develop </a-select-option>
v-if="attributes.findIndex((v) => v == 'annual_leave') !== -1" </a-select>
> </a-form-model-item> -->
<a-form-model-item ref="annual_leave" :label="$t('cs.companyStructure.annualLeave')" prop="annual_leave" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='annual_leave')!==-1">
<a-input-number <a-input-number
:min="0" :min="0"
:step="1" :step="1"
:style="{ width: '100%' }" :style="{ width: '100%' }"
v-model="employeeFormData.annual_leave" v-model="employeeFormData.annual_leave"
placeholder="请输入年假" :placeholder="$t('cs.companyStructure.annualLeavePlaceholder')"
:formatter="(value) => `${value} `" :formatter="(value) => `${value} $t('cs.companyStructure.day')`"
/> />
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item ref="virtual_annual_leave" :label="$t('cs.companyStructure.virtualAnnualLeave')" prop="virtual_annual_leave" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='virtual_annual_leave')!==-1">
ref="virtual_annual_leave"
label="虚拟年假"
prop="virtual_annual_leave"
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'virtual_annual_leave') !== -1"
>
<a-input-number <a-input-number
:min="0" :min="0"
:step="1" :step="1"
:style="{ width: '100%' }" :style="{ width: '100%' }"
v-model="employeeFormData.virtual_annual_leave" v-model="employeeFormData.virtual_annual_leave"
placeholder="请输入虚拟年假" :placeholder="$t('cs.companyStructure.virtualAnnualLeavePlaceholder')"
:formatter="(value) => `${value} `" :formatter="(value) => `${value} $t('cs.companyStructure.day')`"
/> />
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item ref="parenting_leave" :label="$t('cs.companyStructure.parentingLeave')" prop="parenting_leave" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='parenting_leave')!==-1">
ref="parenting_leave"
label="育儿假"
prop="parenting_leave"
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'parenting_leave') !== -1"
>
<a-input-number <a-input-number
:min="0" :min="0"
:step="1" :step="1"
:style="{ width: '100%' }" :style="{ width: '100%' }"
v-model="employeeFormData.parenting_leave" v-model="employeeFormData.parenting_leave"
placeholder="请输入育儿假" :placeholder="$t('cs.companyStructure.parentingLeavePlaceholder')"
:formatter="(value) => `${value} `" :formatter="(value) => `${value} $t('cs.companyStructure.day')`"
/> />
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item v-if="attributes.findIndex(v=>v=='current_company')!==-1" ref="current_company" :label="$t('cs.companyStructure.currentCompany')" prop="current_company" :style="formModalItemStyle">
ref="entry_date" <a-input v-model="employeeFormData.current_company" :placeholder="$t('cs.companyStructure.currentCompanyPlaceholder')" />
label="目前主体入职日期"
prop="entry_date"
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'entry_date') !== -1"
>
<a-date-picker
placeholder="请选择目前主体入职日期"
v-model="employeeFormData.entry_date"
:style="{ width: '100%' }"
@change="onChange($event, 'entry_date')"
></a-date-picker>
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item v-if="attributes.findIndex(v=>v=='dfc_entry_date')!==-1" ref="dfc_entry_date" :label="$t('cs.companyStructure.dfcEntryDate')" prop="dfc_entry_date" :style="formModalItemStyle">
ref="is_internship" <a-date-picker :placeholder="$t('cs.companyStructure.dfcEntryDatePlaceholder')" v-model="employeeFormData.dfc_entry_date" :style="{ width: '100%'}" @change="onChange($event, 'dfc_entry_date')"></a-date-picker>
label="正式/实习生" </a-form-model-item>
prop="is_internship" <a-form-model-item ref="entry_date" :label="$t('cs.companyStructure.entryDate')" prop="entry_date" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='entry_date')!==-1">
:style="formModalItemStyle" <a-date-picker :placeholder="$t('cs.companyStructure.entryDatePlaceholder')" v-model="employeeFormData.entry_date" :style="{ width: '100%'}" @change="onChange($event, 'entry_date')"></a-date-picker>
v-if="attributes.findIndex((v) => v == 'is_internship') !== -1" </a-form-model-item>
> <a-form-model-item ref="is_internship" :label="$t('cs.companyStructure.isInternship')" prop="is_internship" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='is_internship')!==-1">
<a-select v-model="employeeFormData.is_internship" placeholder="请选择是否正式/实习生"> <a-select v-model="employeeFormData.is_internship" :placeholder="$t('cs.companyStructure.isInternshipPlaceholder')">
<a-select-option :value="0"> 正式 </a-select-option> <a-select-option :value="0"> {{ $t('cs.companyStructure.fullTime') }} </a-select-option>
<a-select-option :value="1"> 实习生 </a-select-option> <a-select-option :value="1"> {{ $t('cs.companyStructure.internship') }} </a-select-option>
</a-select> </a-select>
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item ref="leave_date" :label="$t('cs.companyStructure.leaveDate')" prop="leave_date" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='leave_date')!==-1">
ref="leave_date" <a-date-picker v-model="employeeFormData.leave_date" :placeholder="$t('cs.companyStructure.leaveDatePlaceholder')" :style="{ width: '100%'}" @change="onChange($event, 'leave_date')"></a-date-picker>
label="离职日期"
prop="leave_date"
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'leave_date') !== -1"
>
<a-date-picker
v-model="employeeFormData.leave_date"
placeholder="请选择离职日期"
:style="{ width: '100%' }"
@change="onChange($event, 'leave_date')"
></a-date-picker>
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item ref="id_card" :label="$t('cs.companyStructure.idCard')" prop="id_card" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='id_card')!==-1">
ref="id_card" <a-input v-model="employeeFormData.id_card" :placeholder="$t('cs.companyStructure.idCardPlaceholder')" />
label="身份证号码"
prop="id_card"
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'id_card') !== -1"
>
<a-input v-model="employeeFormData.id_card" placeholder="请输入身份证号码" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item ref="nation" :label="$t('cs.companyStructure.nation')" prop="nation" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='nation')!==-1">
ref="nation" <a-input v-model="employeeFormData.nation" :placeholder="$t('cs.companyStructure.nationPlaceholder')" />
label="民族"
prop="nation"
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'nation') !== -1"
>
<a-input v-model="employeeFormData.nation" placeholder="请输入民族" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item ref="id_place" :label="$t('cs.companyStructure.idPlace')" prop="id_place" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='id_place')!==-1">
ref="id_place" <a-input v-model="employeeFormData.id_place" :placeholder="$t('cs.companyStructure.idPlacePlaceholder')" />
label="籍贯"
prop="id_place"
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'id_place') !== -1"
>
<a-input v-model="employeeFormData.id_place" placeholder="请输入籍贯" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item ref="party" :label="$t('cs.companyStructure.party')" prop="party" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='party')!==-1">
ref="party" <a-select v-model="employeeFormData.party" :placeholder="$t('cs.companyStructure.')">
label="组织关系" <a-select-option value="党员"> {{ $t('cs.companyStructure.partyMember') }} </a-select-option>
prop="party" <a-select-option value="团员"> {{ $t('cs.companyStructure.member') }} </a-select-option>
:style="formModalItemStyle" <a-select-option value="群众"> {{ $t('cs.companyStructure.masses') }} </a-select-option>
v-if="attributes.findIndex((v) => v == 'party') !== -1"
>
<a-select v-model="employeeFormData.party" placeholder="请选择组织关系">
<a-select-option value="党员"> 党员 </a-select-option>
<a-select-option value="团员"> 团员 </a-select-option>
<a-select-option value="群众"> 群众 </a-select-option>
</a-select> </a-select>
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item ref="household_registration_type" :label="$t('cs.companyStructure.householdRegistrationType')" prop="household_registration_type" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='household_registration_type')!==-1">
ref="household_registration_type" <a-select v-model="employeeFormData.household_registration_type" :placeholder="$t('cs.companyStructure.')">
label="户籍类型" <a-select-option value="城镇"> {{ $t('cs.companyStructure.town') }} </a-select-option>
prop="household_registration_type" <a-select-option value="农业"> {{ $t('cs.companyStructure.agriculture') }} </a-select-option>
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'household_registration_type') !== -1"
>
<a-select v-model="employeeFormData.household_registration_type" placeholder="请选择户籍类型">
<a-select-option value="城镇"> 城镇 </a-select-option>
<a-select-option value="农业"> 农业 </a-select-option>
</a-select> </a-select>
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item ref="hometown" :label="$t('cs.companyStructure.hometown')" prop="hometown" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='hometown')!==-1">
ref="hometown" <a-input v-model="employeeFormData.hometown" :placeholder="$t('cs.companyStructure.hometownPlaceholder')" />
label="户口所在地"
prop="hometown"
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'hometown') !== -1"
>
<a-input v-model="employeeFormData.hometown" placeholder="请输入户口所在地" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item ref="marry" :label="$t('cs.companyStructure.marry')" prop="marry" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='marry')!==-1">
ref="marry" <a-select v-model="employeeFormData.marry" :placeholder="$t('cs.companyStructure.')">
label="婚姻情况" <a-select-option value="未婚"> {{ $t('cs.companyStructure.unmarried') }}</a-select-option>
prop="marry" <a-select-option value="已婚"> {{ $t('cs.companyStructure.married') }} </a-select-option>
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'marry') !== -1"
>
<a-select v-model="employeeFormData.marry" placeholder="请选择婚姻情况">
<a-select-option value="未婚"> 未婚 </a-select-option>
<a-select-option value="已婚"> 已婚 </a-select-option>
</a-select> </a-select>
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item ref="max_degree" :label="$t('cs.companyStructure.maxDegree')" prop="max_degree" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='max_degree')!==-1">
ref="max_degree" <a-select v-model="employeeFormData.max_degree" :placeholder="$t('cs.companyStructure.maxDegreePlaceholder')">
label="最高学历" <a-select-option value="博士"> {{ $t('cs.companyStructure.phd') }} </a-select-option>
prop="max_degree" <a-select-option value="硕士"> {{ $t('cs.companyStructure.master') }} </a-select-option>
:style="formModalItemStyle" <a-select-option value="本科"> {{ $t('cs.companyStructure.undergraduate') }} </a-select-option>
v-if="attributes.findIndex((v) => v == 'max_degree') !== -1" <a-select-option value="专科"> {{ $t('cs.companyStructure.specialist') }} </a-select-option>
> <a-select-option value="高中"> {{ $t('cs.companyStructure.highSchool') }} </a-select-option>
<a-select v-model="employeeFormData.max_degree" placeholder="请选择最高学历">
<a-select-option value="博士"> 博士 </a-select-option>
<a-select-option value="硕士"> 硕士 </a-select-option>
<a-select-option value="本科"> 本科 </a-select-option>
<a-select-option value="专科"> 专科 </a-select-option>
<a-select-option value="高中"> 高中 </a-select-option>
</a-select> </a-select>
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item ref="emergency_person" :label="$t('cs.companyStructure.emergencyPerson')" prop="emergency_person" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='emergency_person')!==-1">
ref="emergency_person" <a-input v-model="employeeFormData.emergency_person" :placeholder="$t('cs.companyStructure.emergencyPersonPlaceholder')" />
label="紧急联系人"
prop="emergency_person"
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'emergency_person') !== -1"
>
<a-input v-model="employeeFormData.emergency_person" placeholder="请输入紧急联系人" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item ref="emergency_phone" :label="$t('cs.companyStructure.emergencyPhone')" prop="emergency_phone" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='emergency_phone')!==-1">
ref="emergency_phone" <a-input v-model="employeeFormData.emergency_phone" :placeholder="$t('cs.companyStructure.emergencyPhonePlaceholder')" />
label="紧急联系电话"
prop="emergency_phone"
:style="formModalItemStyle"
v-if="attributes.findIndex((v) => v == 'emergency_phone') !== -1"
>
<a-input v-model="employeeFormData.emergency_phone" placeholder="请输入紧急联系电话" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item ref="birth_date" :label="$t('cs.companyStructure.birthDate')" prop="birth_date" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='birth_date')!==-1">
label="教育经历" <a-date-picker v-model="employeeFormData.birth_date" :placeholder="$t('cs.companyStructure.birthDatePlaceholder')" :style="{ width: '100%'}" @change="onChange($event, 'birth_date')"></a-date-picker>
prop="employeeFormData" </a-form-model-item>
:style="{ display: 'inline-block', width: '100%', margin: '0 7px' }" <a-form-model-item ref="birth_place" :label="$t('cs.companyStructure.birthPlace')" prop="birth_place" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='birth_place')!==-1">
v-if="attributes.findIndex((v) => v == 'educational_experience') !== -1" <a-input v-model="employeeFormData.birth_place" :placeholder="$t('cs.companyStructure.birthPlacePlaceholder')" />
> </a-form-model-item>
<a-row :gutter="[8, { xs: 8 }]" v-for="item in educational_experience" :key="item.id"> <a-form-model-item ref="nationality_region" :label="$t('cs.companyStructure.nationalityRegion')" prop="nationality_region" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='nationality_region')!==-1">
<a-input v-model="employeeFormData.nationality_region" :placeholder="$t('cs.companyStructure.nationalityRegionPlaceholder')" />
</a-form-model-item>
<a-form-model-item ref="first_entry_date" :label="$t('cs.companyStructure.firstEntryDate')" prop="first_entry_date" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='first_entry_date')!==-1">
<a-date-picker v-model="employeeFormData.first_entry_date" :placeholder="$t('cs.companyStructure.firstEntryDatePlaceholder')" :style="{ width: '100%'}" @change="onChange($event, 'first_entry_date')"></a-date-picker>
</a-form-model-item>
<a-form-model-item ref="estimated_departure_date" :label="$t('cs.companyStructure.estimatedDepartureDate')" prop="estimated_departure_date" :style="formModalItemStyle" v-if="attributes.findIndex(v=>v=='estimated_departure_date')!==-1">
<a-date-picker v-model="employeeFormData.estimated_departure_date" :placeholder="$t('cs.companyStructure.estimatedDepartureDatePlaceholder')" :style="{ width: '100%'}" @change="onChange($event, 'estimated_departure_date')"></a-date-picker>
</a-form-model-item>
<a-form-model-item :label="$t('cs.companyStructure.educationalExperience')" prop="employeeFormData" :style="{ display: 'inline-block', width: '100%', margin: '0 7px'}" v-if="attributes.findIndex(v=>v=='educational_experience')!==-1">
<a-row
:gutter="[8,{xs:8}]"
v-for="(item) in educational_experience"
:key="item.id"
>
<a-col :span="5"> <a-col :span="5">
<a-input v-model="item.school" placeholder="学校" allowClear></a-input> <a-input v-model="item.school" :placeholder="$t('cs.companyStructure.school')" allowClear></a-input>
</a-col> </a-col>
<a-col :span="5"> <a-col :span="5">
<a-input v-model="item.major" placeholder="专业" allowClear></a-input> <a-input v-model="item.major" :placeholder="$t('cs.companyStructure.major')" allowClear></a-input>
</a-col> </a-col>
<a-col :span="5"> <a-col :span="5">
<a-select v-model="item.education" placeholder="学历" allowClear> <a-select v-model="item.education" :placeholder="$t('cs.companyStructure.education')" allowClear>
<a-select-option value="小学"> 小学 </a-select-option> <a-select-option value="小学"> {{ $t('cs.companyStructure.primarySchool') }} </a-select-option>
<a-select-option value="初中"> 初中 </a-select-option> <a-select-option value="初中"> {{ $t('cs.companyStructure.juniorHighSchool') }} </a-select-option>
<a-select-option value="中专/高中"> 中专/高中 </a-select-option> <a-select-option value="中专/高中"> {{ $t('cs.companyStructure.technicalSecondaryOrHighSchool') }} </a-select-option>
<a-select-option value="专科"> 专科 </a-select-option> <a-select-option value="专科"> {{ $t('cs.companyStructure.specialist') }} </a-select-option>
<a-select-option value="本科"> 本科 </a-select-option> <a-select-option value="本科"> {{ $t('cs.companyStructure.undergraduate') }} </a-select-option>
<a-select-option value="硕士"> 硕士 </a-select-option> <a-select-option value="硕士"> {{ $t('cs.companyStructure.master') }} </a-select-option>
<a-select-option value="博士"> 博士 </a-select-option> <a-select-option value="博士"> {{ $t('cs.companyStructure.phd') }} </a-select-option>
</a-select> </a-select>
</a-col> </a-col>
<a-col :span="5"> <a-col :span="5">
<a-month-picker <a-month-picker v-model="item.graduation_year" :placeholder="$t('cs.companyStructure.graduationYearPlaceholder')" @change="onChange($event, 'graduation_year',item.id)" ></a-month-picker>
v-model="item.graduation_year"
placeholder="毕业年份"
@change="onChange($event, 'graduation_year', item.id)"
></a-month-picker>
</a-col> </a-col>
<a-col :span="1"> <a-col :span="1">
<a @click="addEducation"> <a
@click="addEducation"
>
<a-icon type="plus-circle" /> <a-icon type="plus-circle" />
</a> </a>
</a-col> </a-col>
<a-col :span="1" v-if="educational_experience.length > 1"> <a-col :span="1" v-if="educational_experience.length > 1">
<a @click="() => removeEducation(item.id)" :style="{ color: 'red' }"> <a
@click="() => removeEducation(item.id)"
:style="{ color: 'red' }"
>
<a-icon type="delete" /> <a-icon type="delete" />
</a> </a>
</a-col> </a-col>
</a-row> </a-row>
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item :label="$t('cs.companyStructure.childrenInformation')" prop="employeeFormData" :style="{ display: 'inline-block', width: '100%', margin: '0 7px'}" v-if="attributes.findIndex(v=>v=='children_information')!==-1">
label="子女信息"
prop="employeeFormData"
:style="{ display: 'inline-block', width: '100%', margin: '0 7px' }"
v-if="attributes.findIndex((v) => v == 'children_information') !== -1"
>
<!-- <a-space <!-- <a-space
v-for="(item,index) in educational_experience" v-for="(item,index) in educational_experience"
:key="index" :key="index"
align="baseline" align="baseline"
> --> > -->
<a-row :gutter="[8, { xs: 8 }]" v-for="item in children_information" :key="item.id"> <a-row
:gutter="[8,{xs:8}]"
v-for="(item) in children_information"
:key="item.id"
>
<a-col :span="5"> <a-col :span="5">
<a-input v-model="item.name" placeholder="姓名" allowClear></a-input> <a-input v-model="item.name" :placeholder="$t('cs.companyStructure.childrenName')" allowClear></a-input>
</a-col> </a-col>
<a-col :span="5"> <a-col :span="5">
<a-select v-model="item.gender" placeholder="请选择性别" allowClear> <a-select v-model="item.gender" :placeholder="$t('cs.companyStructure.sex')" allowClear>
<a-select-option value=""> </a-select-option> <a-select-option value=""> {{ $t('cs.companyStructure.male') }} </a-select-option>
<a-select-option value=""> </a-select-option> <a-select-option value=""> {{ $t('cs.companyStructure.female') }} </a-select-option>
</a-select> </a-select>
</a-col> </a-col>
<a-col :span="5"> <a-col :span="5">
<a-date-picker <a-date-picker v-model="item.birthday" :placeholder="$t('cs.companyStructure.birthDatePlaceholder')" @change="onChange($event, 'birthday',item.id)"></a-date-picker>
v-model="item.birthday"
placeholder="出生日期"
@change="onChange($event, 'birth_date', item.id)"
></a-date-picker>
</a-col> </a-col>
<a-col :span="5"> <a-col :span="5">
<a-input-number <a-input-number
@ -360,52 +236,52 @@
:step="1" :step="1"
:style="{ width: '100%' }" :style="{ width: '100%' }"
v-model="item.parental_leave_left" v-model="item.parental_leave_left"
placeholder="请输入剩余育儿假" :placeholder="$t('cs.companyStructure.')"
:formatter="(value) => `${value} `" :formatter="(value) => `${value} $t('cs.companyStructure.day')`"
/> />
</a-col> </a-col>
<a-col :span="1"> <a-col :span="1">
<a @click="addChildren"> <a
@click="addChildren"
>
<a-icon type="plus-circle" /> <a-icon type="plus-circle" />
</a> </a>
</a-col> </a-col>
<a-col :span="1" v-if="children_information.length > 1"> <a-col :span="1" v-if="children_information.length > 1">
<a @click="() => removeChildren(item.id)" :style="{ color: 'red' }"> <a
@click="() => removeChildren(item.id)"
:style="{ color: 'red' }"
>
<a-icon type="delete" /> <a-icon type="delete" />
</a> </a>
</a-col> </a-col>
</a-row> </a-row>
</a-form-model-item> </a-form-model-item>
<a-form-model-item <a-form-model-item
label="银行卡" :label="$t('cs.companyStructure.bankCardInfo')"
prop="bank_card" prop="bank_card"
:style="{ display: 'inline-block', width: '98%', margin: '0 7px 24px' }" :style="{display: 'inline-block', width: '98%', margin: '0 7px 24px'}"
v-if=" v-if="attributes.findIndex(v=>v=='bank_card_number')!==-1 || attributes.findIndex(v=>v=='bank_card_name')!==-1 || attributes.findIndex(v=>v=='opening_bank')!==-1 || attributes.findIndex(v=>v=='account_opening_location')!==-1"
attributes.findIndex((v) => v == 'bank_card_number') !== -1 ||
attributes.findIndex((v) => v == 'bank_card_name') !== -1 ||
attributes.findIndex((v) => v == 'opening_bank') !== -1 ||
attributes.findIndex((v) => v == 'account_opening_location') !== -1
"
> >
<a-row :gutter="[8, { xs: 8 }]"> <a-row :gutter="[8,{xs:8}]">
<a-col :span="6" v-if="attributes.findIndex((v) => v == 'bank_card_number') !== -1"> <a-col :span="6" v-if="attributes.findIndex(v=>v=='bank_card_number')!==-1">
<a-input v-model="employeeFormData.bank_card_number" placeholder="卡号" allowClear></a-input> <a-input v-model="employeeFormData.bank_card_number" :placeholder="$t('cs.companyStructure.bankCardNumberPlaceholder')" allowClear></a-input>
</a-col> </a-col>
<a-col :span="6" v-if="attributes.findIndex((v) => v == 'bank_card_name') !== -1"> <a-col :span="6" v-if="attributes.findIndex(v=>v=='bank_card_name')!==-1">
<a-input v-model="employeeFormData.bank_card_name" placeholder="银行" allowClear></a-input> <a-input v-model="employeeFormData.bank_card_name" :placeholder="$t('cs.companyStructure.bankCardNamePlaceholder')" allowClear></a-input>
</a-col> </a-col>
<a-col :span="6" v-if="attributes.findIndex((v) => v == 'opening_bank') !== -1"> <a-col :span="6" v-if="attributes.findIndex(v=>v=='opening_bank')!==-1">
<a-input v-model="employeeFormData.opening_bank" placeholder="开户行" allowClear></a-input> <a-input v-model="employeeFormData.opening_bank" :placeholder="$t('cs.companyStructure.openingBankPlaceholder')" allowClear></a-input>
</a-col> </a-col>
<a-col :span="6" v-if="attributes.findIndex((v) => v == 'account_opening_location') !== -1"> <a-col :span="6" v-if="attributes.findIndex(v=>v=='account_opening_location')!==-1">
<a-input v-model="employeeFormData.account_opening_location" placeholder="开户地" allowClear></a-input> <a-input v-model="employeeFormData.account_opening_location" :placeholder="$t('cs.companyStructure.accountOpeningLocationPlaceholder')" allowClear></a-input>
</a-col> </a-col>
</a-row> </a-row>
</a-form-model-item> </a-form-model-item>
</a-form-model> </a-form-model>
<template slot="footer"> <template slot="footer">
<a-button key="back" @click="close"> 取消 </a-button> <a-button key="back" @click="close"> {{ $t('cancel') }} </a-button>
<a-button type="primary" @click="employeeModalHandleOk"> 确定 </a-button> <a-button type="primary" @click="employeeModalHandleOk"> {{ $t('confirm') }} </a-button>
</template> </template>
</a-modal> </a-modal>
</template> </template>
@ -425,38 +301,11 @@ export default {
visible: false, visible: false,
employeeFormData: {}, employeeFormData: {},
formModalItemStyle: { display: 'inline-block', width: '48%', margin: '0 7px 24px', overflow: 'hidden' }, formModalItemStyle: { display: 'inline-block', width: '48%', margin: '0 7px 24px', overflow: 'hidden' },
rules: {
email: [
{ required: true, whitespace: true, message: '请输入邮箱', trigger: 'blur' },
{
pattern: /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/,
message: '邮箱格式错误',
trigger: 'blur',
},
{ max: 50, message: '字符数须小于50' },
],
username: [
{ required: true, whitespace: true, message: '请输入用户名', trigger: 'blur' },
{ max: 20, message: '字符数须小于20' },
],
password: [{ required: true, whitespace: true, message: '请输入密码', trigger: 'blur' }],
nickname: [
{ required: true, whitespace: true, message: '请输入姓名', trigger: 'blur' },
{ max: 20, message: '字符数须小于20' },
],
mobile: [
{
pattern: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/,
message: '请输入正确的手机号',
trigger: 'blur',
},
],
},
type: 'add', type: 'add',
educational_experience: [], educational_experience: [],
children_information: [], children_information: [],
file_is_show: true, file_is_show: true,
attributes: [], attributes: []
} }
}, },
created() { created() {
@ -466,7 +315,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() {
@ -477,10 +326,39 @@ export default {
}, },
title() { title() {
if (this.type === 'add') { if (this.type === 'add') {
return '新建员工' return this.$t('cs.companyStructure.createEmployee')
} }
return '编辑员工' return this.$t('cs.companyStructure.editEmployee')
}, },
rules() {
return {
email: [
{ 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}$/,
message: this.$t('cs.companyStructure.emailFormatErr'),
trigger: 'blur',
},
{ max: 50, message: this.$t('cs.person.inputStrCountLimit', { limit: 50 }) },
],
username: [
{ required: true, whitespace: true, message: '请输入用户名', trigger: 'blur' },
{ max: 20, message: this.$t('cs.person.inputStrCountLimit', { limit: 20 }) },
],
password: [{ required: true, whitespace: true, message: '请输入密码', trigger: 'blur' }],
nickname: [
{ required: true, whitespace: true, message: '请输入姓名', trigger: 'blur' },
{ max: 20, message: this.$t('cs.person.inputStrCountLimit', { limit: 20 }) },
],
mobile: [
{
pattern: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/,
message: this.$t('cs.companyStructure.mobileFormatErr'),
trigger: 'blur',
},
],
}
}
}, },
beforeDestroy() { beforeDestroy() {
Bus.$off('getAttributes') Bus.$off('getAttributes')
@ -488,8 +366,7 @@ 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 } = const { school, major, education, graduation_year, name, gender, birthday, parental_leave_left, ...newGetData } = getData
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) {
@ -502,54 +379,46 @@ 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(),
id: uuidv4(), name: '',
name: '', gender: undefined,
gender: undefined, birthday: null,
birthday: null, parental_leave_left: 0
parental_leave_left: 0, }]
}, this.educational_experience = this.formatEducationalExperienceList() || [{
] id: uuidv4(),
this.educational_experience = this.formatEducationalExperienceList() || [ school: '',
{ major: '',
id: uuidv4(), education: undefined,
school: '', graduation_year: null
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: '',
school: '', major: '',
major: '', education: undefined,
education: undefined, graduation_year: null
graduation_year: null, }]
}, this.children_information = [{
] id: uuidv4(),
this.children_information = [ name: '',
{ gender: undefined,
id: uuidv4(), birthday: null,
name: '', parental_leave_left: 0
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
@ -560,7 +429,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
@ -573,12 +442,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)
} }
@ -589,12 +458,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)
} }
@ -615,10 +484,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 === 'birth_date') { } 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')
@ -649,12 +518,12 @@ export default {
if (this.type === 'edit') { if (this.type === 'edit') {
await putEmployee(getFormData.employee_id, getFormData) await putEmployee(getFormData.employee_id, getFormData)
} }
this.$message.success('操作成功') this.$message.success(this.$t('cs.companyStructure.opSuccess'))
this.$emit('refresh') this.$emit('refresh')
Bus.$emit('updataAllIncludeEmployees') Bus.$emit('updataAllIncludeEmployees')
this.close() this.close()
} else { } else {
this.$message.warning('检查您的输入是否正确!') this.$message.warning(this.$t('cs.companyInfo.checkInputCorrect'))
return false return false
} }
}) })
@ -664,7 +533,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>

View File

@ -21,7 +21,7 @@
:class="{ 'group-selected': groupIndex === activeGroupIndex }" :class="{ '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"
@ -46,7 +46,7 @@
> >
<div class="ops-setting-structure-sidebar-group-category-item-title" @click="clickSelectItem(0)"> <div class="ops-setting-structure-sidebar-group-category-item-title" @click="clickSelectItem(0)">
<div class="item-title"> <div class="item-title">
在职员工 {{ $t('cs.companyStructure.activeEmployee') }}
</div> </div>
<div class="item-count"> <div class="item-count">
<div class="item-count-before">{{ activeEmployeeCount }}</div> <div class="item-count-before">{{ activeEmployeeCount }}</div>
@ -61,7 +61,7 @@
> >
<div class="ops-setting-structure-sidebar-group-category-item-title" @click="clickSelectItem(1)"> <div class="ops-setting-structure-sidebar-group-category-item-title" @click="clickSelectItem(1)">
<div class="item-title"> <div class="item-title">
停用员工 {{ $t('cs.companyStructure.blockEmployee') }}
</div> </div>
<div class="item-count"> <div class="item-count">
<div class="item-count-before">{{ deactiveEmployeeCount }}</div> <div class="item-count-before">{{ deactiveEmployeeCount }}</div>
@ -70,7 +70,7 @@
</div> </div>
</div> </div>
</CollapseTransition> </CollapseTransition>
<ul :style="{ marginTop: '10px' }" v-if="activeGroupIndex === groupIndex && activeGroupIndex === 1" > <ul :style="{ marginTop: '10px' }" v-if="activeGroupIndex === groupIndex && activeGroupIndex === 1">
<CategroyTree <CategroyTree
v-for="(subTree, subIndex) in departmentList" v-for="(subTree, subIndex) in departmentList"
:id="subTree.id" :id="subTree.id"
@ -96,7 +96,7 @@
v-model="filterName" v-model="filterName"
:style="{ minWidth: '200px' }" :style="{ minWidth: '200px' }"
class="ops-input ops-input-radius" class="ops-input ops-input-radius"
placeholder="请输入姓名/邮箱" :placeholder="$t('cs.role.inputNameOrEmail')"
@search="updateTableDataByFilter()" @search="updateTableDataByFilter()"
/> />
</div> </div>
@ -123,16 +123,16 @@
</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">
@ -144,10 +144,12 @@
icon="plus" icon="plus"
ghost ghost
/> />
<a-button type="primary" size="small" ghost @click="batchUpload"> 批量导入 </a-button> <a-button type="primary" size="small" ghost @click="batchUpload">
{{ $t('cs.companyStructure.batchImport') }}
</a-button>
<template v-if="activeGroupIndex === 1 && selectDepartment.hasOwnProperty('id')"> <template v-if="activeGroupIndex === 1 && selectDepartment.hasOwnProperty('id')">
<a-button type="primary" size="small" ghost @click="openDepartmentModal('add')"> <a-button type="primary" size="small" ghost @click="openDepartmentModal('add')">
创建子部门 {{ $t('cs.companyStructure.createSubDepartment') }}
</a-button> </a-button>
<a-button <a-button
type="primary" type="primary"
@ -156,10 +158,10 @@
@click="openDepartmentModal('edit')" @click="openDepartmentModal('edit')"
v-if="selectDepartment.id" v-if="selectDepartment.id"
> >
编辑部门 {{ $t('cs.companyStructure.editDepartment') }}
</a-button> </a-button>
<a-button v-if="selectDepartment.id" type="danger" size="small" ghost @click="deleteDepartment"> <a-button v-if="selectDepartment.id" type="danger" size="small" ghost @click="deleteDepartment">
删除部门 {{ $t('cs.companyStructure.deleteDepartment') }}
</a-button> </a-button>
</template> </template>
</a-space> </a-space>
@ -168,25 +170,26 @@
<div class="ops-setting-batch"> <div class="ops-setting-batch">
<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">下载全部</span> <span @click="downloadEmployeeAll">{{ $t('cs.companyStructure.downloadAll') }}</span>
<a-divider type="vertical" /> <a-divider type="vertical"/>
<span @click="exportSelectEvent">下载选中</span> <span @click="exportSelectEvent">{{ $t('cs.companyStructure.downloadSelected') }}</span>
<a-divider type="vertical" /> <a-divider type="vertical"/>
<span @click="openBatchModal('department_id')">编辑部门</span> <span @click="openBatchModal('department_id')">{{ $t('cs.companyStructure.editDepartment') }}</span>
<a-divider type="vertical" /> <a-divider type="vertical"/>
<span @click="openBatchModal('direct_supervisor_id')">编辑上级</span> <span
<a-divider type="vertical" /> @click="openBatchModal('direct_supervisor_id')">{{ $t('cs.companyStructure.editDirectSupervisor') }}</span>
<span @click="openBatchModal('position_name')">编辑岗位</span> <a-divider type="vertical"/>
<a-divider type="vertical" /> <span @click="openBatchModal('position_name')">{{ $t('cs.companyStructure.editPosition') }}</span>
<span @click="openBatchModal('annual_leave')">编辑年假</span> <a-divider type="vertical"/>
<a-divider type="vertical" /> <span @click="openBatchModal('annual_leave')">{{ $t('cs.companyStructure.editAnnualLeave') }}</span>
<span @click="openBatchModal('password')">重置密码</span> <a-divider type="vertical"/>
<a-divider type="vertical" /> <span @click="openBatchModal('password')">{{ $t('cs.companyStructure.resetPassword') }}</span>
<span @click="openBatchModal('block', null, 1)">禁用</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, 0)">恢复</span> <a-divider type="vertical"/>
<a-divider type="vertical" /> <span @click="openBatchModal('block', null, 0)">{{ $t('cs.companyStructure.recover') }}</span>
<span>选取: {{ selectedRowKeys.length }} </span> <a-divider type="vertical"/>
<span>{{ $t('selectRows', {rows: selectedRowKeys.length}) }}</span>
</div> </div>
</div> </div>
<!-- <div> <!-- <div>
@ -197,14 +200,15 @@
</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
ref="employeeTable"
:tableData="tableData" :tableData="tableData"
:tableHeight="tableHeight" :tableHeight="tableHeight"
@sortChangeEvent="sortChangeEvent" @sortChangeEvent="sortChangeEvent"
@ -226,15 +230,15 @@
:page-size-options="pageSizeOptions" :page-size-options="pageSizeOptions"
:current="tablePage.currentPage" :current="tablePage.currentPage"
:total="tablePage.totalResult" :total="tablePage.totalResult"
:show-total="(total, range) => `当前展示 ${range[0]}-${range[1]} 条数据, 共 ${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"
@showSizeChange="pageOrSizeChange" @showSizeChange="pageOrSizeChange"
> >
<template #buildOptionText="props"> <template #buildOptionText="props">
<span v-if="props.value !== '9999'">{{ props.value }}/</span> <span v-if="props.value !== '9999'">{{ props.value }}{{ $t('itemsPerPage') }}</span>
<span v-else>全部</span> <span v-else>{{ $t('all') }}</span>
</template> </template>
</a-pagination> </a-pagination>
</div> </div>
@ -288,74 +292,16 @@ export default {
SearchForm SearchForm
}, },
data() { data() {
const canSearchPreferenceAttrList = [
{ label: '姓名', value: 'nickname' },
{ label: '用户名', value: 'username' },
{ label: '邮箱', value: 'email' },
{ label: '性别', value: 'sex', is_choice: true, choice_value: [{ label: '', value: '' }, { label: '', value: '' }] },
{ label: '手机号', value: 'mobile' },
{ label: '部门', value: 'department_name' },
{ label: '岗位', value: 'position_name' },
{ label: '直接上级', value: 'direct_supervisor_id' },
{ label: '年假', value: 'annual_leave' },
{ label: '目前所属主体', value: 'current_company' },
{ label: '初始入职日期', value: 'dfc_entry_date' },
{ label: '目前主体入职日期', value: 'entry_date' },
{ label: '正式/实习生', value: 'is_internship', is_choice: true, choice_value: [{ label: '正式', value: 0 }, { label: '实习生', value: 1 }] },
{ label: '离职日期', value: 'leave_date' },
{ label: '身份证号码', value: 'id_card' },
{ label: '民族', value: 'nation' },
{ label: '籍贯', value: 'id_place' },
{ label: '组织关系', value: 'party', is_choice: true, choice_value: [{ label: '党员', value: '党员' }, { label: '团员', value: '团员' }, { label: '群众', value: '群众' }] },
{ label: '户籍类型', value: 'household_registration_type', is_choice: true, choice_value: [{ label: '城镇', value: '城镇' }, { label: '农业', value: '农业' }] },
{ label: '户口所在地', value: 'hometown' },
{ label: '婚姻情况', value: 'marry', is_choice: true, choice_value: [{ label: '未婚', value: '未婚' }, { label: '已婚', value: '已婚' }] },
{ label: '最高学历', value: 'max_degree', is_choice: true, choice_value: [{ label: '博士', value: '博士' }, { label: '硕士', value: '硕士' }, { label: '本科', value: '本科' }, { label: '专科', value: '专科' }, { label: '高中', value: '高中' }] },
{ label: '紧急联系人', value: 'emergency_person' },
{ label: '紧急联系电话', value: 'emergency_phone' },
{ label: '卡号', value: 'bank_card_number' },
{ label: '银行', value: 'bank_card_name' },
{ label: '开户行', value: 'opening_bank' },
{ label: '开户地', value: 'account_opening_location' },
{ label: '上次登录时间', value: 'last_login' },
]
return { return {
isActive: '', isActive: '',
visible: true, visible: true,
sceneList: [ localStorageKey: 'itsm-company-strcutre',
{
label: '全部',
value: -1,
},
{
label: '在职员工',
value: 0,
},
{
label: '停用员工',
value: 1,
},
],
localStorageKey: 'setting-company-strcutre',
localStoragePaneLengthPixel: 'setting-structure-paneLengthPixel', localStoragePaneLengthPixel: 'setting-structure-paneLengthPixel',
displayTimeIcon: 'down', displayTimeIcon: 'down',
currentScene: '', currentScene: '',
// historySceneitemSelected: 'history-scene-item-selected', // historySceneitemSelected: 'history-scene-item-selected',
// historySceneItem: 'history-scene-item', // historySceneItem: 'history-scene-item',
paneLengthPixel: 204, paneLengthPixel: 204,
groupData: [
{
id: 0,
title: '员工',
icon: 'user',
},
{
id: 1,
title: '部门',
icon: 'apartment',
},
],
tableData: [], tableData: [],
activeEmployeeCount: 0, activeEmployeeCount: 0,
deactiveEmployeeCount: 0, deactiveEmployeeCount: 0,
@ -378,7 +324,6 @@ export default {
allTreeDepartment: [], allTreeDepartment: [],
allTreeDepAndEmp: [], allTreeDepAndEmp: [],
isFolder: false, isFolder: false,
canSearchPreferenceAttrList,
attributes: [], attributes: [],
pageSizeOptions: ['50', '100', '200', '9999'], pageSizeOptions: ['50', '100', '200', '9999'],
expression: [], expression: [],
@ -413,6 +358,115 @@ export default {
isEditable() { isEditable() {
return this.hasDetailPermission('backend', '公司架构', ['update']) return this.hasDetailPermission('backend', '公司架构', ['update'])
}, },
canSearchPreferenceAttrList() {
return [
{ label: this.$t('cs.companyStructure.nickname'), value: 'nickname' },
{ label: this.$t('cs.companyStructure.username'), value: 'username' },
{ label: this.$t('cs.companyStructure.email'), value: 'email' },
{
label: this.$t('cs.companyStructure.sex'),
value: 'sex',
is_choice: true,
choice_value: [
{ label: this.$t('cs.companyStructure.male'), value: '' },
{ label: this.$t('cs.companyStructure.female'), value: '' }]
},
{ label: this.$t('cs.companyStructure.mobile'), value: 'mobile' },
{ label: this.$t('cs.companyStructure.departmentName'), value: 'department_name' },
{ label: this.$t('cs.companyStructure.positionName'), value: 'position_name' },
{ label: this.$t('cs.companyStructure.departmentDirector'), value: 'direct_supervisor_id' },
{ label: this.$t('cs.companyStructure.annualLeave'), value: 'annual_leave' },
{ label: this.$t('cs.companyStructure.currentCompany'), value: 'current_company' },
{ label: this.$t('cs.companyStructure.dfcEntryDate'), value: 'dfc_entry_date' },
{ label: this.$t('cs.companyStructure.entryDate'), value: 'entry_date' },
{
label: this.$t('cs.companyStructure.isInternship'),
value: 'is_internship',
is_choice: true,
choice_value: [{ label: this.$t('cs.companyStructure.fullTime'), value: 0 },
{ label: this.$t('cs.companyStructure.internship'), value: 1 }]
},
{ label: this.$t('cs.companyStructure.leaveDate'), value: 'leave_date' },
{ label: this.$t('cs.companyStructure.idCard'), value: 'id_card' },
{ label: this.$t('cs.companyStructure.nation'), value: 'nation' },
{ label: this.$t('cs.companyStructure.idPlace'), value: 'id_place' },
{
label: this.$t('cs.companyStructure.party'),
value: 'party',
is_choice: true,
choice_value: [
{ label: this.$t('cs.companyStructure.partyMember'), value: '党员' },
{ label: this.$t('cs.companyStructure.member'), value: '团员' },
{ label: this.$t('cs.companyStructure.masses'), value: '群众' }]
},
{
label: this.$t('cs.companyStructure.householdRegistrationType'),
value: 'household_registration_type',
is_choice: true,
choice_value: [{ label: this.$t('cs.companyStructure.town'), value: '城镇' }, { label: this.$t('cs.companyStructure.agriculture'), value: '农业' }]
},
{ label: this.$t('cs.companyStructure.hometown'), value: 'hometown' },
{
label: this.$t('cs.companyStructure.marry'),
value: 'marry',
is_choice: true,
choice_value: [{ label: this.$t('cs.companyStructure.unmarried'), value: '未婚' }, { label: this.$t('cs.companyStructure.married'), value: '已婚' }]
},
{
label: this.$t('cs.companyStructure.maxDegree'),
value: 'max_degree',
is_choice: true,
choice_value: [{ label: this.$t('cs.companyStructure.phd'), value: '博士' }, { label: this.$t('cs.companyStructure.master'), value: '硕士' }, {
label: this.$t('cs.companyStructure.undergraduate'),
value: '本科'
}, { label: this.$t('cs.companyStructure.specialist'), value: '专科' }, { label: this.$t('cs.companyStructure.highSchool'), value: '高中' }]
},
{ label: this.$t('cs.companyStructure.emergencyPerson'), value: 'emergency_person' },
{ label: this.$t('cs.companyStructure.emergencyPhone'), value: 'emergency_phone' },
{ label: this.$t('cs.companyStructure.bankCardNumber'), value: 'bank_card_number' },
{ label: this.$t('cs.companyStructure.bankCardName'), value: 'bank_card_name' },
{ label: this.$t('cs.companyStructure.openingBank'), value: 'opening_bank' },
{ label: this.$t('cs.companyStructure.accountOpeningLocation'), value: 'account_opening_location' },
{ label: this.$t('cs.companyStructure.birthDate'), value: 'birth_date' },
{ label: this.$t('cs.companyStructure.nationalityRegion'), value: 'nationality_region' },
{ label: this.$t('cs.companyStructure.birthPlace'), value: 'birth_place' },
{ label: this.$t('cs.companyStructure.firstEntryDate'), value: 'first_entry_date' },
{ label: this.$t('cs.companyStructure.estimatedDepartureDate'), value: 'estimated_departure_date' },
// { label: '角色', value: 'roles' },
{ label: this.$t('cs.companyStructure.lastLogin'), value: 'last_login' },
]
},
sceneList () {
return [
{
label: this.$t('all'),
value: -1,
},
{
label: this.$t('cs.companyStructure.activeEmployee'),
value: 0,
},
{
label: this.$t('cs.companyStructure.blockEmployee'),
value: 1,
},
]
},
groupData () {
return [
{
id: 0,
title: this.$t('cs.companyStructure.employee'),
icon: 'user',
},
{
id: 1,
title: this.$t('cs.companyStructure.departmentName'),
icon: 'apartment',
},
]
}
}, },
provide() { provide() {
return { return {
@ -470,6 +524,9 @@ export default {
Bus.$on('clickSelectGroup', async (index) => { Bus.$on('clickSelectGroup', async (index) => {
this.clickSelectGroup(index) this.clickSelectGroup(index)
}) })
Bus.$on('changeSelectedRowKeys', (selectedRowKeys) => {
this.selectedRowKeys = selectedRowKeys
})
this.getAllFlatEmployees() this.getAllFlatEmployees()
this.getAllFlatDepartment() this.getAllFlatDepartment()
this.getAllTreeDepartment() this.getAllTreeDepartment()
@ -480,6 +537,7 @@ export default {
Bus.$off('updateAllIncludeDepartment') Bus.$off('updateAllIncludeDepartment')
Bus.$off('selectDepartment') Bus.$off('selectDepartment')
Bus.$off('reqChildren') Bus.$off('reqChildren')
Bus.$off('changeSelectedRowKeys')
}, },
methods: { methods: {
// mouseOver: function() { // mouseOver: function() {
@ -579,55 +637,7 @@ export default {
order: this.tableSortData || 'direct_supervisor_id', order: this.tableSortData || 'direct_supervisor_id',
}) })
} }
// console.log(this.activeGroupIndex, reqEmployeeData) this.tableData = this.FilterTableData(reqEmployeeData)
this.tableData = reqEmployeeData.data_list
if (reqEmployeeData.data_list.length) {
// 筛选教育经历数组中学历最高的一条记录
if (reqEmployeeData.data_list[0].educational_experience) {
reqEmployeeData.data_list.forEach((row, row_index) => {
const educational_experience = row.educational_experience
if (educational_experience.length > 1) {
let max_index = 0
educational_experience.forEach((item, index) => {
if (index < educational_experience.length - 1) {
max_index = item.graduation_year > educational_experience[index + 1].graduation_year ? index : index + 1
}
})
this.tableData[row_index].school = educational_experience[max_index].school
this.tableData[row_index].major = educational_experience[max_index].major
this.tableData[row_index].education = educational_experience[max_index].education
this.tableData[row_index].graduation_year = educational_experience[max_index].graduation_year
} else if (educational_experience.length === 1) {
this.tableData[row_index].school = educational_experience[0].school
this.tableData[row_index].major = educational_experience[0].major
this.tableData[row_index].education = educational_experience[0].education
this.tableData[row_index].graduation_year = educational_experience[0].graduation_year
} else {
this.tableData[row_index].school = ''
this.tableData[row_index].major = ''
this.tableData[row_index].education = ''
this.tableData[row_index].graduation_year = ''
}
})
}
// 筛选子女信息中第一位展示在employeeTable
if (reqEmployeeData.data_list[0].children_information) {
reqEmployeeData.data_list.forEach((row, row_index) => {
const children_information = row.children_information
if (children_information.length) {
this.tableData[row_index].name = children_information[0].name
this.tableData[row_index].gender = children_information[0].gender
this.tableData[row_index].birthday = children_information[0].birthday
this.tableData[row_index].parental_leave_left = children_information[0].parental_leave_left
} else {
this.tableData[row_index].name = ''
this.tableData[row_index].gender = ''
this.tableData[row_index].birthday = ''
this.tableData[row_index].parental_leave_left = ''
}
})
}
}
this.tablePage = { this.tablePage = {
...this.tablePage, ...this.tablePage,
currentPage: reqEmployeeData.page, currentPage: reqEmployeeData.page,
@ -661,57 +671,7 @@ export default {
order: this.tableSortData || 'direct_supervisor_id', order: this.tableSortData || 'direct_supervisor_id',
}) })
} }
const tableData = reqEmployeeData.data_list this.tableData = this.FilterTableData(reqEmployeeData)
// 筛选教育经历数组中学历最高的一条记录
if (reqEmployeeData.data_list.length) {
if (reqEmployeeData.data_list[0].educational_experience) {
// reqEmployeeData.data_list.forEach((row, row_index) => {
for (let index = 0, len = reqEmployeeData.data_list.length; index < len; index++) {
const educational_experience = reqEmployeeData.data_list[index].educational_experience
if (educational_experience.length > 1) {
let max_index = 0
educational_experience.forEach((item, index) => {
if (index < educational_experience.length - 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].major = educational_experience[max_index].major
tableData[index].education = educational_experience[max_index].education
tableData[index].graduation_year = educational_experience[max_index].graduation_year
} else if (educational_experience.length === 1) {
tableData[index].school = educational_experience[0].school
tableData[index].major = educational_experience[0].major
tableData[index].education = educational_experience[0].education
tableData[index].graduation_year = educational_experience[0].graduation_year
} else {
tableData[index].school = ''
tableData[index].major = ''
tableData[index].education = ''
tableData[index].graduation_year = ''
}
}
}
// 筛选子女信息中第一位展示在employeeTable
if (reqEmployeeData.data_list[0].children_information) {
// reqEmployeeData.data_list.forEach((row, row_index) => {
for (let row_index = 0, len = reqEmployeeData.data_list.length; row_index < len; row_index++) {
const children_information = reqEmployeeData.data_list[row_index].children_information
if (children_information.length) {
tableData[row_index].name = children_information[0].name
tableData[row_index].gender = children_information[0].gender
tableData[row_index].birthday = children_information[0].birthday
tableData[row_index].parental_leave_left = children_information[0].parental_leave_left
} else {
tableData[row_index].name = ''
tableData[row_index].gender = ''
tableData[row_index].birthday = ''
tableData[row_index].parental_leave_left = ''
}
}
}
}
this.tableData = tableData
this.tablePage = { this.tablePage = {
...this.tablePage, ...this.tablePage,
currentPage: reqEmployeeData.page, currentPage: reqEmployeeData.page,
@ -720,6 +680,63 @@ export default {
} }
this.loading = false this.loading = false
}, },
FilterTableData(reqEmployeeData) {
const tableData = reqEmployeeData.data_list
// 筛选教育经历数组中学历最高的一条记录
if (reqEmployeeData.data_list.length) {
if (reqEmployeeData.data_list[0].educational_experience) {
// reqEmployeeData.data_list.forEach((row, row_index) => {
for (let index = 0, len = reqEmployeeData.data_list.length; index < len; index++) {
const educational_experience = reqEmployeeData.data_list[index].educational_experience
if (educational_experience) {
if (educational_experience.length > 1) {
let max_index = 0
educational_experience.forEach((item, index) => {
if (index < educational_experience.length - 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].major = educational_experience[max_index].major
tableData[index].education = educational_experience[max_index].education
tableData[index].graduation_year = educational_experience[max_index].graduation_year
} else if (educational_experience.length === 1) {
tableData[index].school = educational_experience[0].school
tableData[index].major = educational_experience[0].major
tableData[index].education = educational_experience[0].education
tableData[index].graduation_year = educational_experience[0].graduation_year
} else {
tableData[index].school = ''
tableData[index].major = ''
tableData[index].education = ''
tableData[index].graduation_year = ''
}
}
}
}
// 筛选子女信息中第一位展示在employeeTable
if (reqEmployeeData.data_list[0].children_information) {
// reqEmployeeData.data_list.forEach((row, row_index) => {
for (let row_index = 0, len = reqEmployeeData.data_list.length; row_index < len; row_index++) {
const children_information = reqEmployeeData.data_list[row_index].children_information
if (children_information) {
if (children_information.length) {
tableData[row_index].name = children_information[0].name
tableData[row_index].gender = children_information[0].gender
tableData[row_index].birthday = children_information[0].birthday
tableData[row_index].parental_leave_left = children_information[0].parental_leave_left
} else {
tableData[row_index].name = ''
tableData[row_index].gender = ''
tableData[row_index].birthday = ''
tableData[row_index].parental_leave_left = ''
}
}
}
}
}
return tableData
},
updateAll() { updateAll() {
// this.expression = [] // this.expression = []
this.updateCount() this.updateCount()
@ -771,6 +788,11 @@ export default {
a.click() a.click()
window.URL.revokeObjectURL(url) window.URL.revokeObjectURL(url)
}) })
this.$refs.employeeTable.getVxetableRef().clearCheckboxRow()
this.$refs.employeeTable.getVxetableRef().clearCheckboxReserve()
this.$refs.employeeTable.getVxetableRef().clearSort()
this.tableSortData = undefined
this.selectedRowKeys = []
}, },
reset() { reset() {
this.filterName = '' this.filterName = ''
@ -842,18 +864,18 @@ export default {
if (this.selectDepartment.hasOwnProperty('id')) { if (this.selectDepartment.hasOwnProperty('id')) {
this.$refs.DepartmentModal.open({ type, selectDepartment: this.selectDepartment }) this.$refs.DepartmentModal.open({ type, selectDepartment: this.selectDepartment })
} else { } else {
this.$message.error('请选择部门') this.$message.error(this.$t('cs.companyStructure.selectDepartment'))
} }
}, },
async deleteDepartment() { async deleteDepartment() {
const that = this const that = this
this.$confirm({ this.$confirm({
title: '警告', title: this.$t('warning'),
content: `确认删除 ${this.selectDepartment.title}`, content: this.$t('confirmDelete2', { name: this.selectDepartment.title }),
onOk() { onOk() {
deleteDepartmentById(that.selectDepartment.id).then((res) => { deleteDepartmentById(that.selectDepartment.id).then((res) => {
that.clickSelectGroup(1) that.clickSelectGroup(1)
that.$message.success('删除成功!') that.$message.success(that.$t('deleteSuccess'))
Bus.$emit('updateAllIncludeDepartment') Bus.$emit('updateAllIncludeDepartment')
}) })
}, },
@ -876,14 +898,20 @@ 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 }) {
if (property === 'is_internship') { if (property === 'roles') {
this.tableFilterData = {
...this.tableFilterData,
// role_id_list: values && values.length ? values.join(',') : undefined,
role_id_list: values && values.length ? values : undefined,
}
} else if (property === 'is_internship') {
this.tableFilterData = { this.tableFilterData = {
...this.tableFilterData, ...this.tableFilterData,
is_internship: values && values.length ? values[0] : undefined, is_internship: values && values.length ? values[0] : undefined,
@ -1098,7 +1126,8 @@ export default {
} }
} }
} }
.ops-setting-batch{
.ops-setting-batch {
width: 100%; width: 100%;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;

View File

@ -18,14 +18,13 @@
:img="cropperImg" :img="cropperImg"
output-type="png" output-type="png"
@realTime="realTime" @realTime="realTime"
v-bind="eidtImageOption"
/> />
<div class="ops-modal-preview"> <div class="ops-modal-preview">
<div class="ops-modal-preview-name">预览</div> <div class="ops-modal-preview-name">{{ $t('cs.components.preview') }}</div>
<img <img
:style="{ :style="{
width: eidtImageOption.previewWidth, width: previewWidth,
height: eidtImageOption.previewHeight, height: previewHeight,
border: '1px solid #f2f2f2', border: '1px solid #f2f2f2',
}" }"
:src="previewImg" :src="previewImg"
@ -35,7 +34,7 @@
</div> </div>
<div slot="footer" class="ops-modal-dialog-footer"> <div slot="footer" class="ops-modal-dialog-footer">
<a-button type="primary" @click="submitImage()">确定</a-button> <a-button type="primary" @click="submitImage()">{{ $t('confirm') }}</a-button>
</div> </div>
</a-modal> </a-modal>
</template> </template>
@ -50,7 +49,7 @@ export default {
props: { props: {
title: { title: {
type: String, type: String,
default: '编辑头像', default: () => this.$t('cs.components.editAvatar'),
}, },
show: { show: {
type: Boolean, type: Boolean,
@ -60,9 +59,13 @@ export default {
type: String, type: String,
default: '', default: '',
}, },
eidtImageOption: { previewWidth: {
type: Object, type: String,
default: () => {}, default: '60px',
},
previewHeight: {
type: String,
default: '60px',
}, },
}, },
data() { data() {

View File

@ -9,7 +9,7 @@
> >
<div slot="popover_item" class="search-form-bar-filter"> <div slot="popover_item" class="search-form-bar-filter">
<a-icon :class="filterExp.length ? 'search-form-bar-filter-icon' : 'search-form-bar-filter-icon_selected'" type="filter"/> <a-icon :class="filterExp.length ? 'search-form-bar-filter-icon' : 'search-form-bar-filter-icon_selected'" type="filter"/>
条件过滤 {{ $t('cs.components.conditionFilter') }}
<a-icon :class="filterExp.length ? 'search-form-bar-filter-icon' : 'search-form-bar-filter-icon_selected'" type="down"/> <a-icon :class="filterExp.length ? 'search-form-bar-filter-icon' : 'search-form-bar-filter-icon_selected'" type="down"/>
</div> </div>
</FilterComp> </FilterComp>

View File

@ -2,12 +2,12 @@
<treeselect <treeselect
:multiple="false" :multiple="false"
:options="departemntTreeSelectOption" :options="departemntTreeSelectOption"
placeholder="请选择部门" :placeholder="readOnly ? '' : $t('cs.companyStructure.selectDepartment')"
v-model="treeValue" v-model="treeValue"
:normalizer="normalizer" :normalizer="normalizer"
noChildrenText="" :noChildrenText="$t('cs.components.empty')"
noOptionsText="" :noOptionsText="$t('cs.components.empty')"
class="ops-setting-treeselect" :class="className ? className : 'ops-setting-treeselect'"
v-bind="$attrs" v-bind="$attrs"
appendToBody appendToBody
:zIndex="1050" :zIndex="1050"
@ -28,6 +28,10 @@ export default {
type: [String, Array, Number, null], type: [String, Array, Number, null],
default: null, default: null,
}, },
className: {
type: String,
default: 'ops-setting-treeselect',
},
}, },
data() { data() {
return { return {
@ -46,7 +50,15 @@ export default {
}, },
} }
}, },
inject: ['provide_allTreeDepartment'], inject: {
provide_allTreeDepartment: {
from: 'provide_allTreeDepartment',
},
readOnly: {
from: 'readOnly',
default: false,
},
},
computed: { computed: {
departemntTreeSelectOption() { departemntTreeSelectOption() {
return this.provide_allTreeDepartment() return this.provide_allTreeDepartment()

View File

@ -26,7 +26,7 @@
<vxe-column <vxe-column
field="nickname" field="nickname"
min-width="100px" min-width="100px"
title="姓名" :title="$t('cs.companyStructure.nickname')"
sortable sortable
v-if="checkedCols.findIndex((v) => v == 'nickname') !== -1 && attributes.findIndex((v) => v == 'nickname') !== -1" v-if="checkedCols.findIndex((v) => v == 'nickname') !== -1 && attributes.findIndex((v) => v == 'nickname') !== -1"
key="nickname" key="nickname"
@ -49,7 +49,7 @@
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="username" field="username"
title="用户名" :title="$t('cs.companyStructure.username')"
min-width="120px" min-width="120px"
sortable sortable
v-if="checkedCols.findIndex((v) => v == 'username') !== -1 && attributes.findIndex((v) => v == 'username') !== -1" v-if="checkedCols.findIndex((v) => v == 'username') !== -1 && attributes.findIndex((v) => v == 'username') !== -1"
@ -58,13 +58,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>用户名</span> <span>{{ $t('cs.companyStructure.username') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="email" field="email"
title="邮箱" :title="$t('cs.companyStructure.email')"
min-width="140px" min-width="140px"
sortable sortable
v-if="checkedCols.findIndex((v) => v == 'email') !== -1 && attributes.findIndex((v) => v == 'email') !== -1" v-if="checkedCols.findIndex((v) => v == 'email') !== -1 && attributes.findIndex((v) => v == 'email') !== -1"
@ -73,13 +73,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>邮箱</span> <span>{{ $t('cs.companyStructure.email') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="sex" field="sex"
title="性别" :title="$t('cs.companyStructure.sex')"
width="70px" width="70px"
sortable sortable
align="center" align="center"
@ -89,13 +89,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>性别</span> <span>{{ $t('cs.companyStructure.sex') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="mobile" field="mobile"
title="手机号" :title="$t('cs.companyStructure.mobile')"
min-width="100px" min-width="100px"
v-if="checkedCols.findIndex((v) => v == 'mobile') !== -1 && attributes.findIndex((v) => v == 'mobile') !== -1" v-if="checkedCols.findIndex((v) => v == 'mobile') !== -1 && attributes.findIndex((v) => v == 'mobile') !== -1"
sortable sortable
@ -104,13 +104,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>手机号</span> <span>{{ $t('cs.companyStructure.mobile') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="department_name" field="department_name"
title="部门" :title="$t('cs.companyStructure.departmentName')"
min-width="90px" min-width="90px"
sortable sortable
v-if=" v-if="
@ -122,7 +122,7 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>部门</span> <span>{{ $t('cs.companyStructure.departmentName') }}</span>
</span> </span>
</template> </template>
<template #default="{ row }"> <template #default="{ row }">
@ -132,7 +132,7 @@
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="position_name" field="position_name"
title="岗位" :title="$t('cs.companyStructure.positionName')"
min-width="120px" min-width="120px"
sortable sortable
v-if=" v-if="
@ -144,13 +144,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>岗位</span> <span>{{ $t('cs.companyStructure.positionName') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="direct_supervisor_id" field="direct_supervisor_id"
title="直接上级" :title="$t('cs.companyStructure.supervisor')"
min-width="120px" min-width="120px"
sortable sortable
v-if=" v-if="
@ -162,7 +162,7 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>直接上级</span> <span>{{ $t('cs.companyStructure.supervisor') }}</span>
</span> </span>
</template> </template>
<template #default="{ row }"> <template #default="{ row }">
@ -173,7 +173,7 @@
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="annual_leave" field="annual_leave"
title="年假" :title="$t('cs.companyStructure.annualLeave')"
sortable sortable
min-width="80" min-width="80"
v-if=" v-if="
@ -186,13 +186,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>年假</span> <span>{{ $t('cs.companyStructure.annualLeave') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="virtual_annual_leave" field="virtual_annual_leave"
title="虚拟年假" :title="$t('cs.companyStructure.virtualAnnualLeave')"
sortable sortable
min-width="100" min-width="100"
v-if=" v-if="
@ -205,13 +205,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>虚拟年假</span> <span>{{ $t('cs.companyStructure.virtualAnnualLeave') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="parenting_leave" field="parenting_leave"
title="育儿假" :title="$t('cs.companyStructure.parentingLeave')"
sortable sortable
min-width="100" min-width="100"
v-if=" v-if="
@ -224,13 +224,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>育儿假</span> <span>{{ $t('cs.companyStructure.parentingLeave') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="entry_date" field="entry_date"
title="目前主体入职日期" :title="$t('cs.companyStructure.entryDate')"
sortable sortable
min-width="150" min-width="150"
v-if=" v-if="
@ -243,13 +243,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>目前主体入职日期</span> <span>{{ $t('cs.companyStructure.entryDate') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="is_internship" field="is_internship"
title="正式/实习生" :title="$t('cs.companyStructure.isInternship')"
sortable sortable
min-width="140" min-width="140"
v-bind="tableType === 'structure' ? { filters: internOptions, 'filter-multiple': false } : {}" v-bind="tableType === 'structure' ? { filters: internOptions, 'filter-multiple': false } : {}"
@ -263,7 +263,7 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>正式/实习生</span> <span>{{ $t('cs.companyStructure.isInternship') }}</span>
</span> </span>
</template> </template>
<template #default="{ row }"> <template #default="{ row }">
@ -272,7 +272,7 @@
>I >I
<vxe-column <vxe-column
field="leave_date" field="leave_date"
title="离职日期" :title="$t('cs.companyStructure.leaveDate')"
sortable sortable
min-width="100" min-width="100"
v-if=" v-if="
@ -285,13 +285,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>离职日期</span> <span>{{ $t('cs.companyStructure.leaveDate') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="id_card" field="id_card"
title="身份证号码" :title="$t('cs.companyStructure.idCard')"
sortable sortable
min-width="120" min-width="120"
v-if=" v-if="
@ -304,13 +304,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>身份证号码</span> <span>{{ $t('cs.companyStructure.idCard') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="nation" field="nation"
title="民族" :title="$t('cs.companyStructure.nation')"
sortable sortable
min-width="80" min-width="80"
v-if=" v-if="
@ -323,13 +323,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>民族</span> <span>{{ $t('cs.companyStructure.idPlace') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="id_place" field="id_place"
title="籍贯" :title="$t('cs.companyStructure.nation')"
sortable sortable
min-width="120" min-width="120"
v-if=" v-if="
@ -342,13 +342,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>籍贯</span> <span>{{ $t('cs.companyStructure.idPlace') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="party" field="party"
title="组织关系" :title="$t('cs.companyStructure.party')"
sortable sortable
min-width="100" min-width="100"
v-if=" v-if="
@ -361,13 +361,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>组织关系</span> <span>{{ $t('cs.companyStructure.party') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="household_registration_type" field="household_registration_type"
title="户籍类型" :title="$t('cs.companyStructure.householdRegistrationType')"
sortable sortable
min-width="100" min-width="100"
v-if=" v-if="
@ -380,13 +380,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>户籍类型</span> <span>{{ $t('cs.companyStructure.hometown') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="hometown" field="hometown"
title="户口所在地" :title="$t('cs.companyStructure.householdRegistrationType') "
sortable sortable
min-width="120" min-width="120"
v-if=" v-if="
@ -399,13 +399,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>户口所在地</span> <span>{{ $t('cs.companyStructure.hometown') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="marry" field="marry"
title="婚姻情况" :title="$t('cs.companyStructure.marry')"
sortable sortable
min-width="100" min-width="100"
v-if=" v-if="
@ -418,13 +418,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>婚姻情况</span> <span>{{ $t('cs.companyStructure.marry') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="max_degree" field="max_degree"
title="最高学历" :title="$t('cs.companyStructure.maxDegree')"
sortable sortable
min-width="100" min-width="100"
v-if=" v-if="
@ -437,13 +437,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>最高学历</span> <span>{{ $t('cs.companyStructure.maxDegree') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="emergency_person" field="emergency_person"
title="紧急联系人" :title="$t('cs.companyStructure.emergencyPerson')"
sortable sortable
min-width="110" min-width="110"
v-if=" v-if="
@ -456,13 +456,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>紧急联系人</span> <span>{{ $t('cs.companyStructure.emergencyPerson') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="emergency_phone" field="emergency_phone"
title="紧急联系电话" :title="$t('cs.companyStructure.emergencyPhone')"
sortable sortable
min-width="120" min-width="120"
v-if=" v-if="
@ -475,13 +475,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>紧急联系电话</span> <span>{{ $t('cs.companyStructure.emergencyPhone') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="bank_card_number" field="bank_card_number"
title="卡号" :title="$t('cs.companyStructure.bankCardNumber')"
sortable sortable
min-width="120" min-width="120"
v-if=" v-if="
@ -494,13 +494,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>卡号</span> <span>{{ $t('cs.companyStructure.bankCardNumber') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="bank_card_name" field="bank_card_name"
title="银行" :title="$t('cs.companyStructure.bankCardName')"
sortable sortable
min-width="100" min-width="100"
v-if=" v-if="
@ -513,13 +513,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>银行</span> <span>{{ $t('cs.companyStructure.bankCardName') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="opening_bank" field="opening_bank"
title="开户行" :title="$t('cs.companyStructure.openingBank')"
sortable sortable
min-width="100" min-width="100"
v-if=" v-if="
@ -532,13 +532,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>开户行</span> <span>{{ $t('cs.companyStructure.openingBank') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="account_opening_location" field="account_opening_location"
title="开户地" :title="$t('cs.companyStructure.accountOpeningLocation')"
sortable sortable
min-width="120" min-width="120"
v-if=" v-if="
@ -551,13 +551,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>开户地</span> <span>{{ $t('cs.companyStructure.accountOpeningLocation') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="school" field="school"
title="学校" :title="$t('cs.companyStructure.school')"
min-width="100" min-width="100"
v-if=" v-if="
checkedCols.findIndex((v) => v == 'school') !== -1 && checkedCols.findIndex((v) => v == 'school') !== -1 &&
@ -569,13 +569,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>学校</span> <span>{{ $t('cs.companyStructure.school') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="major" field="major"
title="专业" :title="$t('cs.companyStructure.major')"
min-width="100" min-width="100"
v-if=" v-if="
checkedCols.findIndex((v) => v == 'major') !== -1 && checkedCols.findIndex((v) => v == 'major') !== -1 &&
@ -587,13 +587,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>专业</span> <span>{{ $t('cs.companyStructure.major') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="education" field="education"
title="学历" :title="$t('cs.companyStructure.education')"
min-width="80" min-width="80"
v-if=" v-if="
checkedCols.findIndex((v) => v == 'education') !== -1 && checkedCols.findIndex((v) => v == 'education') !== -1 &&
@ -605,13 +605,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>学历</span> <span>{{ $t('cs.companyStructure.education') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="graduation_year" field="graduation_year"
title="毕业年份" :title="$t('cs.companyStructure.graduationYear')"
min-width="100" min-width="100"
v-if=" v-if="
checkedCols.findIndex((v) => v == 'graduation_year') !== -1 && checkedCols.findIndex((v) => v == 'graduation_year') !== -1 &&
@ -623,13 +623,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>毕业年份</span> <span>{{ $t('cs.companyStructure.graduationYear') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="name" field="name"
title="子女姓名" :title="$t('cs.companyStructure.childrenName')"
min-width="80" min-width="80"
v-if=" v-if="
checkedCols.findIndex((v) => v == 'name') !== -1 && checkedCols.findIndex((v) => v == 'name') !== -1 &&
@ -641,13 +641,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>子女姓名</span> <span>{{ $t('cs.companyStructure.childrenName') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="gender" field="gender"
title="子女性别" :title="$t('cs.companyStructure.sex')"
min-width="80" min-width="80"
v-if=" v-if="
checkedCols.findIndex((v) => v == 'gender') !== -1 && checkedCols.findIndex((v) => v == 'gender') !== -1 &&
@ -659,13 +659,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>子女性别</span> <span>{{ $t('cs.companyStructure.sex') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="birthday" field="birthday"
title="子女出生日期" :title="$t('cs.companyStructure.birthDate')"
min-width="100" min-width="100"
v-if=" v-if="
checkedCols.findIndex((v) => v == 'birthday') !== -1 && checkedCols.findIndex((v) => v == 'birthday') !== -1 &&
@ -677,13 +677,13 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>子女出生日期</span> <span>{{ $t('cs.companyStructure.birthDate') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="parental_leave_left" field="parental_leave_left"
title="剩余育儿假" :title="$t('cs.companyStructure.leftParentingLeave')"
min-width="100" min-width="100"
v-if=" v-if="
checkedCols.findIndex((v) => v == 'parental_leave_left') !== -1 && checkedCols.findIndex((v) => v == 'parental_leave_left') !== -1 &&
@ -695,13 +695,103 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>剩余育儿假</span> <span>{{ $t('cs.companyStructure.leftParentingLeave') }}</span>
</span>
</template>
</vxe-column>
<vxe-column
field="birth_date"
:title="$t('cs.companyStructure.birthDate')"
min-width="100"
v-if="
checkedCols.findIndex((v) => v == 'birth_date') !== -1 &&
tableType == 'structure' &&
attributes.findIndex((v) => v == 'birth_date') !== -1
"
key="birth_date"
>
<template #header>
<span class="vxe-handle">
<OpsMoveIcon class="move-icon" />
<span>{{ $t('cs.companyStructure.birthDate') }}</span>
</span>
</template>
</vxe-column>
<vxe-column
field="birth_place"
:title="$t('cs.companyStructure.birthPlace')"
min-width="100"
v-if="
checkedCols.findIndex((v) => v == 'birth_place') !== -1 &&
tableType == 'structure' &&
attributes.findIndex((v) => v == 'birth_place') !== -1
"
key="birth_place"
>
<template #header>
<span class="vxe-handle">
<OpsMoveIcon class="move-icon" />
<span>{{ $t('cs.companyStructure.birthPlace') }}</span>
</span>
</template>
</vxe-column>
<vxe-column
field="nationality_region"
:title="$t('cs.companyStructure.nationalityRegion')"
min-width="100"
v-if="
checkedCols.findIndex((v) => v == 'nationality_region') !== -1 &&
tableType == 'structure' &&
attributes.findIndex((v) => v == 'nationality_region') !== -1
"
key="nationality_region"
>
<template #header>
<span class="vxe-handle">
<OpsMoveIcon class="move-icon" />
<span>{{ $t('cs.companyStructure.nationalityRegion') }}</span>
</span>
</template>
</vxe-column>
<vxe-column
field="first_entry_date"
:title="$t('cs.companyStructure.firstEntryDate')"
min-width="100"
v-if="
checkedCols.findIndex((v) => v == 'first_entry_date') !== -1 &&
tableType == 'structure' &&
attributes.findIndex((v) => v == 'first_entry_date') !== -1
"
key="first_entry_date"
>
<template #header>
<span class="vxe-handle">
<OpsMoveIcon class="move-icon" />
<span>{{ $t('cs.companyStructure.firstEntryDate') }}</span>
</span>
</template>
</vxe-column>
<vxe-column
field="estimated_departure_date"
:title="$t('cs.companyStructure.estimatedDepartureDate')"
min-width="100"
v-if="
checkedCols.findIndex((v) => v == 'estimated_departure_date') !== -1 &&
tableType == 'structure' &&
attributes.findIndex((v) => v == 'estimated_departure_date') !== -1
"
key="estimated_departure_date"
>
<template #header>
<span class="vxe-handle">
<OpsMoveIcon class="move-icon" />
<span>{{ $t('cs.companyStructure.estimatedDepartureDate') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column <vxe-column
field="last_login" field="last_login"
title="上次登录时间" :title="$t('cs.companyStructure.lastLogin')"
min-width="140px" min-width="140px"
sortable sortable
:formatter="formatDate" :formatter="formatDate"
@ -715,7 +805,7 @@
<template #header> <template #header>
<span class="vxe-handle"> <span class="vxe-handle">
<OpsMoveIcon class="move-icon" /> <OpsMoveIcon class="move-icon" />
<span>上次登录时间</span> <span>{{ $t('cs.companyStructure.lastLogin') }}</span>
</span> </span>
</template> </template>
</vxe-column> </vxe-column>
@ -728,10 +818,10 @@
key="control" key="control"
> >
<template #header> <template #header>
<span>操作</span> <span>{{ $t('operation') }}</span>
<template> <template>
<a-popover <a-popover
title="请选择需要展示的列" :title="$t('cs.companyStructure.selectDisplayColumn')"
placement="bottom" placement="bottom"
v-model="visible" v-model="visible"
trigger="click" trigger="click"
@ -741,7 +831,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
@ -753,36 +843,44 @@
justifyContent: 'flex-end', justifyContent: 'flex-end',
}" }"
> >
<a-button :style="{ marginRight: '10px' }" size="small" @click="handleCancel">取消</a-button> <a-button :style="{ marginRight: '10px' }" size="small" @click="handleCancel">{{ $t('cancel') }}</a-button>
<a-button size="small" @click="handleSubmit" type="primary">确定</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> <template slot="title">
<a><a-icon type="reload" @click="openBatchModal('password', row)" /></a> {{ $t('cs.companyStructure.resetPassword') }}
</template>
<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> <template slot="title">
{{ $t('cs.companyStructure.block') }}
</template>
<a :style="{ color: 'red' }" @click="openBatchModal('block', row, 1)"> <a :style="{ color: 'red' }" @click="openBatchModal('block', row, 1)">
<ops-icon type="icon-xianxing-weilianjie" /> <ops-icon type="icon-xianxing-weilianjie" />
</a> </a>
</a-tooltip> </a-tooltip>
<a-tooltip v-else> <a-tooltip v-else>
<template slot="title"> 恢复 </template> <template slot="title">
{{ $t('cs.companyStructure.recover') }}
</template>
<a @click="openBatchModal('block', row, 0)"> <a @click="openBatchModal('block', row, 0)">
<ops-icon type="icon-xianxing-yilianjie" /> <ops-icon type="icon-xianxing-yilianjie" />
</a> </a>
</a-tooltip> </a-tooltip>
</a-space> </a-space>
<a-tooltip v-else> <a-tooltip v-else>
<template slot="title"> 移除 </template> <template slot="title">
{{ $t('cs.role.remove') }}
</template>
<a :style="{ color: 'red' }" @click="removeEmployee(row)"> <a :style="{ color: 'red' }" @click="removeEmployee(row)">
<ops-icon type="icon-xianxing-shanchuyonghu" /> <ops-icon type="icon-xianxing-shanchuyonghu" />
</a> </a>
@ -792,7 +890,7 @@
<template #empty> <template #empty>
<div> <div>
<img :style="{ width: '200px' }" :src="require('@/assets/data_empty.png')" /> <img :style="{ width: '200px' }" :src="require('@/assets/data_empty.png')" />
<div>暂无数据</div> <div>{{ $t('noData') }}</div>
</div> </div>
</template> </template>
</vxe-table> </vxe-table>
@ -833,46 +931,49 @@ export default {
}, },
data() { data() {
const options = [ const options = [
{ label: '姓名', value: 'nickname' }, { label: this.$t('cs.companyStructure.nickname'), value: 'nickname' },
{ label: '用户名', value: 'username' }, { label: this.$t('cs.companyStructure.username'), value: 'username' },
{ label: '邮箱', value: 'email' }, { label: this.$t('cs.companyStructure.email'), value: 'email' },
{ label: '性别', value: 'sex' }, { label: this.$t('cs.companyStructure.sex'), value: 'sex' },
{ label: '手机号', value: 'mobile' }, { label: this.$t('cs.companyStructure.mobile'), value: 'mobile' },
{ label: '部门', value: 'department_name' }, { label: this.$t('cs.companyStructure.departmentName'), value: 'department_name' },
{ label: '岗位', value: 'position_name' }, { label: this.$t('cs.companyStructure.positionName'), value: 'position_name' },
{ label: '直接上级', value: 'direct_supervisor_id' }, { label: this.$t('cs.companyStructure.supervisor'), value: 'direct_supervisor_id' },
{ label: '年假', value: 'annual_leave' }, { label: this.$t('cs.companyStructure.annualLeave'), value: 'annual_leave' },
{ label: '虚拟年假', value: 'virtual_annual_leave' }, { label: this.$t('cs.companyStructure.virtualAnnualLeave'), value: 'virtual_annual_leave' },
{ label: '育儿假', value: 'parenting_leave' }, { label: this.$t('cs.companyStructure.parentingLeave'), value: 'parenting_leave' },
{ label: '目前所属主体', value: 'current_company' }, { label: this.$t('cs.companyStructure.entryDate'), value: 'entry_date' },
{ label: '初始入职日期', value: 'dfc_entry_date' }, { label: this.$t('cs.companyStructure.isInternship'), value: 'is_internship' },
{ label: '目前主体入职日期', value: 'entry_date' }, { label: this.$t('cs.companyStructure.leaveDate'), value: 'leave_date' },
{ label: '正式/实习生', value: 'is_internship' }, { label: this.$t('cs.companyStructure.idCard'), value: 'id_card' },
{ label: '离职日期', value: 'leave_date' }, { label: this.$t('cs.companyStructure.nation'), value: 'nation' },
{ label: '身份证号码', value: 'id_card' }, { label: this.$t('cs.companyStructure.idPlace'), value: 'id_place' },
{ label: '民族', value: 'nation' }, { label: this.$t('cs.companyStructure.party'), value: 'party' },
{ label: '籍贯', value: 'id_place' }, { label: this.$t('cs.companyStructure.householdRegistrationType'), value: 'household_registration_type' },
{ label: '组织关系', value: 'party' }, { label: this.$t('cs.companyStructure.hometown'), value: 'hometown' },
{ label: '户籍类型', value: 'household_registration_type' }, { label: this.$t('cs.companyStructure.marry'), value: 'marry' },
{ label: '户口所在地', value: 'hometown' }, { label: this.$t('cs.companyStructure.maxDegree'), value: 'max_degree' },
{ label: '婚姻情况', value: 'marry' }, { label: this.$t('cs.companyStructure.emergencyPerson'), value: 'emergency_person' },
{ label: '最高学历', value: 'max_degree' }, { label: this.$t('cs.companyStructure.emergencyPhone'), value: 'emergency_phone' },
{ label: '紧急联系人', value: 'emergency_person' }, { label: this.$t('cs.companyStructure.bankCardNumber'), value: 'bank_card_number' },
{ label: '紧急联系电话', value: 'emergency_phone' }, { label: this.$t('cs.companyStructure.bankCardName'), value: 'bank_card_name' },
{ label: '卡号', value: 'bank_card_number' }, { label: this.$t('cs.companyStructure.openingBank'), value: 'opening_bank' },
{ label: '银行', value: 'bank_card_name' }, { label: this.$t('cs.companyStructure.accountOpeningLocation'), value: 'account_opening_location' },
{ label: '开户行', value: 'opening_bank' }, { label: this.$t('cs.companyStructure.school'), value: 'school' },
{ label: '开户地', value: 'account_opening_location' }, { label: this.$t('cs.companyStructure.major'), value: 'major' },
{ label: '学校', value: 'school' }, { label: this.$t('cs.companyStructure.education'), value: 'education' },
{ label: '专业', value: 'major' }, { label: this.$t('cs.companyStructure.graduationYear'), value: 'graduation_year' },
{ label: '学历', value: 'education' }, { label: this.$t('cs.companyStructure.childrenName'), value: 'name' },
{ label: '毕业年份', value: 'graduation_year' }, { label: this.$t('cs.companyStructure.childrenGender'), value: 'gender' },
{ label: '子女姓名', value: 'name' }, { label: this.$t('cs.companyStructure.childrenBirthday'), value: 'birthday' },
{ label: '子女性别', value: 'gender' }, { label: this.$t('cs.companyStructure.leftParentingLeave'), value: 'parental_leave_left' },
{ label: '子女出生日期', value: 'birthday' }, { label: this.$t('cs.companyStructure.birthDate'), value: 'birth_date' },
{ label: '剩余育儿假', value: 'parental_leave_left' }, { label: this.$t('cs.companyStructure.nationalityRegion'), value: 'nationality_region' },
{ label: '角色', value: 'roles' }, { label: this.$t('cs.companyStructure.birthPlace'), value: 'birth_place' },
{ label: '上次登录时间', value: 'last_login' }, { label: this.$t('cs.companyStructure.firstEntryDate'), value: 'first_entry_date' },
{ label: this.$t('cs.companyStructure.estimatedDepartureDate'), value: 'estimated_departure_date' },
{ label: this.$t('cs.companyStructure.role'), value: 'roles' },
{ label: this.$t('cs.companyStructure.lastLogin'), value: 'last_login' },
] ]
const checkedCols = JSON.parse(localStorage.getItem('setting-table-CheckedCols')) || [ const checkedCols = JSON.parse(localStorage.getItem('setting-table-CheckedCols')) || [
'nickname', 'nickname',
@ -889,7 +990,6 @@ export default {
'roles', 'roles',
'last_login', 'last_login',
'current_company', 'current_company',
'dfc_entry_date',
'is_internship', 'is_internship',
'entry_date', 'entry_date',
'leave_date', 'leave_date',
@ -924,24 +1024,28 @@ export default {
visible: false, visible: false,
tableDragClassName: [], // 表格拖拽的参数 tableDragClassName: [], // 表格拖拽的参数
attributes: [], attributes: [],
internMap: [
{
id: 0,
label: '正式',
},
{
id: 1,
label: '实习生',
},
],
internOptions: [
{ label: '正式', value: 0 },
{ label: '实习生', value: 1 },
],
} }
}, },
inject: ['provide_allFlatEmployees', 'provide_allFlatDepartments'], inject: ['provide_allFlatEmployees', 'provide_allFlatDepartments'],
computed: { computed: {
internOptions() {
return [
{ label: this.$t('cs.companyStructure.fullTime'), value: 0 },
{ label: this.$t('cs.companyStructure.internship'), value: 1 },
]
},
internMap() {
return [
{
id: 0,
label: this.$t('cs.companyStructure.fullTime'),
},
{
id: 1,
label: this.$t('cs.companyStructure.internship'),
},
]
},
allFlatEmployees() { allFlatEmployees() {
return this.provide_allFlatEmployees() return this.provide_allFlatEmployees()
}, },
@ -956,9 +1060,6 @@ export default {
Bus.$on('reqExportSelectEvent', () => { Bus.$on('reqExportSelectEvent', () => {
this.exportExcel() this.exportExcel()
}) })
this.options = this.options
.filter((item) => item.label !== '目前所属主体')
.filter((item) => item.label !== '初始入职日期')
this.unsbmitCheckedCols = this.checkedCols this.unsbmitCheckedCols = this.checkedCols
}, },
beforeDestroy() { beforeDestroy() {
@ -1064,8 +1165,8 @@ export default {
removeEmployee(row) { removeEmployee(row) {
const that = this const that = this
this.$confirm({ this.$confirm({
title: '提示', title: that.$t('warning'),
content: '确认移除该员工?', content: that.$t('cs.role.confirmRemoveEmployee'),
onOk() { onOk() {
that.$emit('removeEmployee', row) that.$emit('removeEmployee', row)
}, },
@ -1140,7 +1241,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是复选框 不导出
}, },

View File

@ -3,12 +3,12 @@
:disable-branch-nodes="multiple ? false : true" :disable-branch-nodes="multiple ? false : true"
:multiple="multiple" :multiple="multiple"
:options="employeeTreeSelectOption" :options="employeeTreeSelectOption"
placeholder="请选择员工" :placeholder="readOnly ? '' : placeholder || $t('cs.components.selectEmployee')"
v-model="treeValue" v-model="treeValue"
:max-height="200" :max-height="200"
noChildrenText="" :noChildrenText="$t('cs.components.empty')"
noOptionsText="" :noOptionsText="$t('cs.components.empty')"
:class="className ? className: 'ops-setting-treeselect'" :class="className ? className : 'ops-setting-treeselect'"
value-consists-of="LEAF_PRIORITY" value-consists-of="LEAF_PRIORITY"
:limit="20" :limit="20"
:limitText="(count) => `+ ${count}`" :limitText="(count) => `+ ${count}`"
@ -42,13 +42,37 @@ export default {
}, },
className: { className: {
type: String, type: String,
default: 'ops-setting-treeselect' default: 'ops-setting-treeselect',
} },
placeholder: {
type: String,
default: '',
},
idType: {
type: Number,
default: 1,
},
departmentKey: {
type: String,
default: 'department_id',
},
employeeKey: {
type: String,
default: 'employee_id',
},
}, },
data() { data() {
return {} return {}
}, },
inject: ['provide_allTreeDepAndEmp'], inject: {
provide_allTreeDepAndEmp: {
from: 'provide_allTreeDepAndEmp',
},
readOnly: {
from: 'readOnly',
default: false,
},
},
computed: { computed: {
treeValue: { treeValue: {
get() { get() {
@ -63,12 +87,11 @@ export default {
return this.provide_allTreeDepAndEmp() return this.provide_allTreeDepAndEmp()
}, },
employeeTreeSelectOption() { employeeTreeSelectOption() {
return formatOption(this.allTreeDepAndEmp) return formatOption(this.allTreeDepAndEmp, this.idType, false, this.departmentKey, this.employeeKey)
}, },
}, },
methods: {}, methods: {},
} }
</script> </script>
<style scoped> <style scoped></style>
</style>

View File

@ -1,5 +1,5 @@
<template> <template>
<a-modal title="关联员工" :visible="visible" @cancel="handleCancel" @ok="handleOK"> <a-modal :title="$t('cs.role.associatedEmployees')" :visible="visible" @cancel="handleCancel" @ok="handleOK">
<EmployeeTreeSelect v-model="values" :multiple="true" /> <EmployeeTreeSelect v-model="values" :multiple="true" />
</a-modal> </a-modal>
</template> </template>

View File

@ -1,20 +1,22 @@
import i18n from '@/lang'
export const ruleTypeList = [ export const ruleTypeList = [
{ value: '&', label: '与' }, { value: '&', label: i18n.t('cs.components.and') },
{ value: '|', label: '或' }, { value: '|', label: i18n.t('cs.components.or') },
// { value: 'not', label: '非' }, // { value: 'not', label: '非' },
] ]
export const expList = [ export const expList = [
{ value: 1, label: '等于' }, { value: 1, label: i18n.t('cs.components.equal') },
{ value: 2, label: '不等于' }, { value: 2, label: i18n.t('cs.components.notEqual') },
// { value: 'contain', label: '包含' }, // { value: 'contain', label: '包含' },
// { value: '~contain', label: '不包含' }, // { value: '~contain', label: '不包含' },
// { value: 'start_with', label: '以...开始' }, // { value: 'start_with', label: '以...开始' },
// { value: '~start_with', label: '不以...开始' }, // { value: '~start_with', label: '不以...开始' },
// { value: 'end_with', label: '以...结束' }, // { value: 'end_with', label: '以...结束' },
// { value: '~end_with', label: '不以...结束' }, // { value: '~end_with', label: '不以...结束' },
{ value: 7, label: '为空' }, // 为空的定义有点绕 { value: 7, label: i18n.t('cs.components.isEmpty') }, // 为空的定义有点绕
{ value: 8, label: '不为空' }, { value: 8, label: i18n.t('cs.components.isNotEmpty') },
] ]
export const advancedExpList = [ export const advancedExpList = [
@ -22,12 +24,12 @@ export const advancedExpList = [
// { value: '~in', label: '非in查询' }, // { value: '~in', label: '非in查询' },
// { value: 'range', label: '范围' }, // { value: 'range', label: '范围' },
// { value: '~range', label: '范围外' }, // { value: '~range', label: '范围外' },
{ value: 'compare', label: '比较' }, { value: 'compare', label: i18n.t('cs.components.compare') },
] ]
export const compareTypeList = [ export const compareTypeList = [
{ value: 5, label: '大于' }, { value: 5, label: i18n.t('cs.components.moreThan') },
// { value: '2', label: '>=' }, // { value: '2', label: '>=' },
{ value: 6, label: '小于' }, { value: 6, label: i18n.t('cs.components.lessThan') },
// { value: '4', label: '<=' }, // { value: '4', label: '<=' },
] ]

View File

@ -7,7 +7,7 @@
@visibleChange="visibleChange" @visibleChange="visibleChange"
> >
<slot name="popover_item"> <slot name="popover_item">
<a-button type="primary" ghost>条件过滤<a-icon type="filter"/></a-button> <a-button type="primary" ghost>{{ $t('cs.components.conditionFilter') }}<a-icon type="filter"/></a-button>
</slot> </slot>
<template slot="content"> <template slot="content">
<svg <svg
@ -106,7 +106,7 @@
searchable searchable
v-if="isChoiceByProperty(item.column) && (item.operator === 1 || item.operator === 2)" v-if="isChoiceByProperty(item.column) && (item.operator === 1 || item.operator === 2)"
:options="getChoiceValueByProperty(item.column)" :options="getChoiceValueByProperty(item.column)"
placeholder="请选择" :placeholder="$t('cs.components.selectPlaceholder')"
:normalizer=" :normalizer="
(node) => { (node) => {
return { return {
@ -133,26 +133,26 @@
v-else-if="item.operator !== 7 && item.operator !== 8" v-else-if="item.operator !== 7 && item.operator !== 8"
size="small" size="small"
v-model="item.value" v-model="item.value"
:placeholder="item.exp === 'in' || item.exp === '~in' ? '以 ; 分隔' : ''" :placeholder="item.exp === 'in' || item.exp === '~in' ? $t('cs.components.operatorInPlaceholder') : ''"
class="ops-input" class="ops-input"
></a-input> ></a-input>
<!-- <div v-else :style="{ width: '175px' }"></div> --> <!-- <div v-else :style="{ width: '175px' }"></div> -->
<a-tooltip title="复制"> <a-tooltip :title="$t('cs.components.copy')">
<a class="operation" @click="handleCopyRule(item)"><a-icon type="copy"/></a> <a class="operation" @click="handleCopyRule(item)"><a-icon type="copy"/></a>
</a-tooltip> </a-tooltip>
<a-tooltip title="删除"> <a-tooltip :title="$t('delete')">
<a class="operation" @click="handleDeleteRule(item)" :style="{ color: 'red' }"><a-icon type="delete"/></a> <a class="operation" @click="handleDeleteRule(item)" :style="{ color: 'red' }"><a-icon type="delete"/></a>
</a-tooltip> </a-tooltip>
</a-space> </a-space>
<div class="table-filter-add"> <div class="table-filter-add">
<a @click="handleAddRule">+ 新增</a> <a @click="handleAddRule">+ {{ $t('new') }}</a>
</div> </div>
<a-divider :style="{ margin: '10px 0' }" /> <a-divider :style="{ margin: '10px 0' }" />
<div style="width:534px"> <div style="width:534px">
<a-space :style="{ display: 'flex', justifyContent: 'flex-end' }"> <a-space :style="{ display: 'flex', justifyContent: 'flex-end' }">
<a-button type="primary" size="small" @click="handleSubmit">确定</a-button> <a-button type="primary" size="small" @click="handleSubmit">{{ $t('confirm') }}</a-button>
<a-button size="small" @click="handleClear">清空</a-button> <a-button size="small" @click="handleClear">{{ $t('clear') }}</a-button>
</a-space> </a-space>
</div> </div>
</template> </template>

View File

@ -0,0 +1,443 @@
const cs_en = {
menu: {
person: 'Personal Center',
companyInfo: 'Company Info',
companyStructure: 'Company Structure',
notice: 'Notification Settings',
email: 'Email Settings',
wx: 'WeChat Work',
dingding: 'DingTalk',
feishu: 'Feishu',
auth: 'Auth Settings',
role: 'Role Management',
sys: 'System Role',
technician: 'Technician Role',
user: 'User Role',
group: 'User Group',
duty: 'Duty Management',
},
companyInfo: {
spanCompany: 'Description',
name: 'Company Name',
nameValidate: 'Please enter name',
description: 'Description',
spanAddress: 'Address',
country: 'Country/Region',
city: 'City',
address: 'Address',
postcode: 'Postal Code',
spanContract: 'Contact Information',
spanLogo: 'Company Logo',
website: 'Website',
phone: 'Phone Number',
phoneValidate: 'Please enter a valid phone number',
faxCode: 'Fax Number',
faxCodeValidate: 'Please enter a valid fax number',
email: 'Email',
emailValidate: 'Please enter a valid email address',
messenger: 'Messenger Address',
domainName: 'Deployment Domain',
logo: 'Company Logo',
upload: 'Upload',
editCompanyLogo: 'Edit Company Logo',
editCompanyLogoSmall: 'Edit Company Logo Thumbnail',
imageSizeLimit2MB: 'Image size does not exceed 2MB',
checkInputCorrect: 'Please check if the input content is correct',
},
companyStructure: {
batchImport: 'Batch Import',
batchEdit: 'Batch Edit',
selectFile: 'Select File',
clickDownloadImportTemplate: 'Click to download Employee Import Template',
importSuccess: 'Imported total {allCount} items, imported successfully',
importFailed: 'Import failed',
count: 'items',
email: 'Email',
emailPlaceholder: 'Please enter email',
emailFormatErr: 'Email format error',
username: 'Username',
usernamePlaceholder: 'Please enter username',
nickname: 'Full Name',
nicknamePlaceholder: 'Please enter full name',
password: 'Password',
passwordPlaceholder: 'Please enter password',
sex: 'Gender',
sexPlaceholder: 'Please select gender',
male: 'Male',
female: 'Female',
mobile: 'Mobile Number',
mobilePlaceholder: 'Please enter mobile number',
mobileFormatErr: 'Please enter a valid mobile number',
positionName: 'Position',
positionNamePlaceholder: 'Please enter position',
employee: 'Employee',
departmentName: 'Department',
currentCompany: 'Current Company',
currentCompanyPlaceholder: 'Please select current company',
dfcEntryDate: 'Initial Entry Date',
dfcEntryDatePlaceholder: 'Please select initial entry date',
entryDate: 'Current Company Entry Date',
entryDatePlaceholder: 'Please select current company entry date',
isInternship: 'Full-time/Intern',
isInternshipPlaceholder: 'Please select full-time/intern',
internship: 'Intern',
fullTime: 'Full-time',
leaveDate: 'Resignation Date',
leaveDatePlaceholder: 'Please select resignation date',
idCard: 'ID Card Number',
idCardPlaceholder: 'Please enter ID card number',
nation: 'Ethnicity',
nationPlaceholder: 'Please select ethnicity',
idPlace: 'Native Place',
idPlacePlaceholder: 'Please enter native place',
party: 'Political Affiliation',
partyPlaceholder: 'Please select political affiliation',
partyMember: 'Party Member',
member: 'League Member',
masses: 'Masses',
householdRegistrationType: 'Residency Type',
householdRegistrationTypePlaceholder: 'Please select residency type',
town: 'Urban',
agriculture: 'Rural',
hometown: 'Residence Location',
hometownPlaceholder: 'Please enter residence location',
marry: 'Marital Status',
unmarried: 'Unmarried',
married: 'Married',
marryPlaceholder: 'Please select marital status',
maxDegree: 'Highest Degree',
maxDegreePlaceholder: 'Please select highest degree',
phd: 'PhD',
master: 'Master',
undergraduate: 'Bachelor',
specialist: 'Associate',
highSchool: 'High School',
technicalSecondaryOrHighSchool: 'Technical/High School',
juniorHighSchool: 'Junior High School',
primarySchool: 'Primary School',
emergencyPerson: 'Emergency Contact',
emergencyPersonPlaceholder: 'Please enter emergency contact',
emergencyPhone: 'Emergency Contact Number',
emergencyPhonePlaceholder: 'Please enter emergency contact number',
bankCardInfo: 'Bank Card',
bankCardNumber: 'Bank Card Number',
bankCardNumberPlaceholder: 'Please enter bank card number',
bankCardName: 'Bank',
bankCardNamePlaceholder: 'Please enter bank',
openingBank: 'Issuing Bank',
openingBankPlaceholder: 'Please enter issuing bank',
accountOpeningLocation: 'Account Opening Location',
accountOpeningLocationPlaceholder: 'Please enter account opening location',
school: 'Graduated School',
schoolPlaceholder: 'Please enter graduated school',
major: 'Major',
majorPlaceholder: 'Please enter major',
education: 'Education',
educationPlaceholder: 'Please select education',
educationalExperience: 'Education History',
graduationYear: 'Graduation Year',
graduationYearPlaceholder: 'Please select graduation year',
birthDate: 'Date of Birth',
birthDatePlaceholder: 'Please select date of birth',
birthPlace: 'Place of Birth',
birthPlacePlaceholder: 'Please enter place of birth',
nationalityRegion: 'Nationality/Region',
nationalityRegionPlaceholder: 'Please select nationality/region',
firstEntryDate: 'First Entry Date',
firstEntryDatePlaceholder: 'Please select first entry date',
estimatedDepartureDate: 'Estimated Departure Date',
estimatedDepartureDatePlaceholder: 'Please select estimated departure date',
lastLogin: 'Last Login Time',
importFailedReason: 'Failure Reason',
selectDepartment: 'Select Department',
supervisor: 'Supervisor',
editDirectSupervisor: 'Edit Supervisor',
selectDirectSupervisor: 'Select Supervisor',
annualLeave: 'Annual Leave',
editPosition: 'Edit Position',
editAnnualLeave: 'Edit Annual Leave',
annualLeavePlaceholder: 'Please enter annual leave',
virtualAnnualLeave: 'Virtual Annual Leave',
virtualAnnualLeavePlaceholder: 'Please enter virtual annual leave',
parentingLeave: 'Parenting Leave',
leftParentingLeave: 'Remaining Parenting Leave',
parentingLeavePlaceholder: 'Please enter parenting leave',
day: 'day(s)',
resetPassword: 'Reset Password',
confirmPassword: 'Confirm Password',
block: 'Disable',
blockUserConfirm: 'This user will be disabled, continue?',
batchBlockUserConfirm: 'These users will be disabled, continue?',
recover: 'Recover',
recoverUserConfirm: 'This user will be recovered, continue?',
batchRecoverUserConfirm: 'These users will be recovered, continue?',
opFailed: 'Operation failed',
opSuccess: 'Operation successful',
createSubDepartment: 'Create Sub-department',
editDepartment: 'Edit Department',
deleteDepartment: 'Delete Department',
downloadAll: 'Download All',
downloadSelected: 'Download Selected',
departmentLabel: 'Department Name',
departmentLabelPlaceholder: 'Please enter department name',
parentDepartment: 'Parent Department',
parentDepartmentPlaceholder: 'Please select parent department',
departmentDirector: 'Department Director',
childrenInformation: 'Children Information',
childrenName: 'Children Name',
childrenGender: 'Children Gender',
childrenBirthday: 'Children Birthday',
allEmployee: 'All Employees',
activeEmployee: 'Active',
blockEmployee: 'Disabled',
prevStep: 'Previous',
nextStep: 'Next',
done: 'Done',
uploadFile: 'Upload File',
confirmData: 'Confirm Data',
uploadDone: 'Upload Done',
dataErr: 'Data Error',
createEmployee: 'Create Employee',
editEmployee: 'Edit Employee',
role: 'Role',
selectDisplayColumn: 'Please select columns to display'
},
auth: {
basic: 'Basic',
other: 'Other',
isEnable: 'Is Enabled',
common: 'Common',
testConnect: 'Test Connection',
testLogin: 'Test Login',
testSuccess: 'Test Successful',
ldap: {
serverAddress: 'Server Address',
serverAddressHelp: 'E.g. 192.168.1.6 or ldap://192.168.1.6 or ldap://192.168.1.6:389',
serverAddressPlaceholder: 'Please enter server address',
domain: 'Domain',
domainPlaceholder: 'Please enter domain',
user: 'User',
username: 'Username',
userPlaceholder: 'Please enter username',
userHelp: 'User DN: cn={},ou=users,dc=xxx,dc=com {} will be replaced by username'
},
cas: {
server: 'Server Address',
serverHelp: 'Without url path, e.g. https://xxx.com',
serverPlaceholder: 'Please enter CAS server address',
validateServer: 'Validation Server Address',
validateServerHelp: 'Without url path, e.g. https://xxx.com',
validateServerPlaceholder: 'Please enter validation server address',
loginRoute: 'Login Route',
loginRoutePlaceholder: 'Please enter login route',
logoutRoute: 'Logout Route',
logoutRoutePlaceholder: 'Please enter logout route',
validateRoute: 'Validate Route',
validateRoutePlaceholder: 'Please enter validate route',
afterLoginRoute: 'Redirect Route',
afterLoginRoutePlaceholder: 'Please enter redirect route',
userMap: 'User Attribute Mapping'
},
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',
usernameOrEmail: 'Username/Email',
usernameOrEmailPlaceholder: 'Please enter username/email',
password: 'Password',
passwordPlaceholder: 'Please enter password',
oauth2: {
clientId: 'Client ID',
clientIdPlaceholder: 'Please enter client ID',
clientSecret: 'Client Secret',
clientSecretPlaceholder: 'Please enter client secret',
authorizeUrl: 'Authorize URL',
authorizeUrlPlaceholder: 'Please enter authorize URL',
tokenUrl: 'Token URL',
tokenUrlPlaceholder: 'Please enter token URL',
userInfo: 'User Info',
scopes: 'Scopes',
scopesPlaceholder: 'Please enter scopes',
}
},
duty: {
basicSetting: 'Basic Settings',
ruleName: 'Title',
ruleNamePlaceholder: 'Please enter title',
principalId: 'Person in Charge',
specifyId: 'Appointee',
principalIdPlaceholder: 'Please select person in charge/single select',
remark: 'Remark',
remarkPlaceholder: 'Please enter remark',
remindTime: 'Duty Remind Time',
remindWay: 'Remind Way',
remindPeople: 'Remind People',
mainDutyPeople: 'Main Duty Person',
deputyDutyPeople: 'Deputy Duty Person',
dutyRule: 'Duty Rule',
'一': 'Mon',
'二': 'Tue',
'三': 'Wed',
'四': 'Thu',
'五': 'Fri',
'六': 'Sat',
'日': 'Sun',
searchPlaceholder: 'Please search',
dutyTable: 'Duty Schedule',
dutyMember: 'Duty Member',
dutyMemberPlaceholder: 'Please select duty member',
startDutyMember: 'Start Duty Member',
startEndDate: 'Start End Date',
startEndDatePlaceholder: 'Please select start end date',
dutyPeriod: 'Duty Period',
dutyFrequency: 'Duty Frequency',
fullDay: 'Full Day',
specifyTime: 'Specify Time',
monthDayFormat: 'MM/DD',
week: 'Week',
month: 'Month',
hour: 'Hour',
min: 'min',
before: 'Before',
fixed: 'Fixed Time',
removeHolidays: 'Remove Holidays',
offDutyReceiver: 'Off-duty Receiver',
offDutyReceiverPlaceholder: 'Please select off-duty receiver',
titleLimit: 'Please enter title (20 characters)',
remarkLimit: 'Remark 150 characters max',
frequencyLimit: 'Please enter duty frequency (positive integer)'
},
group: {
groupName: 'User Group',
groupNamePlaceholder: 'Please enter user group',
addGroup: 'Add Group',
editGroup: 'Edit Group',
},
components: {
preview: 'Preview',
copy: 'Copy',
editAvatar: 'Edit Avatar',
conditionFilter: 'Condition Filter',
selectPlaceholder: 'Please select',
empty: 'Empty',
and: 'And',
or: 'Or',
equal: 'Equal',
notEqual: 'Not Equal',
isEmpty: 'Is Empty',
isNotEmpty: 'Is Not Empty',
compare: 'Compare',
moreThan: 'More Than',
lessThan: 'Less Than',
operatorInPlaceholder: 'Separate by ;',
selectEmployee: 'Select Employee'
},
notice: {
corpid: 'Corp ID',
agentid: 'Self-built App ID',
corpsecret: 'Self-built App Secret',
itsmAppId: 'ITSM App ID',
robot: 'Robot',
selectRobot: 'Please select robot',
robotConfigErrorTips: 'Please fill out robot configuration completely',
webhookAddress: 'Webhook Address',
appKey: 'App Key',
appSecret: 'App Secret',
robotCode: 'Robot Code',
sendServer: 'Outgoing Server',
connectProtocol: 'Connection Protocol',
ews: 'EWS(Exchange Web Services)',
authType: 'Auth Type',
base: 'Base',
oauth: 'OAuth',
ip: 'Server Name/IP Address',
username: 'Username',
password: 'Password',
email: 'Email Address',
emailType: 'Email Type',
port: 'Port',
testEmailConfig: 'Test Email Settings',
testRecyclingBin: 'Test Recycle Bin',
receiveEmailFailed: 'Receive email failed',
emailServiceNotConfig: 'Email server is not configured, please configure one email server',
troubleshooting: 'Troubleshooting',
emailConfig: 'Email Settings',
receiveEmailInterval: 'Get Email Interval',
startProxyServer: 'Start Proxy Server',
configProxyServer: 'Config Proxy Server',
startEmailTest: 'Start Email Test',
disableCreationOfRequestsViaEmail: 'Disable Creation of Requests Via Email',
specifyAllowedEmails: 'Specify Allowed Emails/Domains, Separate Multiple Values By Comma',
specifyAllowedEmailsExample: 'E.g. user@domain.com,*@domain.com',
specifyAllowedEmailsLimit: 'Limit cannot apply to requests already in sessions, it will aggregate to its parent ticket',
messageConfig: 'Message Settings',
moveWrongMessagesToFolder: 'Move Messages to Wrong Folder',
knowMore: 'Learn More',
configProxySettings: 'Config Proxy Settings',
host: 'Host',
isEncrypted: 'Is Encrypted',
emailTest: 'Email Test',
testSendAddress: 'Test Send Email Address',
testMailSend: 'Test Mail Send',
portPlaceholder: 'Please enter port',
testSendAddressPlaceholder: 'Please enter test send email address',
emailSendSuccess: 'Email Send Success',
title: 'Title',
},
person: {
spanTitle: 'Personal Info',
accountAndPassword: 'Account Password',
avatar: 'Avatar',
changeAvatar: 'Change Avatar',
email: 'Email',
wechatApp: 'WeChat Work',
feishuApp: 'Feishu',
dingdingApp: 'DingTalk',
bindInfo: 'Bind Info',
newPassword: 'New Password',
confirmPassword: 'Confirm Password',
pleaseConfirmNewPasswordSecondTime: 'Please confirm new password again',
thePasswordEnteredTwiceIsInconsistent: 'The password entered twice is inconsistent',
inputStrCountLimit20: 'Character count must be less than 20',
inputStrCountLimit: 'Character count must be less than {limit}',
alert: 'Warning',
confirmUnbind: 'Confirm unbind?',
unbindSuccess: 'Unbind successful',
bindSuccess: 'Bind successful',
},
role: {
systemRole: 'System Role',
technicianRole: 'Technician Role',
userRole: 'User Role',
authorizedByTheCreator: 'Authorized By The Creator',
authorizeAccordingToRules: 'Authorize According To Rules',
expression: 'Expression',
matchResults: 'Match Results',
matchResultEmpty: 'Empty',
pleaseFillInTheCompleteRules: 'Please fill in the complete rules',
roleName: 'Role Name',
pleaseEnterRoleName: 'Please enter role name',
appName: 'App Name',
pleaseEnterAppName: 'Please enter app name',
createRole: 'Create Role',
editRole: 'Edit Role',
copyRole: 'Copy Role From {roleName}',
associatedEmployees: 'Associated Employees',
inputNameOrEmail: 'Enter Name/Email',
remove: 'Remove',
confirmRemoveEmployee: 'Confirm remove this employee?',
removeSuccess: 'Remove successful',
associatedSuccess: 'Associate successful',
roleEmployee: 'Role Employee',
operationPermission: 'Operation Permission',
dataPermission: 'Data Permission',
confirmDeleteRole: 'Confirm delete role [{roleName}]?',
deleteRoleSuccess: 'Delete successful',
mySelf: 'My self',
mySubordinates: 'My Subordinates',
myDepartment: 'My Department',
myDepartmentAndSubordinateDepartments: 'My Department And Subordinate Departments',
test: 'Test',
selectApp: 'Select App',
}
}
export default cs_en

View File

@ -0,0 +1,442 @@
const cs_zh = {
menu: {
person: '个人中心',
companyInfo: '公司信息',
companyStructure: '公司架构',
notice: '通知设置',
email: '邮件设置',
wx: '企业微信',
dingding: '钉钉',
feishu: '飞书',
auth: '认证设置',
role: '角色管理',
sys: '系统角色',
technician: '技术员角色',
user: '用户角色',
group: '用户分组',
duty: '值班管理',
},
companyInfo: {
spanCompany: '公司描述',
name: '公司名称',
nameValidate: '请输入名称',
description: '描述',
spanAddress: '公司地址',
country: '国家/地区',
city: '城市',
address: '地址',
postcode: '邮政编码',
spanContract: '联系方式',
spanLogo: '公司标识',
website: '网站',
phone: '电话号码',
phoneValidate: '请输入正确的电话号码',
faxCode: '传真号码',
faxCodeValidate: '请输入正确的传真号码',
email: '邮箱',
emailValidate: '请输入正确的邮箱地址',
messenger: 'Messenger地址',
domainName: '部署域名',
logo: '公司logo',
upload: '上传',
editCompanyLogo: '编辑公司logo',
editCompanyLogoSmall: '编辑公司logo缩略图',
imageSizeLimit2MB: '图片大小不超过2MB',
checkInputCorrect: '请检查输入内容是否正确',
},
companyStructure: {
batchImport: '批量导入',
batchEdit: '批量编辑',
selectFile: '选择文件',
clickDownloadImportTemplate: '点击下载《员工导入模板》',
importSuccess: '导入总数据 {allCount} 条, 导入成功',
importFailed: '导入失败',
count: '条',
email: '邮箱',
emailPlaceholder: '请输入邮箱',
emailFormatErr: '邮箱格式错误',
username: '用户名',
usernamePlaceholder: '请输入用户名',
nickname: '姓名',
nicknamePlaceholder: '请输入姓名',
password: '密码',
passwordPlaceholder: '请输入密码',
sex: '性别',
sexPlaceholder: '请选择性别',
male: '男',
female: '女',
mobile: '手机号',
mobilePlaceholder: '请输入手机号',
mobileFormatErr: '请输入正确的手机号',
positionName: '岗位',
positionNamePlaceholder: '请输入岗位',
employee: '员工',
departmentName: '部门',
currentCompany: '目前所属主体',
currentCompanyPlaceholder: '请选择目前所属主体',
dfcEntryDate: '初始入职日期',
dfcEntryDatePlaceholder: '请选择初始入职日期',
entryDate: '目前主体入职日期',
entryDatePlaceholder: '请选择目前主体入职日期',
isInternship: '正式/实习生',
isInternshipPlaceholder: '请选择正式/实习生',
internship: '实习生',
fullTime: '正式',
leaveDate: '离职日期',
leaveDatePlaceholder: '请选择离职日期',
idCard: '身份证号',
idCardPlaceholder: '请输入身份证号',
nation: '民族',
nationPlaceholder: '请选择民族',
idPlace: '籍贯',
idPlacePlaceholder: '请输入籍贯',
party: '组织关系',
partyPlaceholder: '请选择组织关系',
partyMember: '党员',
member: '团员',
masses: '群众',
householdRegistrationType: '户籍类型',
householdRegistrationTypePlaceholder: '请选择户籍类型',
town: '城镇',
agriculture: '农业',
hometown: '户口所在地',
hometownPlaceholder: '请输入户口所在地',
marry: '婚姻状况',
unmarried: '未婚',
married: '已婚',
marryPlaceholder: '请选择婚姻状况',
maxDegree: '最高学历',
maxDegreePlaceholder: '请选择最高学历',
phd: '博士',
master: '硕士',
undergraduate: '本科',
specialist: '专科',
highSchool: '高中',
technicalSecondaryOrHighSchool: '中专/高中',
juniorHighSchool: '初中',
primarySchool: '小学',
emergencyPerson: '紧急联系人',
emergencyPersonPlaceholder: '请输入紧急联系人',
emergencyPhone: '紧急联系人电话',
emergencyPhonePlaceholder: '请输入紧急联系人电话',
bankCardInfo: '银行卡',
bankCardNumber: '银行卡号',
bankCardNumberPlaceholder: '请输入银行卡号',
bankCardName: '银行',
bankCardNamePlaceholder: '请输入银行',
openingBank: '开户行',
openingBankPlaceholder: '请输入开户行',
accountOpeningLocation: '开户地',
accountOpeningLocationPlaceholder: '请输入开户地',
school: '毕业学校',
schoolPlaceholder: '请输入毕业学校',
major: '专业',
majorPlaceholder: '请输入专业',
education: '学历',
educationPlaceholder: '请选择学历',
educationalExperience: '教育经历',
graduationYear: '毕业年份',
graduationYearPlaceholder: '请选择毕业年份',
birthDate: '出生日期',
birthDatePlaceholder: '请选择出生日期',
birthPlace: '出生地',
birthPlacePlaceholder: '请输入出生地',
nationalityRegion: '国籍/地区',
nationalityRegionPlaceholder: '请选择国籍/地区',
firstEntryDate: '首次入境日期',
firstEntryDatePlaceholder: '请选择首次入境日期',
estimatedDepartureDate: '预计离境日期',
estimatedDepartureDatePlaceholder: '请选择预计离境日期',
lastLogin: '上次登录时间',
importFailedReason: '失败原因',
selectDepartment: '选择部门',
supervisor: '上级',
editDirectSupervisor: '编辑上级',
selectDirectSupervisor: '选择上级',
annualLeave: '年假',
editPosition: '编辑岗位',
editAnnualLeave: '编辑年假',
annualLeavePlaceholder: '请输入年假',
virtualAnnualLeave: '虚拟年假',
virtualAnnualLeavePlaceholder: '请输入虚拟年假',
parentingLeave: '育儿假',
leftParentingLeave: '剩余育儿假',
parentingLeavePlaceholder: '请输入育儿假',
day: '天',
resetPassword: '重置密码',
confirmPassword: '确认密码',
block: '禁用',
blockUserConfirm: '该用户将会被禁用,是否继续?',
batchBlockUserConfirm: '这些用户将会被禁用,是否继续?',
recover: '恢复',
recoverUserConfirm: '该用户将会被恢复,是否继续?',
batchRecoverUserConfirm: '这些用户将会被恢复,是否继续?',
opFailed: '操作失败',
opSuccess: '操作成功',
createSubDepartment: '创建子部门',
editDepartment: '编辑部门',
deleteDepartment: '删除部门',
downloadAll: '下载全部',
downloadSelected: '下载选中',
departmentLabel: '部门名称',
departmentLabelPlaceholder: '请输入部门名称',
parentDepartment: '上级部门',
parentDepartmentPlaceholder: '请选择上级部门',
departmentDirector: '部门负责人',
childrenInformation: '子女信息',
childrenName: '子女姓名',
childrenGender: '子女性别',
childrenBirthday: '子女出生日期',
allEmployee: '全部',
activeEmployee: '在职员工',
blockEmployee: '停用员工',
prevStep: '上一步',
nextStep: '下一步',
done: '完成',
uploadFile: '上传文件',
confirmData: '确认数据',
uploadDone: '上传完成',
dataErr: '数据有误',
createEmployee: '新建员工',
editEmployee: '编辑员工',
role: '角色',
selectDisplayColumn: '请选择需要展示的列'
},
auth: {
basic: '基本',
other: '其他',
isEnable: '是否启用',
common: '通用',
testConnect: '测试连接',
testLogin: '测试登录',
testSuccess: '测试成功',
ldap: {
serverAddress: '服务器地址',
serverAddressHelp: '例如: 192.168.1.6 或者 ldap://192.168.1.6 或者 ldap://192.168.1.6:389',
serverAddressPlaceholder: '请输入服务器地址',
domain: '域',
domainPlaceholder: '请输入域',
user: '用户',
username: '用户名称',
userPlaceholder: '请输入用户名称',
userHelp: '用户dn: cn={},ou=users,dc=xxx,dc=com {}会替换成用户名'
},
cas: {
server: '服务端地址',
serverHelp: '不包括url path例如https://xxx.com',
serverPlaceholder: '请输入cas服务器地址',
validateServer: '验证服务端地址',
validateServerHelp: '不包括url path例如https://xxx.com',
validateServerPlaceholder: '请输入验证服务端地址',
loginRoute: '登录路由',
loginRoutePlaceholder: '请输入登录路由',
logoutRoute: '注销路由',
logoutRoutePlaceholder: '请输入注销路由',
validateRoute: '验证路由',
validateRoutePlaceholder: '请输入验证路由',
afterLoginRoute: '重定向路由',
afterLoginRoutePlaceholder: '请输入重定向路由',
userMap: '用户属性映射'
},
autoRedirectLogin: '自动跳转到第三方登录页',
autoRedirectLoginHelp: '如果关闭,则会弹出跳转到第三方登录页的确认,点取消按钮会进入系统内置的登录页',
usernameOrEmail: '用户名/邮箱',
usernameOrEmailPlaceholder: '请输入用户名/邮箱',
password: '密码',
passwordPlaceholder: '请输入密码',
oauth2: {
clientId: '客户端ID',
clientIdPlaceholder: '请输入客户端ID',
clientSecret: '客户端密钥',
clientSecretPlaceholder: '请输入客户端密钥',
authorizeUrl: '授权链接',
authorizeUrlPlaceholder: '请输入授权链接',
tokenUrl: '令牌链接',
tokenUrlPlaceholder: '请输入令牌链接',
userInfo: '用户信息',
scopes: '授权范围',
scopesPlaceholder: '请输入授权范围',
}
},
duty: {
basicSetting: '基础设置',
ruleName: '标题',
ruleNamePlaceholder: '请输入标题',
principalId: '负责人',
specifyId: '指定人',
principalIdPlaceholder: '请选择负责人/单选',
remark: '备注',
remarkPlaceholder: '请输入备注',
remindTime: '值班提醒时间',
remindWay: '提醒方式',
remindPeople: '提醒人',
mainDutyPeople: '主值班人',
deputyDutyPeople: '副值班人',
dutyRule: '排班规则',
'一': '一',
'二': '二',
'三': '三',
'四': '四',
'五': '五',
'六': '六',
'日': '日',
searchPlaceholder: '请查找',
dutyTable: '值班表',
dutyMember: '值班人员',
dutyMemberPlaceholder: '请选择值班人员',
startDutyMember: '开始值班人员',
startEndDate: '起止日期',
startEndDatePlaceholder: '请选择起止日期',
dutyPeriod: '值班时段',
dutyFrequency: '值班频次',
fullDay: '全天',
specifyTime: '指定时间',
monthDayFormat: 'MM月DD日',
week: '周',
month: '月',
hour: '小时',
min: '分',
before: '提前',
fixed: '固定时间',
removeHolidays: '是否去除节假日',
offDutyReceiver: '非值班时间接收人',
offDutyReceiverPlaceholder: '请选择非值班时间接收人',
titleLimit: '请输入标题20个字符',
remarkLimit: '备注150个字符以内',
frequencyLimit: '请输入值班频次(正整数)'
},
group: {
groupName: '用户分组',
groupNamePlaceholder: '请输入用户分组',
addGroup: '新增分组',
editGroup: '编辑分组',
},
components: {
preview: '预览',
copy: '复制',
editAvatar: '编辑头像',
conditionFilter: '条件过滤',
selectPlaceholder: '请选择',
empty: '空',
and: '与',
or: '或',
equal: '等于',
notEqual: '不等于',
isEmpty: '为空',
isNotEmpty: '不为空',
compare: '比较',
moreThan: '大于',
lessThan: '小于',
operatorInPlaceholder: '以 ; 分隔',
selectEmployee: '选择员工'
},
notice: {
corpid: '企业ID',
agentid: '自建应用ID',
corpsecret: '自建应用密钥',
itsmAppId: 'ITSM应用ID',
robot: '机器人',
selectRobot: '请选择机器人',
robotConfigErrorTips: '请完整填写机器人配置',
webhookAddress: 'Webhook地址',
appKey: '应用Key',
appSecret: '应用密码',
robotCode: '机器人码',
sendServer: '发送服务器',
connectProtocol: '连接协议',
ews: 'EWS(Exchange Web服务)',
authType: '认证类型',
base: '基本',
oauth: 'OAuth',
ip: '服务器名/IP地址',
username: '用户名',
password: '密码',
email: '邮件地址',
emailType: '邮件类型',
port: '端口',
testEmailConfig: '测试邮件设置',
testRecyclingBin: '测试回收箱',
receiveEmailFailed: '接收邮件失败',
emailServiceNotConfig: '邮箱服务器未配置,请配置一个邮箱服务器',
troubleshooting: '故障诊断',
emailConfig: '邮件设置',
receiveEmailInterval: '获取邮件间隔',
startProxyServer: '启动代理服务器',
configProxyServer: '配置代理服务器',
startEmailTest: '启动邮件测试',
disableCreationOfRequestsViaEmail: '禁用通过邮件创建请求',
specifyAllowedEmails: '指定允许的邮件/域名,逗号分隔多个值',
specifyAllowedEmailsExample: '例如:user@domain.com,*@domain.com',
specifyAllowedEmailsLimit: '限制不能适用于已在会话中的请求,它将聚集到它的上级工单中',
messageConfig: '消息设置',
moveWrongMessagesToFolder: '将消息移动到错误的文件夹',
knowMore: '了解更多',
configProxySettings: '配置代理设置',
host: '主机',
isEncrypted: '是否加密',
emailTest: '邮件测试',
testSendAddress: '测试发送邮件地址',
testMailSend: '测试邮件发送',
portPlaceholder: '请输入端口',
testSendAddressPlaceholder: '请输入测试发送邮件地址',
emailSendSuccess: '已发送邮件,请查收',
title: '名称',
},
person: {
spanTitle: '个人信息',
accountAndPassword: '账号密码',
avatar: '头像',
changeAvatar: '更换头像',
email: '邮件',
wechatApp: '企业微信',
feishuApp: '飞书',
dingdingApp: '钉钉',
bindInfo: '绑定信息',
newPassword: '新密码',
confirmPassword: '确认密码',
pleaseConfirmNewPasswordSecondTime: '请再次确认新密码',
thePasswordEnteredTwiceIsInconsistent: '两次输入的密码不一致',
inputStrCountLimit20: '字符数须小于20',
inputStrCountLimit: '字符数须小于{limit}',
alert: '警告',
confirmUnbind: '确认解绑?',
unbindSuccess: '解绑成功',
bindSuccess: '绑定成功',
},
role: {
systemRole: '系统角色',
technicianRole: '技术员角色',
userRole: '用户角色',
authorizedByTheCreator: '按照创建人授权',
authorizeAccordingToRules: '按照规则授权',
expression: '表达式',
matchResults: '匹配结果',
matchResultEmpty: '无',
pleaseFillInTheCompleteRules: '请填写完整的规则',
roleName: '角色名称',
pleaseEnterRoleName: '请输入角色名称',
appName: '应用名称',
pleaseEnterAppName: '请输入应用名称',
createRole: '新建角色',
editRole: '编辑角色',
copyRole: '从 {roleName} 复制角色',
associatedEmployees: '关联员工',
inputNameOrEmail: '请输入姓名/邮箱',
remove: '移除',
confirmRemoveEmployee: '确认移除该员工?',
removeSuccess: '移除成功',
associatedSuccess: '关联成功',
roleEmployee: '角色员工',
operationPermission: '操作权限',
dataPermission: '数据权限',
confirmDeleteRole: '确认删除角色 [{roleName}]?',
deleteRoleSuccess: '删除成功',
mySelf: '本人', // Myself
mySubordinates: '本人及下属', // my subordinates
myDepartment: '本部门', // my department
myDepartmentAndSubordinateDepartments: '本部门及下属部门',
test: '测试',
selectApp: '选择应用',
}
}
export default cs_zh

View File

@ -1,122 +1,106 @@
<template> <template>
<div> <div>
<vxe-table <vxe-table
ref="xTable" ref="xTable"
:data="tableData" :data="tableData"
size="mini" size="mini"
stripe stripe
class="ops-stripe-table" class="ops-stripe-table"
show-overflow show-overflow
:edit-config="{ showIcon: false, trigger: 'manual', mode: 'row' }" :edit-config="{ showIcon: false, trigger: 'manual', mode: 'row' }"
> >
<vxe-column v-for="col in columns" :key="col.field" :field="col.field" :title="col.title" :edit-render="{}"> <vxe-column v-for="col in columns" :key="col.field" :field="col.field" :title="col.title" :edit-render="{}">
<template #header> <span v-if="col.required" :style="{ color: 'red' }">* </span>{{ col.title }} </template> <template #header> <span v-if="col.required" :style="{ color: 'red' }">* </span>{{ col.title }} </template>
<template #edit="{ row }"> <template #edit="{ row }">
<vxe-input v-model="row[col.field]" type="text"></vxe-input> <vxe-input v-model="row[col.field]" type="text"></vxe-input>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column title="操作" width="80" v-if="!disabled"> <vxe-column :title="$t('operation')" width="80" v-if="!disabled">
<template #default="{ row }"> <template #default="{ row }">
<template v-if="$refs.xTable.isActiveByRow(row)"> <template v-if="$refs.xTable.isActiveByRow(row)">
<a @click="saveRowEvent(row)"><a-icon type="save"/></a> <a @click="saveRowEvent(row)"><a-icon type="save"/></a>
</template> </template>
<a-space v-else> <a-space v-else>
<a @click="editRowEvent(row)"><ops-icon type="icon-xianxing-edit"/></a> <a @click="editRowEvent(row)"><ops-icon type="icon-xianxing-edit"/></a>
<a style="color:red" @click="deleteRowEvent(row)"><ops-icon type="icon-xianxing-delete"/></a> <a style="color:red" @click="deleteRowEvent(row)"><ops-icon type="icon-xianxing-delete"/></a>
</a-space> </a-space>
</template> </template>
</vxe-column> </vxe-column>
</vxe-table> </vxe-table>
<div :style="{ color: '#f5222d' }" v-if="errorFlag">请完整填写机器人配置</div> <div :style="{ color: '#f5222d' }" v-if="errorFlag">{{ $t('cs.notice.robotConfigErrorTips') }}</div>
<a-button <a-button v-if="!disabled" icon="plus-circle" class="ops-button-primary" type="primary" @click="insertEvent">{{
v-if="!disabled" $t('add')
icon="plus-circle" }}</a-button>
class="ops-button-primary" </div>
type="primary" </template>
@click="insertEvent"
>添加</a-button <script>
> export default {
</div> name: 'Bot',
</template> props: {
columns: {
<script> type: Array,
export default { default: () => [],
name: 'Bot', },
props: { disabled: {
columns: { type: Boolean,
type: Array, default: false,
default: () => [ },
{ },
field: 'name', data() {
title: '名称', return {
required: true, tableData: [],
}, errorFlag: false,
{ }
field: 'url', },
title: 'Webhook地址', methods: {
required: true, async insertEvent() {
}, const $table = this.$refs.xTable
], const record = {
}, name: '',
disabled: { url: '',
type: Boolean, }
default: false, const { row: newRow } = await $table.insertAt(record, -1)
}, await $table.setActiveRow(newRow)
}, },
data() { saveRowEvent(row) {
return { const $table = this.$refs.xTable
tableData: [], $table.clearActived()
errorFlag: false, },
} editRowEvent(row) {
}, const $table = this.$refs.xTable
methods: { $table.setActiveRow(row)
async insertEvent() { },
const $table = this.$refs.xTable deleteRowEvent(row) {
const record = { const $table = this.$refs.xTable
name: '', $table.remove(row)
url: '', },
} getData(callback) {
const { row: newRow } = await $table.insertAt(record, -1) const $table = this.$refs.xTable
await $table.setActiveRow(newRow) const { fullData: _tableData } = $table.getTableData()
}, const requiredObj = {}
saveRowEvent(row) { this.columns.forEach((col) => {
const $table = this.$refs.xTable if (col.required) {
$table.clearActived() requiredObj[col.field] = true
}, }
editRowEvent(row) { })
const $table = this.$refs.xTable let flag = true
$table.setActiveRow(row) _tableData.forEach((td) => {
}, Object.keys(requiredObj).forEach((key) => {
deleteRowEvent(row) { if (requiredObj[key]) {
const $table = this.$refs.xTable flag = !!(flag && td[`${key}`])
$table.remove(row) }
}, })
getData(callback) { })
const $table = this.$refs.xTable this.errorFlag = !flag
const { fullData: _tableData } = $table.getTableData() callback(flag, _tableData)
const requiredObj = {} },
this.columns.forEach((col) => { setData(value) {
if (col.required) { this.tableData = value
requiredObj[col.field] = true this.errorFlag = false
} },
}) },
let flag = true }
_tableData.forEach((td) => { </script>
Object.keys(requiredObj).forEach((key) => {
if (requiredObj[key]) { <style></style>
flag = !!(flag && td[`${key}`])
}
})
})
this.errorFlag = !flag
callback(flag, _tableData)
},
setData(value) {
this.tableData = value
this.errorFlag = false
},
},
}
</script>
<style></style>

View File

@ -1,151 +1,151 @@
<template> <template>
<div class="notice-dingding-wrapper" :style="{ height: `${windowHeight - 64}px` }"> <div class="notice-dingding-wrapper" :style="{ height: `${windowHeight - 64}px` }">
<a-form-model ref="dingdingForm" :model="dingdingData" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-model ref="dingdingForm" :model="dingdingData" :label-col="labelCol" :wrapper-col="wrapperCol">
<SpanTitle>基础设置</SpanTitle> <SpanTitle>{{ $t('cs.duty.basicSetting') }}</SpanTitle>
<a-form-model-item label="应用Key"> <a-form-model-item :label="$t('cs.notice.appKey')">
<a-input v-model="dingdingData.appKey" :disabled="!isEditable" /> <a-input v-model="dingdingData.appKey" :disabled="!isEditable" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="应用密码"> <a-form-model-item :label="$t('cs.notice.appSecret')">
<a-input v-model="dingdingData.appSecret" :disabled="!isEditable" /> <a-input v-model="dingdingData.appSecret" :disabled="!isEditable" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="机器人码"> <a-form-model-item :label="$t('cs.notice.robotCode')">
<a-input v-model="dingdingData.robotCode" :disabled="!isEditable" /> <a-input v-model="dingdingData.robotCode" :disabled="!isEditable" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="机器人"> <a-form-model-item :label="$t('cs.notice.robot')">
<Bot <Bot
ref="bot" ref="bot"
:disabled="!isEditable" :disabled="!isEditable"
:columns="[ :columns="[
{ {
field: 'name', field: 'name',
title: '名称', title: $t('cs.notice.title'),
required: true, required: true,
}, },
{ {
field: 'url', field: 'url',
title: 'Webhook地址', title: $t('cs.notice.webhookAddress'),
required: true, required: true,
}, },
{ {
field: 'token', field: 'token',
title: 'token', title: 'token',
required: false, required: false,
}, },
]" ]"
/> />
</a-form-model-item> </a-form-model-item>
<!-- <a-form-model-item label="测试邮件设置"> <!-- <a-form-model-item :label="测试邮件设置">
<a-button type="primary" ghost>测试回收箱</a-button> <a-button type="primary" ghost>测试回收箱</a-button>
<br /> <br />
<span <span
class="notice-dingding-wrapper-tips" class="notice-dingding-wrapper-tips"
><ops-icon type="icon-shidi-quxiao" :style="{ color: '#D81E06' }" /> 邮件接收失败</span ><ops-icon type="icon-shidi-quxiao" :style="{ color: '#D81E06' }" /> 邮件接收失败</span
> >
<br /> <br />
<span>邮箱服务器未配置请配置一个邮箱服务器 | <a>故障诊断</a></span> <span>邮箱服务器未配置请配置一个邮箱服务器 | <a>故障诊断</a></span>
</a-form-model-item> --> </a-form-model-item> -->
<a-row v-if="isEditable"> <a-row v-if="isEditable">
<a-col :span="16" :offset="3"> <a-col :span="16" :offset="3">
<a-form-model-item :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-model-item :label-col="labelCol" :wrapper-col="wrapperCol">
<a-button type="primary" @click="onSubmit"> 保存 </a-button> <a-button type="primary" @click="onSubmit"> {{ $t('save') }} </a-button>
<a-button ghost type="primary" style="margin-left: 28px;" @click="resetForm"> 重置 </a-button> <a-button ghost type="primary" style="margin-left: 28px;" @click="resetForm"> {{ $t('reset') }} </a-button>
</a-form-model-item> </a-form-model-item>
</a-col> </a-col>
</a-row> </a-row>
</a-form-model> </a-form-model>
</div> </div>
</template> </template>
<script> <script>
import { mapState } from 'vuex' import { mapState } from 'vuex'
import SpanTitle from '../components/spanTitle.vue' import SpanTitle from '../components/spanTitle.vue'
import { getNoticeConfigByPlatform, postNoticeConfigByPlatform, putNoticeConfigByPlatform } from '@/api/noticeSetting' import { getNoticeConfigByPlatform, postNoticeConfigByPlatform, putNoticeConfigByPlatform } from '@/api/noticeSetting'
import { mixinPermissions } from '@/utils/mixin' import { mixinPermissions } from '@/utils/mixin'
import Bot from './bot.vue' import Bot from './bot.vue'
export default { export default {
name: 'NoticeDingding', name: 'NoticeDingding',
components: { SpanTitle, Bot }, components: { SpanTitle, Bot },
mixins: [mixinPermissions], mixins: [mixinPermissions],
data() { data() {
return { return {
labelCol: { lg: 3, md: 5, sm: 8 }, labelCol: { lg: 3, md: 5, sm: 8 },
wrapperCol: { lg: 15, md: 19, sm: 16 }, wrapperCol: { lg: 15, md: 19, sm: 16 },
id: null, id: null,
dingdingData: { dingdingData: {
appKey: '', appKey: '',
appSecret: '', appSecret: '',
robotCode: '', robotCode: '',
}, },
} }
}, },
computed: { computed: {
...mapState({ ...mapState({
windowHeight: (state) => state.windowHeight, windowHeight: (state) => state.windowHeight,
}), }),
isEditable() { isEditable() {
return this.hasDetailPermission('backend', '通知设置', ['update']) return this.hasDetailPermission('backend', '通知设置', ['update'])
}, },
}, },
mounted() { mounted() {
this.getData() this.getData()
}, },
methods: { methods: {
getData() { getData() {
getNoticeConfigByPlatform({ platform: 'dingdingApp' }).then((res) => { getNoticeConfigByPlatform({ platform: 'dingdingApp' }).then((res) => {
this.id = res?.id ?? null this.id = res?.id ?? null
if (this.id) { if (this.id) {
this.dingdingData = res.info this.dingdingData = res.info
this.$refs.bot.setData(res?.info?.bot) this.$refs.bot.setData(res?.info?.bot)
} }
}) })
}, },
onSubmit() { onSubmit() {
this.$refs.dingdingForm.validate(async (valid) => { this.$refs.dingdingForm.validate(async (valid) => {
if (valid) { if (valid) {
this.$refs.bot.getData(async (flag, bot) => { this.$refs.bot.getData(async (flag, bot) => {
if (flag) { if (flag) {
if (this.id) { if (this.id) {
await putNoticeConfigByPlatform(this.id, { info: { ...this.dingdingData, bot, label: '钉钉' } }) await putNoticeConfigByPlatform(this.id, { info: { ...this.dingdingData, bot, label: this.$t('cs.person.dingdingApp') } })
} else { } else {
await postNoticeConfigByPlatform({ await postNoticeConfigByPlatform({
platform: 'dingdingApp', platform: 'dingdingApp',
info: { ...this.dingdingData, bot, label: '钉钉' }, info: { ...this.dingdingData, bot, label: this.$t('cs.person.dingdingApp') },
}) })
} }
this.$message.success('保存成功') this.$message.success(this.$t('saveSuccess'))
this.getData() this.getData()
} }
}) })
} }
}) })
}, },
resetForm() { resetForm() {
this.dingdingData = { this.dingdingData = {
appKey: '', appKey: '',
appSecret: '', appSecret: '',
robotCode: '', robotCode: '',
} }
}, },
}, },
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.notice-dingding-wrapper { .notice-dingding-wrapper {
background-color: #fff; background-color: #fff;
padding-top: 15px; padding-top: 15px;
overflow: auto; overflow: auto;
margin-bottom: -24px; margin-bottom: -24px;
border-radius: 15px; border-radius: 15px;
.notice-dingding-wrapper-tips { .notice-dingding-wrapper-tips {
display: inline-block; display: inline-block;
background-color: #ffdfdf; background-color: #ffdfdf;
border-radius: 4px; border-radius: 4px;
padding: 0 12px; padding: 0 12px;
width: 300px; width: 300px;
color: #000000; color: #000000;
margin-top: 8px; margin-top: 8px;
} }
} }
</style> </style>

View File

@ -1,17 +1,17 @@
.notice-email-wrapper { .notice-email-wrapper {
background-color: #fff; background-color: #fff;
padding-top: 24px; padding-top: 24px;
overflow: auto; overflow: auto;
.notice-email-error-tips { .notice-email-error-tips {
display: inline-block; display: inline-block;
background-color: #ffdfdf; background-color: #ffdfdf;
border-radius: 4px; border-radius: 4px;
padding: 0 12px; padding: 0 12px;
width: 300px; width: 300px;
color: #000000; color: #000000;
margin-top: 8px; margin-top: 8px;
} }
.ant-form-item { .ant-form-item {
margin-bottom: 10px; margin-bottom: 10px;
} }
} }

View File

@ -1,33 +1,33 @@
<template> <template>
<div :style="{ marginBottom: '-24px' }"> <div :style="{ marginBottom: '-24px' }">
<a-tabs :activeKey="activeKey" @change="changeTab" class="ops-tab" type="card"> <a-tabs :activeKey="activeKey" @change="changeTab" class="ops-tab" type="card">
<!-- <a-tab-pane key="1" tab="接收服务器"> <!-- <a-tab-pane key="1" tab="接收服务器">
<Receive /> <Receive />
</a-tab-pane> --> </a-tab-pane> -->
<a-tab-pane key="2" tab="发送服务器"> <a-tab-pane key="2" :tab="$t('cs.notice.sendServer')">
<Send /> <Send />
</a-tab-pane> </a-tab-pane>
</a-tabs> </a-tabs>
</div> </div>
</template> </template>
<script> <script>
import Receive from './receive.vue' import Receive from './receive.vue'
import Send from './send.vue' import Send from './send.vue'
export default { export default {
name: 'NoticeEmail', name: 'NoticeEmail',
components: { Receive, Send }, components: { Receive, Send },
data() { data() {
return { return {
activeKey: '2', activeKey: '2',
} }
}, },
methods: { methods: {
changeTab(activeKey) { changeTab(activeKey) {
this.activeKey = activeKey this.activeKey = activeKey
}, },
}, },
} }
</script> </script>
<style></style> <style></style>

View File

@ -1,196 +1,196 @@
<template> <template>
<div class="notice-email-wrapper" :style="{ height: `${windowHeight - 104}px` }"> <div class="notice-email-wrapper" :style="{ height: `${windowHeight - 104}px` }">
<a-form-model :model="settingData" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-model :model="settingData" :label-col="labelCol" :wrapper-col="wrapperCol">
<SpanTitle>基础设置</SpanTitle> <SpanTitle>{{ $t('cs.duty.basicSetting') }}</SpanTitle>
<a-form-model-item label="连接协议"> <a-form-model-item :label="$t('cs.notice.connectProtocol')">
<a-radio-group v-model="settingData.connectProtocol" :default-value="1" @change="changeConnectProtocol"> <a-radio-group v-model="settingData.connectProtocol" :default-value="1" @change="changeConnectProtocol">
<a-radio :value="1" :default-checked="true"> POP/IMAP/POPS/IMAPS </a-radio> <a-radio :value="1" :default-checked="true"> POP/IMAP/POPS/IMAPS </a-radio>
<a-radio :value="2"> EWS(Exchange Web服务) </a-radio> <a-radio :value="2">{{ $t('cs.notice.ews') }}</a-radio>
</a-radio-group> </a-radio-group>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="认证类型"> <a-form-model-item :label="$t('cs.notice.authType')">
<a-select v-model="settingData.authentication"> <a-select v-model="settingData.authentication">
<a-select-option value="Base"> 基本 </a-select-option> <a-select-option value="Base"> {{ $t('cs.notice.base') }} </a-select-option>
<a-select-option value="OAuth"> OAuth </a-select-option> <a-select-option value="OAuth"> {{ $t('cs.notice.oauth') }} </a-select-option>
</a-select> </a-select>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="服务器名/IP地址" prop="IP"> <a-form-model-item :label="$t('cs.notice.ip')" prop="IP">
<a-input v-model="settingData.IP" /> <a-input v-model="settingData.IP" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="用户名"> <a-form-model-item :label="$t('cs.notice.username')">
<a-input v-model="settingData.username" /> <a-input v-model="settingData.username" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="密码"> <a-form-model-item :label="$t('cs.notice.password')">
<a-input v-model="settingData.password" /> <a-input v-model="settingData.password" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="邮件地址"> <a-form-model-item :label="$t('cs.notice.email')">
<a-input v-model="settingData.email" /> <a-input v-model="settingData.email" />
</a-form-model-item> </a-form-model-item>
<template v-if="settingData.connectProtocol === 1"> <template v-if="settingData.connectProtocol === 1">
<a-form-model-item label="邮件类型"> <a-form-model-item :label="$t('cs.notice.emailType')">
<a-select v-model="settingData.emailType"> <a-select v-model="settingData.emailType">
<a-select-option value="POP"> POP </a-select-option> <a-select-option value="POP"> POP </a-select-option>
<a-select-option value="IMAP"> IMAP </a-select-option> <a-select-option value="IMAP"> IMAP </a-select-option>
<a-select-option value="POPS"> POPS </a-select-option> <a-select-option value="POPS"> POPS </a-select-option>
<a-select-option value="IMAPS"> IMAPS </a-select-option> <a-select-option value="IMAPS"> IMAPS </a-select-option>
</a-select> </a-select>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="端口"> <a-form-model-item :label="$t('cs.notice.port')">
<a-input v-model="settingData.port" /> <a-input v-model="settingData.port" />
</a-form-model-item> </a-form-model-item>
</template> </template>
<a-form-model-item label="测试邮件设置"> <a-form-model-item :label="$t('cs.notice.oauth')">
<a-button type="primary" ghost>测试回收箱</a-button> <a-button type="primary" ghost>{{ $t('cs.notice.testRecyclingBin') }}</a-button>
<br /> <br />
<span class="notice-email-error-tips"> <span class="notice-email-error-tips">
<ops-icon type="icon-shidi-quxiao" :style="{ color: '#D81E06' }" /> <ops-icon type="icon-shidi-quxiao" :style="{ color: '#D81E06' }" />
邮件接收失败 {{ $t('cs.notice.receiveEmailFailed') }}
</span> </span>
<br /> <br />
<span <span
>邮箱服务器未配置请配置一个邮箱服务器 <a-divider type="vertical" :style="{ backgroundColor: '#2F54EB' }" /> >{{ $('cs.notice.emailServiceNotConfig') }} <a-divider type="vertical" :style="{ backgroundColor: '#2F54EB' }" />
<a>故障诊断</a></span <a>{{ $('cs.notice.troubleshooting') }}</a></span
> >
</a-form-model-item> </a-form-model-item>
<SpanTitle>邮件设置</SpanTitle> <SpanTitle>{{ $('cs.notice.emailConfig') }}</SpanTitle>
<a-form-model-item label="获取邮件间隔" :wrapperCol="{ span: 4 }"> <a-form-model-item :label="$('cs.notice.receiveEmailInterval')" :wrapperCol="{ span: 4 }">
<a-input class="ant-input-after" v-model="settingData.getEmailTimeout" /> <a-input class="ant-input-after" v-model="settingData.getEmailTimeout" />
<span :style="{ position: 'absolute', marginLeft: '8px' }"></span> <span :style="{ position: 'absolute', marginLeft: '8px' }">{{ $t('cs.duty.min') }}</span>
</a-form-model-item> </a-form-model-item>
<a-row> <a-row>
<a-col :span="16" :offset="3"> <a-col :span="16" :offset="3">
<a-checkbox :default-checked="false" disabled>启动代理服务器</a-checkbox> <a-checkbox :default-checked="false" disabled>{{ $('cs.notice.startProxyServer') }}</a-checkbox>
<a-icon type="info-circle" :style="{ color: '#FF9E58', fontSize: '16px' }" /> <a-icon type="info-circle" :style="{ color: '#FF9E58', fontSize: '16px' }" />
<a-divider type="vertical" :style="{ backgroundColor: '#2F54EB' }" /> <a-divider type="vertical" :style="{ backgroundColor: '#2F54EB' }" />
<a @click="configProxySetting">配置代理设置</a> <a @click="configProxySetting">{{ $('cs.notice.configProxyServer') }}</a>
<br /> <br />
<a-checkbox :default-checked="false">启动邮件测试</a-checkbox> <a-checkbox :default-checked="false">{{ $('cs.notice.startEmailTest') }}</a-checkbox>
<br /><br /> <br /><br />
<a-checkbox :default-checked="false" @change="changeCreateReqByEmail">禁用通过邮件创建请求</a-checkbox> <a-checkbox :default-checked="false" @change="changeCreateReqByEmail">{{ $('cs.notice.disableCreationOfRequestsViaEmail') }}</a-checkbox>
<br /> <br />
<template v-if="settingData.banReqByEmail"> <template v-if="settingData.banReqByEmail">
<strong>指定允许的邮件/域名,逗号分隔多个值</strong> <strong>{{ $('cs.notice.specifyAllowedEmails') }}</strong>
<a-input type="textarea" :style="{ borderRadius: '8px', borderColor: '#2F54EB' }" /> <a-input type="textarea" :style="{ borderRadius: '8px', borderColor: '#2F54EB' }" />
<p :style="{ fontSize: '12px' }">例如:user@domain.com,*@domain.com</p> <p :style="{ fontSize: '12px' }">{{ $('cs.notice.specifyAllowedEmailsExample') }}</p>
<p :style="{ fontSize: '12px' }">限制不能适用于已在会话中的请求,它将聚集到它的上级工单中</p> <p :style="{ fontSize: '12px' }">{{ $('cs.notice.specifyAllowedEmailsLimit') }}</p>
</template> </template>
</a-col> </a-col>
</a-row> </a-row>
<SpanTitle>消息设置</SpanTitle> <SpanTitle>{{ $('cs.notice.messageConfig') }}</SpanTitle>
<a-row> <a-row>
<a-col :span="16" :offset="3"> <a-col :span="16" :offset="3">
<a-checkbox :default-checked="false">将消息移动到错误的文件夹</a-checkbox> <a-checkbox :default-checked="false">{{ $('cs.notice.moveWrongMessagesToFolder') }}</a-checkbox>
<a-icon type="info-circle" :style="{ color: '#FF9E58', fontSize: '16px' }" /> <a-icon type="info-circle" :style="{ color: '#FF9E58', fontSize: '16px' }" />
<a-divider type="vertical" :style="{ backgroundColor: '#2F54EB' }" /> <a-divider type="vertical" :style="{ backgroundColor: '#2F54EB' }" />
<a href="#">了解更多</a> <a href="#">{{ $('cs.notice.knowMore') }}</a>
</a-col> </a-col>
</a-row> </a-row>
<br /><br /> <br /><br />
<a-row> <a-row>
<a-col :span="16" :offset="3"> <a-col :span="16" :offset="3">
<a-form-model-item :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-model-item :label-col="labelCol" :wrapper-col="wrapperCol">
<a-button type="primary" @click="onSubmit"> 保存 </a-button> <a-button type="primary" @click="onSubmit"> {{ $('save') }} </a-button>
<a-button ghost type="primary" style="margin-left: 28px;" @click="resetForm"> 重置 </a-button> <a-button ghost type="primary" style="margin-left: 28px;" @click="resetForm"> {{ $('reset') }} </a-button>
</a-form-model-item> </a-form-model-item>
</a-col> </a-col>
</a-row> </a-row>
</a-form-model> </a-form-model>
<a-modal dialogClass="ops-modal" width="500px" v-model="visible" title="配置代理设置"> <a-modal dialogClass="ops-modal" width="500px" v-model="visible" :title="$('cs.notice.configProxySettings')">
<a-form-model v-model="proxySetting" :label-col="{ span: 4 }" :wrapper-col="{ span: 19 }"> <a-form-model v-model="proxySetting" :label-col="{ span: 4 }" :wrapper-col="{ span: 19 }">
<a-form-model-item label="主机"> <a-form-model-item :label="$('cs.notice.host')">
<a-input v-model="proxySetting.host" /> <a-input v-model="proxySetting.host" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="端口"> <a-form-model-item :label="$('cs.notice.port')">
<a-input v-model="proxySetting.port" /> <a-input v-model="proxySetting.port" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="用户名"> <a-form-model-item :label="$('cs.notice.username')">
<a-input v-model="proxySetting.username" /> <a-input v-model="proxySetting.username" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="密码"> <a-form-model-item :label="$('cs.notice.password')">
<a-input v-model="proxySetting.password" /> <a-input v-model="proxySetting.password" />
</a-form-model-item> </a-form-model-item>
</a-form-model> </a-form-model>
</a-modal> </a-modal>
</div> </div>
</template> </template>
<script> <script>
import { mapState } from 'vuex' import { mapState } from 'vuex'
import SpanTitle from '../../components/spanTitle.vue' import SpanTitle from '../../components/spanTitle.vue'
export default { export default {
name: 'Receive', name: 'Receive',
components: { SpanTitle }, components: { SpanTitle },
data() { data() {
return { return {
labelCol: { span: 3 }, labelCol: { span: 3 },
wrapperCol: { span: 10 }, wrapperCol: { span: 10 },
settingData: { settingData: {
connectProtocol: 1, connectProtocol: 1,
authentication: 'Base', authentication: 'Base',
IP: '', IP: '',
username: '', username: '',
password: '', password: '',
email: '', email: '',
emailType: '', emailType: '',
port: '', port: '',
getEmailTimeout: '', getEmailTimeout: '',
activeProxy: false, activeProxy: false,
activeEmailDebug: false, activeEmailDebug: false,
banReqByEmail: false, banReqByEmail: false,
transfromMessage: false, transfromMessage: false,
}, },
visible: false, visible: false,
proxySetting: { proxySetting: {
host: '', host: '',
post: '', post: '',
username: '', username: '',
password: '', password: '',
}, },
} }
}, },
computed: { computed: {
...mapState({ ...mapState({
windowHeight: (state) => state.windowHeight, windowHeight: (state) => state.windowHeight,
}), }),
}, },
methods: { methods: {
changeConnectProtocol(e) { changeConnectProtocol(e) {
console.log(e.target.value) console.log(e.target.value)
}, },
changeCreateReqByEmail(e) { changeCreateReqByEmail(e) {
this.settingData.banReqByEmail = e.target.checked this.settingData.banReqByEmail = e.target.checked
}, },
configProxySetting() { configProxySetting() {
this.visible = true this.visible = true
}, },
onSubmit() { onSubmit() {
console.log(this.settingData) console.log(this.settingData)
}, },
resetForm() { resetForm() {
this.settingData = { this.settingData = {
connectProtocol: 1, connectProtocol: 1,
authentication: '', authentication: '',
IP: '', IP: '',
username: '', username: '',
password: '', password: '',
email: '', email: '',
emailType: '', emailType: '',
port: '', port: '',
getEmailTimeout: '', getEmailTimeout: '',
activeProxy: false, activeProxy: false,
activeEmailDebug: false, activeEmailDebug: false,
banReqByEmail: false, banReqByEmail: false,
transfromMessage: false, transfromMessage: false,
} }
}, },
}, },
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import './index.less'; @import './index.less';
</style> </style>

View File

@ -1,169 +1,171 @@
<template> <template>
<div class="notice-email-wrapper" :style="{ height: `${windowHeight - 104}px` }"> <div class="notice-email-wrapper" :style="{ height: `${windowHeight - 104}px` }">
<a-form-model ref="sendForm" :model="settingData" :label-col="labelCol" :rules="rules" :wrapper-col="wrapperCol"> <a-form-model ref="sendForm" :model="settingData" :label-col="labelCol" :rules="rules" :wrapper-col="wrapperCol">
<SpanTitle>基础设置</SpanTitle> <SpanTitle>{{ $t('cs.duty.basicSetting') }}</SpanTitle>
<a-form-model-item label="是否加密"> <a-form-model-item :label="$t('cs.notice.isEncrypted')">
<a-radio-group v-model="settingData.tls" :disabled="!isEditable"> <a-radio-group v-model="settingData.tls" :disabled="!isEditable">
<a-radio :value="true"> <a-radio :value="true">
{{ $t('yes') }}
</a-radio> </a-radio>
<a-radio :value="false"> <a-radio :value="false">
{{ $t('no') }}
</a-radio> </a-radio>
</a-radio-group> </a-radio-group>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="端口" prop="port"> <a-form-model-item :label="$t('cs.notice.port')" prop="port">
<a-input v-model="settingData.port" :disabled="!isEditable" /> <a-input v-model="settingData.port" :disabled="!isEditable" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="邮件服务器" prop="host"> <a-form-model-item :label="$t('cs.notice.host')" prop="host">
<a-input v-model="settingData.host" :disabled="!isEditable" /> <a-input v-model="settingData.host" :disabled="!isEditable" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="用户名" prop="account"> <a-form-model-item :label="$t('cs.notice.username')" prop="account">
<a-input v-model="settingData.account" :disabled="!isEditable" /> <a-input v-model="settingData.account" :disabled="!isEditable" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="密码" prop="password"> <a-form-model-item :label="$t('cs.notice.password')" prop="password">
<a-input-password v-model="settingData.password" :disabled="!isEditable" /> <a-input-password v-model="settingData.password" :disabled="!isEditable" />
</a-form-model-item> </a-form-model-item>
<SpanTitle>邮件测试</SpanTitle> <SpanTitle>{{ $t('cs.notice.emailTest') }}</SpanTitle>
<a-form-model-item label="测试发送邮件地址" prop="receive_address"> <a-form-model-item :label="$t('cs.notice.testSendAddress')" prop="receive_address">
<a-input v-model="settingData.receive_address" :disabled="!isEditable"> <a-input v-model="settingData.receive_address" :disabled="!isEditable">
<span <span
v-if="isEditable" v-if="isEditable"
:style="{ cursor: 'pointer' }" :style="{ cursor: 'pointer' }"
@click="testSendEmail" @click="testSendEmail"
slot="addonAfter" slot="addonAfter"
>测试邮件发送</span >{{ $t('cs.notice.testMailSend') }}</span
> >
</a-input> </a-input>
</a-form-model-item> </a-form-model-item>
<a-row v-if="isEditable"> <a-row v-if="isEditable">
<a-col :span="16" :offset="3"> <a-col :span="16" :offset="3">
<a-form-model-item :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-model-item :label-col="labelCol" :wrapper-col="wrapperCol">
<a-button type="primary" @click="onSubmit"> 保存 </a-button> <a-button type="primary" @click="onSubmit"> {{ $t('save') }} </a-button>
<a-button ghost type="primary" style="margin-left: 28px;" @click="resetForm"> 重置 </a-button> <a-button ghost type="primary" style="margin-left: 28px;" @click="resetForm"> {{ $t('reset') }} </a-button>
</a-form-model-item> </a-form-model-item>
</a-col> </a-col>
</a-row> </a-row>
</a-form-model> </a-form-model>
</div> </div>
</template> </template>
<script> <script>
import { mapState } from 'vuex' import { mapState } from 'vuex'
import SpanTitle from '../../components/spanTitle.vue' import SpanTitle from '../../components/spanTitle.vue'
import { import {
getNoticeConfigByPlatform, getNoticeConfigByPlatform,
postNoticeConfigByPlatform, postNoticeConfigByPlatform,
putNoticeConfigByPlatform, putNoticeConfigByPlatform,
sendTestEmail, sendTestEmail,
} from '@/api/noticeSetting' } from '@/api/noticeSetting'
import { mixinPermissions } from '@/utils/mixin' import { mixinPermissions } from '@/utils/mixin'
export default { export default {
name: 'Send', name: 'Send',
mixins: [mixinPermissions], mixins: [mixinPermissions],
components: { SpanTitle }, components: { SpanTitle },
data() { data() {
return { return {
labelCol: { lg: 3, md: 5, sm: 8 }, labelCol: { lg: 3, md: 5, sm: 8 },
wrapperCol: { lg: 10, md: 12, sm: 12 }, wrapperCol: { lg: 10, md: 12, sm: 12 },
id: null, id: null,
settingData: { settingData: {
tls: true, tls: true,
host: '', host: '',
account: '', account: '',
password: '', password: '',
port: '', port: '',
receive_address: '', receive_address: '',
}, }
rules: { }
port: [{ required: true, message: '请输入端口', trigger: 'blur' }], },
host: [{ required: true, whitespace: true, message: '请输入服务器', trigger: 'blur' }], computed: {
account: [ ...mapState({
{ required: true, whitespace: true, message: '请输入用户名', trigger: 'blur' }, rules() {
{ return {
pattern: /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/, port: [{ required: true, message: this.$t('cs.notice.portPlaceholder'), trigger: 'blur' }],
message: '邮箱格式错误', host: [{ required: true, whitespace: true, message: this.$t('cs.auth.ldap.serverAddressPlaceholder'), trigger: 'blur' }],
trigger: 'blur', account: [
}, { required: true, whitespace: true, message: this.$t('cs.auth.ldap.userPlaceholder'), trigger: 'blur' },
], {
password: [{ required: false, whitespace: true, message: '请输入密码', trigger: 'blur' }], pattern: /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/,
receive_address: [ message: this.$t('cs.companyStructure.emailFormatErr'),
{ required: false, whitespace: true, message: '请输入测试发送邮件地址', trigger: 'blur' }, trigger: 'blur',
{ },
pattern: /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/, ],
message: '邮箱格式错误', password: [{ required: false, whitespace: true, message: this.$t('cs.companyStructure.passwordPlaceholder'), trigger: 'blur' }],
trigger: 'blur', receive_address: [
}, { required: false, whitespace: true, message: this.$t('cs.notice.testSendAddressPlaceholder'), trigger: 'blur' },
], {
}, 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'),
}, trigger: 'blur',
computed: { },
...mapState({ ]
windowHeight: (state) => state.windowHeight, }
}), },
isEditable() { windowHeight: (state) => state.windowHeight,
return this.hasDetailPermission('backend', '通知设置', ['update']) }),
}, isEditable() {
}, return this.hasDetailPermission('backend', '通知设置', ['update'])
watch: { },
'settingData.tls': { },
handler(newV, oldV) { watch: {
if (newV === false) { 'settingData.tls': {
this.settingData.port = 25 handler(newV, oldV) {
} if (newV === false) {
if (newV === true) { this.settingData.port = 25
this.settingData.port = 465 }
} if (newV === true) {
}, this.settingData.port = 465
immediate: true, }
}, },
}, immediate: true,
mounted() { },
this.getData() },
}, mounted() {
methods: { this.getData()
getData() { },
getNoticeConfigByPlatform({ platform: 'email' }).then((res) => { methods: {
this.id = res?.id ?? null getData() {
if (this.id) { getNoticeConfigByPlatform({ platform: 'email' }).then((res) => {
this.settingData = res.info this.id = res?.id ?? null
} if (this.id) {
}) this.settingData = res.info
}, }
async testSendEmail() { })
await sendTestEmail(this.settingData.receive_address, { },
info: { ...this.settingData, receive_address: undefined }, async testSendEmail() {
}) await sendTestEmail(this.settingData.receive_address, {
this.$message.success('已发送邮件,请查收') info: { ...this.settingData, receive_address: undefined },
}, })
onSubmit() { this.$message.success(this.$t('cs.notice.emailSendSuccess'))
this.$refs.sendForm.validate(async (valid) => { },
if (valid) { onSubmit() {
if (this.id) { this.$refs.sendForm.validate(async (valid) => {
await putNoticeConfigByPlatform(this.id, { info: { ...this.settingData, label: '邮箱' } }) if (valid) {
} else { if (this.id) {
await postNoticeConfigByPlatform({ platform: 'email', info: { ...this.settingData, label: '邮箱' } }) await putNoticeConfigByPlatform(this.id, { info: { ...this.settingData, label: this.$t('cs.companyInfo.email') } })
} } else {
this.$message.success('保存成功') await postNoticeConfigByPlatform({ platform: 'email', info: { ...this.settingData, label: this.$t('cs.companyInfo.email') } })
this.getData() }
} this.$message.success(this.$t('saveSuccess'))
}) this.getData()
}, }
resetForm() { })
this.settingData = { },
tls: true, resetForm() {
host: '', this.settingData = {
account: '', tls: true,
password: '', host: '',
port: 25, account: '',
receive_address: '', password: '',
} port: 25,
}, receive_address: '',
}, }
} },
</script> },
}
<style lang="less" scoped> </script>
@import './index.less';
</style> <style lang="less" scoped>
@import './index.less';
</style>

View File

@ -1,131 +1,131 @@
<template> <template>
<div class="notice-feishu-wrapper" :style="{ height: `${windowHeight - 64}px` }"> <div class="notice-feishu-wrapper" :style="{ height: `${windowHeight - 64}px` }">
<a-form-model ref="feishuForm" :model="feishuData" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-model ref="feishuForm" :model="feishuData" :label-col="labelCol" :wrapper-col="wrapperCol">
<SpanTitle>基础设置</SpanTitle> <SpanTitle>{{ $t('cs.duty.basicSetting') }}</SpanTitle>
<a-form-model-item label="应用ID"> <a-form-model-item :label="$t('cs.notice.appKey')">
<a-input v-model="feishuData.id" :disabled="!isEditable" /> <a-input v-model="feishuData.id" :disabled="!isEditable" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="应用密码"> <a-form-model-item :label="$t('cs.notice.appSecret')">
<a-input v-model="feishuData.password" :disabled="!isEditable" /> <a-input v-model="feishuData.password" :disabled="!isEditable" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="机器人"> <a-form-model-item :label="$t('cs.notice.robot')">
<Bot <Bot
ref="bot" ref="bot"
:disabled="!isEditable" :disabled="!isEditable"
:columns="[ :columns="[
{ {
field: 'name', field: 'name',
title: '名称', title: $t('cs.notice.title'),
required: true, required: true,
}, },
{ {
field: 'url', field: 'url',
title: 'Webhook地址', title: $t('cs.notice.webhookAddress'),
required: true, required: true,
}, },
]" ]"
/> />
</a-form-model-item> </a-form-model-item>
<a-row v-if="isEditable"> <a-row v-if="isEditable">
<a-col :span="16" :offset="3"> <a-col :span="16" :offset="3">
<a-form-model-item :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-model-item :label-col="labelCol" :wrapper-col="wrapperCol">
<a-button type="primary" @click="onSubmit"> 保存 </a-button> <a-button type="primary" @click="onSubmit"> {{ $t('save') }} </a-button>
<a-button ghost type="primary" style="margin-left: 28px;" @click="resetForm"> 重置 </a-button> <a-button ghost type="primary" style="margin-left: 28px;" @click="resetForm"> {{ $t('reset') }} </a-button>
</a-form-model-item> </a-form-model-item>
</a-col> </a-col>
</a-row> </a-row>
</a-form-model> </a-form-model>
</div> </div>
</template> </template>
<script> <script>
import { mapState } from 'vuex' import { mapState } from 'vuex'
import SpanTitle from '../components/spanTitle.vue' import SpanTitle from '../components/spanTitle.vue'
import { getNoticeConfigByPlatform, postNoticeConfigByPlatform, putNoticeConfigByPlatform } from '@/api/noticeSetting' import { getNoticeConfigByPlatform, postNoticeConfigByPlatform, putNoticeConfigByPlatform } from '@/api/noticeSetting'
import { mixinPermissions } from '@/utils/mixin' import { mixinPermissions } from '@/utils/mixin'
import Bot from './bot.vue' import Bot from './bot.vue'
export default { export default {
name: 'NoticeFeishu', name: 'NoticeFeishu',
components: { SpanTitle, Bot }, components: { SpanTitle, Bot },
mixins: [mixinPermissions], mixins: [mixinPermissions],
data() { data() {
return { return {
labelCol: { lg: 3, md: 5, sm: 8 }, labelCol: { lg: 3, md: 5, sm: 8 },
wrapperCol: { lg: 15, md: 19, sm: 16 }, wrapperCol: { lg: 15, md: 19, sm: 16 },
id: null, id: null,
feishuData: { feishuData: {
id: '', id: '',
password: '', password: '',
}, },
} }
}, },
computed: { computed: {
...mapState({ ...mapState({
windowHeight: (state) => state.windowHeight, windowHeight: (state) => state.windowHeight,
}), }),
isEditable() { isEditable() {
return this.hasDetailPermission('backend', '通知设置', ['update']) return this.hasDetailPermission('backend', '通知设置', ['update'])
}, },
}, },
mounted() { mounted() {
this.getData() this.getData()
}, },
methods: { methods: {
getData() { getData() {
getNoticeConfigByPlatform({ platform: 'feishuApp' }).then((res) => { getNoticeConfigByPlatform({ platform: 'feishuApp' }).then((res) => {
this.id = res?.id ?? null this.id = res?.id ?? null
if (this.id) { if (this.id) {
this.feishuData = res.info this.feishuData = res.info
this.$refs.bot.setData(res?.info?.bot) this.$refs.bot.setData(res?.info?.bot)
} }
}) })
}, },
onSubmit() { onSubmit() {
this.$refs.feishuForm.validate(async (valid) => { this.$refs.feishuForm.validate(async (valid) => {
if (valid) { if (valid) {
this.$refs.bot.getData(async (flag, bot) => { this.$refs.bot.getData(async (flag, bot) => {
if (flag) { if (flag) {
if (this.id) { if (this.id) {
await putNoticeConfigByPlatform(this.id, { info: { ...this.feishuData, bot, label: '飞书' } }) await putNoticeConfigByPlatform(this.id, { info: { ...this.feishuData, bot, label: this.$t('cs.person.feishuApp') } })
} else { } else {
await postNoticeConfigByPlatform({ await postNoticeConfigByPlatform({
platform: 'feishuApp', platform: 'feishuApp',
info: { ...this.feishuData, bot, label: '飞书' }, info: { ...this.feishuData, bot, label: this.$t('cs.person.feishuApp') },
}) })
} }
this.$message.success('保存成功') this.$message.success(this.$t('saveSuccess'))
this.getData() this.getData()
} }
}) })
} }
}) })
}, },
resetForm() { resetForm() {
this.feishuData = { this.feishuData = {
id: '', id: '',
password: '', password: '',
} }
}, },
}, },
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.notice-feishu-wrapper { .notice-feishu-wrapper {
background-color: #fff; background-color: #fff;
padding-top: 15px; padding-top: 15px;
overflow: auto; overflow: auto;
margin-bottom: -24px; margin-bottom: -24px;
border-radius: 15px; border-radius: 15px;
.notice-feishu-wrapper-tips { .notice-feishu-wrapper-tips {
display: inline-block; display: inline-block;
background-color: #ffdfdf; background-color: #ffdfdf;
border-radius: 4px; border-radius: 4px;
padding: 0 12px; padding: 0 12px;
width: 300px; width: 300px;
color: #000000; color: #000000;
margin-top: 8px; margin-top: 8px;
} }
} }
</style> </style>

View File

@ -1,135 +1,152 @@
<template> <template>
<div class="notice-wx-wrapper" :style="{ height: `${windowHeight - 64}px` }"> <div class="notice-wx-wrapper" :style="{ height: `${windowHeight - 64}px` }">
<a-form-model ref="wxForm" :model="wxData" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form-model ref="wxForm" :model="wxData" :label-col="labelCol" :wrapper-col="wrapperCol">
<SpanTitle>基础设置</SpanTitle> <SpanTitle>{{ $t('cs.duty.basicSetting') }}</SpanTitle>
<a-form-model-item label="企业ID"> <a-form-model-item :label="$t('cs.notice.corpid')">
<a-input v-model="wxData.corpid" :disabled="!isEditable" /> <a-input v-model="wxData.corpid" :disabled="!isEditable" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="自建应用ID"> <a-form-model-item :label="$t('cs.notice.agentid')">
<a-input v-model="wxData.agentid" :disabled="!isEditable" /> <a-input v-model="wxData.agentid" :disabled="!isEditable" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="自建应用密码"> <a-form-model-item :label="$t('cs.notice.corpsecret')">
<a-input-password v-model="wxData.corpsecret" :disabled="!isEditable" /> <a-input-password v-model="wxData.corpsecret" :disabled="!isEditable" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="ITSM AppId"> <a-form-model-item label="ITSM AppId">
<a-input v-model="wxData.itsm_app_id" :disabled="!isEditable" /> <a-input v-model="wxData.itsm_app_id" :disabled="!isEditable" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="机器人"> <a-form-model-item :label="$t('cs.notice.robot')">
<Bot ref="bot" :disabled="!isEditable" /> <Bot
</a-form-model-item> ref="bot"
<!-- <a-form-model-item label="测试邮件设置"> :disabled="!isEditable"
<a-button type="primary" ghost>测试回收箱</a-button> :columns="[
<br /> {
<span field: 'name',
class="notice-wx-wrapper-tips" title: $t('cs.notice.title'),
><ops-icon type="icon-shidi-quxiao" :style="{ color: '#D81E06' }" /> 邮件接收失败</span required: true,
> },
<br /> {
<span>邮箱服务器未配置请配置一个邮箱服务器 | <a>故障诊断</a></span> field: 'url',
</a-form-model-item> --> title: $t('cs.notice.webhookAddress'),
<a-row v-if="isEditable"> required: true,
<a-col :span="16" :offset="3"> },
<a-form-model-item :label-col="labelCol" :wrapper-col="wrapperCol"> ]"
<a-button type="primary" @click="onSubmit"> 保存 </a-button> />
<a-button ghost type="primary" style="margin-left: 28px;" @click="resetForm"> 重置 </a-button> </a-form-model-item>
</a-form-model-item> <!-- <a-form-model-item :label="测试邮件设置">
</a-col> <a-button type="primary" ghost>测试回收箱</a-button>
</a-row> <br />
</a-form-model> <span
</div> class="notice-wx-wrapper-tips"
</template> ><ops-icon type="icon-shidi-quxiao" :style="{ color: '#D81E06' }" /> 邮件接收失败</span
>
<script> <br />
import { mapState } from 'vuex' <span>邮箱服务器未配置请配置一个邮箱服务器 | <a>故障诊断</a></span>
import SpanTitle from '../components/spanTitle.vue' </a-form-model-item> -->
import { getNoticeConfigByPlatform, postNoticeConfigByPlatform, putNoticeConfigByPlatform } from '@/api/noticeSetting' <a-row v-if="isEditable">
import { mixinPermissions } from '@/utils/mixin' <a-col :span="16" :offset="3">
import Bot from './bot.vue' <a-form-model-item :label-col="labelCol" :wrapper-col="wrapperCol">
export default { <a-button type="primary" @click="onSubmit"> {{ $t('save') }} </a-button>
name: 'NoticeWx', <a-button ghost type="primary" style="margin-left: 28px;" @click="resetForm"> {{ $t('reset') }} </a-button>
mixins: [mixinPermissions], </a-form-model-item>
components: { SpanTitle, Bot }, </a-col>
data() { </a-row>
return { </a-form-model>
labelCol: { lg: 3, md: 5, sm: 8 }, </div>
wrapperCol: { lg: 15, md: 19, sm: 16 }, </template>
id: null,
wxData: { <script>
corpid: '', import { mapState } from 'vuex'
agentid: '', import SpanTitle from '../components/spanTitle.vue'
corpsecret: '', import { getNoticeConfigByPlatform, postNoticeConfigByPlatform, putNoticeConfigByPlatform } from '@/api/noticeSetting'
itsm_app_id: '', import { mixinPermissions } from '@/utils/mixin'
}, import Bot from './bot.vue'
} export default {
}, name: 'NoticeWx',
computed: { mixins: [mixinPermissions],
...mapState({ components: { SpanTitle, Bot },
windowHeight: (state) => state.windowHeight, data() {
}), return {
isEditable() { labelCol: { lg: 3, md: 5, sm: 8 },
return this.hasDetailPermission('backend', '通知设置', ['update']) wrapperCol: { lg: 15, md: 19, sm: 16 },
}, id: null,
}, wxData: {
mounted() { corpid: '',
this.getData() agentid: '',
}, corpsecret: '',
methods: { itsm_app_id: '',
getData() { },
getNoticeConfigByPlatform({ platform: 'wechatApp' }).then((res) => { }
this.id = res?.id ?? null },
if (this.id) { computed: {
this.wxData = res.info ...mapState({
this.$refs.bot.setData(res?.info?.bot) windowHeight: (state) => state.windowHeight,
} }),
}) isEditable() {
}, return this.hasDetailPermission('backend', '通知设置', ['update'])
onSubmit() { },
this.$refs.wxForm.validate(async (valid) => { },
if (valid) { mounted() {
this.$refs.bot.getData(async (flag, bot) => { this.getData()
if (flag) { },
if (this.id) { methods: {
await putNoticeConfigByPlatform(this.id, { info: { ...this.wxData, bot, label: '企业微信' } }) getData() {
} else { getNoticeConfigByPlatform({ platform: 'wechatApp' }).then((res) => {
await postNoticeConfigByPlatform({ this.id = res?.id ?? null
platform: 'wechatApp', if (this.id) {
info: { ...this.wxData, bot, label: '企业微信' }, this.wxData = res.info
}) this.$refs.bot.setData(res?.info?.bot)
} }
this.$message.success('保存成功') })
this.getData() },
} onSubmit() {
}) this.$refs.wxForm.validate(async (valid) => {
} if (valid) {
}) this.$refs.bot.getData(async (flag, bot) => {
}, if (flag) {
resetForm() { if (this.id) {
this.wxData = { await putNoticeConfigByPlatform(this.id, {
corpid: '', info: { ...this.wxData, bot, label: this.$t('cs.person.wechatApp') },
agentid: '', })
corpsecret: '', } else {
itsm_app_id: '', await postNoticeConfigByPlatform({
} platform: 'wechatApp',
}, info: { ...this.wxData, bot, label: this.$t('cs.person.wechatApp') },
}, })
} }
</script> this.$message.success(this.$t('saveSuccess'))
this.getData()
<style lang="less" scoped> }
.notice-wx-wrapper { })
background-color: #fff; }
padding-top: 15px; })
overflow: auto; },
margin-bottom: -24px; resetForm() {
border-radius: 15px; this.wxData = {
.notice-wx-wrapper-tips { corpid: '',
display: inline-block; agentid: '',
background-color: #ffdfdf; corpsecret: '',
border-radius: 4px; itsm_app_id: '',
padding: 0 12px; }
width: 300px; },
color: #000000; },
margin-top: 8px; }
} </script>
}
</style> <style lang="less" scoped>
.notice-wx-wrapper {
background-color: #fff;
padding-top: 15px;
overflow: auto;
margin-bottom: -24px;
border-radius: 15px;
.notice-wx-wrapper-tips {
display: inline-block;
background-color: #ffdfdf;
border-radius: 4px;
padding: 0 12px;
width: 300px;
color: #000000;
margin-top: 8px;
}
}
</style>

View File

@ -1,405 +1,425 @@
<template> <template>
<div class="setting-person"> <div class="setting-person">
<div class="setting-person-left"> <div class="setting-person-left">
<div <div
@click=" @click="
() => { () => {
$refs.personForm.clearValidate() $refs.personForm.clearValidate()
$nextTick(() => { $nextTick(() => {
current = '1' 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" />个人信息 <ops-icon type="icon-shidi-yonghu" />{{ $t('cs.person.spanTitle') }}
</div> </div>
<div <div
@click=" @click="
() => { () => {
$refs.personForm.clearValidate() $refs.personForm.clearValidate()
$nextTick(() => { $nextTick(() => {
current = '2' 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" />账号密码 <a-icon type="unlock" theme="filled" />{{ $t('cs.person.accountAndPassword') }}
</div> </div>
</div> </div>
<div class="setting-person-right"> <div class="setting-person-right">
<a-form-model <a-form-model
ref="personForm" ref="personForm"
:model="form" :model="form"
:rules="current === '1' ? rules1 : rules2" :rules="current === '1' ? rules1 : rules2"
:colon="false" :colon="false"
labelAlign="left" labelAlign="left"
:labelCol="{ span: 4 }" :labelCol="{ span: 4 }"
:wrapperCol="{ span: 10 }" :wrapperCol="{ span: 10 }"
> >
<div v-show="current === '1'"> <div v-show="current === '1'">
<a-form-model-item label="头像" :style="{ display: 'flex', alignItems: 'center' }"> <a-form-model-item :label="$t('cs.person.avatar')" :style="{ display: 'flex', alignItems: 'center' }">
<a-space> <a-space>
<a-avatar v-if="form.avatar" :src="`/api/common-setting/v1/file/${form.avatar}`" :size="64"> </a-avatar> <a-avatar v-if="form.avatar" :src="`/api/common-setting/v1/file/${form.avatar}`" :size="64"> </a-avatar>
<a-avatar v-else style="backgroundColor:#F0F5FF" :size="64"> <a-avatar v-else style="backgroundColor:#F0F5FF" :size="64">
<ops-icon type="icon-shidi-yonghu" :style="{ color: '#2F54EB' }" /> <ops-icon type="icon-shidi-yonghu" :style="{ color: '#2F54EB' }" />
</a-avatar> </a-avatar>
<a-upload <a-upload
name="avatar" name="avatar"
:show-upload-list="false" :show-upload-list="false"
:customRequest="customRequest" :customRequest="customRequest"
:before-upload="beforeUpload" :before-upload="beforeUpload"
:style="{ width: '310px', height: '100px' }" :style="{ width: '310px', height: '100px' }"
accept=".svg,.png,.jpg,.jpeg" accept=".svg,.png,.jpg,.jpeg"
> >
<a-button type="primary" ghost size="small">更换头像</a-button> <a-button type="primary" ghost size="small">{{ $t('cs.person.changeAvatar') }}</a-button>
</a-upload> </a-upload>
</a-space> </a-space>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="姓名" prop="nickname"> <a-form-model-item :label="$t('cs.companyStructure.nickname')" prop="nickname">
<a-input v-model="form.nickname" /> <a-input v-model="form.nickname" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="用户名"> <a-form-model-item :label="$t('cs.companyStructure.username')">
<div class="setting-person-right-disabled">{{ form.username }}</div> <div class="setting-person-right-disabled">{{ form.username }}</div>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="邮箱"> <a-form-model-item :label="$t('cs.companyStructure.email')">
<div class="setting-person-right-disabled">{{ form.email }}</div> <div class="setting-person-right-disabled">{{ form.email }}</div>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="直属上级"> <a-form-model-item :label="$t('cs.companyStructure.supervisor')">
<div class="setting-person-right-disabled"> <div class="setting-person-right-disabled">
{{ getDirectorName(allFlatEmployees, form.direct_supervisor_id) }} {{ getDirectorName(allFlatEmployees, form.direct_supervisor_id) }}
</div> </div>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="性别"> <a-form-model-item :label="$t('cs.companyStructure.sex')">
<a-select v-model="form.sex"> <a-select v-model="form.sex">
<a-select-option value=""></a-select-option> <a-select-option value="">{{ $t('cs.companyStructure.male') }}</a-select-option>
<a-select-option value=""></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 label="手机号" prop="mobile"> <a-form-model-item :label="$t('cs.companyStructure.mobile')" prop="mobile">
<a-input v-model="form.mobile" /> <a-input v-model="form.mobile" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="部门"> <a-form-model-item :label="$t('cs.companyStructure.departmentName')">
<div class="setting-person-right-disabled"> <div class="setting-person-right-disabled">
{{ getDepartmentName(allFlatDepartments, form.department_id) }} {{ getDepartmentName(allFlatDepartments, form.department_id) }}
</div> </div>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="岗位"> <a-form-model-item :label="$t('cs.companyStructure.positionName')">
<div class="setting-person-right-disabled">{{ form.position_name }}</div> <div class="setting-person-right-disabled">{{ form.position_name }}</div>
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="绑定信息"> <a-form-model-item :label="$t('cs.person.bindInfo')">
<a-space> <a-space>
<a-tooltip title="企业微信"> <a-tooltip :title="$t('cs.person.wechatApp')">
<div <div
@click="handleBind('wechatApp', form.notice_info && form.notice_info.wechatApp)" @click="handleBind('wechatApp', form.notice_info && form.notice_info.wechatApp)"
:class="{ :class="{
'setting-person-bind': true, 'setting-person-bind': true,
'setting-person-bind-existed': form.notice_info && form.notice_info.wechatApp, 'setting-person-bind-existed': form.notice_info && form.notice_info.wechatApp,
}" }"
> >
<ops-icon type="ops-setting-notice-wx" /> <ops-icon type="ops-setting-notice-wx" />
</div> </div>
</a-tooltip> </a-tooltip>
<a-tooltip title="飞书"> <a-tooltip :title="$t('cs.person.feishuApp')">
<div <div
@click="handleBind('feishuApp', form.notice_info && form.notice_info.feishuApp)" @click="handleBind('feishuApp', form.notice_info && form.notice_info.feishuApp)"
:class="{ :class="{
'setting-person-bind': true, 'setting-person-bind': true,
'setting-person-bind-existed': form.notice_info && form.notice_info.feishuApp, 'setting-person-bind-existed': form.notice_info && form.notice_info.feishuApp,
}" }"
> >
<ops-icon type="ops-setting-notice-feishu" /> <ops-icon type="ops-setting-notice-feishu" />
</div> </div>
</a-tooltip> </a-tooltip>
<a-tooltip title="钉钉"> <a-tooltip :title="$t('cs.person.dingdingApp')">
<div <div
@click="handleBind('dingdingApp', form.notice_info && form.notice_info.dingdingApp)" @click="handleBind('dingdingApp', form.notice_info && form.notice_info.dingdingApp)"
:class="{ :class="{
'setting-person-bind': true, 'setting-person-bind': true,
'setting-person-bind-existed': form.notice_info && form.notice_info.dingdingApp, 'setting-person-bind-existed': form.notice_info && form.notice_info.dingdingApp,
}" }"
> >
<ops-icon type="ops-setting-notice-dingding" /> <ops-icon type="ops-setting-notice-dingding" />
</div> </div>
</a-tooltip> </a-tooltip>
</a-space> </a-space>
</a-form-model-item> </a-form-model-item>
</div> </div>
<div v-show="current === '2'"> <div v-show="current === '2'">
<a-form-model-item label="新密码" prop="password1"> <a-form-model-item :label="$t('cs.person.newPassword')" prop="password1">
<a-input v-model="form.password1" /> <a-input v-model="form.password1" />
</a-form-model-item> </a-form-model-item>
<a-form-model-item label="确认密码" prop="password2"> <a-form-model-item :label="$t('cs.person.confirmPassword')" prop="password2">
<a-input v-model="form.password2" /> <a-input v-model="form.password2" />
</a-form-model-item> </a-form-model-item>
</div> </div>
<div style="margin-right: 120px"> <div style="margin-right: 120px">
<a-form-model-item label=" "> <a-form-model-item label=" ">
<a-button type="primary" @click="handleSave" :style="{ width: '100%' }">保存</a-button> <a-button type="primary" @click="handleSave" :style="{ width: '100%' }">{{ $t('save') }}</a-button>
</a-form-model-item> </a-form-model-item>
</div> </div>
</a-form-model> </a-form-model>
</div> </div>
<EditImage <EditImage
v-if="showEditImage" v-if="showEditImage"
:show="showEditImage" :show="showEditImage"
:image="editImage" :image="editImage"
:title="eidtImageOption.title" :title="eidtImageOption.title"
:preview-width="eidtImageOption.previewWidth" :preview-width="eidtImageOption.previewWidth"
:preview-height="eidtImageOption.previewHeight" :preview-height="eidtImageOption.previewHeight"
preview-radius="0" preview-radius="0"
width="550px" width="550px"
save-button-title="确定" :save-button-title="$t('confirm')"
@save="submitImage" @save="submitImage"
@close="showEditImage = false" @close="showEditImage = false"
/> />
</div> </div>
</template> </template>
<script> <script>
import { mapActions, mapGetters } from 'vuex' import { mapActions, mapGetters } from 'vuex'
import { getAllDepartmentList } from '@/api/company' import { getAllDepartmentList } from '@/api/company'
import { postImageFile } from '@/api/file' import { postImageFile } from '@/api/file'
import { import {
getEmployeeList, getEmployeeList,
getEmployeeByUid, getEmployeeByUid,
updateEmployeeByUid, updateEmployeeByUid,
updatePasswordByUid, updatePasswordByUid,
bindPlatformByUid, bindPlatformByUid,
unbindPlatformByUid, unbindPlatformByUid,
} from '@/api/employee' } from '@/api/employee'
import { getDepartmentName, getDirectorName } from '@/utils/util' import { getDepartmentName, getDirectorName } from '@/utils/util'
import EditImage from '../components/EditImage.vue' import EditImage from '../components/EditImage.vue'
export default { export default {
name: 'Person', name: 'Person',
components: { EditImage }, components: { EditImage },
data() { data() {
const validatePassword = (rule, value, callback) => { return {
if (!value) { current: '1',
callback(new Error('请二次确认新密码')) form: {},
} allFlatEmployees: [],
if (value !== this.form.password1) { allFlatDepartments: [],
callback(new Error('两次输入密码不一致')) showEditImage: false,
} editImage: null,
callback() }
} },
return { computed: {
current: '1', ...mapGetters(['uid']),
form: {}, rules1() {
rules1: { return {
nickname: [ nickname: [
{ required: true, whitespace: true, message: '请输入姓名', trigger: 'blur' }, {
{ max: 20, message: '字符数须小于20' }, required: true,
], whitespace: true,
mobile: [ message: this.$t('cs.companyStructure.nicknamePlaceholder'),
{ trigger: 'blur',
pattern: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/, },
message: '请输入正确的手机号', { max: 20, message: this.$t('cs.person.inputStrCountLimit', { limit: 20 }) },
trigger: 'blur', ],
}, mobile: [
], {
}, pattern: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/,
rules2: { message: this.$t('cs.companyStructure.mobileFormatErr'),
password1: [{ required: true, message: '请输入新密码', trigger: 'blur' }], trigger: 'blur',
password2: [{ required: true, message: '两次输入密码不一致', trigger: 'blur', validator: validatePassword }], },
}, ],
allFlatEmployees: [], }
allFlatDepartments: [], },
showEditImage: false, rules2() {
eidtImageOption: { const validatePassword = (rule, value, callback) => {
type: 'avatar', if (!value) {
fixedNumber: [4, 4], callback(new Error(this.$t('cs.person.pleaseConfirmNewPasswordSecondTime')))
title: '编辑头像', }
previewWidth: '60px', if (value !== this.form.password1) {
previewHeight: '60px', callback(new Error(this.$t('cs.person.thePasswordEnteredTwiceIsInconsistent')))
}, }
editImage: null, callback()
} }
}, return {
computed: { password1: [
...mapGetters(['uid']), { required: true, message: this.$t('cs.person.pleaseConfirmNewPasswordSecondTime'), trigger: 'blur' },
}, ],
mounted() { password2: [
this.getAllFlatEmployees() {
this.getAllFlatDepartment() required: true,
this.getEmployeeByUid() message: this.$t('cs.person.thePasswordEnteredTwiceIsInconsistent'),
}, trigger: 'blur',
methods: { validator: validatePassword,
...mapActions(['GetInfo']), },
getDepartmentName, ],
getDirectorName, }
getEmployeeByUid() { },
getEmployeeByUid(this.uid).then((res) => { eidtImageOption() {
this.form = { ...res } return {
}) type: 'avatar',
}, fixedNumber: [4, 4],
getAllFlatEmployees() { title: this.$t('cs.components.editAvatar'),
getEmployeeList({ block_status: 0, page_size: 99999 }).then((res) => { previewWidth: '60px',
this.allFlatEmployees = res.data_list previewHeight: '60px',
}) }
}, },
getAllFlatDepartment() { },
getAllDepartmentList({ is_tree: 0 }).then((res) => { mounted() {
this.allFlatDepartments = res this.getAllFlatEmployees()
}) this.getAllFlatDepartment()
}, this.getEmployeeByUid()
async handleSave() { },
await this.$refs.personForm.validate(async (valid) => { methods: {
if (valid) { ...mapActions(['GetInfo']),
const { nickname, mobile, sex, avatar, password1 } = this.form getDepartmentName,
const params = { nickname, mobile, sex, avatar } getDirectorName,
if (this.current === '1') { getEmployeeByUid() {
await updateEmployeeByUid(this.uid, params).then((res) => { getEmployeeByUid(this.uid).then((res) => {
this.$message.success('保存成功!') this.form = { ...res }
this.getEmployeeByUid() })
this.GetInfo() },
}) getAllFlatEmployees() {
} else { getEmployeeList({ block_status: 0, page_size: 99999 }).then((res) => {
await updatePasswordByUid(this.uid, { password: password1 }).then((res) => { this.allFlatEmployees = res.data_list
this.$message.success('保存成功!') })
}) },
} getAllFlatDepartment() {
} getAllDepartmentList({ is_tree: 0 }).then((res) => {
}) this.allFlatDepartments = res
}, })
customRequest(file) { },
const reader = new FileReader() async handleSave() {
var self = this await this.$refs.personForm.validate(async (valid) => {
reader.onload = function(e) { if (valid) {
let result const { nickname, mobile, sex, avatar, password1 } = this.form
if (typeof e.target.result === 'object') { const params = { nickname, mobile, sex, avatar }
// 把Array Buffer转化为blob 如果是base64不需要 if (this.current === '1') {
result = window.URL.createObjectURL(new Blob([e.target.result])) await updateEmployeeByUid(this.uid, params).then((res) => {
} else { this.$message.success(this.$t('saveSuccess'))
result = e.target.result this.getEmployeeByUid()
} this.GetInfo()
})
self.editImage = result } else {
self.showEditImage = true await updatePasswordByUid(this.uid, { password: password1 }).then((res) => {
} this.$message.success(this.$t('saveSuccess'))
reader.readAsDataURL(file.file) })
}, }
beforeUpload(file) { }
const isLt2M = file.size / 1024 / 1024 < 2 })
if (!isLt2M) { },
this.$message.error('图片大小不可超过2MB!') customRequest(file) {
} const reader = new FileReader()
return isLt2M var self = this
}, reader.onload = function(e) {
submitImage(file) { let result
postImageFile(file).then((res) => { if (typeof e.target.result === 'object') {
if (res.file_name) { // 把Array Buffer转化为blob 如果是base64不需要
this.form.avatar = res.file_name result = window.URL.createObjectURL(new Blob([e.target.result]))
} } else {
}) result = e.target.result
}, }
async handleBind(platform, isBind) {
if (isBind) { self.editImage = result
const that = this self.showEditImage = true
this.$confirm({ }
title: '警告', reader.readAsDataURL(file.file)
content: `确认解绑`, },
onOk() { beforeUpload(file) {
unbindPlatformByUid(platform, that.uid) const isLt2M = file.size / 1024 / 1024 < 2
.then(() => { if (!isLt2M) {
that.$message.success('解绑成功!') this.$message.error(this.$t('cs.companyInfo.imageSizeLimit2MB'))
}) }
.finally(() => { return isLt2M
that.getEmployeeByUid() },
that.GetInfo() submitImage(file) {
}) postImageFile(file).then((res) => {
}, if (res.file_name) {
}) this.form.avatar = res.file_name
} else { }
await this.$refs.personForm.validate(async (valid) => { })
if (valid) { },
const { nickname, mobile, sex, avatar } = this.form async handleBind(platform, isBind) {
const params = { nickname, mobile, sex, avatar } if (isBind) {
await updateEmployeeByUid(this.uid, params) const that = this
bindPlatformByUid(platform, this.uid) this.$confirm({
.then(() => { title: this.$t('warning'),
this.$message.success('绑定成功!') content: this.$t('cs.person.confirmUnbind'),
}) onOk() {
.finally(() => { unbindPlatformByUid(platform, that.uid)
this.getEmployeeByUid() .then(() => {
this.GetInfo() that.$message.success(this.$t('cs.person.unbindSuccess'))
}) })
} .finally(() => {
}) that.getEmployeeByUid()
} that.GetInfo()
}, })
}, },
} })
</script> } else {
await this.$refs.personForm.validate(async (valid) => {
<style lang="less" scoped> if (valid) {
@import '~@/style/static.less'; const { nickname, mobile, sex, avatar } = this.form
.setting-person { const params = { nickname, mobile, sex, avatar }
display: flex; await updateEmployeeByUid(this.uid, params)
flex-direction: row; bindPlatformByUid(platform, this.uid)
.setting-person-left { .then(() => {
width: 200px; this.$message.success(this.$t('cs.person.bindSuccess'))
height: 400px; })
margin-right: 24px; .finally(() => {
background-color: #fff; this.getEmployeeByUid()
border-radius: 15px; this.GetInfo()
padding-top: 15px; })
.setting-person-left-item { }
cursor: pointer; })
padding: 10px 20px; }
color: #a5a9bc; },
border-left: 4px solid #fff; },
margin-bottom: 5px; }
&:hover { </script>
.ops_popover_item_selected();
border-color: #custom_colors[color_1]; <style lang="less" scoped>
} @import '~@/style/static.less';
> i { .setting-person {
margin-right: 10px; display: flex;
} flex-direction: row;
} .setting-person-left {
.setting-person-left-item-selected { width: 200px;
.ops_popover_item_selected(); height: 400px;
border-color: #custom_colors[color_1]; margin-right: 24px;
} background-color: #fff;
} border-radius: 15px;
.setting-person-right { padding-top: 15px;
width: 800px; .setting-person-left-item {
height: 700px; cursor: pointer;
background-color: #fff; padding: 10px 20px;
border-radius: 15px; color: #a5a9bc;
padding: 24px 48px; border-left: 4px solid #fff;
.setting-person-right-disabled { margin-bottom: 5px;
background-color: #custom_colors[color_2]; &:hover {
border-radius: 4px; .ops_popover_item_selected();
height: 30px; border-color: #custom_colors[color_1];
line-height: 30px; }
margin-top: 4px; > i {
padding: 0 10px; margin-right: 10px;
color: #a5a9bc; }
} }
.setting-person-bind { .setting-person-left-item-selected {
width: 40px; .ops_popover_item_selected();
height: 40px; border-color: #custom_colors[color_1];
background: #a5a9bc; }
border-radius: 4px; }
color: #fff; .setting-person-right {
font-size: 30px; width: 800px;
text-align: center; height: 700px;
cursor: pointer; background-color: #fff;
} border-radius: 15px;
.setting-person-bind-existed { padding: 24px 48px;
background: #008cee; .setting-person-right-disabled {
} background-color: #custom_colors[color_2];
} border-radius: 4px;
} height: 30px;
</style> line-height: 30px;
<style lang="less"> margin-top: 4px;
.setting-person-right .ant-form-item { padding: 0 10px;
margin-bottom: 12px; color: #a5a9bc;
display: flex; }
justify-content: center; .setting-person-bind {
align-items: center; width: 40px;
} height: 40px;
</style> background: #a5a9bc;
border-radius: 4px;
color: #fff;
font-size: 30px;
text-align: center;
cursor: pointer;
}
.setting-person-bind-existed {
background: #008cee;
}
}
}
</style>
<style lang="less">
.setting-person-right .ant-form-item {
margin-bottom: 12px;
display: flex;
justify-content: center;
align-items: center;
}
</style>