generated from Leo_Ding/web-template
339 lines
9.0 KiB
Vue
339 lines
9.0 KiB
Vue
<template>
|
||
<div class="org-management">
|
||
<div class="header" v-if="!hasData">
|
||
<h1>组织管理</h1>
|
||
<a-button type="primary" @click="showAddModal()">添加根节点</a-button>
|
||
</div>
|
||
|
||
<div class="org-table">
|
||
<a-table
|
||
:columns="columns"
|
||
:data-source="dataSource"
|
||
:pagination="false"
|
||
row-key="orgId"
|
||
:expand-icon-as-cell="false"
|
||
>
|
||
<template #bodyCell="{ column, record }">
|
||
<template v-if="column.key === 'disabled'">
|
||
<a-tag :color="record.disabled === false ? 'green' : 'red'">
|
||
{{ record.disabled === false ? '启用' : '禁用' }}
|
||
</a-tag>
|
||
</template>
|
||
<template v-if="column.key === 'created_at'">
|
||
<div>{{ record.created_at ? dayjs(record.created_at).format('YYYY-MM-DD HH:mm') : '-' }}</div>
|
||
</template>
|
||
<template v-if="column.key === 'updated_at'">
|
||
<div>{{ record.updated_at ? dayjs(record.updated_at).format('YYYY-MM-DD HH:mm') : '-' }}</div>
|
||
</template>
|
||
<template v-if="column.key === 'actions'">
|
||
<div class="actions">
|
||
<!-- 修改这里:只在前两层显示添加子节点按钮 -->
|
||
<a-button
|
||
v-if="getNodeLevel(record) < 2"
|
||
size="small"
|
||
type="primary"
|
||
@click="showAddModal(record)"
|
||
>
|
||
添加子节点
|
||
</a-button>
|
||
<a-button
|
||
style="margin-left: 20px;"
|
||
size="small"
|
||
danger
|
||
@click="handleDelete(record)"
|
||
>
|
||
删除
|
||
</a-button>
|
||
</div>
|
||
</template>
|
||
</template>
|
||
</a-table>
|
||
</div>
|
||
|
||
<!-- 添加节点模态框 -->
|
||
<a-modal
|
||
v-model:visible="addModalVisible"
|
||
:title="isEditing ? '编辑节点' : '添加节点'"
|
||
@ok="handleAdd"
|
||
@cancel="handleCancel"
|
||
:confirm-loading="confirmLoading"
|
||
>
|
||
<a-form
|
||
ref="formRef"
|
||
:model="formState"
|
||
:rules="rules"
|
||
layout="vertical"
|
||
>
|
||
<a-form-item label="节点名称" name="name">
|
||
<a-input v-model:value="formState.name" placeholder="请输入节点名称" />
|
||
</a-form-item>
|
||
<a-form-item label="状态" name="status">
|
||
<a-switch
|
||
v-model:checked="formState.status"
|
||
:checked-children="statusText.checked"
|
||
:un-checked-children="statusText.unchecked"
|
||
:disabled="!isEditing"
|
||
/>
|
||
</a-form-item>
|
||
</a-form>
|
||
</a-modal>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, onMounted, computed } from 'vue';
|
||
import apis from '@/apis';
|
||
import { Modal, message } from 'ant-design-vue';
|
||
import dayjs from 'dayjs';
|
||
import { config } from '@/config';
|
||
import { usePagination } from '@/hooks';
|
||
|
||
const { listData, paginationState, loading, showLoading, hideLoading, resetPagination, searchFormData } = usePagination();
|
||
|
||
// 是否有数据的计算属性
|
||
const hasData = computed(() => {
|
||
return listData.value && listData.value.length > 0;
|
||
});
|
||
|
||
paginationState.onChange = (page, pageSize) => {
|
||
paginationState.current = page
|
||
paginationState.pageSize = pageSize
|
||
getList()
|
||
}
|
||
|
||
// 转换数据格式,将 subOrgList 转换为 children
|
||
const convertData = (data) => {
|
||
if (!data || data.length === 0) return [];
|
||
|
||
return data.map(item => {
|
||
const converted = {
|
||
...item,
|
||
key: item.id, // 使用 id 作为 key,注意这里应该是 id 而不是 orgId
|
||
};
|
||
|
||
if (item.subOrgList && item.subOrgList.length > 0) {
|
||
converted.children = convertData(item.subOrgList);
|
||
}
|
||
|
||
return converted;
|
||
});
|
||
};
|
||
|
||
// 数据源
|
||
const dataSource = ref([]);
|
||
|
||
// 模态框状态
|
||
const addModalVisible = ref(false);
|
||
const isEditing = ref(false);
|
||
const currentParent = ref(null);
|
||
const confirmLoading = ref(false);
|
||
|
||
// 表单状态 - 默认状态为启用(false)
|
||
const formState = reactive({
|
||
name: '',
|
||
status: false // 默认为false表示启用
|
||
});
|
||
|
||
// 状态显示文本
|
||
const statusText = computed(() => {
|
||
return {
|
||
checked: '禁用',
|
||
unchecked: '启用'
|
||
};
|
||
});
|
||
|
||
// 表单验证规则
|
||
const rules = {
|
||
name: [
|
||
{ required: true, message: '请输入节点名称', trigger: 'blur' }
|
||
]
|
||
};
|
||
|
||
// 表格列定义 - 移除 projectType 列
|
||
const columns = [
|
||
{
|
||
title: '组织名称',
|
||
dataIndex: 'name',
|
||
key: 'name',
|
||
width: 200,
|
||
},
|
||
{
|
||
title: '状态',
|
||
dataIndex: 'disabled',
|
||
key: 'disabled',
|
||
width: 100,
|
||
},
|
||
{
|
||
title: '创建时间',
|
||
dataIndex: 'created_at',
|
||
key: 'created_at',
|
||
width: 180,
|
||
},
|
||
{
|
||
title: '更新时间',
|
||
dataIndex: 'updated_at',
|
||
key: 'updated_at',
|
||
width: 180,
|
||
},
|
||
{
|
||
title: '操作',
|
||
key: 'actions',
|
||
width: 200,
|
||
},
|
||
];
|
||
|
||
/**
|
||
* 获取节点的层级
|
||
* @param {Object} node 节点数据
|
||
* @param {Array} data 数据源
|
||
* @param {number} level 当前层级
|
||
* @returns {number} 节点层级(0表示第一层,1表示第二层,2表示第三层)
|
||
*/
|
||
const getNodeLevel = (node, data = null, level = 0) => {
|
||
// 如果是根节点,直接返回0
|
||
if (!node.parentId || node.parentId === "") {
|
||
return 0;
|
||
}
|
||
|
||
// 如果没有传入data,使用dataSource
|
||
const searchData = data || dataSource.value;
|
||
|
||
// 递归查找父节点
|
||
const findParentLevel = (nodes, targetId, currentLevel) => {
|
||
for (const item of nodes) {
|
||
if (item.id === targetId) {
|
||
return currentLevel;
|
||
}
|
||
if (item.children && item.children.length > 0) {
|
||
const found = findParentLevel(item.children, targetId, currentLevel + 1);
|
||
if (found !== -1) {
|
||
return found;
|
||
}
|
||
}
|
||
}
|
||
return -1;
|
||
};
|
||
|
||
// 查找父节点的层级
|
||
const parentLevel = findParentLevel(searchData, node.parentId, 0);
|
||
|
||
// 返回当前节点层级(父节点层级 + 1)
|
||
return parentLevel + 1;
|
||
};
|
||
|
||
/**
|
||
* 获取表格数据
|
||
* @returns {Promise<void>}
|
||
*/
|
||
async function getList() {
|
||
try {
|
||
showLoading()
|
||
const { pageSize, current } = paginationState
|
||
const { success, data, total } = await apis.serviceMenu
|
||
.getNodeList({
|
||
pageSize,
|
||
current: current
|
||
})
|
||
.catch(() => {
|
||
throw new Error()
|
||
})
|
||
hideLoading()
|
||
if (config('http.code.success') === success) {
|
||
console.log("接口返回数据:", data)
|
||
listData.value = data || [];
|
||
paginationState.total = total || 0;
|
||
|
||
// 转换数据格式用于表格显示
|
||
dataSource.value = convertData(listData.value);
|
||
}
|
||
} catch (error) {
|
||
hideLoading()
|
||
console.error('获取数据失败:', error);
|
||
message.error('获取数据失败');
|
||
}
|
||
}
|
||
|
||
// 删除节点
|
||
const handleDelete = async (record) => {
|
||
Modal.confirm({
|
||
title: '确认删除',
|
||
content: `确定要删除"${record.name}"吗?${record.children && record.children.length > 0 ? '此操作将同时删除所有子节点。' : ''}`,
|
||
async onOk() {
|
||
console.log('删除节点:', record.id);
|
||
try {
|
||
// 调用删除接口
|
||
const { success } = await apis.serviceMenu.delNode(record.id);
|
||
if (config('http.code.success') === success) {
|
||
message.success('删除成功');
|
||
// 重新获取数据
|
||
await getList();
|
||
} else {
|
||
message.error('删除失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('删除失败:', error);
|
||
message.error('删除失败');
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
// 显示添加模态框
|
||
const showAddModal = (parent = null) => {
|
||
currentParent.value = parent;
|
||
isEditing.value = false;
|
||
// 重置表单 - 默认启用状态
|
||
Object.assign(formState, {
|
||
name: '',
|
||
status: false // 默认为启用状态
|
||
});
|
||
addModalVisible.value = true;
|
||
};
|
||
|
||
// 处理添加节点
|
||
const handleAdd = async () => {
|
||
if (!formState.name) {
|
||
message.error('请输入节点名称');
|
||
return;
|
||
}
|
||
|
||
confirmLoading.value = true;
|
||
|
||
try {
|
||
// 准备提交数据 - 始终包含 parentId 字段
|
||
const submitData = {
|
||
companyId: 'c001',
|
||
disabled: formState.status, // 状态为false表示启用,true表示禁用
|
||
name: formState.name,
|
||
status: "",
|
||
parentId: currentParent.value ? currentParent.value.id : "" // 使用 id 字段
|
||
};
|
||
|
||
// 调用添加接口
|
||
const { success } = await apis.serviceMenu.createNode(submitData);
|
||
|
||
if (config('http.code.success') === success) {
|
||
addModalVisible.value = false;
|
||
message.success('添加成功');
|
||
// 重新获取数据
|
||
await getList();
|
||
} else {
|
||
message.error('添加失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('添加失败:', error);
|
||
message.error('添加失败');
|
||
} finally {
|
||
confirmLoading.value = false;
|
||
}
|
||
};
|
||
|
||
// 取消添加
|
||
const handleCancel = () => {
|
||
addModalVisible.value = false;
|
||
};
|
||
|
||
onMounted(() => {
|
||
getList();
|
||
});
|
||
</script> |