perf: 优化团队部门支持3级部门

This commit is contained in:
kuaifan 2025-03-01 13:38:32 +08:00
parent cfd2e1fd7b
commit 36cdf87bfe
4 changed files with 97 additions and 35 deletions

View File

@ -1653,19 +1653,22 @@ class UsersController extends AbstractController
if (empty($parentDepartment)) { if (empty($parentDepartment)) {
return Base::retError('上级部门不存在或已被删除'); return Base::retError('上级部门不存在或已被删除');
} }
if ($parentDepartment->parent_id > 0) { if (count($parentDepartment->parents()) > 2) {
return Base::retError('上级部门层级错误'); return Base::retError('部门层级最多只能创建3级');
} }
if (UserDepartment::whereParentId($parent_id)->count() > 20) { if ($id > 0 && UserDepartment::whereParentId($id)->whereId($parent_id)->exists()) {
return Base::retError('不能选择自己的子部门作为上级部门');
}
if (UserDepartment::whereParentId($parent_id)->count() >= 20) {
return Base::retError('每个部门最多只能创建20个子部门'); return Base::retError('每个部门最多只能创建20个子部门');
} }
if ($id > 0 && UserDepartment::whereParentId($id)->exists()) {
return Base::retError('含有子部门无法修改上级部门');
}
} }
if (empty($owner_userid) || !User::whereUserid($owner_userid)->exists()) { if (empty($owner_userid) || !User::whereUserid($owner_userid)->exists()) {
return Base::retError('请选择正确的部门负责人'); return Base::retError('请选择正确的部门负责人');
} }
if (UserDepartment::whereOwnerUserid($owner_userid)->count() >= 10) {
return Base::retError('每个用户最多只能负责10个部门');
}
// //
$userDepartment->saveDepartment([ $userDepartment->saveDepartment([
'name' => $name, 'name' => $name,
@ -1674,7 +1677,7 @@ class UsersController extends AbstractController
], $dialog_useid); ], $dialog_useid);
Cache::forever("UserDepartment::rand", Base::generatePassword()); Cache::forever("UserDepartment::rand", Base::generatePassword());
// //
return Base::retSuccess($parent_id > 0 ? '保存成功' : '新建成功'); return Base::retSuccess($id > 0 ? '保存成功' : '新建成功');
} }
/** /**
@ -1701,6 +1704,9 @@ class UsersController extends AbstractController
if (empty($userDepartment)) { if (empty($userDepartment)) {
return Base::retError('部门不存在或已被删除'); return Base::retError('部门不存在或已被删除');
} }
if (UserDepartment::whereParentId($id)->exists()) {
return Base::retError('含有子部门无法删除');
}
$userDepartment->deleteDepartment(); $userDepartment->deleteDepartment();
Cache::forever("UserDepartment::rand", Base::generatePassword()); Cache::forever("UserDepartment::rand", Base::generatePassword());
// //

View File

@ -34,6 +34,21 @@ use App\Exceptions\ApiException;
*/ */
class UserDepartment extends AbstractModel class UserDepartment extends AbstractModel
{ {
/**
* 获取所有父级部门
* @return array
*/
public function parents()
{
$parents = [];
$parent = $this;
while ($parent) {
$parents[] = $parent;
$parent = $parent->parent_id ? self::find($parent->parent_id) : null;
}
return $parents;
}
/** /**
* 保存部门 * 保存部门
* @param $data * @param $data
@ -131,9 +146,7 @@ class UserDepartment extends AbstractModel
}); });
// 解散群组 // 解散群组
$dialog = WebSocketDialog::find($this->dialog_id); $dialog = WebSocketDialog::find($this->dialog_id);
if ($dialog) { $dialog?->deleteDialog();
$dialog->deleteDialog();
}
// //
$this->delete(); $this->delete();
} }

View File

@ -44,7 +44,7 @@
@command="onOpDepartment"> @command="onOpDepartment">
<i @click.stop="" class="taskfont department-menu">&#xe6e9;</i> <i @click.stop="" class="taskfont department-menu">&#xe6e9;</i>
<EDropdownMenu slot="dropdown"> <EDropdownMenu slot="dropdown">
<EDropdownItem v-if="item.level <= 2" :command="`add_${item.id}`"> <EDropdownItem v-if="item.level <= 3" :command="`add_${item.id}`">
<div>{{$L('添加子部门')}}</div> <div>{{$L('添加子部门')}}</div>
</EDropdownItem> </EDropdownItem>
<EDropdownItem v-if="item.dialog_id" :command="`dialog_${item.dialog_id}`"> <EDropdownItem v-if="item.dialog_id" :command="`dialog_${item.dialog_id}`">
@ -183,11 +183,19 @@
<Input type="text" v-model="departmentData.name" :placeholder="$L('请输入部门名称')"></Input> <Input type="text" v-model="departmentData.name" :placeholder="$L('请输入部门名称')"></Input>
</FormItem> </FormItem>
<FormItem prop="parent_id" :label="$L('上级部门')"> <FormItem prop="parent_id" :label="$L('上级部门')">
<Select v-model="departmentData.parent_id" :disabled="departmentParentDisabled" :placeholder="$L('请选择上级部门')"> <Select v-model="departmentData.parent_id" :placeholder="$L('请选择上级部门')">
<Option :value="0">{{ $L('默认部门') }}</Option> <Option :value="0">
<Option v-for="(item, index) in departmentList" v-if="item.parent_id == 0 && item.id != departmentData.id" :value="item.id" :key="index" :label="item.name">&nbsp;&nbsp;&nbsp;&nbsp;{{ item.name }}</Option> <div class="team-department-level-name level-1">{{ $L('默认部门') }}</div>
</Option>
<Option
v-for="(item, index) in departmentList"
:disabled="item.level > 3 || item.id == departmentData.id || item.parent_id == departmentData.id"
:value="item.id"
:key="index"
:label="item.chains.join(' - ')">
<div :class="`team-department-level-name level-${item.level}`">{{ item.name }}</div>
</Option>
</Select> </Select>
<div v-if="departmentParentDisabled" class="form-tip" style="margin-bottom:-16px">{{$L('含有子部门无法修改上级部门')}}</div>
</FormItem> </FormItem>
<FormItem prop="owner_userid" :label="$L('部门负责人')"> <FormItem prop="owner_userid" :label="$L('部门负责人')">
<UserSelect v-model="departmentData.owner_userid" :multiple-max="1" :title="$L('请选择部门负责人')"/> <UserSelect v-model="departmentData.owner_userid" :multiple-max="1" :title="$L('请选择部门负责人')"/>
@ -286,8 +294,19 @@
<Form :model="departmentEditData" v-bind="formOptions" @submit.native.prevent> <Form :model="departmentEditData" v-bind="formOptions" @submit.native.prevent>
<Alert type="error" style="margin-bottom:18px">{{$L(`正在进行帐号【ID:${departmentEditData.userid}, ${departmentEditData.nickname}】部门修改。`)}}</Alert> <Alert type="error" style="margin-bottom:18px">{{$L(`正在进行帐号【ID:${departmentEditData.userid}, ${departmentEditData.nickname}】部门修改。`)}}</Alert>
<FormItem :label="$L('修改部门')"> <FormItem :label="$L('修改部门')">
<Select v-model="departmentEditData.department" multiple :multiple-max="10" :placeholder="$L('留空为默认部门')"> <Select
<Option v-for="(item, index) in departmentList" :value="item.id" :key="index">{{ item.name }}</Option> v-model="departmentEditData.department"
multiple
:multiple-max="10"
:multiple-max-before="onMultipleMaxBefore"
:placeholder="$L('留空为默认部门')">
<Option
v-for="(item, index) in departmentList"
:value="item.id"
:key="index"
:label="item.chains.join(' - ')">
<div :class="`team-department-level-name level-${item.level - 1}`">{{ item.name }}</div>
</Option>
</Select> </Select>
</FormItem> </FormItem>
</Form> </Form>
@ -515,34 +534,44 @@ export default {
key: 'department', key: 'department',
minWidth: 80, minWidth: 80,
render: (h, {row}) => { render: (h, {row}) => {
let departments = [] const departments = []
row.department.some(did => { row.department.some(did => {
const data = this.departmentList.find(d => d.id == did) const data = this.departmentList.find(d => d.id == did)
if (data) { if (data) {
departments.push(data.name) departments.push({
id: data.id,
name: data.name,
chain: data.chains.join(' - ')
})
} }
}) })
departments.sort((a, b) => {
return a.id - b.id
})
if (departments.length === 0) { if (departments.length === 0) {
return h('AutoTip', this.$L('默认部门')); return h('AutoTip', this.$L('默认部门'));
} else { } else {
const tmp = [] const tmp = []
tmp.push(h('span', { tmp.push(h('span', {
domProps: { domProps: {
title: departments[0] title: departments[0].chain
} }
}, departments[0])) }, departments[0].name))
if (departments.length > 1) { if (departments.length > 1) {
departments = departments.splice(1)
tmp.push(h('ETooltip', [ tmp.push(h('ETooltip', [
h('div', { h('ol', {
slot: 'content', slot: 'content',
style: {
lineHeight: '1.5',
paddingLeft: '18px'
},
domProps: { domProps: {
innerHTML: departments.join("<br/>") innerHTML: departments.map(({chain}) => `<li>${chain}</li>`).join('')
} }
}), }),
h('div', { h('div', {
class: 'department-tag-num' class: 'department-tag-num'
}, ` +${departments.length}`) }, departments.length)
])) ]))
} }
return h('div', { return h('div', {
@ -910,10 +939,6 @@ export default {
computed: { computed: {
...mapState(['formOptions']), ...mapState(['formOptions']),
departmentParentDisabled() {
return !!(this.departmentData.id > 0 && this.departmentList.find(({parent_id}) => parent_id == this.departmentData.id));
},
userStyle({minWidth, windowPortrait}) { userStyle({minWidth, windowPortrait}) {
const style = {} const style = {}
if (minWidth > 0 && windowPortrait) { if (minWidth > 0 && windowPortrait) {
@ -1206,23 +1231,29 @@ export default {
url: 'users/department/list', url: 'users/department/list',
}).then(({data}) => { }).then(({data}) => {
this.departmentList = [] this.departmentList = []
this.generateDepartmentList(data, 0, 1) this.generateDepartmentList(data, 0, 1, [])
}).finally(_ => { }).finally(_ => {
this.departmentLoading--; this.departmentLoading--;
}) })
}, },
generateDepartmentList(data, parent_id, level) { generateDepartmentList(data, parent_id, level, chains = []) {
data.some(item => { data.some(item => {
if (item.parent_id == parent_id) { if (item.parent_id == parent_id) {
this.departmentList.push(Object.assign(item, { this.departmentList.push(Object.assign(item, {
chains: chains.concat([item.name]),
level: level + 1 level: level + 1
})) }))
this.generateDepartmentList(data, item.id, level + 1) this.generateDepartmentList(data, item.id, level + 1, chains.concat([item.name]))
} }
}) })
}, },
onMultipleMaxBefore(num) {
$A.messageError(`最多选择${num}个部门`)
return false
},
onShowDepartment(data) { onShowDepartment(data) {
this.departmentData = Object.assign({ this.departmentData = Object.assign({
id: 0, id: 0,

View File

@ -83,13 +83,13 @@
font-weight: 500; font-weight: 500;
} }
&.level-2 { &.level-2 {
margin-left: 24px; margin-left: 18px;
} }
&.level-3 { &.level-3 {
margin-left: 48px; margin-left: 36px;
} }
&.level-4 { &.level-4 {
margin-left: 72px; margin-left: 54px;
} }
.department-icon { .department-icon {
padding: 8px; padding: 8px;
@ -155,6 +155,18 @@
} }
} }
.team-department-level-name {
&.level-2 {
margin-left: 18px;
}
&.level-3 {
margin-left: 36px;
}
&.level-4 {
margin-left: 54px;
}
}
.team-department-add-dialog-group { .team-department-add-dialog-group {
display: flex; display: flex;
align-items: center; align-items: center;