feat(users): 组织树支持删除院区与科室

This commit is contained in:
yelan
2026-10-07 21:02:24 +08:00
parent 99521efc1a
commit 891b59d328
2 changed files with 136 additions and 34 deletions
@@ -20,6 +20,8 @@ const emit = defineEmits<{
addDepartment: [] addDepartment: []
editCampus: [campus: CampusRecord] editCampus: [campus: CampusRecord]
editDepartment: [department: DepartmentRecord] editDepartment: [department: DepartmentRecord]
deleteCampus: [campus: CampusRecord]
deleteDepartment: [department: DepartmentRecord]
}>() }>()
const institutionGroups = computed(() => { const institutionGroups = computed(() => {
@@ -115,15 +117,24 @@ function isDescendantSelected(department: DepartmentRecord): boolean {
<span class="org-tree__name">{{ campus.name }}</span> <span class="org-tree__name">{{ campus.name }}</span>
<span class="org-tree__count">{{ departmentsForCampus(campus.id).length }} 科室</span> <span class="org-tree__count">{{ departmentsForCampus(campus.id).length }} 科室</span>
</button> </button>
<button <div v-if="canManageCampuses" class="org-tree__actions">
v-if="canManageCampuses" <button
type="button" type="button"
class="org-tree__edit" class="org-tree__edit"
:aria-label="`编辑院区${campus.name}`" :aria-label="`编辑院区${campus.name}`"
@click="emit('editCampus', campus)" @click="emit('editCampus', campus)"
> >
编辑 编辑
</button> </button>
<button
type="button"
class="org-tree__remove"
:aria-label="`删除院区${campus.name}`"
@click="emit('deleteCampus', campus)"
>
删除
</button>
</div>
</div> </div>
<div <div
@@ -142,15 +153,24 @@ function isDescendantSelected(department: DepartmentRecord): boolean {
> >
<span class="org-tree__name">🗂 {{ department.name }}</span> <span class="org-tree__name">🗂 {{ department.name }}</span>
</button> </button>
<button <div v-if="canManageDepartments" class="org-tree__actions">
v-if="canManageDepartments" <button
type="button" type="button"
class="org-tree__edit" class="org-tree__edit"
:aria-label="`编辑科室${department.name}`" :aria-label="`编辑科室${department.name}`"
@click="emit('editDepartment', department)" @click="emit('editDepartment', department)"
> >
编辑 编辑
</button> </button>
<button
type="button"
class="org-tree__remove"
:aria-label="`删除科室${department.name}`"
@click="emit('deleteDepartment', department)"
>
删除
</button>
</div>
</div> </div>
<div <div
v-for="child in childrenFor(department.id, campus.id)" v-for="child in childrenFor(department.id, campus.id)"
@@ -165,15 +185,24 @@ function isDescendantSelected(department: DepartmentRecord): boolean {
> >
<span class="org-tree__name">{{ child.name }}</span> <span class="org-tree__name">{{ child.name }}</span>
</button> </button>
<button <div v-if="canManageDepartments" class="org-tree__actions">
v-if="canManageDepartments" <button
type="button" type="button"
class="org-tree__edit" class="org-tree__edit"
:aria-label="`编辑科室${child.name}`" :aria-label="`编辑科室${child.name}`"
@click="emit('editDepartment', child)" @click="emit('editDepartment', child)"
> >
编辑 编辑
</button> </button>
<button
type="button"
class="org-tree__remove"
:aria-label="`删除科室${child.name}`"
@click="emit('deleteDepartment', child)"
>
删除
</button>
</div>
</div> </div>
</template> </template>
<p v-if="!childrenFor(null, campus.id).length" class="org-tree__empty"> <p v-if="!childrenFor(null, campus.id).length" class="org-tree__empty">
@@ -371,19 +400,37 @@ function isDescendantSelected(department: DepartmentRecord): boolean {
font-size: 12px; font-size: 12px;
} }
.org-tree__edit { .org-tree__actions {
padding: 3px 6px; display: flex;
margin-right: 6px; flex: 0 0 auto;
color: var(--brand); gap: 4px;
align-items: center;
}
.org-tree__edit,
.org-tree__remove {
padding: 3px 7px;
font-size: 10.5px; font-size: 10.5px;
background: #fff; background: #fff;
border: 1px solid #d3e7ee;
border-radius: 5px; border-radius: 5px;
opacity: 0; opacity: 0;
} }
.org-tree__edit {
color: var(--brand);
border: 1px solid #d3e7ee;
}
.org-tree__remove {
margin-right: 6px;
color: var(--err);
border: 1px solid #f0cdcd;
}
.org-tree__node:hover .org-tree__edit, .org-tree__node:hover .org-tree__edit,
.org-tree__node:focus-within .org-tree__edit { .org-tree__node:hover .org-tree__remove,
.org-tree__node:focus-within .org-tree__edit,
.org-tree__node:focus-within .org-tree__remove {
opacity: 1; opacity: 1;
} }
@@ -1,10 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue' import { computed, onMounted, ref, watch } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { import {
createCampus, createCampus,
createDepartment, createDepartment,
deleteCampus,
deleteDepartment,
getAllDepartments, getAllDepartments,
getCampuses, getCampuses,
updateCampus, updateCampus,
@@ -664,6 +666,57 @@ async function saveOrganizationNode(form: OrganizationNodeSave) {
} }
} }
async function removeCampus(campus: CampusRecord) {
if (!canManageCampuses.value) return
const departmentCount = departments.value.filter(
(department) => department.campusId === campus.id,
).length
const confirmed = await ElMessageBox.confirm(
departmentCount
? `删除院区“${campus.name}”会同时移除其下 ${departmentCount} 个科室,且无法恢复,是否继续?`
: `删除院区“${campus.name}”后无法恢复,是否继续?`,
'删除院区',
{ type: 'warning', confirmButtonText: '删除', cancelButtonText: '取消' },
)
.then(() => true)
.catch(() => false)
if (!confirmed) return
try {
await deleteCampus(campus.id)
if (selectedCampusId.value === campus.id) selectedDepartmentId.value = null
await appStore.loadCampuses(true)
await loadOrganization()
ElMessage.success('院区已删除')
} catch (error) {
ElMessage.error(toUserMessage(error, '院区删除失败,请稍后重试'))
}
}
async function removeDepartment(department: DepartmentRecord) {
if (!canManageDepartments.value) return
const childCount = departments.value.filter((item) => item.parentId === department.id).length
const confirmed = await ElMessageBox.confirm(
childCount
? `删除科室“${department.name}”会同时移除其下 ${childCount} 个下级科室,且无法恢复,是否继续?`
: `删除科室“${department.name}”后无法恢复,是否继续?`,
'删除科室',
{ type: 'warning', confirmButtonText: '删除', cancelButtonText: '取消' },
)
.then(() => true)
.catch(() => false)
if (!confirmed) return
try {
await deleteDepartment(department.id)
if (selectedDepartmentId.value === department.id) selectedDepartmentId.value = null
await loadOrganization()
ElMessage.success('科室已删除')
} catch (error) {
ElMessage.error(toUserMessage(error, '科室删除失败,请稍后重试'))
}
}
watch( watch(
() => appStore.selectedCampusId, () => appStore.selectedCampusId,
(campusId) => { (campusId) => {
@@ -724,6 +777,8 @@ onMounted(loadOrganization)
@add-department="openAddDepartment" @add-department="openAddDepartment"
@edit-campus="editCampus" @edit-campus="editCampus"
@edit-department="editDepartment" @edit-department="editDepartment"
@delete-campus="removeCampus"
@delete-department="removeDepartment"
/> />
<section class="employee-card"> <section class="employee-card">