2026-01-18 22:54:43 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="department-management">
|
|
|
|
|
|
<!-- 头部区域 -->
|
|
|
|
|
|
<div class="header-section">
|
|
|
|
|
|
<div class="header-content">
|
2026-03-24 02:32:35 +08:00
|
|
|
|
<div class="section-title">部门管理</div>
|
|
|
|
|
|
<p class="section-description">管理系统部门,部门下的用户会被隔离管理。</p>
|
2026-01-18 22:54:43 +08:00
|
|
|
|
</div>
|
2026-03-24 02:32:35 +08:00
|
|
|
|
<a-button type="primary" @click="showAddDepartmentModal" class="add-btn lucide-icon-btn">
|
|
|
|
|
|
<template #icon><Plus :size="16" /></template>
|
2026-01-18 22:54:43 +08:00
|
|
|
|
添加部门
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 主内容区域 -->
|
|
|
|
|
|
<div class="content-section">
|
|
|
|
|
|
<a-spin :spinning="departmentManagement.loading">
|
|
|
|
|
|
<div v-if="departmentManagement.error" class="error-message">
|
|
|
|
|
|
<a-alert type="error" :message="departmentManagement.error" show-icon />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<template v-if="departmentManagement.departments.length > 0">
|
|
|
|
|
|
<a-table
|
|
|
|
|
|
:dataSource="departmentManagement.departments"
|
|
|
|
|
|
:columns="columns"
|
2026-01-18 23:07:21 +08:00
|
|
|
|
:rowKey="(record) => record.id"
|
2026-01-18 22:54:43 +08:00
|
|
|
|
:pagination="false"
|
|
|
|
|
|
class="department-table"
|
|
|
|
|
|
>
|
|
|
|
|
|
<template #bodyCell="{ column, record }">
|
|
|
|
|
|
<template v-if="column.key === 'name'">
|
|
|
|
|
|
<div class="department-name">
|
|
|
|
|
|
<span class="name-text">{{ record.name }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<template v-if="column.key === 'description'">
|
|
|
|
|
|
<span class="description-text">{{ record.description || '-' }}</span>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<template v-if="column.key === 'userCount'">
|
|
|
|
|
|
<span>{{ record.user_count ?? 0 }} 人</span>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<template v-if="column.key === 'action'">
|
|
|
|
|
|
<a-space>
|
|
|
|
|
|
<a-tooltip title="编辑部门">
|
2026-01-18 23:07:21 +08:00
|
|
|
|
<a-button
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@click="showEditDepartmentModal(record)"
|
2026-03-24 02:32:35 +08:00
|
|
|
|
class="action-btn lucide-icon-btn"
|
2026-01-18 23:07:21 +08:00
|
|
|
|
>
|
2026-03-24 02:32:35 +08:00
|
|
|
|
<Pencil :size="14" />
|
2026-01-18 22:54:43 +08:00
|
|
|
|
</a-button>
|
|
|
|
|
|
</a-tooltip>
|
|
|
|
|
|
<a-tooltip title="删除部门">
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
danger
|
|
|
|
|
|
@click="confirmDeleteDepartment(record)"
|
2026-04-04 11:10:30 +08:00
|
|
|
|
:disabled="record.id === 1"
|
2026-03-24 02:32:35 +08:00
|
|
|
|
class="action-btn lucide-icon-btn"
|
2026-01-18 22:54:43 +08:00
|
|
|
|
>
|
2026-03-24 02:32:35 +08:00
|
|
|
|
<Trash2 :size="14" />
|
2026-01-18 22:54:43 +08:00
|
|
|
|
</a-button>
|
|
|
|
|
|
</a-tooltip>
|
|
|
|
|
|
</a-space>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</a-table>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<div v-else class="empty-state">
|
|
|
|
|
|
<a-empty description="暂无部门数据" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</a-spin>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 部门表单模态框 -->
|
|
|
|
|
|
<a-modal
|
|
|
|
|
|
v-model:open="departmentManagement.modalVisible"
|
|
|
|
|
|
:title="departmentManagement.modalTitle"
|
|
|
|
|
|
@ok="handleDepartmentFormSubmit"
|
|
|
|
|
|
:confirmLoading="departmentManagement.loading"
|
|
|
|
|
|
@cancel="departmentManagement.modalVisible = false"
|
|
|
|
|
|
:maskClosable="false"
|
|
|
|
|
|
width="520px"
|
|
|
|
|
|
class="department-modal"
|
|
|
|
|
|
>
|
|
|
|
|
|
<a-form layout="vertical" class="department-form">
|
|
|
|
|
|
<a-form-item label="部门名称" required class="form-item">
|
|
|
|
|
|
<a-input
|
|
|
|
|
|
v-model:value="departmentManagement.form.name"
|
|
|
|
|
|
placeholder="请输入部门名称"
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
:maxlength="50"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item label="部门描述" class="form-item">
|
|
|
|
|
|
<a-textarea
|
|
|
|
|
|
v-model:value="departmentManagement.form.description"
|
|
|
|
|
|
placeholder="请输入部门描述(可选)"
|
|
|
|
|
|
:rows="3"
|
|
|
|
|
|
:maxlength="255"
|
|
|
|
|
|
show-count
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-divider v-if="!departmentManagement.editMode" />
|
|
|
|
|
|
|
|
|
|
|
|
<template v-if="!departmentManagement.editMode">
|
|
|
|
|
|
<div class="admin-section-title">
|
2026-03-24 02:32:35 +08:00
|
|
|
|
<Users :size="16" />
|
2026-01-18 22:54:43 +08:00
|
|
|
|
<span>部门管理员</span>
|
|
|
|
|
|
</div>
|
2026-01-18 23:07:21 +08:00
|
|
|
|
<p class="admin-section-hint">
|
|
|
|
|
|
创建部门时必须同时创建管理员,该管理员将负责管理本部门用户
|
|
|
|
|
|
</p>
|
2026-01-18 22:54:43 +08:00
|
|
|
|
|
|
|
|
|
|
<a-form-item label="管理员用户ID" required class="form-item">
|
|
|
|
|
|
<a-input
|
|
|
|
|
|
v-model:value="departmentManagement.form.adminUserId"
|
|
|
|
|
|
placeholder="请输入管理员用户ID(3-20位字母/数字/下划线)"
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
:maxlength="20"
|
|
|
|
|
|
@blur="checkAdminUserId"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<div v-if="departmentManagement.form.userIdError" class="error-text">
|
|
|
|
|
|
{{ departmentManagement.form.userIdError }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div v-else class="help-text">此ID将用于登录</div>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item label="密码" required class="form-item">
|
|
|
|
|
|
<a-input-password
|
|
|
|
|
|
v-model:value="departmentManagement.form.adminPassword"
|
|
|
|
|
|
placeholder="请输入管理员密码"
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
:maxlength="50"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item label="确认密码" required class="form-item">
|
|
|
|
|
|
<a-input-password
|
|
|
|
|
|
v-model:value="departmentManagement.form.adminConfirmPassword"
|
|
|
|
|
|
placeholder="请再次输入密码"
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
:maxlength="50"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item label="手机号(可选)" class="form-item">
|
|
|
|
|
|
<a-input
|
|
|
|
|
|
v-model:value="departmentManagement.form.adminPhone"
|
|
|
|
|
|
placeholder="请输入手机号(可用于登录)"
|
|
|
|
|
|
size="large"
|
|
|
|
|
|
:maxlength="11"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<div v-if="departmentManagement.form.phoneError" class="error-text">
|
|
|
|
|
|
{{ departmentManagement.form.phoneError }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</a-form>
|
|
|
|
|
|
</a-modal>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import { reactive, onMounted, watch } from 'vue'
|
|
|
|
|
|
import { notification, Modal } from 'ant-design-vue'
|
|
|
|
|
|
import { departmentApi, apiSuperAdminGet } from '@/apis'
|
2026-03-24 02:32:35 +08:00
|
|
|
|
import { Delete as Trash2, Edit3 as Pencil, Plus, Users } from 'lucide-vue-next'
|
2026-01-18 22:54:43 +08:00
|
|
|
|
|
|
|
|
|
|
// 表格列定义
|
|
|
|
|
|
const columns = [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '部门名称',
|
|
|
|
|
|
dataIndex: 'name',
|
|
|
|
|
|
key: 'name',
|
|
|
|
|
|
width: 200
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '描述',
|
|
|
|
|
|
dataIndex: 'description',
|
|
|
|
|
|
key: 'description',
|
|
|
|
|
|
ellipsis: true
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '用户数量',
|
|
|
|
|
|
dataIndex: 'user_count',
|
|
|
|
|
|
key: 'userCount',
|
|
|
|
|
|
width: 100,
|
|
|
|
|
|
align: 'center'
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '操作',
|
|
|
|
|
|
key: 'action',
|
|
|
|
|
|
width: 120,
|
|
|
|
|
|
align: 'center'
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
// 部门管理状态
|
|
|
|
|
|
const departmentManagement = reactive({
|
|
|
|
|
|
loading: false,
|
|
|
|
|
|
departments: [],
|
|
|
|
|
|
error: null,
|
|
|
|
|
|
modalVisible: false,
|
|
|
|
|
|
modalTitle: '添加部门',
|
|
|
|
|
|
editMode: false,
|
|
|
|
|
|
editDepartmentId: null,
|
|
|
|
|
|
form: {
|
|
|
|
|
|
name: '',
|
|
|
|
|
|
description: '',
|
|
|
|
|
|
adminUserId: '',
|
|
|
|
|
|
adminPassword: '',
|
|
|
|
|
|
adminConfirmPassword: '',
|
|
|
|
|
|
adminPhone: '',
|
|
|
|
|
|
userIdError: '',
|
|
|
|
|
|
phoneError: ''
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 获取部门列表
|
|
|
|
|
|
const fetchDepartments = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
departmentManagement.loading = true
|
|
|
|
|
|
departmentManagement.error = null
|
|
|
|
|
|
const departments = await departmentApi.getDepartments()
|
|
|
|
|
|
departmentManagement.departments = departments
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取部门列表失败:', error)
|
|
|
|
|
|
departmentManagement.error = '获取部门列表失败'
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
departmentManagement.loading = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 打开添加部门模态框
|
|
|
|
|
|
const showAddDepartmentModal = () => {
|
|
|
|
|
|
departmentManagement.modalTitle = '添加部门'
|
|
|
|
|
|
departmentManagement.editMode = false
|
|
|
|
|
|
departmentManagement.editDepartmentId = null
|
|
|
|
|
|
departmentManagement.form = {
|
|
|
|
|
|
name: '',
|
|
|
|
|
|
description: '',
|
|
|
|
|
|
adminUserId: '',
|
|
|
|
|
|
adminPassword: '',
|
|
|
|
|
|
adminConfirmPassword: '',
|
|
|
|
|
|
adminPhone: '',
|
|
|
|
|
|
userIdError: '',
|
|
|
|
|
|
phoneError: ''
|
|
|
|
|
|
}
|
|
|
|
|
|
departmentManagement.modalVisible = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 打开编辑部门模态框
|
|
|
|
|
|
const showEditDepartmentModal = (department) => {
|
|
|
|
|
|
departmentManagement.modalTitle = '编辑部门'
|
|
|
|
|
|
departmentManagement.editMode = true
|
|
|
|
|
|
departmentManagement.editDepartmentId = department.id
|
|
|
|
|
|
departmentManagement.form = {
|
|
|
|
|
|
name: department.name,
|
|
|
|
|
|
description: department.description || '',
|
|
|
|
|
|
adminUserId: '',
|
|
|
|
|
|
adminPassword: '',
|
|
|
|
|
|
adminConfirmPassword: '',
|
|
|
|
|
|
adminPhone: '',
|
|
|
|
|
|
userIdError: '',
|
|
|
|
|
|
phoneError: ''
|
|
|
|
|
|
}
|
|
|
|
|
|
departmentManagement.modalVisible = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证手机号格式
|
|
|
|
|
|
const validatePhoneNumber = (phone) => {
|
|
|
|
|
|
if (!phone) {
|
|
|
|
|
|
return true // 手机号可选
|
|
|
|
|
|
}
|
|
|
|
|
|
const phoneRegex = /^1[3-9]\d{9}$/
|
|
|
|
|
|
return phoneRegex.test(phone)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 监听手机号输入变化
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => departmentManagement.form.adminPhone,
|
|
|
|
|
|
(newPhone) => {
|
|
|
|
|
|
departmentManagement.form.phoneError = ''
|
|
|
|
|
|
if (newPhone && !validatePhoneNumber(newPhone)) {
|
|
|
|
|
|
departmentManagement.form.phoneError = '请输入正确的手机号格式'
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 检查管理员用户ID是否可用
|
|
|
|
|
|
const checkAdminUserId = async () => {
|
|
|
|
|
|
const userId = departmentManagement.form.adminUserId.trim()
|
|
|
|
|
|
departmentManagement.form.userIdError = ''
|
|
|
|
|
|
|
|
|
|
|
|
if (!userId) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证格式
|
|
|
|
|
|
if (!/^[a-zA-Z0-9_]+$/.test(userId)) {
|
|
|
|
|
|
departmentManagement.form.userIdError = '用户ID只能包含字母、数字和下划线'
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (userId.length < 3 || userId.length > 20) {
|
|
|
|
|
|
departmentManagement.form.userIdError = '用户ID长度必须在3-20个字符之间'
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已存在
|
|
|
|
|
|
try {
|
|
|
|
|
|
const result = await apiSuperAdminGet(`/api/auth/check-user-id/${userId}`)
|
|
|
|
|
|
if (!result.is_available) {
|
|
|
|
|
|
departmentManagement.form.userIdError = '该用户ID已被使用'
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('检查用户ID失败:', error)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理部门表单提交
|
|
|
|
|
|
const handleDepartmentFormSubmit = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 验证部门名称
|
|
|
|
|
|
if (!departmentManagement.form.name.trim()) {
|
|
|
|
|
|
notification.error({ message: '部门名称不能为空' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (departmentManagement.form.name.trim().length < 2) {
|
|
|
|
|
|
notification.error({ message: '部门名称至少2个字符' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证管理员用户ID
|
|
|
|
|
|
const adminUserId = departmentManagement.form.adminUserId.trim()
|
|
|
|
|
|
if (!adminUserId) {
|
|
|
|
|
|
notification.error({ message: '请输入管理员用户ID' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!/^[a-zA-Z0-9_]+$/.test(adminUserId)) {
|
|
|
|
|
|
notification.error({ message: '用户ID只能包含字母、数字和下划线' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (adminUserId.length < 3 || adminUserId.length > 20) {
|
|
|
|
|
|
notification.error({ message: '用户ID长度必须在3-20个字符之间' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (departmentManagement.form.userIdError) {
|
|
|
|
|
|
notification.error({ message: '管理员用户ID已存在或格式错误' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证密码
|
|
|
|
|
|
if (!departmentManagement.form.adminPassword) {
|
|
|
|
|
|
notification.error({ message: '请输入管理员密码' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-18 23:07:21 +08:00
|
|
|
|
if (
|
|
|
|
|
|
departmentManagement.form.adminPassword !== departmentManagement.form.adminConfirmPassword
|
|
|
|
|
|
) {
|
2026-01-18 22:54:43 +08:00
|
|
|
|
notification.error({ message: '两次输入的密码不一致' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证手机号
|
2026-01-18 23:07:21 +08:00
|
|
|
|
if (
|
|
|
|
|
|
departmentManagement.form.adminPhone &&
|
|
|
|
|
|
!validatePhoneNumber(departmentManagement.form.adminPhone)
|
|
|
|
|
|
) {
|
2026-01-18 22:54:43 +08:00
|
|
|
|
notification.error({ message: '请输入正确的手机号格式' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
departmentManagement.loading = true
|
|
|
|
|
|
|
|
|
|
|
|
if (departmentManagement.editMode) {
|
|
|
|
|
|
// 更新部门
|
|
|
|
|
|
await departmentApi.updateDepartment(departmentManagement.editDepartmentId, {
|
|
|
|
|
|
name: departmentManagement.form.name.trim(),
|
|
|
|
|
|
description: departmentManagement.form.description.trim() || undefined
|
|
|
|
|
|
})
|
|
|
|
|
|
notification.success({ message: '部门更新成功' })
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 创建部门,同时创建管理员
|
|
|
|
|
|
await departmentApi.createDepartment({
|
|
|
|
|
|
name: departmentManagement.form.name.trim(),
|
|
|
|
|
|
description: departmentManagement.form.description.trim() || undefined,
|
|
|
|
|
|
admin_user_id: adminUserId,
|
|
|
|
|
|
admin_password: departmentManagement.form.adminPassword,
|
|
|
|
|
|
admin_phone: departmentManagement.form.adminPhone || undefined
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
notification.success({ message: `部门创建成功,管理员 "${adminUserId}" 已创建` })
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重新获取部门列表
|
|
|
|
|
|
await fetchDepartments()
|
|
|
|
|
|
departmentManagement.modalVisible = false
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('部门操作失败:', error)
|
|
|
|
|
|
notification.error({
|
|
|
|
|
|
message: '操作失败',
|
|
|
|
|
|
description: error.message || '请稍后重试'
|
|
|
|
|
|
})
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
departmentManagement.loading = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 删除部门
|
|
|
|
|
|
const confirmDeleteDepartment = (department) => {
|
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
|
title: '确认删除部门',
|
2026-04-04 11:10:30 +08:00
|
|
|
|
content: `确定要删除部门 "${department.name}" 吗?此操作不可撤销。该部门下的用户会被迁移到默认部门,部门级配置和部门 API Key 会一并清理。`,
|
2026-01-18 22:54:43 +08:00
|
|
|
|
okText: '删除',
|
|
|
|
|
|
okType: 'danger',
|
|
|
|
|
|
cancelText: '取消',
|
|
|
|
|
|
async onOk() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
departmentManagement.loading = true
|
|
|
|
|
|
await departmentApi.deleteDepartment(department.id)
|
|
|
|
|
|
notification.success({ message: '部门删除成功' })
|
|
|
|
|
|
// 重新获取部门列表
|
|
|
|
|
|
await fetchDepartments()
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('删除部门失败:', error)
|
|
|
|
|
|
notification.error({
|
|
|
|
|
|
message: '删除失败',
|
|
|
|
|
|
description: error.message || '请稍后重试'
|
|
|
|
|
|
})
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
departmentManagement.loading = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 在组件挂载时获取部门列表
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
fetchDepartments()
|
|
|
|
|
|
})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
|
|
|
.department-management {
|
|
|
|
|
|
.content-section {
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
|
|
|
|
|
|
.error-message {
|
|
|
|
|
|
padding: 16px 24px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.empty-state {
|
|
|
|
|
|
padding: 60px 20px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.department-table {
|
|
|
|
|
|
:deep(.ant-table-thead > tr > th) {
|
|
|
|
|
|
background: var(--gray-50);
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
padding: 8px 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.ant-table-tbody > tr > td) {
|
|
|
|
|
|
padding: 8px 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.department-name {
|
|
|
|
|
|
.name-text {
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
color: var(--gray-900);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.description-text {
|
|
|
|
|
|
color: var(--gray-600);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.action-btn {
|
|
|
|
|
|
padding: 4px 8px;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
background: var(--gray-25);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.department-modal {
|
|
|
|
|
|
:deep(.ant-modal-header) {
|
|
|
|
|
|
padding: 20px 24px;
|
|
|
|
|
|
border-bottom: 1px solid var(--gray-150);
|
|
|
|
|
|
|
|
|
|
|
|
.ant-modal-title {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: var(--gray-900);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.ant-modal-body) {
|
|
|
|
|
|
padding: 24px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.department-form {
|
|
|
|
|
|
.form-item {
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.ant-form-item-label) {
|
|
|
|
|
|
padding-bottom: 4px;
|
|
|
|
|
|
|
|
|
|
|
|
label {
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
color: var(--gray-900);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.error-text {
|
|
|
|
|
|
color: var(--color-error-500);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
|
line-height: 1.3;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.help-text {
|
|
|
|
|
|
color: var(--gray-600);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
|
line-height: 1.3;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|