|
@@ -28,7 +28,7 @@
|
|
|
<el-button :icon="Search" @click="getTableData()" />
|
|
|
</template>
|
|
|
</el-input>
|
|
|
-
|
|
|
+
|
|
|
<div class="formItem mr-6 flex items-center">
|
|
|
<div class="text-nowrap">状态:</div>
|
|
|
<el-select v-model="teamForm.status" placeholder="请选择" size="default" style="width: 100px"
|
|
@@ -43,8 +43,10 @@
|
|
|
<el-option v-for="item in roleList" :key="item.id" :label="item.rolename" :value="item.id" />
|
|
|
</el-select>
|
|
|
</div>
|
|
|
- <el-button type="primary" v-if="userInfo.userNameNeedTranslate == 1" @click="transitionOperation('exportUser', '')" v-permission="['teamExport']">导出人员</el-button>
|
|
|
- <el-button type="primary" v-if="userInfo.userNameNeedTranslate == 1" @click="dialogFrom.newSyncWithCorpWxDayloadVisable = true">同步企微通讯录</el-button>
|
|
|
+ <el-button type="primary" v-if="userInfo.userNameNeedTranslate == 1"
|
|
|
+ @click="transitionOperation('exportUser', '')" v-permission="['teamExport']">导出人员</el-button>
|
|
|
+ <el-button type="primary" v-if="userInfo.userNameNeedTranslate == 1"
|
|
|
+ @click="dialogFrom.newSyncWithCorpWxDayloadVisable = true">同步企微通讯录</el-button>
|
|
|
<el-dropdown v-if="userInfo.userNameNeedTranslate != 1">
|
|
|
<el-button type="primary">
|
|
|
更多操作<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
|
@@ -52,8 +54,19 @@
|
|
|
<template #dropdown>
|
|
|
<el-dropdown-menu>
|
|
|
<el-dropdown-item @click="addPersone(false)" v-permission="['teamAdd']">添加人员</el-dropdown-item>
|
|
|
- <el-dropdown-item @click="transitionOperation('exportUser', '')" v-permission="['teamExport']">导出人员</el-dropdown-item>
|
|
|
- <el-dropdown-item @click="transitionOperation('importUser', '')" v-permission="['teamImport']">批量导入</el-dropdown-item>
|
|
|
+ <el-dropdown-item @click="transitionOperation('exportUser', '')"
|
|
|
+ v-permission="['teamExport']">导出人员</el-dropdown-item>
|
|
|
+ <el-dropdown-item @click="transitionOperation('importUser', '')"
|
|
|
+ v-permission="['teamImport']">批量导入</el-dropdown-item>
|
|
|
+ <el-dropdown-item @click="officialAccountSetting()">
|
|
|
+ {{ officialAccountInformation.id ? '修改公众号配置' : '配置公众号' }}
|
|
|
+ </el-dropdown-item>
|
|
|
+ <el-dropdown-item @click="oneClickGenerationOfQrCode()" v-if="officialAccountInformation.id">
|
|
|
+ 一键生成员工二维码
|
|
|
+ </el-dropdown-item>
|
|
|
+ <el-dropdown-item @click="exportQrCode()" v-if="officialAccountInformation.id">
|
|
|
+ 导出员工二维码
|
|
|
+ </el-dropdown-item>
|
|
|
</el-dropdown-menu>
|
|
|
</template>
|
|
|
</el-dropdown>
|
|
@@ -67,11 +80,17 @@
|
|
|
<el-tree style="max-width: 600px" :data="deptList" :props="treeProps" @node-click="treeNode">
|
|
|
<template #default="{ node, data }">
|
|
|
<div class="flex justify-between treeContent">
|
|
|
- <div class="custom-tree-node" @mouseleave="mouseleave(data,$event)" @mouseover="mouseover(data,$event)">
|
|
|
- <div class="treeLabel"><TextTranslation translationTypes="departmentName" :translationValue="node.label"></TextTranslation></div>
|
|
|
+ <div class="custom-tree-node" @mouseleave="mouseleave(data, $event)"
|
|
|
+ @mouseover="mouseover(data, $event)">
|
|
|
+ <div class="treeLabel">
|
|
|
+ <TextTranslation translationTypes="departmentName" :translationValue="node.label">
|
|
|
+ </TextTranslation>
|
|
|
+ </div>
|
|
|
<div class="treeIcon nodeEle" id="treeIcon" v-if="data.id > 0">
|
|
|
- <el-link type="primary" :icon="CirclePlus" :underline="false" @click.stop="dialogFromCli('addDeptDialogVisible', data, true)"></el-link>
|
|
|
- <el-link type="primary" :icon="Delete" :underline="false" style="margin-left: 6px;" @click.stop="deteleDept(data)"></el-link>
|
|
|
+ <el-link type="primary" :icon="CirclePlus" :underline="false"
|
|
|
+ @click.stop="dialogFromCli('addDeptDialogVisible', data, true)"></el-link>
|
|
|
+ <el-link type="primary" :icon="Delete" :underline="false" style="margin-left: 6px;"
|
|
|
+ @click.stop="deteleDept(data)"></el-link>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -88,14 +107,26 @@
|
|
|
<el-table-column type="selection" width="55" />
|
|
|
<el-table-column label="姓名" property="name" width="150">
|
|
|
<template #default="scope">
|
|
|
- <TextTranslation translationTypes="userName" :translationValue="scope.row.name"></TextTranslation>
|
|
|
+ <div class="flex items-center">
|
|
|
+ <TextTranslation translationTypes="userName" :translationValue="scope.row.name"></TextTranslation>
|
|
|
+ <template v-if="officialAccountInformation.id && scope.row.wxImgUrlWithTicket">
|
|
|
+ <el-tooltip class="box-item" effect="dark" content="点击查看销售二维码" placement="top">
|
|
|
+ <div class="ml-2 cursor-pointer" @click="viewQrCode(scope.row)">
|
|
|
+ <el-icon color="#075985">
|
|
|
+ <PictureFilled />
|
|
|
+ </el-icon>
|
|
|
+ </div>
|
|
|
+ </el-tooltip>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="手机" property="phone"></el-table-column>
|
|
|
<el-table-column label="工号" property="jobNumber"></el-table-column>
|
|
|
<el-table-column label="部门" property="departmentName">
|
|
|
<template #default="scope">
|
|
|
- <TextTranslation translationTypes="departmentName" :translationValue="scope.row.departmentName"></TextTranslation>
|
|
|
+ <TextTranslation translationTypes="departmentName" :translationValue="scope.row.departmentName">
|
|
|
+ </TextTranslation>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="角色" property="roleName"></el-table-column>
|
|
@@ -159,7 +190,8 @@
|
|
|
<el-form ref="deptRuleFormRef" style="max-width: 500px" :model="deptForm" :rules="deptRules" label-width="140px"
|
|
|
size="large" status-icon>
|
|
|
<el-form-item label="部门名称" prop="name">
|
|
|
- <el-input v-model="deptForm.name" placeholder="请输入部门名称" clearable :disabled="userInfo.userNameNeedTranslate == 1" />
|
|
|
+ <el-input v-model="deptForm.name" placeholder="请输入部门名称" clearable
|
|
|
+ :disabled="userInfo.userNameNeedTranslate == 1" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="主要负责人">
|
|
|
<!-- <el-select v-model="deptForm.managerId" placeholder="请选择" style="width: 100%" clearable>
|
|
@@ -171,7 +203,8 @@
|
|
|
<!-- <el-select v-model="deptForm.otherManagerIds" placeholder="请选择" style="width: 100%" multiple clearable>
|
|
|
<el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id" />
|
|
|
</el-select> -->
|
|
|
- <personnel-search v-model="deptForm.otherManagerIds" :size="''" multiple placeholder="请选择"></personnel-search>
|
|
|
+ <personnel-search v-model="deptForm.otherManagerIds" :size="''" multiple
|
|
|
+ placeholder="请选择"></personnel-search>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
</div>
|
|
@@ -247,13 +280,15 @@
|
|
|
</el-dialog>
|
|
|
|
|
|
<!-- 同步企业微信通讯录 -->
|
|
|
- <el-dialog v-model="dialogFrom.newSyncWithCorpWxDayloadVisable" width="600" :show-close="false" :before-close="handleClose">
|
|
|
+ <el-dialog v-model="dialogFrom.newSyncWithCorpWxDayloadVisable" width="600" :show-close="false"
|
|
|
+ :before-close="handleClose">
|
|
|
<template #header="{ close, titleId, titleClass }">
|
|
|
<div class="flex justify-between items-center border-b pb-3 dialog-header">
|
|
|
<h4 :id="titleId">同步企微通讯录</h4>
|
|
|
<div class="flex">
|
|
|
<el-button @click="dialogFrom.newSyncWithCorpWxDayloadVisable = false">取消</el-button>
|
|
|
- <el-button type="primary" :loading="loadingFrom.newSyncWithCorpWxDayloadLoading" @click="newSyncWithCorpWx()">
|
|
|
+ <el-button type="primary" :loading="loadingFrom.newSyncWithCorpWxDayloadLoading"
|
|
|
+ @click="newSyncWithCorpWx()">
|
|
|
开始同步
|
|
|
</el-button>
|
|
|
</div>
|
|
@@ -264,6 +299,38 @@
|
|
|
</div>
|
|
|
</el-dialog>
|
|
|
|
|
|
+ <!-- 公众号配置 -->
|
|
|
+ <el-dialog v-model="dialogFrom.officialAccountSettingVisable" width="600" :show-close="false"
|
|
|
+ :before-close="handleClose" :close="closeOfficialAccountInformation(officialAccountInformationRef)">
|
|
|
+ <template #header="{ close, titleId, titleClass }">
|
|
|
+ <div class="flex justify-between items-center border-b pb-3 dialog-header">
|
|
|
+ <h4 :id="titleId">公众号配置</h4>
|
|
|
+ <div class="flex">
|
|
|
+ <el-button @click="dialogFrom.officialAccountSettingVisable = false">取消</el-button>
|
|
|
+ <el-button type="primary" :loading="loadingFrom.officialAccountSettingLoading"
|
|
|
+ @click="configureOfficialAccountInformation(officialAccountInformationRef)">
|
|
|
+ 配置
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div class="pt-4 px-12 py-2">
|
|
|
+ <el-form ref="officialAccountInformationRef" style="max-width: 600px" :model="officialAccountInformationFrom"
|
|
|
+ status-icon :rules="officialAccountInformationFromRules" label-width="auto" class="demo-ruleForm">
|
|
|
+ <el-form-item label="名称:" prop="companyName">
|
|
|
+ <el-input v-model.trim="officialAccountInformationFrom.companyName" placeholder="请输入" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="appId:" prop="appId">
|
|
|
+ <el-input v-model.trim="officialAccountInformationFrom.appId" placeholder="请输入" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="appSecret:" prop="appSecret">
|
|
|
+ <el-input v-model.trim="officialAccountInformationFrom.appSecret" placeholder="请输入" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <el-text class="mx-1" type="warning">请联系客服, 获取ip白名单参数, 配置后方可生效</el-text>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
<!-- 新增人员 -->
|
|
|
<AddPersonnelModal :data="{
|
|
|
addPersonnelDialogVisible: dialogFrom.addPersonnelDialogVisible,
|
|
@@ -275,17 +342,26 @@
|
|
|
<!-- 批量操作 -->
|
|
|
<BatchOperation :batchData="visibleData" :batchNode="batchTableData" :visibleText="allText.batchText"
|
|
|
:popup="visibleType" :batchOperationVisible="dialogFrom.batchOperationVisible" @close="closeModal" />
|
|
|
+
|
|
|
+ <!-- 图片预览 -->
|
|
|
+ <el-image-viewer
|
|
|
+ v-if="showPreview"
|
|
|
+ :url-list="previewSrcList"
|
|
|
+ show-progress
|
|
|
+ :initial-index="0"
|
|
|
+ @close="showPreview = false"
|
|
|
+ />
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
import { ref, reactive, onMounted, onBeforeMount, inject } from 'vue';
|
|
|
-import { UploadRequestOptions, dayjs, ElLoading } from 'element-plus'
|
|
|
-import { Search, CirclePlusFilled, Edit, CirclePlus, Delete } from '@element-plus/icons-vue'
|
|
|
+import { UploadRequestOptions, dayjs, ElLoading, ElNotification } from 'element-plus'
|
|
|
+import { Search, CirclePlusFilled, Edit, CirclePlus, Delete, PictureFilled } from '@element-plus/icons-vue'
|
|
|
import { FormInstance, FormRules, ElMessageBox } from 'element-plus'
|
|
|
import { useStore } from '@/store/index'
|
|
|
-import { GET_DATA_LIST, DETELE_DEPT, MOD, GET_USERINFO, GET_ROUTELIST, DEACTIVEUSER, SETACTIVE, GET_DEPTLIST, BACTHSERROLE, GET_USERLIST, GET_ADDDEPT, ADD_USER, SETRESETPWD, EXPOERTUSER, EDIT_ADDDEPT } from './api'
|
|
|
-import { post, uploadFile } from "@/utils/request";
|
|
|
+import { GET_DATA_LIST, DETELE_DEPT, MOD, GET_USERINFO, GET_ROUTELIST, DEACTIVEUSER, SETACTIVE, GET_DEPTLIST, BACTHSERROLE, GET_USERLIST, GET_ADDDEPT, ADD_USER, SETRESETPWD, EXPOERTUSER, EDIT_ADDDEPT, GET_COMPANY_WEI_XIN, SAVE_OR_UPDATE, ONE_CLICK_GENERATION, EXPORT_QR_CODE } from './api'
|
|
|
+import { post, uploadFile, downloadFileRequest } from "@/utils/request";
|
|
|
import { getFromValue, updateDepTreeData, resetFromValue, confirmAction, downloadFile } from '@/utils/tools'
|
|
|
import { storeToRefs } from 'pinia';
|
|
|
|
|
@@ -310,6 +386,13 @@ interface deptRuleForm { // 部门表单类型
|
|
|
otherManagerIds: string[] | number[],
|
|
|
}
|
|
|
|
|
|
+interface officialAccountInformationInterface { // 公众号类型
|
|
|
+ id?: string | number,
|
|
|
+ companyName: string,
|
|
|
+ appId: string,
|
|
|
+ appSecret: string,
|
|
|
+}
|
|
|
+
|
|
|
// 固定数据
|
|
|
const stateOptions = [{ value: '3', label: '全部' }, { value: '1', label: '在职' }, { value: '0', label: '停用' }]
|
|
|
|
|
@@ -325,7 +408,8 @@ const loadingFrom = reactive({ // 所有加载状态
|
|
|
resignationLoading: false,
|
|
|
exportUserLoading: false,
|
|
|
importLoading: false,
|
|
|
- newSyncWithCorpWxDayloadLoading: false
|
|
|
+ newSyncWithCorpWxDayloadLoading: false,
|
|
|
+ officialAccountSettingLoading: false,
|
|
|
})
|
|
|
const dialogFrom: any = reactive({ // 所有弹窗状态
|
|
|
addDeptDialogVisible: false,
|
|
@@ -334,7 +418,8 @@ const dialogFrom: any = reactive({ // 所有弹窗状态
|
|
|
resignationVisible: false,
|
|
|
exportUserVisible: false,
|
|
|
importVisible: false,
|
|
|
- newSyncWithCorpWxDayloadVisable: false
|
|
|
+ newSyncWithCorpWxDayloadVisable: false,
|
|
|
+ officialAccountSettingVisable: false,
|
|
|
});
|
|
|
const allText = reactive({
|
|
|
batchText: '批量操作'
|
|
@@ -375,12 +460,61 @@ const treeProps = { // 部门树配置
|
|
|
children: 'children',
|
|
|
label: 'label',
|
|
|
}
|
|
|
+const officialAccountInformation = ref<officialAccountInformationInterface>({
|
|
|
+ id: '',
|
|
|
+ companyName: '',
|
|
|
+ appId: '',
|
|
|
+ appSecret: '',
|
|
|
+})
|
|
|
+
|
|
|
+const officialAccountInformationFrom = ref<officialAccountInformationInterface>({
|
|
|
+ id: '',
|
|
|
+ companyName: '',
|
|
|
+ appId: '',
|
|
|
+ appSecret: '',
|
|
|
+})
|
|
|
+const officialAccountInformationRef = ref<FormInstance>()
|
|
|
+const showPreview = ref(false)
|
|
|
+const previewSrcList = ref<string[]>([])
|
|
|
|
|
|
// 定义校验规则
|
|
|
const deptRules = reactive<FormRules<typeof deptForm>>({ // 部门表单校验规则
|
|
|
name: [{ required: true, trigger: 'blur', message: '请输入部门名称' }]
|
|
|
})
|
|
|
|
|
|
+const officialAccountInformationFromRules = reactive<FormRules<typeof officialAccountInformation>>({
|
|
|
+ companyName: [{ required: true, trigger: 'blur', message: '请输入' }],
|
|
|
+ appId: [{ required: true, trigger: 'blur', message: '请输入' }],
|
|
|
+ appSecret: [{ required: true, trigger: 'blur', message: '请输入' }]
|
|
|
+})
|
|
|
+
|
|
|
+function viewQrCode(row: any) {
|
|
|
+ const { wxImgUrlWithTicket = '' } = row
|
|
|
+ previewSrcList.value = [wxImgUrlWithTicket]
|
|
|
+ showPreview.value = true
|
|
|
+}
|
|
|
+
|
|
|
+function exportQrCode() {
|
|
|
+ ElNotification({
|
|
|
+ title: '提示',
|
|
|
+ message: '二维码导出中...',
|
|
|
+ type: 'info',
|
|
|
+ showClose: false,
|
|
|
+ duration: 0
|
|
|
+ })
|
|
|
+ downloadFileRequest(EXPORT_QR_CODE, {}).then((blob) => {
|
|
|
+ const url = window.URL.createObjectURL(blob);
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = url;
|
|
|
+ link.setAttribute('download', '员工销售二维码.zip'); // 根据需要设定文件名
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ link.remove();
|
|
|
+ window.URL.revokeObjectURL(url);
|
|
|
+ globalPopup?.showSuccess('下载中 请稍后')
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
// 同步企业微信通讯录
|
|
|
function newSyncWithCorpWx() {
|
|
|
const loading = ElLoading.service({
|
|
@@ -419,6 +553,58 @@ async function importUser(param: UploadRequestOptions) {
|
|
|
globalPopup?.showError(res.msg || '')
|
|
|
}
|
|
|
|
|
|
+// 获取公众号配置信息
|
|
|
+function getCompanyWeiXin() {
|
|
|
+ post(GET_COMPANY_WEI_XIN, {}).then((res) => {
|
|
|
+ const { companyName = '', id = '', appId = '', appSecret = '' } = res.data
|
|
|
+ officialAccountInformation.value = {
|
|
|
+ id, companyName, appId, appSecret
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+function oneClickGenerationOfQrCode() {
|
|
|
+ ElNotification({
|
|
|
+ title: '提示',
|
|
|
+ message: '生成二维码中...',
|
|
|
+ type: 'info',
|
|
|
+ showClose: false,
|
|
|
+ duration: 0
|
|
|
+ })
|
|
|
+ post(ONE_CLICK_GENERATION, {}).then(() => {
|
|
|
+ globalPopup?.showSuccess('生成成功')
|
|
|
+ getTableData()
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+async function configureOfficialAccountInformation(formEl: FormInstance | undefined) {
|
|
|
+ if (!formEl) return
|
|
|
+ await formEl.validate((valid) => {
|
|
|
+ if (valid) {
|
|
|
+ confirmAction('确定保存当前公众号的配置吗?', '公众号配置', 'warning').then(() => {
|
|
|
+ loadingFrom.officialAccountSettingLoading = true
|
|
|
+ post(SAVE_OR_UPDATE, getFromValue(officialAccountInformationFrom.value)).then(() => {
|
|
|
+ globalPopup?.showSuccess('配置成功')
|
|
|
+ closeModal('officialAccountSettingVisable')
|
|
|
+ getCompanyWeiXin()
|
|
|
+ }).finally(() => {
|
|
|
+ loadingFrom.officialAccountSettingLoading = false
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+function closeOfficialAccountInformation(formEl: FormInstance | undefined) {
|
|
|
+ if (!formEl) return
|
|
|
+ formEl.resetFields()
|
|
|
+}
|
|
|
+
|
|
|
+function officialAccountSetting() {
|
|
|
+ officialAccountInformationFrom.value = JSON.parse(JSON.stringify(officialAccountInformation.value))
|
|
|
+ dialogFrom.officialAccountSettingVisable = true
|
|
|
+}
|
|
|
+
|
|
|
function exportUser() {
|
|
|
loadingFrom.exportUserLoading = true
|
|
|
post(EXPOERTUSER, { containInvalid: exportRadio.value }).then((res) => {
|
|
@@ -490,7 +676,7 @@ function addPersone(item: any) {
|
|
|
post(GET_USERINFO, { userId: item.id }).then(res => {
|
|
|
const { id, name, phone, jobNumber, roleId, departmentCascade, departmentId, inductionDate } = res.data
|
|
|
let newData = {
|
|
|
- id, name, phone, jobNumber, roleId,
|
|
|
+ id, name, phone, jobNumber, roleId,
|
|
|
// departmentId: departmentCascade && departmentCascade.split(',').map(Number).reverse(),
|
|
|
departmentId: departmentId,
|
|
|
inductionDate
|
|
@@ -511,7 +697,7 @@ async function personnelModalConfirm(data: any, modelType: string) {
|
|
|
globalPopup?.showSuccess('添加成功')
|
|
|
getTableData()
|
|
|
}).catch(_err => {
|
|
|
- dialogFrom[modelType] = false
|
|
|
+ dialogFrom[modelType] = false
|
|
|
})
|
|
|
}
|
|
|
|
|
@@ -707,6 +893,7 @@ onMounted(() => {
|
|
|
getUserList()
|
|
|
getTableData()
|
|
|
getDeptList()
|
|
|
+ getCompanyWeiXin()
|
|
|
});
|
|
|
</script>
|
|
|
|
|
@@ -751,6 +938,7 @@ onMounted(() => {
|
|
|
align-items: center;
|
|
|
justify-self: flex-end;
|
|
|
}
|
|
|
+
|
|
|
.nodeEle {
|
|
|
display: none;
|
|
|
}
|
|
@@ -763,7 +951,7 @@ onMounted(() => {
|
|
|
</style>
|
|
|
|
|
|
<style>
|
|
|
- .temaClass .el-tree-node {
|
|
|
- padding: 4px 0;
|
|
|
- }
|
|
|
+.temaClass .el-tree-node {
|
|
|
+ padding: 4px 0;
|
|
|
+}
|
|
|
</style>
|