mirror of
https://github.com/veops/cmdb.git
synced 2025-08-11 19:39:36 +08:00
前端更新 (#189)
* fix:add package * fix:notice_info为null的情况 * fix:2 bugs * feat:1.common增加通知配置 2.cmdb预定义值webhook&其他模型 * fix:json 不支持预定义值 * fix:json 不支持预定义值
This commit is contained in:
@@ -1,372 +1,379 @@
|
||||
<template>
|
||||
<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">
|
||||
<SpanTitle>公司描述</SpanTitle>
|
||||
<a-form-model-item label="名称" prop="name">
|
||||
<a-input v-model="infoData.name" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="描述">
|
||||
<a-input v-model="infoData.description" type="textarea" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<SpanTitle>公司地址</SpanTitle>
|
||||
<a-form-model-item label="国家/地区">
|
||||
<a-input v-model="infoData.country" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="城市">
|
||||
<a-input v-model="infoData.city" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="地址">
|
||||
<a-input v-model="infoData.address" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="邮编">
|
||||
<a-input v-model="infoData.postCode" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<SpanTitle>联系方式</SpanTitle>
|
||||
<a-form-model-item label="网站">
|
||||
<a-input v-model="infoData.website" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="电话号码" prop="phone">
|
||||
<a-input v-model="infoData.phone" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="传真号码" prop="faxCode">
|
||||
<a-input v-model="infoData.faxCode" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="电子邮箱" prop="email">
|
||||
<a-input v-model="infoData.email" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<SpanTitle>公司标识</SpanTitle>
|
||||
<a-form-model-item label="部署域名" prop="domainName">
|
||||
<a-input v-model="infoData.domainName" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="公司logo">
|
||||
<a-space>
|
||||
<a-upload
|
||||
:disabled="!isEditable"
|
||||
name="avatar"
|
||||
list-type="picture-card"
|
||||
class="avatar-uploader"
|
||||
:show-upload-list="false"
|
||||
:customRequest="customRequest"
|
||||
:before-upload="beforeUpload"
|
||||
:style="{ width: '400px', height: '80px' }"
|
||||
accept=".png,.jpg,.jpeg"
|
||||
>
|
||||
<div
|
||||
class="ops-setting-companyinfo-upload-show"
|
||||
v-if="infoData.logoName"
|
||||
:style="{ width: '400px', height: '80px' }"
|
||||
@click="eidtImageOption.type = 'Logo'"
|
||||
>
|
||||
<img :src="`/api/common-setting/v1/file/${infoData.logoName}`" alt="avatar" />
|
||||
<a-icon
|
||||
v-if="isEditable"
|
||||
type="minus-circle"
|
||||
theme="filled"
|
||||
class="delete-icon"
|
||||
@click.stop="deleteLogo"
|
||||
/>
|
||||
</div>
|
||||
<div v-else @click="eidtImageOption.type = 'Logo'">
|
||||
<a-icon type="plus" />
|
||||
<div class="ant-upload-text">上传</div>
|
||||
</div>
|
||||
</a-upload>
|
||||
|
||||
<a-upload
|
||||
:disabled="!isEditable"
|
||||
name="avatar"
|
||||
list-type="picture-card"
|
||||
class="avatar-uploader"
|
||||
:show-upload-list="false"
|
||||
:customRequest="customRequest"
|
||||
:before-upload="beforeUpload"
|
||||
:style="{ width: '82px', height: '82px' }"
|
||||
accept=".png,.jpg,.jpeg"
|
||||
>
|
||||
<div
|
||||
class="ops-setting-companyinfo-upload-show"
|
||||
v-if="infoData.smallLogoName"
|
||||
:style="{ width: '82px', height: '82px' }"
|
||||
@click="eidtImageOption.type = 'SmallLogo'"
|
||||
>
|
||||
<img :src="`/api/common-setting/v1/file/${infoData.smallLogoName}`" alt="avatar" />
|
||||
<a-icon
|
||||
v-if="isEditable"
|
||||
type="minus-circle"
|
||||
theme="filled"
|
||||
class="delete-icon"
|
||||
@click.stop="deleteSmallLogo"
|
||||
/>
|
||||
</div>
|
||||
<div v-else @click="eidtImageOption.type = 'SmallLogo'">
|
||||
<a-icon type="plus" />
|
||||
<div class="ant-upload-text">上传</div>
|
||||
</div>
|
||||
</a-upload>
|
||||
</a-space>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item :wrapper-col="{ span: 14, offset: 3 }" v-if="isEditable">
|
||||
<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>
|
||||
<edit-image
|
||||
v-if="showEditImage"
|
||||
:show="showEditImage"
|
||||
:image="editImage"
|
||||
:title="eidtImageOption.title"
|
||||
:eidtImageOption="eidtImageOption"
|
||||
@save="submitImage"
|
||||
@close="showEditImage = false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCompanyInfo, postCompanyInfo, putCompanyInfo } from '@/api/company'
|
||||
import { postImageFile } from '@/api/file'
|
||||
import { mapMutations, mapState } from 'vuex'
|
||||
import SpanTitle from '../components/spanTitle.vue'
|
||||
import EditImage from '../components/EditImage.vue'
|
||||
import { mixinPermissions } from '@/utils/mixin'
|
||||
export default {
|
||||
name: 'CompanyInfo',
|
||||
mixins: [mixinPermissions],
|
||||
components: { SpanTitle, EditImage },
|
||||
data() {
|
||||
return {
|
||||
labelCol: { span: 3 },
|
||||
wrapperCol: { span: 10 },
|
||||
infoData: {
|
||||
name: '',
|
||||
description: '',
|
||||
address: '',
|
||||
city: '',
|
||||
postCode: '',
|
||||
country: '',
|
||||
website: '',
|
||||
phone: '',
|
||||
faxCode: '',
|
||||
email: '',
|
||||
logoName: '',
|
||||
smallLogoName: '',
|
||||
},
|
||||
rule: {
|
||||
name: [{ required: true, whitespace: true, message: '请输入名称', trigger: 'blur' }],
|
||||
phone: [
|
||||
{
|
||||
required: false,
|
||||
whitespace: true,
|
||||
pattern: new RegExp('^([0-9]|-)+$', 'g'),
|
||||
message: '请输入正确的电话号码',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
faxCode: [
|
||||
{
|
||||
required: false,
|
||||
whitespace: true,
|
||||
pattern: new RegExp('^([0-9]|-)+$', 'g'),
|
||||
message: '请输入正确的传真号码',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
email: [
|
||||
{
|
||||
required: false,
|
||||
whitespace: true,
|
||||
pattern: new RegExp('^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(.[a-zA-Z0-9-]+)*.[a-zA-Z0-9]{2,6}$', 'g'),
|
||||
message: '请输入正确的邮箱地址',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
getId: -1,
|
||||
showEditImage: false,
|
||||
editImage: null,
|
||||
eidtImageOption: {
|
||||
type: 'Logo',
|
||||
fixedNumber: [15, 4],
|
||||
title: '编辑企业logo',
|
||||
previewWidth: '200px',
|
||||
previewHeight: '40px',
|
||||
autoCropWidth: 200,
|
||||
autoCropHeight: 40,
|
||||
},
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
const res = await getCompanyInfo()
|
||||
if (!res.id) {
|
||||
this.getId = -1
|
||||
} else {
|
||||
this.infoData = res.info
|
||||
this.getId = res.id
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
windowHeight: (state) => state.windowHeight,
|
||||
}),
|
||||
isEditable() {
|
||||
return this.hasDetailPermission('backend', '公司信息', ['update'])
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_FILENAME', 'SET_SMALL_FILENAME']),
|
||||
deleteLogo() {
|
||||
this.infoData.logoName = ''
|
||||
},
|
||||
deleteSmallLogo() {
|
||||
this.infoData.smallLogoName = ''
|
||||
},
|
||||
async onSubmit() {
|
||||
this.$refs.infoData.validate(async (valid) => {
|
||||
if (valid) {
|
||||
if (this.getId === -1) {
|
||||
await postCompanyInfo(this.infoData)
|
||||
} else {
|
||||
await putCompanyInfo(this.getId, this.infoData)
|
||||
}
|
||||
this.SET_FILENAME(this.infoData.logoName)
|
||||
this.SET_SMALL_FILENAME(this.infoData.smallFileName)
|
||||
this.$message.success('保存成功')
|
||||
} else {
|
||||
this.$message.warning('检查您的输入是否正确!')
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm() {
|
||||
this.infoData = {
|
||||
name: '',
|
||||
description: '',
|
||||
address: '',
|
||||
city: '',
|
||||
postCode: '',
|
||||
country: '',
|
||||
website: '',
|
||||
phone: '',
|
||||
faxCode: '',
|
||||
email: '',
|
||||
logoName: '',
|
||||
smallLogoName: '',
|
||||
}
|
||||
},
|
||||
customRequest(file) {
|
||||
const reader = new FileReader()
|
||||
var self = this
|
||||
if (this.eidtImageOption.type === 'Logo') {
|
||||
this.eidtImageOption = {
|
||||
type: 'Logo',
|
||||
fixedNumber: [20, 4],
|
||||
title: '编辑企业logo',
|
||||
previewWidth: '200px',
|
||||
previewHeight: '40px',
|
||||
autoCropWidth: 200,
|
||||
autoCropHeight: 40,
|
||||
}
|
||||
} else if (this.eidtImageOption.type === 'SmallLogo') {
|
||||
this.eidtImageOption = {
|
||||
type: 'SmallLogo',
|
||||
fixedNumber: [4, 4],
|
||||
title: '编辑企业logo缩略图',
|
||||
previewWidth: '80px',
|
||||
previewHeight: '80px',
|
||||
autoCropWidth: 250,
|
||||
autoCropHeight: 250,
|
||||
}
|
||||
}
|
||||
reader.onload = function(e) {
|
||||
let result
|
||||
if (typeof e.target.result === 'object') {
|
||||
// 把Array Buffer转化为blob 如果是base64不需要
|
||||
result = window.URL.createObjectURL(new Blob([e.target.result]))
|
||||
} else {
|
||||
result = e.target.result
|
||||
}
|
||||
|
||||
self.editImage = result
|
||||
self.showEditImage = true
|
||||
}
|
||||
reader.readAsDataURL(file.file)
|
||||
},
|
||||
submitImage(file) {
|
||||
postImageFile(file).then((res) => {
|
||||
if (res.file_name) {
|
||||
if (this.eidtImageOption.type === 'Logo') {
|
||||
this.infoData.logoName = res.file_name
|
||||
} else if (this.eidtImageOption.type === 'SmallLogo') {
|
||||
this.infoData.smallLogoName = res.file_name
|
||||
}
|
||||
} else {
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
beforeUpload(file) {
|
||||
const isLt2M = file.size / 1024 / 1024 < 2
|
||||
if (!isLt2M) {
|
||||
this.$message.error('图片大小不可超过2MB!')
|
||||
}
|
||||
return isLt2M
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.ops-setting-companyinfo {
|
||||
padding-top: 15px;
|
||||
background-color: #fff;
|
||||
border-radius: 15px;
|
||||
overflow: auto;
|
||||
margin-bottom: -24px;
|
||||
.ops-setting-companyinfo-upload-show {
|
||||
position: relative;
|
||||
width: 290px;
|
||||
height: 100px;
|
||||
max-height: 100px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.delete-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.ant-upload:hover .delete-icon {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
color: rgb(247, 85, 85);
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.ant-form-item label {
|
||||
padding-right: 10px;
|
||||
}
|
||||
.avatar-uploader > .ant-upload {
|
||||
// max-width: 100px;
|
||||
max-height: 100px;
|
||||
}
|
||||
// .ant-upload.ant-upload-select-picture-card {
|
||||
// width: 100%;
|
||||
// > .ant-upload {
|
||||
// padding: 0px;
|
||||
.ant-upload-picture-card-wrapper {
|
||||
height: 100px;
|
||||
.ant-upload.ant-upload-select-picture-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
> .ant-upload {
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<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">
|
||||
<SpanTitle>公司描述</SpanTitle>
|
||||
<a-form-model-item label="名称" prop="name">
|
||||
<a-input v-model="infoData.name" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="描述">
|
||||
<a-input v-model="infoData.description" type="textarea" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<SpanTitle>公司地址</SpanTitle>
|
||||
<a-form-model-item label="国家/地区">
|
||||
<a-input v-model="infoData.country" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="城市">
|
||||
<a-input v-model="infoData.city" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="地址">
|
||||
<a-input v-model="infoData.address" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="邮编">
|
||||
<a-input v-model="infoData.postCode" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<SpanTitle>联系方式</SpanTitle>
|
||||
<a-form-model-item label="网站">
|
||||
<a-input v-model="infoData.website" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="电话号码" prop="phone">
|
||||
<a-input v-model="infoData.phone" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="传真号码" prop="faxCode">
|
||||
<a-input v-model="infoData.faxCode" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="电子邮箱" prop="email">
|
||||
<a-input v-model="infoData.email" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<SpanTitle>公司标识</SpanTitle>
|
||||
<a-form-model-item label="Messenger地址" prop="messenger">
|
||||
<a-input v-model="infoData.messenger" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="部署域名" prop="domainName">
|
||||
<a-input v-model="infoData.domainName" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="公司logo">
|
||||
<a-space>
|
||||
<a-upload
|
||||
:disabled="!isEditable"
|
||||
name="avatar"
|
||||
list-type="picture-card"
|
||||
class="avatar-uploader"
|
||||
:show-upload-list="false"
|
||||
:customRequest="customRequest"
|
||||
:before-upload="beforeUpload"
|
||||
:style="{ width: '400px', height: '80px' }"
|
||||
accept=".png,.jpg,.jpeg"
|
||||
>
|
||||
<div
|
||||
class="ops-setting-companyinfo-upload-show"
|
||||
v-if="infoData.logoName"
|
||||
:style="{ width: '400px', height: '80px' }"
|
||||
@click="eidtImageOption.type = 'Logo'"
|
||||
>
|
||||
<img :src="`/api/common-setting/v1/file/${infoData.logoName}`" alt="avatar" />
|
||||
<a-icon
|
||||
v-if="isEditable"
|
||||
type="minus-circle"
|
||||
theme="filled"
|
||||
class="delete-icon"
|
||||
@click.stop="deleteLogo"
|
||||
/>
|
||||
</div>
|
||||
<div v-else @click="eidtImageOption.type = 'Logo'">
|
||||
<a-icon type="plus" />
|
||||
<div class="ant-upload-text">上传</div>
|
||||
</div>
|
||||
</a-upload>
|
||||
|
||||
<a-upload
|
||||
:disabled="!isEditable"
|
||||
name="avatar"
|
||||
list-type="picture-card"
|
||||
class="avatar-uploader"
|
||||
:show-upload-list="false"
|
||||
:customRequest="customRequest"
|
||||
:before-upload="beforeUpload"
|
||||
:style="{ width: '82px', height: '82px' }"
|
||||
accept=".png,.jpg,.jpeg"
|
||||
>
|
||||
<div
|
||||
class="ops-setting-companyinfo-upload-show"
|
||||
v-if="infoData.smallLogoName"
|
||||
:style="{ width: '82px', height: '82px' }"
|
||||
@click="eidtImageOption.type = 'SmallLogo'"
|
||||
>
|
||||
<img :src="`/api/common-setting/v1/file/${infoData.smallLogoName}`" alt="avatar" />
|
||||
<a-icon
|
||||
v-if="isEditable"
|
||||
type="minus-circle"
|
||||
theme="filled"
|
||||
class="delete-icon"
|
||||
@click.stop="deleteSmallLogo"
|
||||
/>
|
||||
</div>
|
||||
<div v-else @click="eidtImageOption.type = 'SmallLogo'">
|
||||
<a-icon type="plus" />
|
||||
<div class="ant-upload-text">上传</div>
|
||||
</div>
|
||||
</a-upload>
|
||||
</a-space>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item :wrapper-col="{ span: 14, offset: 3 }" v-if="isEditable">
|
||||
<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>
|
||||
<edit-image
|
||||
v-if="showEditImage"
|
||||
:show="showEditImage"
|
||||
:image="editImage"
|
||||
:title="eidtImageOption.title"
|
||||
:eidtImageOption="eidtImageOption"
|
||||
@save="submitImage"
|
||||
@close="showEditImage = false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCompanyInfo, postCompanyInfo, putCompanyInfo } from '@/api/company'
|
||||
import { postImageFile } from '@/api/file'
|
||||
import { mapMutations, mapState } from 'vuex'
|
||||
import SpanTitle from '../components/spanTitle.vue'
|
||||
import EditImage from '../components/EditImage.vue'
|
||||
import { mixinPermissions } from '@/utils/mixin'
|
||||
export default {
|
||||
name: 'CompanyInfo',
|
||||
mixins: [mixinPermissions],
|
||||
components: { SpanTitle, EditImage },
|
||||
data() {
|
||||
return {
|
||||
labelCol: { span: 3 },
|
||||
wrapperCol: { span: 10 },
|
||||
infoData: {
|
||||
name: '',
|
||||
description: '',
|
||||
address: '',
|
||||
city: '',
|
||||
postCode: '',
|
||||
country: '',
|
||||
website: '',
|
||||
phone: '',
|
||||
faxCode: '',
|
||||
email: '',
|
||||
logoName: '',
|
||||
smallLogoName: '',
|
||||
messenger: '',
|
||||
domainName: '',
|
||||
},
|
||||
rule: {
|
||||
name: [{ required: true, whitespace: true, message: '请输入名称', trigger: 'blur' }],
|
||||
phone: [
|
||||
{
|
||||
required: false,
|
||||
whitespace: true,
|
||||
pattern: new RegExp('^([0-9]|-)+$', 'g'),
|
||||
message: '请输入正确的电话号码',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
faxCode: [
|
||||
{
|
||||
required: false,
|
||||
whitespace: true,
|
||||
pattern: new RegExp('^([0-9]|-)+$', 'g'),
|
||||
message: '请输入正确的传真号码',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
email: [
|
||||
{
|
||||
required: false,
|
||||
whitespace: true,
|
||||
pattern: new RegExp('^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(.[a-zA-Z0-9-]+)*.[a-zA-Z0-9]{2,6}$', 'g'),
|
||||
message: '请输入正确的邮箱地址',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
getId: -1,
|
||||
showEditImage: false,
|
||||
editImage: null,
|
||||
eidtImageOption: {
|
||||
type: 'Logo',
|
||||
fixedNumber: [15, 4],
|
||||
title: '编辑企业logo',
|
||||
previewWidth: '200px',
|
||||
previewHeight: '40px',
|
||||
autoCropWidth: 200,
|
||||
autoCropHeight: 40,
|
||||
},
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
const res = await getCompanyInfo()
|
||||
if (!res.id) {
|
||||
this.getId = -1
|
||||
} else {
|
||||
this.infoData = res.info
|
||||
this.getId = res.id
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
windowHeight: (state) => state.windowHeight,
|
||||
}),
|
||||
isEditable() {
|
||||
return this.hasDetailPermission('backend', '公司信息', ['update'])
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['SET_FILENAME', 'SET_SMALL_FILENAME']),
|
||||
deleteLogo() {
|
||||
this.infoData.logoName = ''
|
||||
},
|
||||
deleteSmallLogo() {
|
||||
this.infoData.smallLogoName = ''
|
||||
},
|
||||
async onSubmit() {
|
||||
this.$refs.infoData.validate(async (valid) => {
|
||||
if (valid) {
|
||||
if (this.getId === -1) {
|
||||
await postCompanyInfo(this.infoData)
|
||||
} else {
|
||||
await putCompanyInfo(this.getId, this.infoData)
|
||||
}
|
||||
this.SET_FILENAME(this.infoData.logoName)
|
||||
this.SET_SMALL_FILENAME(this.infoData.smallFileName)
|
||||
this.$message.success('保存成功')
|
||||
} else {
|
||||
this.$message.warning('检查您的输入是否正确!')
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm() {
|
||||
this.infoData = {
|
||||
name: '',
|
||||
description: '',
|
||||
address: '',
|
||||
city: '',
|
||||
postCode: '',
|
||||
country: '',
|
||||
website: '',
|
||||
phone: '',
|
||||
faxCode: '',
|
||||
email: '',
|
||||
logoName: '',
|
||||
smallLogoName: '',
|
||||
messenger: '',
|
||||
domainName: '',
|
||||
}
|
||||
},
|
||||
customRequest(file) {
|
||||
const reader = new FileReader()
|
||||
var self = this
|
||||
if (this.eidtImageOption.type === 'Logo') {
|
||||
this.eidtImageOption = {
|
||||
type: 'Logo',
|
||||
fixedNumber: [20, 4],
|
||||
title: '编辑企业logo',
|
||||
previewWidth: '200px',
|
||||
previewHeight: '40px',
|
||||
autoCropWidth: 200,
|
||||
autoCropHeight: 40,
|
||||
}
|
||||
} else if (this.eidtImageOption.type === 'SmallLogo') {
|
||||
this.eidtImageOption = {
|
||||
type: 'SmallLogo',
|
||||
fixedNumber: [4, 4],
|
||||
title: '编辑企业logo缩略图',
|
||||
previewWidth: '80px',
|
||||
previewHeight: '80px',
|
||||
autoCropWidth: 250,
|
||||
autoCropHeight: 250,
|
||||
}
|
||||
}
|
||||
reader.onload = function(e) {
|
||||
let result
|
||||
if (typeof e.target.result === 'object') {
|
||||
// 把Array Buffer转化为blob 如果是base64不需要
|
||||
result = window.URL.createObjectURL(new Blob([e.target.result]))
|
||||
} else {
|
||||
result = e.target.result
|
||||
}
|
||||
|
||||
self.editImage = result
|
||||
self.showEditImage = true
|
||||
}
|
||||
reader.readAsDataURL(file.file)
|
||||
},
|
||||
submitImage(file) {
|
||||
postImageFile(file).then((res) => {
|
||||
if (res.file_name) {
|
||||
if (this.eidtImageOption.type === 'Logo') {
|
||||
this.infoData.logoName = res.file_name
|
||||
} else if (this.eidtImageOption.type === 'SmallLogo') {
|
||||
this.infoData.smallLogoName = res.file_name
|
||||
}
|
||||
} else {
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
beforeUpload(file) {
|
||||
const isLt2M = file.size / 1024 / 1024 < 2
|
||||
if (!isLt2M) {
|
||||
this.$message.error('图片大小不可超过2MB!')
|
||||
}
|
||||
return isLt2M
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.ops-setting-companyinfo {
|
||||
padding-top: 15px;
|
||||
background-color: #fff;
|
||||
border-radius: 15px;
|
||||
overflow: auto;
|
||||
margin-bottom: -24px;
|
||||
.ops-setting-companyinfo-upload-show {
|
||||
position: relative;
|
||||
width: 290px;
|
||||
height: 100px;
|
||||
max-height: 100px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.delete-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.ant-upload:hover .delete-icon {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
color: rgb(247, 85, 85);
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.ant-form-item label {
|
||||
padding-right: 10px;
|
||||
}
|
||||
.avatar-uploader > .ant-upload {
|
||||
// max-width: 100px;
|
||||
max-height: 100px;
|
||||
}
|
||||
// .ant-upload.ant-upload-select-picture-card {
|
||||
// width: 100%;
|
||||
// > .ant-upload {
|
||||
// padding: 0px;
|
||||
.ant-upload-picture-card-wrapper {
|
||||
height: 100px;
|
||||
.ant-upload.ant-upload-select-picture-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
> .ant-upload {
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
122
cmdb-ui/src/views/setting/notice/bot.vue
Normal file
122
cmdb-ui/src/views/setting/notice/bot.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<div>
|
||||
<vxe-table
|
||||
ref="xTable"
|
||||
:data="tableData"
|
||||
size="mini"
|
||||
stripe
|
||||
class="ops-stripe-table"
|
||||
show-overflow
|
||||
: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="{}">
|
||||
<template #header> <span v-if="col.required" :style="{ color: 'red' }">* </span>{{ col.title }} </template>
|
||||
<template #edit="{ row }">
|
||||
<vxe-input v-model="row[col.field]" type="text"></vxe-input>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column title="操作" width="80" v-if="!disabled">
|
||||
<template #default="{ row }">
|
||||
<template v-if="$refs.xTable.isActiveByRow(row)">
|
||||
<a @click="saveRowEvent(row)"><a-icon type="save"/></a>
|
||||
</template>
|
||||
<a-space v-else>
|
||||
<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-space>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
<div :style="{ color: '#f5222d' }" v-if="errorFlag">请完整填写机器人配置</div>
|
||||
<a-button
|
||||
v-if="!disabled"
|
||||
icon="plus-circle"
|
||||
class="ops-button-primary"
|
||||
type="primary"
|
||||
@click="insertEvent"
|
||||
>添加</a-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Bot',
|
||||
props: {
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => [
|
||||
{
|
||||
field: 'name',
|
||||
title: '名称',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'url',
|
||||
title: 'Webhook地址',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
errorFlag: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async insertEvent() {
|
||||
const $table = this.$refs.xTable
|
||||
const record = {
|
||||
name: '',
|
||||
url: '',
|
||||
}
|
||||
const { row: newRow } = await $table.insertAt(record, -1)
|
||||
await $table.setActiveRow(newRow)
|
||||
},
|
||||
saveRowEvent(row) {
|
||||
const $table = this.$refs.xTable
|
||||
$table.clearActived()
|
||||
},
|
||||
editRowEvent(row) {
|
||||
const $table = this.$refs.xTable
|
||||
$table.setActiveRow(row)
|
||||
},
|
||||
deleteRowEvent(row) {
|
||||
const $table = this.$refs.xTable
|
||||
$table.remove(row)
|
||||
},
|
||||
getData(callback) {
|
||||
const $table = this.$refs.xTable
|
||||
const { fullData: _tableData } = $table.getTableData()
|
||||
const requiredObj = {}
|
||||
this.columns.forEach((col) => {
|
||||
if (col.required) {
|
||||
requiredObj[col.field] = true
|
||||
}
|
||||
})
|
||||
let flag = true
|
||||
_tableData.forEach((td) => {
|
||||
Object.keys(requiredObj).forEach((key) => {
|
||||
if (requiredObj[key]) {
|
||||
flag = !!(flag && td[`${key}`])
|
||||
}
|
||||
})
|
||||
})
|
||||
this.errorFlag = !flag
|
||||
callback(flag, _tableData)
|
||||
},
|
||||
setData(value) {
|
||||
this.tableData = value
|
||||
this.errorFlag = false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
151
cmdb-ui/src/views/setting/notice/dingding.vue
Normal file
151
cmdb-ui/src/views/setting/notice/dingding.vue
Normal file
@@ -0,0 +1,151 @@
|
||||
<template>
|
||||
<div class="notice-dingding-wrapper" :style="{ height: `${windowHeight - 64}px` }">
|
||||
<a-form-model ref="dingdingForm" :model="dingdingData" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<SpanTitle>基础设置</SpanTitle>
|
||||
<a-form-model-item label="应用Key">
|
||||
<a-input v-model="dingdingData.appKey" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="应用密码">
|
||||
<a-input v-model="dingdingData.appSecret" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="机器人码">
|
||||
<a-input v-model="dingdingData.robotCode" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="机器人">
|
||||
<Bot
|
||||
ref="bot"
|
||||
:disabled="!isEditable"
|
||||
:columns="[
|
||||
{
|
||||
field: 'name',
|
||||
title: '名称',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'url',
|
||||
title: 'Webhook地址',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'token',
|
||||
title: 'token',
|
||||
required: false,
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</a-form-model-item>
|
||||
<!-- <a-form-model-item label="测试邮件设置">
|
||||
<a-button type="primary" ghost>测试回收箱</a-button>
|
||||
<br />
|
||||
<span
|
||||
class="notice-dingding-wrapper-tips"
|
||||
><ops-icon type="icon-shidi-quxiao" :style="{ color: '#D81E06' }" /> 邮件接收失败</span
|
||||
>
|
||||
<br />
|
||||
<span>邮箱服务器未配置,请配置一个邮箱服务器 | <a>故障诊断</a></span>
|
||||
</a-form-model-item> -->
|
||||
<a-row v-if="isEditable">
|
||||
<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-col>
|
||||
</a-row>
|
||||
</a-form-model>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import SpanTitle from '../components/spanTitle.vue'
|
||||
import { getNoticeConfigByPlatform, postNoticeConfigByPlatform, putNoticeConfigByPlatform } from '@/api/noticeSetting'
|
||||
import { mixinPermissions } from '@/utils/mixin'
|
||||
import Bot from './bot.vue'
|
||||
|
||||
export default {
|
||||
name: 'NoticeDingding',
|
||||
components: { SpanTitle, Bot },
|
||||
mixins: [mixinPermissions],
|
||||
data() {
|
||||
return {
|
||||
labelCol: { lg: 3, md: 5, sm: 8 },
|
||||
wrapperCol: { lg: 15, md: 19, sm: 16 },
|
||||
id: null,
|
||||
dingdingData: {
|
||||
appKey: '',
|
||||
appSecret: '',
|
||||
robotCode: '',
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
windowHeight: (state) => state.windowHeight,
|
||||
}),
|
||||
isEditable() {
|
||||
return this.hasDetailPermission('backend', '通知设置', ['update'])
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
getData() {
|
||||
getNoticeConfigByPlatform({ platform: 'dingdingApp' }).then((res) => {
|
||||
this.id = res?.id ?? null
|
||||
if (this.id) {
|
||||
this.dingdingData = res.info
|
||||
this.$refs.bot.setData(res?.info?.bot)
|
||||
}
|
||||
})
|
||||
},
|
||||
onSubmit() {
|
||||
this.$refs.dingdingForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
this.$refs.bot.getData(async (flag, bot) => {
|
||||
if (flag) {
|
||||
if (this.id) {
|
||||
await putNoticeConfigByPlatform(this.id, { info: { ...this.dingdingData, bot, label: '钉钉' } })
|
||||
} else {
|
||||
await postNoticeConfigByPlatform({
|
||||
platform: 'dingdingApp',
|
||||
info: { ...this.dingdingData, bot, label: '钉钉' },
|
||||
})
|
||||
}
|
||||
this.$message.success('保存成功')
|
||||
this.getData()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm() {
|
||||
this.dingdingData = {
|
||||
appKey: '',
|
||||
appSecret: '',
|
||||
robotCode: '',
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.notice-dingding-wrapper {
|
||||
background-color: #fff;
|
||||
padding-top: 15px;
|
||||
overflow: auto;
|
||||
margin-bottom: -24px;
|
||||
border-radius: 15px;
|
||||
.notice-dingding-wrapper-tips {
|
||||
display: inline-block;
|
||||
background-color: #ffdfdf;
|
||||
border-radius: 4px;
|
||||
padding: 0 12px;
|
||||
width: 300px;
|
||||
color: #000000;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
17
cmdb-ui/src/views/setting/notice/email/index.less
Normal file
17
cmdb-ui/src/views/setting/notice/email/index.less
Normal file
@@ -0,0 +1,17 @@
|
||||
.notice-email-wrapper {
|
||||
background-color: #fff;
|
||||
padding-top: 24px;
|
||||
overflow: auto;
|
||||
.notice-email-error-tips {
|
||||
display: inline-block;
|
||||
background-color: #ffdfdf;
|
||||
border-radius: 4px;
|
||||
padding: 0 12px;
|
||||
width: 300px;
|
||||
color: #000000;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
33
cmdb-ui/src/views/setting/notice/email/index.vue
Normal file
33
cmdb-ui/src/views/setting/notice/email/index.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div :style="{ marginBottom: '-24px' }">
|
||||
<a-tabs :activeKey="activeKey" @change="changeTab" class="ops-tab" type="card">
|
||||
<!-- <a-tab-pane key="1" tab="接收服务器">
|
||||
<Receive />
|
||||
</a-tab-pane> -->
|
||||
<a-tab-pane key="2" tab="发送服务器">
|
||||
<Send />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Receive from './receive.vue'
|
||||
import Send from './send.vue'
|
||||
export default {
|
||||
name: 'NoticeEmail',
|
||||
components: { Receive, Send },
|
||||
data() {
|
||||
return {
|
||||
activeKey: '2',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeTab(activeKey) {
|
||||
this.activeKey = activeKey
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
196
cmdb-ui/src/views/setting/notice/email/receive.vue
Normal file
196
cmdb-ui/src/views/setting/notice/email/receive.vue
Normal file
@@ -0,0 +1,196 @@
|
||||
<template>
|
||||
<div class="notice-email-wrapper" :style="{ height: `${windowHeight - 104}px` }">
|
||||
<a-form-model :model="settingData" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<SpanTitle>基础设置</SpanTitle>
|
||||
<a-form-model-item label="连接协议">
|
||||
<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="2"> EWS(Exchange Web服务) </a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="认证类型">
|
||||
<a-select v-model="settingData.authentication">
|
||||
<a-select-option value="Base"> 基本 </a-select-option>
|
||||
<a-select-option value="OAuth"> OAuth </a-select-option>
|
||||
</a-select>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="服务器名/IP地址" prop="IP">
|
||||
<a-input v-model="settingData.IP" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="用户名">
|
||||
<a-input v-model="settingData.username" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="密码">
|
||||
<a-input v-model="settingData.password" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="邮件地址">
|
||||
<a-input v-model="settingData.email" />
|
||||
</a-form-model-item>
|
||||
<template v-if="settingData.connectProtocol === 1">
|
||||
<a-form-model-item label="邮件类型">
|
||||
<a-select v-model="settingData.emailType">
|
||||
<a-select-option value="POP"> POP </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="IMAPS"> IMAPS </a-select-option>
|
||||
</a-select>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="端口">
|
||||
<a-input v-model="settingData.port" />
|
||||
</a-form-model-item>
|
||||
</template>
|
||||
<a-form-model-item label="测试邮件设置">
|
||||
<a-button type="primary" ghost>测试回收箱</a-button>
|
||||
<br />
|
||||
<span class="notice-email-error-tips">
|
||||
<ops-icon type="icon-shidi-quxiao" :style="{ color: '#D81E06' }" />
|
||||
邮件接收失败
|
||||
</span>
|
||||
<br />
|
||||
<span
|
||||
>邮箱服务器未配置,请配置一个邮箱服务器 <a-divider type="vertical" :style="{ backgroundColor: '#2F54EB' }" />
|
||||
<a>故障诊断</a></span
|
||||
>
|
||||
</a-form-model-item>
|
||||
<SpanTitle>邮件设置</SpanTitle>
|
||||
<a-form-model-item label="获取邮件间隔" :wrapperCol="{ span: 4 }">
|
||||
<a-input class="ant-input-after" v-model="settingData.getEmailTimeout" />
|
||||
<span :style="{ position: 'absolute', marginLeft: '8px' }">分</span>
|
||||
</a-form-model-item>
|
||||
<a-row>
|
||||
<a-col :span="16" :offset="3">
|
||||
<a-checkbox :default-checked="false" disabled>启动代理服务器</a-checkbox>
|
||||
<a-icon type="info-circle" :style="{ color: '#FF9E58', fontSize: '16px' }" />
|
||||
<a-divider type="vertical" :style="{ backgroundColor: '#2F54EB' }" />
|
||||
<a @click="configProxySetting">配置代理设置</a>
|
||||
<br />
|
||||
<a-checkbox :default-checked="false">启动邮件测试</a-checkbox>
|
||||
<br /><br />
|
||||
<a-checkbox :default-checked="false" @change="changeCreateReqByEmail">禁用通过邮件创建请求</a-checkbox>
|
||||
<br />
|
||||
<template v-if="settingData.banReqByEmail">
|
||||
<strong>指定允许的邮件/域名,逗号分隔多个值</strong>
|
||||
<a-input type="textarea" :style="{ borderRadius: '8px', borderColor: '#2F54EB' }" />
|
||||
<p :style="{ fontSize: '12px' }">例如:user@domain.com,*@domain.com</p>
|
||||
<p :style="{ fontSize: '12px' }">限制不能适用于已在会话中的请求,它将聚集到它的上级工单中</p>
|
||||
</template>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<SpanTitle>消息设置</SpanTitle>
|
||||
<a-row>
|
||||
<a-col :span="16" :offset="3">
|
||||
<a-checkbox :default-checked="false">将消息移动到错误的文件夹</a-checkbox>
|
||||
<a-icon type="info-circle" :style="{ color: '#FF9E58', fontSize: '16px' }" />
|
||||
<a-divider type="vertical" :style="{ backgroundColor: '#2F54EB' }" />
|
||||
<a href="#">了解更多</a>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<br /><br />
|
||||
<a-row>
|
||||
<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-col>
|
||||
</a-row>
|
||||
</a-form-model>
|
||||
<a-modal dialogClass="ops-modal" width="500px" v-model="visible" title="配置代理设置">
|
||||
<a-form-model v-model="proxySetting" :label-col="{ span: 4 }" :wrapper-col="{ span: 19 }">
|
||||
<a-form-model-item label="主机">
|
||||
<a-input v-model="proxySetting.host" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="端口">
|
||||
<a-input v-model="proxySetting.port" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="用户名">
|
||||
<a-input v-model="proxySetting.username" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="密码">
|
||||
<a-input v-model="proxySetting.password" />
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import SpanTitle from '../../components/spanTitle.vue'
|
||||
export default {
|
||||
name: 'Receive',
|
||||
components: { SpanTitle },
|
||||
data() {
|
||||
return {
|
||||
labelCol: { span: 3 },
|
||||
wrapperCol: { span: 10 },
|
||||
settingData: {
|
||||
connectProtocol: 1,
|
||||
authentication: 'Base',
|
||||
IP: '',
|
||||
username: '',
|
||||
password: '',
|
||||
email: '',
|
||||
emailType: '',
|
||||
port: '',
|
||||
|
||||
getEmailTimeout: '',
|
||||
activeProxy: false,
|
||||
activeEmailDebug: false,
|
||||
banReqByEmail: false,
|
||||
|
||||
transfromMessage: false,
|
||||
},
|
||||
visible: false,
|
||||
proxySetting: {
|
||||
host: '',
|
||||
post: '',
|
||||
username: '',
|
||||
password: '',
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
windowHeight: (state) => state.windowHeight,
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
changeConnectProtocol(e) {
|
||||
console.log(e.target.value)
|
||||
},
|
||||
changeCreateReqByEmail(e) {
|
||||
this.settingData.banReqByEmail = e.target.checked
|
||||
},
|
||||
configProxySetting() {
|
||||
this.visible = true
|
||||
},
|
||||
onSubmit() {
|
||||
console.log(this.settingData)
|
||||
},
|
||||
resetForm() {
|
||||
this.settingData = {
|
||||
connectProtocol: 1,
|
||||
authentication: '',
|
||||
IP: '',
|
||||
username: '',
|
||||
password: '',
|
||||
email: '',
|
||||
emailType: '',
|
||||
port: '',
|
||||
|
||||
getEmailTimeout: '',
|
||||
activeProxy: false,
|
||||
activeEmailDebug: false,
|
||||
banReqByEmail: false,
|
||||
|
||||
transfromMessage: false,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import './index.less';
|
||||
</style>
|
169
cmdb-ui/src/views/setting/notice/email/send.vue
Normal file
169
cmdb-ui/src/views/setting/notice/email/send.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<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">
|
||||
<SpanTitle>基础设置</SpanTitle>
|
||||
<a-form-model-item label="是否加密">
|
||||
<a-radio-group v-model="settingData.tls" :disabled="!isEditable">
|
||||
<a-radio :value="true">
|
||||
是
|
||||
</a-radio>
|
||||
<a-radio :value="false">
|
||||
否
|
||||
</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="端口" prop="port">
|
||||
<a-input v-model="settingData.port" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="邮件服务器" prop="host">
|
||||
<a-input v-model="settingData.host" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="用户名" prop="account">
|
||||
<a-input v-model="settingData.account" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="密码" prop="password">
|
||||
<a-input-password v-model="settingData.password" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<SpanTitle>邮件测试</SpanTitle>
|
||||
<a-form-model-item label="测试发送邮件地址" prop="receive_address">
|
||||
<a-input v-model="settingData.receive_address" :disabled="!isEditable">
|
||||
<span
|
||||
v-if="isEditable"
|
||||
:style="{ cursor: 'pointer' }"
|
||||
@click="testSendEmail"
|
||||
slot="addonAfter"
|
||||
>测试邮件发送</span
|
||||
>
|
||||
</a-input>
|
||||
</a-form-model-item>
|
||||
<a-row v-if="isEditable">
|
||||
<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-col>
|
||||
</a-row>
|
||||
</a-form-model>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import SpanTitle from '../../components/spanTitle.vue'
|
||||
import {
|
||||
getNoticeConfigByPlatform,
|
||||
postNoticeConfigByPlatform,
|
||||
putNoticeConfigByPlatform,
|
||||
sendTestEmail,
|
||||
} from '@/api/noticeSetting'
|
||||
import { mixinPermissions } from '@/utils/mixin'
|
||||
export default {
|
||||
name: 'Send',
|
||||
mixins: [mixinPermissions],
|
||||
components: { SpanTitle },
|
||||
data() {
|
||||
return {
|
||||
labelCol: { lg: 3, md: 5, sm: 8 },
|
||||
wrapperCol: { lg: 10, md: 12, sm: 12 },
|
||||
id: null,
|
||||
settingData: {
|
||||
tls: true,
|
||||
host: '',
|
||||
account: '',
|
||||
password: '',
|
||||
port: '',
|
||||
receive_address: '',
|
||||
},
|
||||
rules: {
|
||||
port: [{ required: true, message: '请输入端口', trigger: 'blur' }],
|
||||
host: [{ required: true, whitespace: true, message: '请输入服务器', trigger: 'blur' }],
|
||||
account: [
|
||||
{ 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',
|
||||
},
|
||||
],
|
||||
password: [{ required: false, whitespace: true, message: '请输入密码', trigger: 'blur' }],
|
||||
receive_address: [
|
||||
{ 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}$/,
|
||||
message: '邮箱格式错误',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
windowHeight: (state) => state.windowHeight,
|
||||
}),
|
||||
isEditable() {
|
||||
return this.hasDetailPermission('backend', '通知设置', ['update'])
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'settingData.tls': {
|
||||
handler(newV, oldV) {
|
||||
if (newV === false) {
|
||||
this.settingData.port = 25
|
||||
}
|
||||
if (newV === true) {
|
||||
this.settingData.port = 465
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
getData() {
|
||||
getNoticeConfigByPlatform({ platform: 'email' }).then((res) => {
|
||||
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 },
|
||||
})
|
||||
this.$message.success('已发送邮件,请查收')
|
||||
},
|
||||
onSubmit() {
|
||||
this.$refs.sendForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
if (this.id) {
|
||||
await putNoticeConfigByPlatform(this.id, { info: { ...this.settingData, label: '邮箱' } })
|
||||
} else {
|
||||
await postNoticeConfigByPlatform({ platform: 'email', info: { ...this.settingData, label: '邮箱' } })
|
||||
}
|
||||
this.$message.success('保存成功')
|
||||
this.getData()
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm() {
|
||||
this.settingData = {
|
||||
tls: true,
|
||||
host: '',
|
||||
account: '',
|
||||
password: '',
|
||||
port: 25,
|
||||
receive_address: '',
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import './index.less';
|
||||
</style>
|
131
cmdb-ui/src/views/setting/notice/feishu.vue
Normal file
131
cmdb-ui/src/views/setting/notice/feishu.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<div class="notice-feishu-wrapper" :style="{ height: `${windowHeight - 64}px` }">
|
||||
<a-form-model ref="feishuForm" :model="feishuData" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<SpanTitle>基础设置</SpanTitle>
|
||||
<a-form-model-item label="应用ID">
|
||||
<a-input v-model="feishuData.id" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="应用密码">
|
||||
<a-input v-model="feishuData.password" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="机器人">
|
||||
<Bot
|
||||
ref="bot"
|
||||
:disabled="!isEditable"
|
||||
:columns="[
|
||||
{
|
||||
field: 'name',
|
||||
title: '名称',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'url',
|
||||
title: 'Webhook地址',
|
||||
required: true,
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</a-form-model-item>
|
||||
<a-row v-if="isEditable">
|
||||
<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-col>
|
||||
</a-row>
|
||||
</a-form-model>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import SpanTitle from '../components/spanTitle.vue'
|
||||
import { getNoticeConfigByPlatform, postNoticeConfigByPlatform, putNoticeConfigByPlatform } from '@/api/noticeSetting'
|
||||
import { mixinPermissions } from '@/utils/mixin'
|
||||
import Bot from './bot.vue'
|
||||
|
||||
export default {
|
||||
name: 'NoticeFeishu',
|
||||
components: { SpanTitle, Bot },
|
||||
mixins: [mixinPermissions],
|
||||
data() {
|
||||
return {
|
||||
labelCol: { lg: 3, md: 5, sm: 8 },
|
||||
wrapperCol: { lg: 15, md: 19, sm: 16 },
|
||||
id: null,
|
||||
feishuData: {
|
||||
id: '',
|
||||
password: '',
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
windowHeight: (state) => state.windowHeight,
|
||||
}),
|
||||
isEditable() {
|
||||
return this.hasDetailPermission('backend', '通知设置', ['update'])
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
getData() {
|
||||
getNoticeConfigByPlatform({ platform: 'feishuApp' }).then((res) => {
|
||||
this.id = res?.id ?? null
|
||||
if (this.id) {
|
||||
this.feishuData = res.info
|
||||
this.$refs.bot.setData(res?.info?.bot)
|
||||
}
|
||||
})
|
||||
},
|
||||
onSubmit() {
|
||||
this.$refs.feishuForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
this.$refs.bot.getData(async (flag, bot) => {
|
||||
if (flag) {
|
||||
if (this.id) {
|
||||
await putNoticeConfigByPlatform(this.id, { info: { ...this.feishuData, bot, label: '飞书' } })
|
||||
} else {
|
||||
await postNoticeConfigByPlatform({
|
||||
platform: 'feishuApp',
|
||||
info: { ...this.feishuData, bot, label: '飞书' },
|
||||
})
|
||||
}
|
||||
this.$message.success('保存成功')
|
||||
this.getData()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm() {
|
||||
this.feishuData = {
|
||||
id: '',
|
||||
password: '',
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.notice-feishu-wrapper {
|
||||
background-color: #fff;
|
||||
padding-top: 15px;
|
||||
overflow: auto;
|
||||
margin-bottom: -24px;
|
||||
border-radius: 15px;
|
||||
.notice-feishu-wrapper-tips {
|
||||
display: inline-block;
|
||||
background-color: #ffdfdf;
|
||||
border-radius: 4px;
|
||||
padding: 0 12px;
|
||||
width: 300px;
|
||||
color: #000000;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
135
cmdb-ui/src/views/setting/notice/wx.vue
Normal file
135
cmdb-ui/src/views/setting/notice/wx.vue
Normal file
@@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<div class="notice-wx-wrapper" :style="{ height: `${windowHeight - 64}px` }">
|
||||
<a-form-model ref="wxForm" :model="wxData" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<SpanTitle>基础设置</SpanTitle>
|
||||
<a-form-model-item label="企业ID">
|
||||
<a-input v-model="wxData.corpid" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="自建应用ID">
|
||||
<a-input v-model="wxData.agentid" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="自建应用密码">
|
||||
<a-input-password v-model="wxData.corpsecret" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="ITSM AppId">
|
||||
<a-input v-model="wxData.itsm_app_id" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="机器人">
|
||||
<Bot ref="bot" :disabled="!isEditable" />
|
||||
</a-form-model-item>
|
||||
<!-- <a-form-model-item label="测试邮件设置">
|
||||
<a-button type="primary" ghost>测试回收箱</a-button>
|
||||
<br />
|
||||
<span
|
||||
class="notice-wx-wrapper-tips"
|
||||
><ops-icon type="icon-shidi-quxiao" :style="{ color: '#D81E06' }" /> 邮件接收失败</span
|
||||
>
|
||||
<br />
|
||||
<span>邮箱服务器未配置,请配置一个邮箱服务器 | <a>故障诊断</a></span>
|
||||
</a-form-model-item> -->
|
||||
<a-row v-if="isEditable">
|
||||
<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-col>
|
||||
</a-row>
|
||||
</a-form-model>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import SpanTitle from '../components/spanTitle.vue'
|
||||
import { getNoticeConfigByPlatform, postNoticeConfigByPlatform, putNoticeConfigByPlatform } from '@/api/noticeSetting'
|
||||
import { mixinPermissions } from '@/utils/mixin'
|
||||
import Bot from './bot.vue'
|
||||
export default {
|
||||
name: 'NoticeWx',
|
||||
mixins: [mixinPermissions],
|
||||
components: { SpanTitle, Bot },
|
||||
data() {
|
||||
return {
|
||||
labelCol: { lg: 3, md: 5, sm: 8 },
|
||||
wrapperCol: { lg: 15, md: 19, sm: 16 },
|
||||
id: null,
|
||||
wxData: {
|
||||
corpid: '',
|
||||
agentid: '',
|
||||
corpsecret: '',
|
||||
itsm_app_id: '',
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
windowHeight: (state) => state.windowHeight,
|
||||
}),
|
||||
isEditable() {
|
||||
return this.hasDetailPermission('backend', '通知设置', ['update'])
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
getData() {
|
||||
getNoticeConfigByPlatform({ platform: 'wechatApp' }).then((res) => {
|
||||
this.id = res?.id ?? null
|
||||
if (this.id) {
|
||||
this.wxData = res.info
|
||||
this.$refs.bot.setData(res?.info?.bot)
|
||||
}
|
||||
})
|
||||
},
|
||||
onSubmit() {
|
||||
this.$refs.wxForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
this.$refs.bot.getData(async (flag, bot) => {
|
||||
if (flag) {
|
||||
if (this.id) {
|
||||
await putNoticeConfigByPlatform(this.id, { info: { ...this.wxData, bot, label: '企业微信' } })
|
||||
} else {
|
||||
await postNoticeConfigByPlatform({
|
||||
platform: 'wechatApp',
|
||||
info: { ...this.wxData, bot, label: '企业微信' },
|
||||
})
|
||||
}
|
||||
this.$message.success('保存成功')
|
||||
this.getData()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm() {
|
||||
this.wxData = {
|
||||
corpid: '',
|
||||
agentid: '',
|
||||
corpsecret: '',
|
||||
itsm_app_id: '',
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<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>
|
@@ -1,368 +1,405 @@
|
||||
<template>
|
||||
<div class="setting-person">
|
||||
<div class="setting-person-left">
|
||||
<div
|
||||
@click="
|
||||
() => {
|
||||
$refs.personForm.clearValidate()
|
||||
$nextTick(() => {
|
||||
current = '1'
|
||||
})
|
||||
}
|
||||
"
|
||||
:class="{ 'setting-person-left-item': true, 'setting-person-left-item-selected': current === '1' }"
|
||||
>
|
||||
<ops-icon type="icon-shidi-yonghu" />个人信息
|
||||
</div>
|
||||
<div
|
||||
@click="
|
||||
() => {
|
||||
$refs.personForm.clearValidate()
|
||||
$nextTick(() => {
|
||||
current = '2'
|
||||
})
|
||||
}
|
||||
"
|
||||
:class="{ 'setting-person-left-item': true, 'setting-person-left-item-selected': current === '2' }"
|
||||
>
|
||||
<a-icon type="unlock" theme="filled" />账号密码
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-person-right">
|
||||
<a-form-model
|
||||
ref="personForm"
|
||||
:model="form"
|
||||
:rules="current === '1' ? rules1 : rules2"
|
||||
:colon="false"
|
||||
labelAlign="left"
|
||||
:labelCol="{ span: 4 }"
|
||||
:wrapperCol="{ span: 10 }"
|
||||
>
|
||||
<div v-show="current === '1'">
|
||||
<a-form-model-item label="头像" :style="{ display: 'flex', alignItems: 'center' }">
|
||||
<a-space>
|
||||
<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">
|
||||
<ops-icon type="icon-shidi-yonghu" :style="{ color: '#2F54EB' }" />
|
||||
</a-avatar>
|
||||
<a-upload
|
||||
name="avatar"
|
||||
:show-upload-list="false"
|
||||
:customRequest="customRequest"
|
||||
:before-upload="beforeUpload"
|
||||
:style="{ width: '310px', height: '100px' }"
|
||||
accept=".svg,.png,.jpg,.jpeg"
|
||||
>
|
||||
<a-button type="primary" ghost size="small">更换头像</a-button>
|
||||
</a-upload>
|
||||
</a-space>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="姓名" prop="nickname">
|
||||
<a-input v-model="form.nickname" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="用户名">
|
||||
<div class="setting-person-right-disabled">{{ form.username }}</div>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="邮箱">
|
||||
<div class="setting-person-right-disabled">{{ form.email }}</div>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="直属上级">
|
||||
<div class="setting-person-right-disabled">
|
||||
{{ getDirectorName(allFlatEmployees, form.direct_supervisor_id) }}
|
||||
</div>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="性别">
|
||||
<a-select v-model="form.sex">
|
||||
<a-select-option value="男">男</a-select-option>
|
||||
<a-select-option value="女">女</a-select-option>
|
||||
</a-select>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="手机号" prop="mobile">
|
||||
<a-input v-model="form.mobile" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="部门">
|
||||
<div class="setting-person-right-disabled">
|
||||
{{ getDepartmentName(allFlatDepartments, form.department_id) }}
|
||||
</div>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="岗位">
|
||||
<div class="setting-person-right-disabled">{{ form.position_name }}</div>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="绑定信息">
|
||||
<a-space>
|
||||
<div :class="{ 'setting-person-bind': true, 'setting-person-bind-existed': form.wx_id }">
|
||||
<ops-icon type="ops-setting-notice-wx" />
|
||||
</div>
|
||||
<div @click="handleBindWx" class="setting-person-bind-button">
|
||||
{{ form.notice_info && form.notice_info.wechatApp ? '重新绑定' : '绑定' }}
|
||||
</div>
|
||||
</a-space>
|
||||
</a-form-model-item>
|
||||
</div>
|
||||
<div v-show="current === '2'">
|
||||
<a-form-model-item label="新密码" prop="password1">
|
||||
<a-input v-model="form.password1" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="确认密码" prop="password2">
|
||||
<a-input v-model="form.password2" />
|
||||
</a-form-model-item>
|
||||
</div>
|
||||
<div style="margin-right: 120px">
|
||||
<a-form-model-item label=" ">
|
||||
<a-button type="primary" @click="handleSave" :style="{ width: '100%' }">保存</a-button>
|
||||
</a-form-model-item>
|
||||
</div>
|
||||
</a-form-model>
|
||||
</div>
|
||||
<EditImage
|
||||
v-if="showEditImage"
|
||||
:fixed-number="eidtImageOption.fixedNumber"
|
||||
:show="showEditImage"
|
||||
:image="editImage"
|
||||
:title="eidtImageOption.title"
|
||||
:preview-width="eidtImageOption.previewWidth"
|
||||
:preview-height="eidtImageOption.previewHeight"
|
||||
preview-radius="0"
|
||||
width="550px"
|
||||
save-button-title="确定"
|
||||
@save="submitImage"
|
||||
@close="showEditImage = false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
import { getAllDepartmentList } from '@/api/company'
|
||||
import { postImageFile } from '@/api/file'
|
||||
import {
|
||||
getEmployeeList,
|
||||
getEmployeeByUid,
|
||||
updateEmployeeByUid,
|
||||
updatePasswordByUid,
|
||||
bindWxByUid,
|
||||
} from '@/api/employee'
|
||||
import { getDepartmentName, getDirectorName } from '@/utils/util'
|
||||
import EditImage from '../components/EditImage.vue'
|
||||
export default {
|
||||
name: 'Person',
|
||||
components: { EditImage },
|
||||
data() {
|
||||
const validatePassword = (rule, value, callback) => {
|
||||
if (!value) {
|
||||
callback(new Error('请二次确认新密码'))
|
||||
}
|
||||
if (value !== this.form.password1) {
|
||||
callback(new Error('两次输入密码不一致'))
|
||||
}
|
||||
callback()
|
||||
}
|
||||
return {
|
||||
current: '1',
|
||||
form: {},
|
||||
rules1: {
|
||||
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',
|
||||
},
|
||||
],
|
||||
},
|
||||
rules2: {
|
||||
password1: [{ required: true, message: '请输入新密码', trigger: 'blur' }],
|
||||
password2: [{ required: true, message: '两次输入密码不一致', trigger: 'blur', validator: validatePassword }],
|
||||
},
|
||||
allFlatEmployees: [],
|
||||
allFlatDepartments: [],
|
||||
showEditImage: false,
|
||||
eidtImageOption: {
|
||||
type: 'avatar',
|
||||
fixedNumber: [4, 4],
|
||||
title: '编辑头像',
|
||||
previewWidth: '60px',
|
||||
previewHeight: '60px',
|
||||
},
|
||||
editImage: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['uid']),
|
||||
},
|
||||
mounted() {
|
||||
this.getAllFlatEmployees()
|
||||
this.getAllFlatDepartment()
|
||||
this.getEmployeeByUid()
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['GetInfo']),
|
||||
getDepartmentName,
|
||||
getDirectorName,
|
||||
getEmployeeByUid() {
|
||||
getEmployeeByUid(this.uid).then((res) => {
|
||||
this.form = { ...res }
|
||||
})
|
||||
},
|
||||
getAllFlatEmployees() {
|
||||
getEmployeeList({ block_status: 0, page_size: 99999 }).then((res) => {
|
||||
this.allFlatEmployees = res.data_list
|
||||
})
|
||||
},
|
||||
getAllFlatDepartment() {
|
||||
getAllDepartmentList({ is_tree: 0 }).then((res) => {
|
||||
this.allFlatDepartments = res
|
||||
})
|
||||
},
|
||||
async handleSave() {
|
||||
await this.$refs.personForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
const { nickname, mobile, sex, avatar, password1 } = this.form
|
||||
const params = { nickname, mobile, sex, avatar }
|
||||
if (this.current === '1') {
|
||||
await updateEmployeeByUid(this.uid, params).then((res) => {
|
||||
this.$message.success('保存成功!')
|
||||
this.getEmployeeByUid()
|
||||
this.GetInfo()
|
||||
})
|
||||
} else {
|
||||
await updatePasswordByUid(this.uid, { password: password1 }).then((res) => {
|
||||
this.$message.success('保存成功!')
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
customRequest(file) {
|
||||
const reader = new FileReader()
|
||||
var self = this
|
||||
reader.onload = function(e) {
|
||||
let result
|
||||
if (typeof e.target.result === 'object') {
|
||||
// 把Array Buffer转化为blob 如果是base64不需要
|
||||
result = window.URL.createObjectURL(new Blob([e.target.result]))
|
||||
} else {
|
||||
result = e.target.result
|
||||
}
|
||||
|
||||
self.editImage = result
|
||||
self.showEditImage = true
|
||||
}
|
||||
reader.readAsDataURL(file.file)
|
||||
},
|
||||
beforeUpload(file) {
|
||||
const isLt2M = file.size / 1024 / 1024 < 2
|
||||
if (!isLt2M) {
|
||||
this.$message.error('图片大小不可超过2MB!')
|
||||
}
|
||||
return isLt2M
|
||||
},
|
||||
submitImage(file) {
|
||||
postImageFile(file).then((res) => {
|
||||
if (res.file_name) {
|
||||
this.form.avatar = res.file_name
|
||||
}
|
||||
})
|
||||
},
|
||||
async handleBindWx() {
|
||||
await this.$refs.personForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
const { nickname, mobile, sex, avatar } = this.form
|
||||
const params = { nickname, mobile, sex, avatar }
|
||||
await updateEmployeeByUid(this.uid, params)
|
||||
bindWxByUid(this.uid)
|
||||
.then(() => {
|
||||
this.$message.success('绑定成功!')
|
||||
})
|
||||
.finally(() => {
|
||||
this.getEmployeeByUid()
|
||||
this.GetInfo()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import '~@/style/static.less';
|
||||
.setting-person {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.setting-person-left {
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
margin-right: 24px;
|
||||
background-color: #fff;
|
||||
border-radius: 15px;
|
||||
padding-top: 15px;
|
||||
.setting-person-left-item {
|
||||
cursor: pointer;
|
||||
padding: 10px 20px;
|
||||
color: #a5a9bc;
|
||||
border-left: 4px solid #fff;
|
||||
margin-bottom: 5px;
|
||||
&:hover {
|
||||
.ops_popover_item_selected();
|
||||
border-color: #custom_colors[color_1];
|
||||
}
|
||||
> i {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.setting-person-left-item-selected {
|
||||
.ops_popover_item_selected();
|
||||
border-color: #custom_colors[color_1];
|
||||
}
|
||||
}
|
||||
.setting-person-right {
|
||||
width: 800px;
|
||||
height: 700px;
|
||||
background-color: #fff;
|
||||
border-radius: 15px;
|
||||
padding: 24px 48px;
|
||||
.setting-person-right-disabled {
|
||||
background-color: #custom_colors[color_2];
|
||||
border-radius: 4px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
margin-top: 4px;
|
||||
padding: 0 10px;
|
||||
color: #a5a9bc;
|
||||
}
|
||||
.setting-person-bind {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: #a5a9bc;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
font-size: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
.setting-person-bind-existed {
|
||||
background: #008cee;
|
||||
}
|
||||
.setting-person-bind-button {
|
||||
height: 40px;
|
||||
width: 72px;
|
||||
background: #f0f5ff;
|
||||
border-radius: 4px;
|
||||
padding: 0 8px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="less">
|
||||
.setting-person-right .ant-form-item {
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<div class="setting-person">
|
||||
<div class="setting-person-left">
|
||||
<div
|
||||
@click="
|
||||
() => {
|
||||
$refs.personForm.clearValidate()
|
||||
$nextTick(() => {
|
||||
current = '1'
|
||||
})
|
||||
}
|
||||
"
|
||||
:class="{ 'setting-person-left-item': true, 'setting-person-left-item-selected': current === '1' }"
|
||||
>
|
||||
<ops-icon type="icon-shidi-yonghu" />个人信息
|
||||
</div>
|
||||
<div
|
||||
@click="
|
||||
() => {
|
||||
$refs.personForm.clearValidate()
|
||||
$nextTick(() => {
|
||||
current = '2'
|
||||
})
|
||||
}
|
||||
"
|
||||
:class="{ 'setting-person-left-item': true, 'setting-person-left-item-selected': current === '2' }"
|
||||
>
|
||||
<a-icon type="unlock" theme="filled" />账号密码
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-person-right">
|
||||
<a-form-model
|
||||
ref="personForm"
|
||||
:model="form"
|
||||
:rules="current === '1' ? rules1 : rules2"
|
||||
:colon="false"
|
||||
labelAlign="left"
|
||||
:labelCol="{ span: 4 }"
|
||||
:wrapperCol="{ span: 10 }"
|
||||
>
|
||||
<div v-show="current === '1'">
|
||||
<a-form-model-item label="头像" :style="{ display: 'flex', alignItems: 'center' }">
|
||||
<a-space>
|
||||
<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">
|
||||
<ops-icon type="icon-shidi-yonghu" :style="{ color: '#2F54EB' }" />
|
||||
</a-avatar>
|
||||
<a-upload
|
||||
name="avatar"
|
||||
:show-upload-list="false"
|
||||
:customRequest="customRequest"
|
||||
:before-upload="beforeUpload"
|
||||
:style="{ width: '310px', height: '100px' }"
|
||||
accept=".svg,.png,.jpg,.jpeg"
|
||||
>
|
||||
<a-button type="primary" ghost size="small">更换头像</a-button>
|
||||
</a-upload>
|
||||
</a-space>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="姓名" prop="nickname">
|
||||
<a-input v-model="form.nickname" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="用户名">
|
||||
<div class="setting-person-right-disabled">{{ form.username }}</div>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="邮箱">
|
||||
<div class="setting-person-right-disabled">{{ form.email }}</div>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="直属上级">
|
||||
<div class="setting-person-right-disabled">
|
||||
{{ getDirectorName(allFlatEmployees, form.direct_supervisor_id) }}
|
||||
</div>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="性别">
|
||||
<a-select v-model="form.sex">
|
||||
<a-select-option value="男">男</a-select-option>
|
||||
<a-select-option value="女">女</a-select-option>
|
||||
</a-select>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="手机号" prop="mobile">
|
||||
<a-input v-model="form.mobile" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="部门">
|
||||
<div class="setting-person-right-disabled">
|
||||
{{ getDepartmentName(allFlatDepartments, form.department_id) }}
|
||||
</div>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="岗位">
|
||||
<div class="setting-person-right-disabled">{{ form.position_name }}</div>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="绑定信息">
|
||||
<a-space>
|
||||
<a-tooltip title="企业微信">
|
||||
<div
|
||||
@click="handleBind('wechatApp', form.notice_info && form.notice_info.wechatApp)"
|
||||
:class="{
|
||||
'setting-person-bind': true,
|
||||
'setting-person-bind-existed': form.notice_info && form.notice_info.wechatApp,
|
||||
}"
|
||||
>
|
||||
<ops-icon type="ops-setting-notice-wx" />
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<a-tooltip title="飞书">
|
||||
<div
|
||||
@click="handleBind('feishuApp', form.notice_info && form.notice_info.feishuApp)"
|
||||
:class="{
|
||||
'setting-person-bind': true,
|
||||
'setting-person-bind-existed': form.notice_info && form.notice_info.feishuApp,
|
||||
}"
|
||||
>
|
||||
<ops-icon type="ops-setting-notice-feishu" />
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<a-tooltip title="钉钉">
|
||||
<div
|
||||
@click="handleBind('dingdingApp', form.notice_info && form.notice_info.dingdingApp)"
|
||||
:class="{
|
||||
'setting-person-bind': true,
|
||||
'setting-person-bind-existed': form.notice_info && form.notice_info.dingdingApp,
|
||||
}"
|
||||
>
|
||||
<ops-icon type="ops-setting-notice-dingding" />
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</a-form-model-item>
|
||||
</div>
|
||||
<div v-show="current === '2'">
|
||||
<a-form-model-item label="新密码" prop="password1">
|
||||
<a-input v-model="form.password1" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="确认密码" prop="password2">
|
||||
<a-input v-model="form.password2" />
|
||||
</a-form-model-item>
|
||||
</div>
|
||||
<div style="margin-right: 120px">
|
||||
<a-form-model-item label=" ">
|
||||
<a-button type="primary" @click="handleSave" :style="{ width: '100%' }">保存</a-button>
|
||||
</a-form-model-item>
|
||||
</div>
|
||||
</a-form-model>
|
||||
</div>
|
||||
<EditImage
|
||||
v-if="showEditImage"
|
||||
:show="showEditImage"
|
||||
:image="editImage"
|
||||
:title="eidtImageOption.title"
|
||||
:preview-width="eidtImageOption.previewWidth"
|
||||
:preview-height="eidtImageOption.previewHeight"
|
||||
preview-radius="0"
|
||||
width="550px"
|
||||
save-button-title="确定"
|
||||
@save="submitImage"
|
||||
@close="showEditImage = false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
import { getAllDepartmentList } from '@/api/company'
|
||||
import { postImageFile } from '@/api/file'
|
||||
import {
|
||||
getEmployeeList,
|
||||
getEmployeeByUid,
|
||||
updateEmployeeByUid,
|
||||
updatePasswordByUid,
|
||||
bindPlatformByUid,
|
||||
unbindPlatformByUid,
|
||||
} from '@/api/employee'
|
||||
import { getDepartmentName, getDirectorName } from '@/utils/util'
|
||||
import EditImage from '../components/EditImage.vue'
|
||||
export default {
|
||||
name: 'Person',
|
||||
components: { EditImage },
|
||||
data() {
|
||||
const validatePassword = (rule, value, callback) => {
|
||||
if (!value) {
|
||||
callback(new Error('请二次确认新密码'))
|
||||
}
|
||||
if (value !== this.form.password1) {
|
||||
callback(new Error('两次输入密码不一致'))
|
||||
}
|
||||
callback()
|
||||
}
|
||||
return {
|
||||
current: '1',
|
||||
form: {},
|
||||
rules1: {
|
||||
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',
|
||||
},
|
||||
],
|
||||
},
|
||||
rules2: {
|
||||
password1: [{ required: true, message: '请输入新密码', trigger: 'blur' }],
|
||||
password2: [{ required: true, message: '两次输入密码不一致', trigger: 'blur', validator: validatePassword }],
|
||||
},
|
||||
allFlatEmployees: [],
|
||||
allFlatDepartments: [],
|
||||
showEditImage: false,
|
||||
eidtImageOption: {
|
||||
type: 'avatar',
|
||||
fixedNumber: [4, 4],
|
||||
title: '编辑头像',
|
||||
previewWidth: '60px',
|
||||
previewHeight: '60px',
|
||||
},
|
||||
editImage: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['uid']),
|
||||
},
|
||||
mounted() {
|
||||
this.getAllFlatEmployees()
|
||||
this.getAllFlatDepartment()
|
||||
this.getEmployeeByUid()
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['GetInfo']),
|
||||
getDepartmentName,
|
||||
getDirectorName,
|
||||
getEmployeeByUid() {
|
||||
getEmployeeByUid(this.uid).then((res) => {
|
||||
this.form = { ...res }
|
||||
})
|
||||
},
|
||||
getAllFlatEmployees() {
|
||||
getEmployeeList({ block_status: 0, page_size: 99999 }).then((res) => {
|
||||
this.allFlatEmployees = res.data_list
|
||||
})
|
||||
},
|
||||
getAllFlatDepartment() {
|
||||
getAllDepartmentList({ is_tree: 0 }).then((res) => {
|
||||
this.allFlatDepartments = res
|
||||
})
|
||||
},
|
||||
async handleSave() {
|
||||
await this.$refs.personForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
const { nickname, mobile, sex, avatar, password1 } = this.form
|
||||
const params = { nickname, mobile, sex, avatar }
|
||||
if (this.current === '1') {
|
||||
await updateEmployeeByUid(this.uid, params).then((res) => {
|
||||
this.$message.success('保存成功!')
|
||||
this.getEmployeeByUid()
|
||||
this.GetInfo()
|
||||
})
|
||||
} else {
|
||||
await updatePasswordByUid(this.uid, { password: password1 }).then((res) => {
|
||||
this.$message.success('保存成功!')
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
customRequest(file) {
|
||||
const reader = new FileReader()
|
||||
var self = this
|
||||
reader.onload = function(e) {
|
||||
let result
|
||||
if (typeof e.target.result === 'object') {
|
||||
// 把Array Buffer转化为blob 如果是base64不需要
|
||||
result = window.URL.createObjectURL(new Blob([e.target.result]))
|
||||
} else {
|
||||
result = e.target.result
|
||||
}
|
||||
|
||||
self.editImage = result
|
||||
self.showEditImage = true
|
||||
}
|
||||
reader.readAsDataURL(file.file)
|
||||
},
|
||||
beforeUpload(file) {
|
||||
const isLt2M = file.size / 1024 / 1024 < 2
|
||||
if (!isLt2M) {
|
||||
this.$message.error('图片大小不可超过2MB!')
|
||||
}
|
||||
return isLt2M
|
||||
},
|
||||
submitImage(file) {
|
||||
postImageFile(file).then((res) => {
|
||||
if (res.file_name) {
|
||||
this.form.avatar = res.file_name
|
||||
}
|
||||
})
|
||||
},
|
||||
async handleBind(platform, isBind) {
|
||||
if (isBind) {
|
||||
const that = this
|
||||
this.$confirm({
|
||||
title: '警告',
|
||||
content: `确认解绑?`,
|
||||
onOk() {
|
||||
unbindPlatformByUid(platform, that.uid)
|
||||
.then(() => {
|
||||
that.$message.success('解绑成功!')
|
||||
})
|
||||
.finally(() => {
|
||||
that.getEmployeeByUid()
|
||||
that.GetInfo()
|
||||
})
|
||||
},
|
||||
})
|
||||
} else {
|
||||
await this.$refs.personForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
const { nickname, mobile, sex, avatar } = this.form
|
||||
const params = { nickname, mobile, sex, avatar }
|
||||
await updateEmployeeByUid(this.uid, params)
|
||||
bindPlatformByUid(platform, this.uid)
|
||||
.then(() => {
|
||||
this.$message.success('绑定成功!')
|
||||
})
|
||||
.finally(() => {
|
||||
this.getEmployeeByUid()
|
||||
this.GetInfo()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import '~@/style/static.less';
|
||||
.setting-person {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.setting-person-left {
|
||||
width: 200px;
|
||||
height: 400px;
|
||||
margin-right: 24px;
|
||||
background-color: #fff;
|
||||
border-radius: 15px;
|
||||
padding-top: 15px;
|
||||
.setting-person-left-item {
|
||||
cursor: pointer;
|
||||
padding: 10px 20px;
|
||||
color: #a5a9bc;
|
||||
border-left: 4px solid #fff;
|
||||
margin-bottom: 5px;
|
||||
&:hover {
|
||||
.ops_popover_item_selected();
|
||||
border-color: #custom_colors[color_1];
|
||||
}
|
||||
> i {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.setting-person-left-item-selected {
|
||||
.ops_popover_item_selected();
|
||||
border-color: #custom_colors[color_1];
|
||||
}
|
||||
}
|
||||
.setting-person-right {
|
||||
width: 800px;
|
||||
height: 700px;
|
||||
background-color: #fff;
|
||||
border-radius: 15px;
|
||||
padding: 24px 48px;
|
||||
.setting-person-right-disabled {
|
||||
background-color: #custom_colors[color_2];
|
||||
border-radius: 4px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
margin-top: 4px;
|
||||
padding: 0 10px;
|
||||
color: #a5a9bc;
|
||||
}
|
||||
.setting-person-bind {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
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>
|
||||
|
Reference in New Issue
Block a user