Browse Source

部门新增,修改功能

master
ma-zhongxu 10 months ago
parent
commit
091c372d9b
  1. 12
      frontend/src/models/admin.js
  2. 112
      frontend/src/pages/Admin/Section/index.jsx
  3. 16
      server/endpoints/dept.js
  4. 40
      server/models/dept.js
  5. 1
      server/storage/localFile/cebc49a6-9df4-46cc-8ba5-672b5d72de0e.txt
  6. 20
      server/storage/localFile/f51243b3-13e6-4374-8b64-a7fa4ba38ed9.txt

12
frontend/src/models/admin.js

@ -270,6 +270,18 @@ const Admin = {
return { depts: null, error: e.message };
});
},
updateDept: async (deptId,data) => {
return await fetch(`${API_BASE}/dept/edit/${deptId}`, {
method: "POST",
headers: baseHeaders(),
body: JSON.stringify(data),
})
.then((res) => res.json())
.catch((e) => {
console.error(e);
return { depts: null, error: e.message };
});
},
};
export default Admin;

112
frontend/src/pages/Admin/Section/index.jsx

@ -112,13 +112,24 @@ function DepartmentsContainer() {
);
}
function DepartmentRow({ dept }) {
const [expanded, setExpanded] = useState(false);
const { isOpen, openModal, closeModal } = useModal();
const toggleExpand = () => {
setExpanded(!expanded);
};
const handleEdit = () => {
openModal();
};
const handleSuccess = () => {
//
window.location.reload(); //
};
return (
<>
<tr className="border-b border-white/10">
@ -155,10 +166,16 @@ function DepartmentRow({ dept }) {
</td>
<td className="px-6 py-4">
<div className="flex items-center gap-x-2">
<button className="text-theme-text-secondary hover:text-theme-text-primary">
<button
onClick={handleEdit}
className="text-theme-text-secondary hover:text-theme-text-primary"
>
<Pencil className="h-4 w-4" />
</button>
<button className="text-theme-text-secondary hover:text-theme-text-primary">
<button
onClick={() => handleDelete(dept.deptId)}
className="text-theme-text-secondary hover:text-theme-text-primary"
>
<Trash className="h-4 w-4" />
</button>
</div>
@ -169,10 +186,16 @@ function DepartmentRow({ dept }) {
dept.children.map((child) => (
<DepartmentRow key={child.deptId} dept={child} />
))}
<ModalWrapper isOpen={isOpen}>
<EditDepartmentModal
dept={dept}
closeModal={closeModal}
onSuccess={handleSuccess}
/>
</ModalWrapper>
</>
);
}
function NewDepartmentModal({ closeModal }) {
const [formData, setFormData] = useState({
deptName: "",
@ -275,6 +298,89 @@ function NewDepartmentModal({ closeModal }) {
);
}
function EditDepartmentModal({ dept, closeModal, onSuccess }) {
const [formData, setFormData] = useState({
deptName: dept.deptName,
parentId: dept.parentId,
orderNum: dept.orderNum,
status: dept.status,
});
const [departments, setDepartments] = useState([]);
const [treeData, setTreeData] = useState([]);
useEffect(() => {
async function fetchDepartments() {
const _departments = await Admin.depts();
setDepartments(_departments);
setTreeData(buildTree(_departments));
}
fetchDepartments();
}, []);
const handleSubmit = async () => {
await Admin.updateDept(dept.deptId,formData); // API
onSuccess(); //
closeModal();
};
function buildTree(depts, parentId = 0) {
return depts
.filter((dept) => dept.parentId === parentId)
.map((dept) => ({
title: dept.deptName, // title
value: dept.deptId, // ID
children: buildTree(depts, dept.deptId), //
}));
}
return (
<div className="p-6">
<h2 className="text-lg font-bold text-theme-text-primary mb-4">
编辑部门
</h2>
<div className="flex flex-col gap-y-4">
<div>
<label className="text-sm font-medium text-theme-text-secondary block mb-2">
上级部门
</label>
<TreeSelect
treeData={treeData}
value={formData.parentId}
onChange={(value) => setFormData({ ...formData, parentId: value })}
placeholder="请选择上级部门"
className="w-full"
dropdownStyle={{ maxHeight: 400, overflow: "auto" }}
/>
</div>
<input
type="text"
placeholder="部门名称"
value={formData.deptName}
onChange={(e) => setFormData({ ...formData, deptName: e.target.value })}
className="border-none bg-theme-settings-input-bg text-white placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
/>
<input
type="number"
placeholder="排序"
value={formData.orderNum}
onChange={(e) => setFormData({ ...formData, orderNum: Number(e.target.value) })}
className="border-none bg-theme-settings-input-bg text-white placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
/>
<select
value={formData.status}
onChange={(e) => setFormData({ ...formData, status: Number(e.target.value) })}
className="border-none bg-theme-settings-input-bg text-white placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
>
<option value={0}>启用</option>
<option value={1}>停用</option>
</select>
<CTAButton onClick={handleSubmit}>保存</CTAButton>
</div>
</div>
);
}
//
function buildTree(departments, parentId = 0) {
return departments

16
server/endpoints/dept.js

@ -4,6 +4,7 @@ const {
strictMultiUserRoleValid,
ROLES
} = require("../utils/middleware/multiUserProtected");
const { reqBody } = require("../utils/http");
function deptEndpoints(app) {
if (!app) return;
@ -57,7 +58,8 @@ function deptEndpoints(app) {
[validatedRequest, strictMultiUserRoleValid([ROLES.admin])],
async (request, response) => {
try {
const dept = request.body; // 获取请求体中的部门数据
const dept = reqBody(request); // 获取请求体中的部门数据
console.log("dept 类型:", typeof dept);
// 检查部门名称是否唯一
const isUnique = await Dept.checkDeptNameUnique(dept);
if (!isUnique) {
@ -86,14 +88,16 @@ function deptEndpoints(app) {
}
});
app.post("/dept/edit",
app.post("/dept/edit/:deptId",
[validatedRequest, strictMultiUserRoleValid([ROLES.admin])],
async (request, response) => {
try {
const dept = request.body; // 获取请求体中的部门数据
const deptId = parseInt(request.params.deptId);
const dept = reqBody(request); // 获取请求体中的部门数据
// 检查部门名称是否唯一
const isUnique = await Dept.checkDeptNameUnique(dept);
console.log("isUnique:", isUnique);
if (!isUnique) {
return response.status(400).json({
success: false,
@ -102,7 +106,7 @@ function deptEndpoints(app) {
}
// 检查上级部门是否是自己
if (dept.parentId === dept.deptId) {
if (dept.parentId === deptId) {
return response.status(400).json({
success: false,
message: `修改部门 '${dept.deptName}' 失败,上级部门不能是自己`,
@ -111,7 +115,7 @@ function deptEndpoints(app) {
// 检查部门是否包含未停用的子部门
if (dept.status === 1) {
const normalChildrenCount = await Dept.selectNormalChildrenDeptById(dept.deptId);
const normalChildrenCount = await Dept.selectNormalChildrenDeptById(deptId);
if (normalChildrenCount > 0) {
return response.status(400).json({
success: false,
@ -120,7 +124,7 @@ function deptEndpoints(app) {
}
}
// 更新部门数据
const updatedDept = await Dept.update(dept);
const updatedDept = await Dept.update(deptId, dept);
// 返回成功响应
response.status(200).json({
success: true,

40
server/models/dept.js

@ -103,26 +103,39 @@ const Dept = {
}
},
update: async function (deptId, updates = {}) {
console.log("更新部门数据:", updates);
try {
if (!deptId) throw new Error('No dept id provided for update');
// 检查 deptId 是否存在
if (!deptId) throw new Error('没有提供用于查询的deptId');
const currentDept = await prisma.dept.findUnique({ where: { deptId } });
if (!currentDept) throw new Error('Dept not found');
// 检查 updates 是否为空
if (Object.keys(updates).length === 0) throw new Error('没有提供更新字段');
Object.entries(updates).forEach(([key, value]) => {
if (this.writable.includes(key)) {
if (Object.prototype.hasOwnProperty.call(this.validations, key)) {
updates[key] = this.validations[key](this.castColumnValue(key, value));
} else {
updates[key] = this.castColumnValue(key, value);
}
}
});
// 查询当前部门
const currentDept = await prisma.dept.findUnique({ where: { deptId } });
if (!currentDept) throw new Error('不存在该部门');
// 更新 lastUpdatedAt 字段
updates.lastUpdatedAt = new Date();
const updatedDept = await prisma.dept.update({ where: { deptId }, data: updates });
// 如果 parentId 发生变化,更新 ancestors 字段
if (updates.parentId !== undefined && updates.parentId !== currentDept.parentId) {
const parentId = updates.parentId;
const parentDept = await prisma.dept.findUnique({ where: { deptId: parentId } });
updates.ancestors = parentDept ? `${parentDept.ancestors},${parentId}` : `${parentId}`;
}
console.log("更新前部门数据:", updates);
// 执行更新操作
const updatedDept = await prisma.dept.update({
where: { deptId }, // 使用 deptId 作为查询条件
data: updates, // 更新的字段
});
console.log("更新后部门数据:", updatedDept);
// 返回成功结果
return { success: true, error: null, dept: updatedDept };
} catch (error) {
console.error(error.message);
@ -174,6 +187,7 @@ const Dept = {
});
// 如果查询到记录,说明部门名称已存在
console.log("existingDept:", existingDept);
return !existingDept;
} catch (error) {
console.error('检查部门名称唯一性失败:', error);

1
server/storage/localFile/cebc49a6-9df4-46cc-8ba5-672b5d72de0e.txt

@ -0,0 +1 @@
你好

20
server/storage/localFile/f51243b3-13e6-4374-8b64-a7fa4ba38ed9.txt

@ -0,0 +1,20 @@
一、数字驼乡
1、政策类型修改增删改查接口的逻辑
2、服务事项主题分类增删改查逻辑修改,信息发布修改数据库字段类型
3、政策内容id改成UUID, 行业资讯id修改为UUID,政策解读ID修改为UUID,用户注册校验用户名是否重复, 商家信息新增和更新时校验商家名称和统一社会信用代码
4、商家信息添加字段:其他证照,商家信息添加字段:审核状态,审核时间,审核人,审核反馈; 商家资质添加字段:审核人
5、添加商家信息图标
7、政企服务建表,页面和路由生成,后端新开一个微服务
8、配合赵洋做商家信息相关的问题
9、 添加5个图标供参考
10、生成提问和反馈的页面和路由
11、商家信息修改时校验审核状态
12、提问反馈的页面字段错误问题和提问反馈的关联用户ID问题
13、修复商家信息和行业类型,行政区划实体里面的对应混乱问题
二、盟林草-森林保险管理系统
1、修改上次测出问题,部署
三、社会治理联动指挥平台(一期)
1、修复导航权限问题,部署
Loading…
Cancel
Save