增加文档管理功能

This commit is contained in:
2026-09-10 00:44:15 +08:00
parent 63bf972c17
commit 8a0334a020
18 changed files with 5958 additions and 4 deletions
@@ -28,6 +28,11 @@
<el-table-column prop="name" label="姓名" min-width="120" align="center" />
<el-table-column prop="phone" label="手机号" min-width="140" align="center" />
<el-table-column prop="email" label="邮箱" min-width="180" align="center" />
<el-table-column prop="org_id" label="部门" min-width="160" align="center">
<template #default="{ row }">
{{ orgNameMap[Number(row.org_id)] || (Number(row.org_id) ? `部门${row.org_id}` : "未分配") }}
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="90" align="center">
<template #default="{ row }">
<el-tag :type="Number(row.status) === 1 ? 'success' : 'danger'">
@@ -35,8 +40,9 @@
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="260" align="center" fixed="right">
<el-table-column label="操作" width="320" align="center" fixed="right">
<template #default="{ row }">
<el-button text type="primary" @click="openEditDialog(row)">编辑</el-button>
<el-button text type="primary" @click="openPasswordDialog(row)">
修改密码
</el-button>
@@ -54,6 +60,45 @@
<AddUser ref="addUserRef" @success="refreshTenantUsers" />
<el-dialog v-model="editDialogVisible" title="编辑用户" width="520px" destroy-on-close>
<el-form :model="editForm" label-width="90px">
<el-form-item label="用户名">
<el-input v-model="editForm.account" disabled />
</el-form-item>
<el-form-item label="姓名">
<el-input v-model="editForm.name" placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="手机号">
<el-input v-model="editForm.phone" placeholder="请输入手机号" />
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="editForm.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="状态">
<el-radio-group v-model="editForm.status">
<el-radio :label="1">启用</el-radio>
<el-radio :label="0">禁用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="所属部门">
<el-tree-select
v-model="editForm.org_id"
:data="orgTree"
:props="{ label: 'label', value: 'value', children: 'children' }"
value-key="value"
placeholder="请选择所属部门(用于文档私密共享按部门可见)"
clearable
check-strictly
style="width: 100%"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="editDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="editSubmitting" @click="submitEdit">确定</el-button>
</template>
</el-dialog>
<el-dialog v-model="passwordDialogVisible" title="修改密码" width="420px" destroy-on-close>
<el-form ref="passwordFormRef" :model="passwordForm" :rules="passwordRules" label-width="90px">
<el-form-item label="新密码" prop="password">
@@ -76,6 +121,7 @@ import { ref, reactive, watch } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { Plus } from "@element-plus/icons-vue";
import { getTenantUserList, editTenantUser, deleteTenantUser } from "@/api/tenantUser";
import { getOrganizationList } from "@/api/erp";
import AddUser from "./adduser.vue";
const props = defineProps<{
@@ -88,6 +134,21 @@ const usersLoading = ref(false);
const userSearchKeyword = ref("");
const addUserRef = ref<{ open: (tenantId: number) => void } | null>(null);
const orgTree = ref<any[]>([]);
const orgNameMap = ref<Record<number, string>>({});
const editDialogVisible = ref(false);
const editSubmitting = ref(false);
const editForm = reactive({
id: 0,
account: "",
name: "",
phone: "",
email: "",
status: 1,
org_id: undefined as number | undefined,
});
const passwordDialogVisible = ref(false);
const passwordSubmitting = ref(false);
const currentTenantUserId = ref<number | null>(null);
@@ -122,6 +183,41 @@ const buildTenantUserQuery = (tid: number) => {
return params;
};
// 将平铺的组织机构列表转换为树结构,供部门选择器使用
const buildOrgTree = (list: any[]): any[] => {
const nodes = (list || []).map((o) => ({
value: Number(o.id),
label: o.org_name || o.name || `部门${o.id}`,
parent_id: Number(o.parent_id || 0),
}));
const map = new Map<number, any>();
nodes.forEach((n) => map.set(n.value, { ...n, children: [] as any[] }));
const tree: any[] = [];
map.forEach((node) => {
const parent = map.get(node.parent_id);
if (parent) parent.children.push(node);
else tree.push(node);
});
return tree;
};
const loadOrgs = async () => {
try {
const res = await getOrganizationList();
if (res?.code === 200) {
const list = res?.data?.list || res?.data || [];
orgTree.value = buildOrgTree(list);
const nameMap: Record<number, string> = {};
(list || []).forEach((o: any) => {
nameMap[Number(o.id)] = o.org_name || o.name || `部门${o.id}`;
});
orgNameMap.value = nameMap;
}
} catch {
orgTree.value = [];
}
};
const refreshTenantUsers = async () => {
const id = props.tid;
if (id == null) return;
@@ -160,6 +256,7 @@ watch(
() => props.tid,
(id) => {
userSearchKeyword.value = "";
loadOrgs();
if (id == null) {
tenantUsers.value = [];
return;
@@ -191,6 +288,42 @@ const openPasswordDialog = (row: any) => {
passwordDialogVisible.value = true;
};
const openEditDialog = (row: any) => {
editForm.id = Number(row?.id || 0);
editForm.account = row?.account || "";
editForm.name = row?.name || "";
editForm.phone = row?.phone || "";
editForm.email = row?.email || "";
editForm.status = Number(row?.status ?? 1) === 1 ? 1 : 0;
editForm.org_id = row?.org_id ? Number(row.org_id) : undefined;
editDialogVisible.value = true;
};
const submitEdit = async () => {
if (!editForm.id) return;
editSubmitting.value = true;
try {
const res = await editTenantUser(editForm.id, {
name: editForm.name,
phone: editForm.phone,
email: editForm.email,
status: editForm.status,
org_id: editForm.org_id || 0,
});
if (res.code === 200) {
ElMessage.success("保存成功");
editDialogVisible.value = false;
refreshTenantUsers();
} else {
ElMessage.error(res.msg || "保存失败");
}
} catch (e: any) {
ElMessage.error(e?.message || "保存失败");
} finally {
editSubmitting.value = false;
}
};
const submitPassword = async () => {
if (!passwordFormRef.value || !currentTenantUserId.value) return;
@@ -27,6 +27,18 @@
<el-radio :label="0">禁用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="所属部门" prop="org_id">
<el-tree-select
v-model="formData.org_id"
:data="orgTree"
:props="{ label: 'label', value: 'value', children: 'children' }"
value-key="value"
placeholder="请选择所属部门(用于文档私密共享按部门可见)"
clearable
check-strictly
style="width: 100%"
/>
</el-form-item>
</el-form>
<template #footer>
@@ -41,9 +53,10 @@
* 租户详情内「添加用户」:提交到 /platform/tenantUser/create,
* 后端写入 yz_tenant_user(租户-用户绑定,含冗余账号/密码等字段)。
*/
import { ref, reactive } from 'vue';
import { ref, reactive, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { createTenantUser } from '@/api/tenantUser';
import { getOrganizationList } from '@/api/erp';
const emit = defineEmits(['success']);
const visible = ref(false);
@@ -52,6 +65,8 @@ const submitting = ref(false);
const formRef = ref();
const currentTenantId = ref<number | null>(null);
const orgTree = ref<any[]>([]);
const formData = reactive({
account: '',
password: '',
@@ -59,9 +74,42 @@ const formData = reactive({
name: '',
phone: '',
email: '',
status: 1
status: 1,
org_id: undefined as number | undefined
});
// 将平铺的组织机构列表转换为树结构,供部门选择器使用
const buildOrgTree = (list: any[]): any[] => {
const nodes = (list || []).map((o) => ({
value: Number(o.id),
label: o.org_name || o.name || `部门${o.id}`,
parent_id: Number(o.parent_id || 0),
}));
const map = new Map<number, any>();
nodes.forEach((n) => map.set(n.value, { ...n, children: [] as any[] }));
const tree: any[] = [];
map.forEach((node) => {
const parent = map.get(node.parent_id);
if (parent) parent.children.push(node);
else tree.push(node);
});
return tree;
};
const loadOrgs = async () => {
try {
const res = await getOrganizationList();
if (res?.code === 200) {
const list = res?.data?.list || res?.data || [];
orgTree.value = buildOrgTree(list);
}
} catch {
orgTree.value = [];
}
};
onMounted(loadOrgs);
const rules = {
account: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur', min: 5 }],
@@ -100,7 +148,8 @@ const open = (tenantId: number) => {
name: '',
phone: '',
email: '',
status: 1
status: 1,
org_id: undefined
});
};
@@ -120,6 +169,7 @@ const submitForm = async () => {
const submitData = {
...formData,
tid: currentTenantId.value,
org_id: formData.org_id || 0,
};
// 提交时不需要把确认密码发给后端
delete (submitData as any).password2;