企微部门和企微用户同步的列表

This commit is contained in:
zhonghua.li
2026-04-24 20:49:02 +08:00
parent df9b3961a2
commit 996ff4b491
6 changed files with 705 additions and 3 deletions

View File

@@ -0,0 +1,46 @@
import request from '@/utils/request'
export function getQweiDepartmentList(params) {
return request({
url: '/qweiDepartment/list',
method: 'get',
params: {
current: params.current || 1,
size: params.size || 10,
deptId: params.deptId,
deptName: params.deptName,
parentDeptId: params.parentDeptId
}
})
}
export function addQweiDepartment(data) {
return request({
url: '/qweiDepartment/add',
method: 'post',
data
})
}
export function updateQweiDepartment(data) {
return request({
url: '/qweiDepartment/update',
method: 'put',
data
})
}
export function deleteQweiDepartment(id) {
return request({
url: `/qweiDepartment/delete/${id}`,
method: 'delete'
})
}
export function syncQweiDepartment() {
return request({
url: '/qweiDepartment/sync',
method: 'post'
})
}

47
src/api/qwei-user.js Normal file
View File

@@ -0,0 +1,47 @@
import request from '@/utils/request'
export function getQweiUserList(params) {
return request({
url: '/qweiUser/list',
method: 'get',
params: {
current: params.current || 1,
size: params.size || 10,
userid: params.userid,
userName: params.userName,
mainDepartmentId: params.mainDepartmentId,
status: params.status
}
})
}
export function addQweiUser(data) {
return request({
url: '/qweiUser/add',
method: 'post',
data
})
}
export function updateQweiUser(data) {
return request({
url: '/qweiUser/update',
method: 'put',
data
})
}
export function deleteQweiUser(id) {
return request({
url: `/qweiUser/delete/${id}`,
method: 'delete'
})
}
export function syncQweiUser() {
return request({
url: '/qweiUser/sync',
method: 'post'
})
}

View File

@@ -404,6 +404,12 @@ export const constantRoutes = [
name: 'DictItem',
component: () => import('@/views/system/dict-item/index'),
meta: { title: '字典管理', icon: 'el-icon-collection' }
},
{
path: 'qwei-data',
name: 'QweiData',
component: () => import('@/views/system/qwei-data/index'),
meta: { title: '企微数据', icon: 'el-icon-connection' }
}
]
},

View File

