Compare commits

..

No commits in common. "6cca9c2ae7dd8e6bf3be0cfa6f6435cbd604c93d" and "b6b192461b61c3bcfbf39f3d42d8601dccc20450" have entirely different histories.

4 changed files with 143 additions and 248 deletions

View File

@ -10,7 +10,7 @@ module.exports = {
javaGitBranch: "<branch-name>", javaGitBranch: "<branch-name>",
// 本地联调 safetyEval-servicecontext-path: /safetyEval默认端口 8095 // 本地联调 safetyEval-servicecontext-path: /safetyEval默认端口 8095
// 可通过环境变量覆盖: SAFETY_EVAL_API_HOST=http://192.168.x.x:8095 // 可通过环境变量覆盖: SAFETY_EVAL_API_HOST=http://192.168.x.x:8095
API_HOST: "http://192.168.0.152", API_HOST: "http://127.0.0.1",
}, },
production: { production: {
// 应用后端分支名称,部署上线需要 // 应用后端分支名称,部署上线需要

View File

@ -1,35 +1,42 @@
import { declareRequest } from "@cqsjjb/jjb-dva-runtime"; import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
import {
buildDepartmentTree,
fromDepartmentForm,
fromPageResponse,
fromSingleResponse,
toDepartmentForm,
toPageQuery,
} from "../../utils/enterpriseInfo/adapter";
import { apiGet, apiPost, apiPostDelete, safeAction, safePageResult } from "../../utils/enterpriseInfo/http";
export const orgDepartmentGet = declareRequest("orgDepartmentLoading", safeAction(async (params) => {
const res = await apiGet("/safetyEval/org-department/get", { id: params.id });
return fromSingleResponse(res, toDepartmentForm);
}));
export const orgDepartmentGet = declareRequest( export const orgDepartmentTree = declareRequest("orgDepartmentLoading", safeAction(async () => {
"orgDepartmentLoading", const res = await apiGet("/safetyEval/org-department/page", toPageQuery({ current: 1, size: 500 }));
"Get > /safetyEval/org-department/get", const pageData = fromPageResponse(res, toDepartmentForm);
"orgDepartmentDetail: {} | res.data || {}", return {
); success: true,
data: buildDepartmentTree(pageData.data || []),
};
}));
export const orgDepartmentTree = declareRequest( export const orgDepartmentList = declareRequest("orgDepartmentLoading", safePageResult(async (params) => {
"orgDepartmentLoading", const query = toPageQuery(params, { likeDeptName: "deptName" });
"Get > /safetyEval/org-department/tree", const res = await apiGet("/safetyEval/org-department/page", query);
"orgDepartmentTreeData: [] | res.data || []", return fromPageResponse(res, toDepartmentForm);
); }));
export const orgDepartmentList = declareRequest( export const orgDepartmentAdd = declareRequest("orgDepartmentLoading", safeAction(async (values) => {
"orgDepartmentLoading", return apiPost("/safetyEval/org-department/save", fromDepartmentForm(values));
"Get > /safetyEval/org-department/page", }));
"dataSource: [] | res.data || [] & total: 0 | res.totalCount || 0",
);
export const orgDepartmentAdd = declareRequest( export const orgDepartmentEdit = declareRequest("orgDepartmentLoading", safeAction(async (values) => {
"orgDepartmentLoading", return apiPost("/safetyEval/org-department/modify", fromDepartmentForm(values));
"Post > @/safetyEval/org-department/save", }));
);
export const orgDepartmentEdit = declareRequest( export const orgDepartmentRemove = declareRequest("orgDepartmentLoading", safeAction(async ({ id }) => {
"orgDepartmentLoading", return apiPostDelete("/safetyEval/org-department/delete", id);
"Post > @/safetyEval/org-department/modify", }));
);
export const orgDepartmentRemove = declareRequest(
"orgDepartmentLoading",
"Post > @/safetyEval/org-department/delete",
);

View File

@ -1,22 +1,29 @@
import { declareRequest } from "@cqsjjb/jjb-dva-runtime"; import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
import {
fromPageResponse,
fromPositionForm,
toPageQuery,
toPositionForm,
} from "../../utils/enterpriseInfo/adapter";
import { apiGet, apiPost, apiPostDelete, safeAction, safePageResult } from "../../utils/enterpriseInfo/http";
export const orgPositionList = declareRequest( export const orgPositionList = declareRequest("orgPositionLoading", safePageResult(async (params) => {
"orgPositionLoading", const query = toPageQuery(params, {
"Get > /safetyEval/org-position/page", eqDeptId: "deptId",
"dataSource: [] | res.data || [] & total: 0 | res.totalCount || 0", likePositionName: "positionName",
); });
const res = await apiGet("/safetyEval/org-position/page", query);
return fromPageResponse(res, toPositionForm);
}));
export const orgPositionAdd = declareRequest( export const orgPositionAdd = declareRequest("orgPositionLoading", safeAction(async (values) => {
"orgPositionLoading", return apiPost("/safetyEval/org-position/save", fromPositionForm(values));
"Post > @/safetyEval/org-position/save", }));
);
export const orgPositionEdit = declareRequest( export const orgPositionEdit = declareRequest("orgPositionLoading", safeAction(async (values) => {
"orgPositionLoading", return apiPost("/safetyEval/org-position/modify", fromPositionForm(values));
"Post > @/safetyEval/org-position/modify", }));
);
export const orgPositionRemove = declareRequest( export const orgPositionRemove = declareRequest("orgPositionLoading", safeAction(async ({ id }) => {
"orgPositionLoading", return apiPostDelete("/safetyEval/org-position/delete", id);
"Post > @/safetyEval/org-position/delete", }));
);

View File

@ -1,30 +1,15 @@
import { PlusOutlined } from "@ant-design/icons";
import { Connect } from "@cqsjjb/jjb-dva-runtime"; import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { import { Button, Empty, Form, Input, message, Modal, Row, Col, Select, Space, Tree } from "antd";
Button,
Empty,
Form,
Input,
message,
Modal,
Select,
Space,
Tree,
Table,
TreeSelect,
} from "antd";
import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
import TableAction from "@cqsjjb/jjb-react-admin-component/TableAction"; import TableAction from "@cqsjjb/jjb-react-admin-component/TableAction";
import { useEffect, useMemo, useRef, useState } from "react"; import { useEffect, useMemo, useRef, useState } from "react";
import AddIcon from "zy-react-library/components/Icon/AddIcon";
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout"; import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
import SearchForm from "@cqsjjb/jjb-react-admin-component/SearchForm"; import Search from "zy-react-library/components/Search";
import Table from "zy-react-library/components/Table";
import { import useTable from "zy-react-library/hooks/useTable";
NS_ORG_DEPARTMENT, import { NS_ORG_DEPARTMENT, NS_ORG_POSITION, NS_STAFF_INFO } from "~/enumerate/namespace";
NS_ORG_POSITION,
NS_STAFF_INFO,
} from "~/enumerate/namespace";
import { asId, sameId } from "~/utils/enterpriseInfo/idUtil"; import { asId, sameId } from "~/utils/enterpriseInfo/idUtil";
import { safeListRequest, safeRequest } from "~/utils";
function findDeptNode(nodes = [], id) { function findDeptNode(nodes = [], id) {
for (const node of nodes) { for (const node of nodes) {
@ -48,9 +33,9 @@ function toSelectedDept(node) {
return { return {
id: asId(node.id), id: asId(node.id),
deptName: node.deptName || node.title, deptName: node.deptName || node.title,
managerAccount: node.managerAccount, leaderAccount: node.leaderAccount,
managerName: node.managerName, leaderName: node.leaderName,
deptLevelName: node.deptLevelName, deptLevel: node.deptLevel,
}; };
} }
@ -64,62 +49,50 @@ function DepartmentPositionPage(props) {
const [staffOptions, setStaffOptions] = useState([]); const [staffOptions, setStaffOptions] = useState([]);
const [positionForm] = Form.useForm(); const [positionForm] = Form.useForm();
const [modalForm] = Form.useForm(); const [modalForm] = Form.useForm();
const [dataSource, setDataSource] = useState([]);
const [total, setTotal] = useState(0);
const [loading, setLoading] = useState(false);
const [pageIndex, setPageIndex] = useState(1);
const [pageSize, setPageSize] = useState(10);
useEffect(() => { useEffect(() => {
(async () => { (async () => {
try { try {
const res = await props.staffInfoList?.({ const res = await props.staffInfoList?.({ pageIndex: 1, pageSize: 500 });
pageIndex: 1, setStaffOptions((res?.data || []).map((s) => ({
pageSize: 500, label: `${s.userName ?? s.staffName}${s.account}`,
}); value: s.account,
setStaffOptions( staffName: s.userName ?? s.staffName,
(res?.data || []).map((s) => ({ })));
label: `${s.userName ?? s.staffName}${s.account}`, }
value: s.account, catch (err) {
staffName: s.userName ?? s.staffName,
})),
);
} catch (err) {
console.warn("[DepartmentPosition] load staff options failed:", err); console.warn("[DepartmentPosition] load staff options failed:", err);
} }
})(); })();
}, []); }, []);
const fetchPositionData = async (page = 1, size = 10) => { const { tableProps: positionTableProps, getData: getPositionData } = useTable(
if (!selectedDept?.id) return; safeListRequest(props.orgPositionList),
setLoading(true); {
try { form: positionForm,
const formData = positionForm.getFieldsValue(); transform: (formData) => ({
const res = await props.orgPositionList({
...formData, ...formData,
pageIndex: page, eqDeptId: asId(selectedDept?.id),
pageSize: size, }),
deptId: asId(selectedDept.id), },
}); );
setDataSource(res?.data || []);
setTotal(res?.totalCount || 0);
} catch {
setDataSource([]);
setTotal(0);
} finally {
setLoading(false);
}
};
const loadTree = async () => { const loadTree = async () => {
try { try {
const res = await props.orgDepartmentTree(); const res = await props.orgDepartmentTree();
const tree = res?.data || []; const normalizeTree = (nodes = []) => nodes.map((node) => ({
...node,
title: node.title || node.deptName,
deptName: node.deptName || node.title,
children: node.children ? normalizeTree(node.children) : [],
}));
const tree = normalizeTree(res?.data || []);
setTreeData(tree); setTreeData(tree);
if (tree.length) { if ( tree.length) {
setSelectedDept(toSelectedDept(tree[0])); setSelectedDept(toSelectedDept(tree[0]));
} }
} catch (err) { }
catch (err) {
console.warn("[DepartmentPosition] loadTree failed:", err); console.warn("[DepartmentPosition] loadTree failed:", err);
setTreeData([]); setTreeData([]);
} }
@ -131,7 +104,7 @@ function DepartmentPositionPage(props) {
useEffect(() => { useEffect(() => {
if (selectedDept?.id) { if (selectedDept?.id) {
fetchPositionData(1, 10); getPositionData();
} }
}, [selectedDept?.id]); }, [selectedDept?.id]);
@ -161,7 +134,7 @@ function DepartmentPositionPage(props) {
okText: "是", okText: "是",
cancelText: "否", cancelText: "否",
onOk: async () => { onOk: async () => {
const res = await props.orgDepartmentRemove({ data: id }); const res = await props.orgDepartmentRemove({ id });
if (res?.success !== false) { if (res?.success !== false) {
message.success("删除成功"); message.success("删除成功");
if (sameId(selectedDept?.id, id)) { if (sameId(selectedDept?.id, id)) {
@ -183,7 +156,7 @@ function DepartmentPositionPage(props) {
const res = await props.orgPositionRemove({ id }); const res = await props.orgPositionRemove({ id });
if (res?.success !== false) { if (res?.success !== false) {
message.success("删除成功"); message.success("删除成功");
fetchPositionData(1, 10); getPositionData();
} }
}, },
}); });
@ -219,11 +192,9 @@ function DepartmentPositionPage(props) {
deptId: asId(record.deptId || selectedDept.id), deptId: asId(record.deptId || selectedDept.id),
deptName: record.deptName || selectedDept.deptName, deptName: record.deptName || selectedDept.deptName,
}); });
} else { }
modalForm.setFieldsValue({ else {
deptId: asId(selectedDept.id), modalForm.setFieldsValue({ deptId: asId(selectedDept.id), deptName: selectedDept.deptName });
deptName: selectedDept.deptName,
});
} }
setPositionModalOpen(true); setPositionModalOpen(true);
}; };
@ -239,8 +210,9 @@ function DepartmentPositionPage(props) {
if (res?.success !== false) { if (res?.success !== false) {
message.success(currentId ? "编辑成功" : "添加成功"); message.success(currentId ? "编辑成功" : "添加成功");
closePositionModal(); closePositionModal();
fetchPositionData(pageIndex, pageSize); getPositionData();
} else { }
else {
message.error(res?.message || "操作失败"); message.error(res?.message || "操作失败");
} }
}; };
@ -248,24 +220,9 @@ function DepartmentPositionPage(props) {
return ( return (
<PageLayout title="部门岗位管理"> <PageLayout title="部门岗位管理">
<div style={{ display: "flex", gap: 16, minHeight: 480 }}> <div style={{ display: "flex", gap: 16, minHeight: 480 }}>
<div <div style={{ width: 260, borderRight: "1px solid #f0f0f0", paddingRight: 16, flexShrink: 0 }}>
style={{ <Space direction="vertical" style={{ width: "100%", marginBottom: 12 }}>
width: 260, <Button type="primary" icon={<AddIcon />} block onClick={() => openDeptModal()}>
borderRight: "1px solid #f0f0f0",
paddingRight: 16,
flexShrink: 0,
}}
>
<Space
direction="vertical"
style={{ width: "100%", marginBottom: 12 }}
>
<Button
type="primary"
icon={<PlusOutlined />}
block
onClick={() => openDeptModal()}
>
新增部门 新增部门
</Button> </Button>
<Input.Search <Input.Search
@ -286,45 +243,24 @@ function DepartmentPositionPage(props) {
<div style={{ flex: 1, minWidth: 0 }}> <div style={{ flex: 1, minWidth: 0 }}>
{selectedDept?.id ? ( {selectedDept?.id ? (
<> <>
<div <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }}>
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 16,
}}
>
<span> <span>
当前部门 当前部门
<strong>{selectedDept.deptName}</strong> <strong>{selectedDept.deptName}</strong>
</span> </span>
<Space> <Space>
<Button onClick={() => openDeptModal(selectedDept)}> <Button onClick={() => openDeptModal(selectedDept)}>编辑部门</Button>
编辑部门 <Button danger onClick={() => onDeleteDept(selectedDept.id)}>删除部门</Button>
</Button>
<Button danger onClick={() => onDeleteDept(selectedDept.id)}>
删除部门
</Button>
</Space> </Space>
</div> </div>
<SearchForm <Search
form={positionForm} form={positionForm}
loading={loading} options={[{ name: "likePositionName", label: "岗位名称", placeholder: "请输入岗位名称" }]}
formLine={[ onFinish={getPositionData}
<Form.Item key="positionName" name="positionName">
<Input allowClear placeholder="请输入岗位名称" />
</Form.Item>,
]}
onFinish={() => fetchPositionData(1, 10)}
style={{ marginBottom: 16 }}
/> />
<Table <Table
footer={() => ( toolBarRender={() => (
<Button <Button type="primary" icon={<AddIcon />} onClick={() => openPositionModal()}>
type="primary"
icon={<PlusOutlined />}
onClick={() => openPositionModal()}
>
新增岗位 新增岗位
</Button> </Button>
)} )}
@ -337,38 +273,13 @@ function DepartmentPositionPage(props) {
width: 160, width: 160,
render: (_, record) => ( render: (_, record) => (
<TableAction> <TableAction>
<Button <Button type="link" onClick={() => openPositionModal(record)}>编辑</Button>
type="link" <Button danger type="link" onClick={() => onDeletePosition(record.id)}>删除</Button>
onClick={() => openPositionModal(record)}
>
编辑
</Button>
<Button
danger
type="link"
onClick={() => onDeletePosition(record.id)}
>
删除
</Button>
</TableAction> </TableAction>
), ),
}, },
]} ]}
dataSource={dataSource} {...positionTableProps}
loading={loading}
pagination={{
current: pageIndex,
pageSize,
total,
showSizeChanger: true,
showTotal: (t) => `${t}`,
}}
scroll={{ y: props.scrollY }}
onChange={(pag) => {
setPageIndex(pag.current);
setPageSize(pag.pageSize);
fetchPositionData(pag.current, pag.pageSize);
}}
/> />
</> </>
) : ( ) : (
@ -381,7 +292,6 @@ function DepartmentPositionPage(props) {
<DeptFormModal <DeptFormModal
open={deptModalOpen} open={deptModalOpen}
currentId={currentId} currentId={currentId}
selectedDeptId={selectedDept?.id}
staffOptions={staffOptions} staffOptions={staffOptions}
treeData={treeData} treeData={treeData}
requestAdd={props.orgDepartmentAdd} requestAdd={props.orgDepartmentAdd}
@ -420,20 +330,10 @@ function DepartmentPositionPage(props) {
label="岗位职责" label="岗位职责"
rules={[{ required: true, message: "请输入岗位职责" }]} rules={[{ required: true, message: "请输入岗位职责" }]}
> >
<Input.TextArea <Input.TextArea rows={3} placeholder="请输入岗位职责" showCount maxLength={500} />
rows={3}
placeholder="请输入岗位职责"
showCount
maxLength={500}
/>
</Form.Item> </Form.Item>
<Form.Item name="remark" label="备注"> <Form.Item name="remark" label="备注">
<Input.TextArea <Input.TextArea rows={2} placeholder="请输入备注" showCount maxLength={500} />
rows={2}
placeholder="请输入备注"
showCount
maxLength={500}
/>
</Form.Item> </Form.Item>
</Form> </Form>
</Modal> </Modal>
@ -442,12 +342,12 @@ function DepartmentPositionPage(props) {
); );
} }
function resolveManagerAccount(dept, options) { function resolveLeaderAccount(dept, options) {
if (dept?.managerAccount) { if (dept?.leaderAccount) {
return dept.managerAccount; return dept.leaderAccount;
} }
if (dept?.managerName) { if (dept?.leaderName) {
const matched = options.find((item) => item.staffName === dept.managerName); const matched = options.find((item) => item.staffName === dept.leaderName);
return matched?.value; return matched?.value;
} }
return undefined; return undefined;
@ -463,7 +363,6 @@ function DeptFormModal({
requestDetails, requestDetails,
onCancel, onCancel,
onSuccess, onSuccess,
selectedDeptId,
}) { }) {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [submitting, setSubmitting] = useState(false); const [submitting, setSubmitting] = useState(false);
@ -490,12 +389,8 @@ function DeptFormModal({
let dept = null; let dept = null;
const getDetails = requestDetailsRef.current; const getDetails = requestDetailsRef.current;
if (typeof getDetails === "function") { if (typeof getDetails === "function") {
try { const res = await safeRequest(getDetails, { id: currentId });
const res = await getDetails({ id: currentId }); dept = res?.data || null;
dept = res?.data || null;
} catch {
dept = null;
}
} }
if (!dept) { if (!dept) {
dept = findDeptNode(treeDataRef.current, currentId); dept = findDeptNode(treeDataRef.current, currentId);
@ -503,8 +398,8 @@ function DeptFormModal({
if (!cancelled && dept) { if (!cancelled && dept) {
form.setFieldsValue({ form.setFieldsValue({
...dept, ...dept,
managerAccount: resolveManagerAccount(dept, staffOptionsRef.current), leaderAccount: resolveLeaderAccount(dept, staffOptionsRef.current),
managerName: dept.managerName, leaderName: dept.leaderName,
}); });
} }
}; };
@ -518,9 +413,9 @@ function DeptFormModal({
}; };
}, [open, currentId]); }, [open, currentId]);
const onManagerChange = (account) => { const onLeaderChange = (account) => {
const staff = staffOptions.find((s) => s.value === account); const staff = staffOptions.find((s) => s.value === account);
form.setFieldValue("managerName", staff?.staffName || ""); form.setFieldValue("leaderName", staff?.staffName || "");
}; };
const handleSubmit = async (values) => { const handleSubmit = async (values) => {
@ -537,14 +432,16 @@ function DeptFormModal({
form.resetFields(); form.resetFields();
onCancel(); onCancel();
await onSuccess(); await onSuccess();
} else { }
else {
message.error(res?.message || "操作失败"); message.error(res?.message || "操作失败");
} }
} finally { }
finally {
setSubmitting(false); setSubmitting(false);
} }
}; };
console.log(treeData);
return ( return (
<Modal <Modal
open={open} open={open}
@ -557,19 +454,6 @@ function DeptFormModal({
onOk={form.submit} onOk={form.submit}
> >
<Form form={form} layout="vertical" onFinish={handleSubmit}> <Form form={form} layout="vertical" onFinish={handleSubmit}>
<Form.Item name="parentId" label="上级部门" initialValue={selectedDeptId}>
<TreeSelect
treeData={treeData}
allowClear
fieldNames={{
label: "deptName",
value: "id",
children: "children",
}}
showSearch
placeholder="请选择上级部门"
/>
</Form.Item>
<Form.Item <Form.Item
name="deptName" name="deptName"
label="部门名称" label="部门名称"
@ -577,20 +461,20 @@ function DeptFormModal({
> >
<Input placeholder="请输入部门名称" /> <Input placeholder="请输入部门名称" />
</Form.Item> </Form.Item>
<Form.Item name="managerAccount" label="负责人"> <Form.Item name="leaderAccount" label="负责人">
<Select <Select
allowClear allowClear
showSearch showSearch
placeholder="请选择负责人" placeholder="请选择负责人"
options={staffOptions} options={staffOptions}
optionFilterProp="label" optionFilterProp="label"
onChange={onManagerChange} onChange={onLeaderChange}
/> />
</Form.Item> </Form.Item>
<Form.Item name="managerName" hidden> <Form.Item name="leaderName" hidden>
<Input /> <Input />
</Form.Item> </Form.Item>
<Form.Item name="deptLevelName" label="部门级别"> <Form.Item name="deptLevel" label="部门级别">
<Input placeholder="请输入部门级别" /> <Input placeholder="请输入部门级别" />
</Form.Item> </Form.Item>
</Form> </Form>
@ -598,7 +482,4 @@ function DeptFormModal({
); );
} }
export default Connect( export default Connect([NS_ORG_DEPARTMENT, NS_ORG_POSITION, NS_STAFF_INFO], true)(DepartmentPositionPage);
[NS_ORG_DEPARTMENT, NS_ORG_POSITION, NS_STAFF_INFO],
true,
)(AntdTableFuncControl(DepartmentPositionPage));