@@ -393,8 +393,8 @@ export default {
},
findBindUserOption(userId) {
if (!userId) return null
return this.bindUserSelectOptions.find(o => String(o.value) === String(userId))
|| this.userOptions.find(o => String(o.value) === String(userId))
return this.bindUserSelectOptions.find(o => String(o.value) === String(userId)) ||
this.userOptions.find(o => String(o.value) === String(userId))
},
// 获取机构选项
getDealershipOptions() {

View File

@@ -24,4 +24,3 @@ export default {
}
</style>

View File

@@ -0,0 +1,604 @@
<template>
<div class="app-container">
<el-tabs v-model="activeTab" type="card" @tab-click="handleTabChange">
<el-tab-pane label="企微部门" name="department">
<el-card class="filter-container" shadow="never">
<el-form :model="deptQuery" :inline="true" label-width="90px">
<el-form-item label="部门ID">
<el-input v-model="deptQuery.deptId" placeholder="请输入部门ID" clearable style="width: 200px" />
</el-form-item>
<el-form-item label="部门名称">
<el-input v-model="deptQuery.deptName" placeholder="请输入部门名称" clearable style="width: 220px" />
</el-form-item>
<el-form-item label="上级部门ID">
<el-input v-model="deptQuery.parentDeptId" placeholder="请输入上级部门ID" clearable style="width: 200px" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleDeptQuery">查询</el-button>
<el-button icon="el-icon-delete" @click="resetDeptQuery">清空</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="action-container" shadow="never">
<el-button type="primary" icon="el-icon-plus" @click="openDeptAdd">添加部门</el-button>
<el-button type="success" icon="el-icon-refresh" :loading="deptSyncLoading" @click="handleDeptSync">数据同步</el-button>
</el-card>
<el-card class="table-container" shadow="never">
<el-table v-loading="deptLoading" :data="deptList" style="width: 100%">
<el-table-column label="UUID" prop="id" min-width="220" />
<el-table-column label="部门ID" prop="deptId" width="120" />
<el-table-column label="部门名称" prop="deptName" min-width="160" />
<el-table-column label="上级部门ID" prop="parentDeptId" width="120" />
<el-table-column label="排序" prop="orderNum" width="80" />
<el-table-column label="更新时间" prop="updatedAt" min-width="180">
<template slot-scope="scope">
{{ formatDateTime(scope.row.updatedAt) }}
</template>
</el-table-column>
<el-table-column label="操作" width="160" fixed="right">
<template slot-scope="scope">
<el-button type="text" @click="openDeptEdit(scope.row)">修改</el-button>
<el-button type="text" style="color: #F56C6C;" @click="handleDeptDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="deptQuery.current"
:page-sizes="[10, 20, 50, 100]"
:page-size="deptQuery.size"
:total="deptTotal"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleDeptSizeChange"
@current-change="handleDeptCurrentChange"
/>
</el-card>
</el-tab-pane>
<el-tab-pane label="企微用户" name="user">
<el-card class="filter-container" shadow="never">
<el-form :model="userQuery" :inline="true" label-width="90px">
<el-form-item label="企微用户ID">
<el-input v-model="userQuery.userid" placeholder="请输入userid" clearable style="width: 220px" />
</el-form-item>
<el-form-item label="姓名">
<el-input v-model="userQuery.userName" placeholder="请输入姓名" clearable style="width: 200px" />
</el-form-item>
<el-form-item label="主部门ID">
<el-input v-model="userQuery.mainDepartmentId" placeholder="请输入主部门ID" clearable style="width: 200px" />
</el-form-item>
<el-form-item label="激活状态">
<el-select v-model="userQuery.status" placeholder="请选择" clearable style="width: 160px">
<el-option label="激活" :value="1" />
<el-option label="禁用" :value="0" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleUserQuery">查询</el-button>
<el-button icon="el-icon-delete" @click="resetUserQuery">清空</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="action-container" shadow="never">
<el-button type="primary" icon="el-icon-plus" @click="openUserAdd">添加用户</el-button>
<el-button type="success" icon="el-icon-refresh" :loading="userSyncLoading" @click="handleUserSync">数据同步</el-button>
</el-card>
<el-card class="table-container" shadow="never">
<el-table v-loading="userLoading" :data="userList" style="width: 100%">
<el-table-column label="UUID" prop="id" min-width="220" />
<el-table-column label="企微用户ID" prop="userid" min-width="160" />
<el-table-column label="姓名" prop="userName" min-width="120" />
<el-table-column label="手机号" prop="mobile" min-width="140" />
<el-table-column label="邮箱" prop="email" min-width="180" />
<el-table-column label="主部门ID" prop="mainDepartmentId" width="110" />
<el-table-column label="激活状态" prop="status" width="90">
<template slot-scope="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'">
{{ scope.row.status === 1 ? '激活' : '禁用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="更新时间" prop="updatedAt" min-width="180">
<template slot-scope="scope">
{{ formatDateTime(scope.row.updatedAt) }}
</template>
</el-table-column>
<el-table-column label="操作" width="160" fixed="right">
<template slot-scope="scope">
<el-button type="text" @click="openUserEdit(scope.row)">修改</el-button>
<el-button type="text" style="color: #F56C6C;" @click="handleUserDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="userQuery.current"
:page-sizes="[10, 20, 50, 100]"
:page-size="userQuery.size"
:total="userTotal"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleUserSizeChange"
@current-change="handleUserCurrentChange"
/>
</el-card>
</el-tab-pane>
</el-tabs>
<el-dialog :title="deptDialogTitle" :visible.sync="deptDialogVisible" width="560px" @close="resetDeptForm">
<el-form ref="deptFormRef" :model="deptForm" :rules="deptRules" label-width="110px">
<el-form-item label="部门ID" prop="deptId">
<el-input v-model.number="deptForm.deptId" placeholder="请输入部门ID" />
</el-form-item>
<el-form-item label="部门名称" prop="deptName">
<el-input v-model="deptForm.deptName" placeholder="请输入部门名称" />
</el-form-item>
<el-form-item label="上级部门ID" prop="parentDeptId">
<el-input v-model.number="deptForm.parentDeptId" placeholder="请输入上级部门ID" />
</el-form-item>
<el-form-item label="排序" prop="orderNum">
<el-input-number v-model="deptForm.orderNum" :min="0" :step="1" style="width: 100%" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="deptDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="deptSubmitLoading" @click="submitDept">确定</el-button>
</div>
</el-dialog>
<el-dialog :title="userDialogTitle" :visible.sync="userDialogVisible" width="700px" @close="resetUserForm">
<el-form ref="userFormRef" :model="userForm" :rules="userRules" label-width="110px">
<el-form-item label="企微用户ID" prop="userid">
<el-input v-model="userForm.userid" placeholder="请输入userid" />
</el-form-item>
<el-form-item label="姓名" prop="userName">
<el-input v-model="userForm.userName" placeholder="请输入姓名" />
</el-form-item>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="手机号" prop="mobile">
<el-input v-model="userForm.mobile" placeholder="请输入手机号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="userForm.email" placeholder="请输入邮箱" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="主部门ID" prop="mainDepartmentId">
<el-input v-model.number="userForm.mainDepartmentId" placeholder="请输入主部门ID" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="激活状态" prop="status">
<el-select v-model="userForm.status" placeholder="请选择" style="width: 100%">
<el-option label="激活" :value="1" />
<el-option label="禁用" :value="0" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="所属部门IDs" prop="departmentIdsJson">
<el-input v-model="userForm.departmentIdsJson" placeholder="示例:[1,2,3]JSON字符串可选" />
</el-form-item>
<el-form-item label="职位" prop="position">
<el-input v-model="userForm.position" placeholder="请输入职位(可选)" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="userDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="userSubmitLoading" @click="submitUser">确定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
addQweiDepartment,
deleteQweiDepartment,
getQweiDepartmentList,
syncQweiDepartment,
updateQweiDepartment
} from '@/api/qwei-department'
import {
addQweiUser,
deleteQweiUser,
getQweiUserList,
syncQweiUser,
updateQweiUser
} from '@/api/qwei-user'
export default {
name: 'QweiData',
data() {
return {
activeTab: 'department',
deptLoading: false,
deptSyncLoading: false,
deptSubmitLoading: false,
deptList: [],
deptTotal: 0,
deptQuery: {
current: 1,
size: 10,
deptId: '',
deptName: '',
parentDeptId: ''
},
deptDialogVisible: false,
deptDialogTitle: '',
deptIsEdit: false,
deptForm: {
id: '',
deptId: null,
deptName: '',
parentDeptId: null,
orderNum: 0
},
userLoading: false,
userSyncLoading: false,
userSubmitLoading: false,
userList: [],
userTotal: 0,
userQuery: {
current: 1,
size: 10,
userid: '',
userName: '',
mainDepartmentId: '',
status: undefined
},
userDialogVisible: false,
userDialogTitle: '',
userIsEdit: false,
userForm: {
id: '',
userid: '',
userName: '',
mobile: '',
email: '',
mainDepartmentId: null,
status: 1,
departmentIdsJson: '',
position: ''
}
}
},
computed: {
deptRules() {
return {
deptId: [{ required: true, message: '请输入部门ID', trigger: 'blur' }],
deptName: [{ required: true, message: '请输入部门名称', trigger: 'blur' }]
}
},
userRules() {
return {
userid: [{ required: true, message: '请输入企微用户ID', trigger: 'blur' }],
userName: [{ required: true, message: '请输入姓名', trigger: 'blur' }]
}
}
},
created() {
this.fetchDeptList()
},
methods: {
handleTabChange() {
if (this.activeTab === 'department' && this.deptList.length === 0) {
this.fetchDeptList()
}
if (this.activeTab === 'user' && this.userList.length === 0) {
this.fetchUserList()
}
},
fetchDeptList() {
this.deptLoading = true
const params = {
current: this.deptQuery.current,
size: this.deptQuery.size,
deptId: this.deptQuery.deptId ? Number(this.deptQuery.deptId) : undefined,
deptName: this.deptQuery.deptName || undefined,
parentDeptId: this.deptQuery.parentDeptId ? Number(this.deptQuery.parentDeptId) : undefined
}
getQweiDepartmentList(params).then(res => {
if (res && (res.code === 20000 || res.code === 200)) {
this.deptList = Array.isArray(res.data) ? res.data : []
this.deptTotal = res.total || 0
} else {
this.deptList = []
this.deptTotal = 0
}
}).catch(() => {
this.deptList = []
this.deptTotal = 0
}).finally(() => {
this.deptLoading = false
})
},
handleDeptQuery() {
this.deptQuery.current = 1
this.fetchDeptList()
},
resetDeptQuery() {
this.deptQuery = {
current: 1,
size: 10,
deptId: '',
deptName: '',
parentDeptId: ''
}
this.fetchDeptList()
},
handleDeptSizeChange(size) {
this.deptQuery.size = size
this.fetchDeptList()
},
handleDeptCurrentChange(current) {
this.deptQuery.current = current
this.fetchDeptList()
},
openDeptAdd() {
this.deptDialogTitle = '添加部门'
this.deptIsEdit = false
this.resetDeptForm()
this.deptDialogVisible = true
},
openDeptEdit(row) {
this.deptDialogTitle = '修改部门'
this.deptIsEdit = true
this.deptForm = {
id: row.id,
deptId: row.deptId,
deptName: row.deptName || '',
parentDeptId: row.parentDeptId,
orderNum: row.orderNum || 0
}
this.deptDialogVisible = true
this.$nextTick(() => {
if (this.$refs.deptFormRef) this.$refs.deptFormRef.clearValidate()
})
},
resetDeptForm() {
if (this.$refs.deptFormRef) this.$refs.deptFormRef.resetFields()
this.deptForm = {
id: '',
deptId: null,
deptName: '',
parentDeptId: null,
orderNum: 0
}
},
submitDept() {
this.$refs.deptFormRef.validate(valid => {
if (!valid) return
this.deptSubmitLoading = true
const payload = {
id: this.deptIsEdit ? this.deptForm.id : undefined,
deptId: this.deptForm.deptId,
deptName: this.deptForm.deptName,
parentDeptId: this.deptForm.parentDeptId,
orderNum: this.deptForm.orderNum
}
const fn = this.deptIsEdit ? updateQweiDepartment : addQweiDepartment
fn(payload).then(() => {
this.$message.success(this.deptIsEdit ? '修改成功' : '添加成功')
this.deptDialogVisible = false
this.fetchDeptList()
}).finally(() => {
this.deptSubmitLoading = false
})
})
},
handleDeptDelete(row) {
this.$confirm('确定删除该部门吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return deleteQweiDepartment(row.id)
}).then(() => {
this.$message.success('删除成功')
this.fetchDeptList()
}).catch(() => {})
},
handleDeptSync() {
this.$confirm('将从企微同步部门数据并入库,是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.deptSyncLoading = true
return syncQweiDepartment()
}).then(() => {
this.$message.success('同步成功')
this.fetchDeptList()
}).finally(() => {
this.deptSyncLoading = false
}).catch(() => {})
},
fetchUserList() {
this.userLoading = true
const params = {
current: this.userQuery.current,
size: this.userQuery.size,
userid: this.userQuery.userid || undefined,
userName: this.userQuery.userName || undefined,
mainDepartmentId: this.userQuery.mainDepartmentId ? Number(this.userQuery.mainDepartmentId) : undefined,
status: this.userQuery.status === undefined ? undefined : this.userQuery.status
}
getQweiUserList(params).then(res => {
if (res && (res.code === 20000 || res.code === 200)) {
this.userList = Array.isArray(res.data) ? res.data : []
this.userTotal = res.total || 0
} else {
this.userList = []
this.userTotal = 0
}
}).catch(() => {
this.userList = []
this.userTotal = 0
}).finally(() => {
this.userLoading = false
})
},
handleUserQuery() {
this.userQuery.current = 1
this.fetchUserList()
},
resetUserQuery() {
this.userQuery = {
current: 1,
size: 10,
userid: '',
userName: '',
mainDepartmentId: '',
status: undefined
}
this.fetchUserList()
},
handleUserSizeChange(size) {
this.userQuery.size = size
this.fetchUserList()
},
handleUserCurrentChange(current) {
this.userQuery.current = current
this.fetchUserList()
},
openUserAdd() {
this.userDialogTitle = '添加用户'
this.userIsEdit = false
this.resetUserForm()
this.userDialogVisible = true
},
openUserEdit(row) {
this.userDialogTitle = '修改用户'
this.userIsEdit = true
this.userForm = {
id: row.id,
userid: row.userid || '',
userName: row.userName || '',
mobile: row.mobile || '',
email: row.email || '',
mainDepartmentId: row.mainDepartmentId,
status: row.status === undefined || row.status === null ? 1 : row.status,
departmentIdsJson: row.departmentIdsJson || '',
position: row.position || ''
}
this.userDialogVisible = true
this.$nextTick(() => {
if (this.$refs.userFormRef) this.$refs.userFormRef.clearValidate()
})
},
resetUserForm() {
if (this.$refs.userFormRef) this.$refs.userFormRef.resetFields()
this.userForm = {
id: '',
userid: '',
userName: '',
mobile: '',
email: '',
mainDepartmentId: null,
status: 1,
departmentIdsJson: '',
position: ''
}
},
submitUser() {
this.$refs.userFormRef.validate(valid => {
if (!valid) return
this.userSubmitLoading = true
const payload = {
id: this.userIsEdit ? this.userForm.id : undefined,
userid: this.userForm.userid,
userName: this.userForm.userName,
mobile: this.userForm.mobile || undefined,
email: this.userForm.email || undefined,
mainDepartmentId: this.userForm.mainDepartmentId,
status: this.userForm.status,
departmentIdsJson: this.userForm.departmentIdsJson || undefined,
position: this.userForm.position || undefined
}
const fn = this.userIsEdit ? updateQweiUser : addQweiUser
fn(payload).then(() => {
this.$message.success(this.userIsEdit ? '修改成功' : '添加成功')
this.userDialogVisible = false
this.fetchUserList()
}).finally(() => {
this.userSubmitLoading = false
})
})
},
handleUserDelete(row) {
this.$confirm('确定删除该用户吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return deleteQweiUser(row.id)
}).then(() => {
this.$message.success('删除成功')
this.fetchUserList()
}).catch(() => {})
},
handleUserSync() {
this.$confirm('将从企微同步用户数据并入库,是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.userSyncLoading = true
return syncQweiUser()
}).then(() => {
this.$message.success('同步成功')
this.fetchUserList()
}).finally(() => {
this.userSyncLoading = false
}).catch(() => {})
},
formatDateTime(dateTime) {
if (!dateTime) return '-'
const date = new Date(dateTime)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
const seconds = String(date.getSeconds()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}
}
}
</script>
<style lang="scss" scoped>
.app-container {
.filter-container {
margin-bottom: 20px;
}
.action-container {
margin-bottom: 20px;
display: flex;
gap: 10px;
}
.table-container {
.el-pagination {
margin-top: 20px;
text-align: right;
}
}
}
</style>