| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498 |
- /*
- * @Author: code4eat awesomedema@gmail.com
- * @Date: 2025-06-10 12:15:25
- * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2025-07-25 16:09:17
- * @FilePath: /pfmBackMana/src/pages/checkUnitMana/index.tsx
- * @Description: 查核单位管理
- */
- import {
- createFromIconfontCN,
- SearchOutlined,
- PlusOutlined,
- MoreOutlined,
- InboxOutlined,
- } from '@ant-design/icons';
- import {
- ActionType,
- ProColumns,
- ModalForm,
- ProFormText,
- ProFormRadio,
- ProFormUploadDragger,
- ProFormDigit,
- } from '@ant-design/pro-components';
- import {
- Button,
- Input,
- message,
- Tabs,
- Radio,
- Empty,
- Card,
- Dropdown,
- Menu,
- Modal,
- Select,
- Checkbox,
- Pagination,
- Popconfirm,
- Tooltip,
- } from 'antd';
- import React, { useRef, useState, useEffect } from 'react';
- import { request } from 'umi';
- import {
- getDeptClassList,
- addDeptClass,
- addDepartmentByClass,
- getDeptClassTree,
- getDeptClassFilterConditionList,
- applyDeptClassFilterCondition,
- updateDeptClass,
- delDeptClass,
- updateDepartmentByClass,
- delDepartmentByClass,
- getDeptEmployee,
- getDeptPendingEmployee,
- addDeptEmployee,
- setDeptManager,
- delDeptEmp,
- getDeptCheckpoint,
- getDeptPendingCheckpoint,
- addDeptCheckpoint,
- delDeptCheckpoint,
- } from './service';
- import './style.less';
- import KCIMPagecontainer from '@/components/KCIMPageContainer';
- import { KCIMTable } from '@/components/KCIMTable';
- const IconFont = createFromIconfontCN({
- scriptUrl: '',
- });
- const { TabPane } = Tabs;
- // 下载模板方法
- const downloadTemplate = async (type: number) => {
- try {
- // 获取token(如有)
- let token = '';
- const userDataStr = localStorage.getItem('userData');
- if (userDataStr) {
- try {
- token = JSON.parse(userDataStr).token || '';
- } catch (e) {
- token = '';
- }
- }
- const fetchOptions: any = { method: 'GET' };
- if (token) {
- fetchOptions.headers = { token };
- }
- const res = await fetch(`/gateway/manager/Department/exportPfmKnowledgeTemp?type=${type}`, fetchOptions);
- if (!res.ok) {
- message.error('下载模板失败');
- return;
- }
- const blob = await res.blob();
- // 尝试从header获取文件名
- let fileName = '';
- const disposition = res.headers.get('content-disposition');
- if (disposition && disposition.indexOf('filename=') !== -1) {
- fileName = decodeURIComponent(disposition.split('filename=')[1].replace(/"/g, ''));
- } else {
- fileName = type === 1 ? '系统追踪模板.xlsx' : '自查督查模板.xlsx';
- }
- const url = window.URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url;
- a.download = fileName;
- document.body.appendChild(a);
- a.click();
- a.remove();
- window.URL.revokeObjectURL(url);
- } catch (e) {
- message.error('下载模板失败');
- }
- };
- export default function CheckUnitMana() {
- // 状态定义
- const [selectedDept, setSelectedDept] = useState<any>(null);
- const [deptInfo, setDeptInfo] = useState<string>('');
- const [searchKeywords, setSearchKeywords] = useState<string>('');
- const [personnelSearchInput, setPersonnelSearchInput] = useState<string>(''); // 人员搜索输入框的值
- const [activeTab, setActiveTab] = useState('personnel');
- const tableRef = useRef<ActionType>();
- const conditionTableRef = useRef<ActionType>();
- const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
- const [treeData, setTreeData] = useState<any[]>([]);
- const [treeSearchKeywords, setTreeSearchKeywords] = useState<string>(''); // 树形搜索关键词
- const [filteredTreeData, setFilteredTreeData] = useState<any[]>([]); // 过滤后的树形数据
- const [hoveredNode, setHoveredNode] = useState<string | null>(null); // 当前悬停的节点
- const [openDropdownNode, setOpenDropdownNode] = useState<string | null>(null); // 当前打开下拉菜单的节点
- // 查核条件弹窗相关状态
- const [conditionModalVisible, setConditionModalVisible] = useState(false); // 条件弹窗显示状态
- const [conditionSearchType, setConditionSearchType] = useState('个案'); // 条件搜索类型
- const [conditionSearchKeyword, setConditionSearchKeyword] = useState(''); // 条件搜索关键词
- const [selectedConditions, setSelectedConditions] = useState<string[]>([]); // 已选择的条件ID列表
- const [currentNode, setCurrentNode] = useState<any>(null); // 当前操作的节点
- // 右侧内容区ref和操作栏定位状态
- const cardRef = useRef<HTMLDivElement>(null);
- const [actionBarStyle, setActionBarStyle] = useState<{
- left: number;
- width: number;
- }>({ left: 0, width: 0 });
- // 1. 新增弹窗相关状态
- const [checkPointModalVisible, setCheckPointModalVisible] = useState(false);
- const [checkPointTableRef, setCheckPointTableRef] = useState<any>(null);
- const [selectedCheckPointKeys, setSelectedCheckPointKeys] = useState<
- string[]
- >([]);
- // 记录当前页数据用于全选逻辑
- const [currentCheckPointPageData, setCurrentCheckPointPageData] = useState<
- any[]
- >([]);
- // 获取当前页面所有可选的要点ID(用于全选逻辑)
- const getCurrentPageCheckPointIds = () => {
- return currentCheckPointPageData
- .filter((item) => item.rowSpan > 0) // 只选择有rowSpan的行(要点行)
- .map((item) => item.id);
- };
- // 更新操作栏定位,支持ResizeObserver
- const updateActionBarPosition = () => {
- if (cardRef.current) {
- const rect = cardRef.current.getBoundingClientRect();
- setActionBarStyle({ left: rect.left, width: rect.width });
- }
- };
- useEffect(() => {
- updateActionBarPosition();
- window.addEventListener('resize', updateActionBarPosition);
- window.addEventListener('scroll', updateActionBarPosition, true);
- let resizeObserver: ResizeObserver | null = null;
- if (cardRef.current && typeof ResizeObserver !== 'undefined') {
- resizeObserver = new ResizeObserver(() => {
- updateActionBarPosition();
- });
- resizeObserver.observe(cardRef.current);
- }
- return () => {
- window.removeEventListener('resize', updateActionBarPosition);
- window.removeEventListener('scroll', updateActionBarPosition, true);
- if (resizeObserver && cardRef.current) {
- resizeObserver.unobserve(cardRef.current);
- resizeObserver.disconnect();
- }
- };
- }, []);
- // 获取单位分类树
- const fetchDeptClassList = async () => {
- try {
- const res = await getDeptClassTree();
- // 尝试多种数据结构格式
- let dataArray = null;
- if (res && res.data && Array.isArray(res.data)) {
- // 格式1: { data: [...] }
- dataArray = res.data;
- } else if (Array.isArray(res)) {
- // 格式2: 直接返回数组
- dataArray = res;
- } else if (res && Array.isArray(res.items)) {
- // 格式3: { items: [...] }
- dataArray = res.items;
- }
- if (dataArray && dataArray.length > 0) {
- const transformedData = dataArray.map((item: any) => {
- // 处理子节点数据 - 只处理children字段,不处理filterConditionList
- let children = [];
- // 只使用 children 字段作为子节点
- if (item.children && Array.isArray(item.children)) {
- children = item.children.map((child: any) => ({
- title: child.name,
- key: child.id || child.code,
- type: child.type || 'department', // 标记为查核单位
- visitType: child.visitType,
- deptType: child.deptType ?? 0, // 确保有默认值
- sort: child.sort,
- filterConditionList: child.filterConditionList || [], // 保留查核条件
- }));
- }
- // 如果没有children,说明这是叶子节点,不需要处理filterConditionList作为子节点
- return {
- title: item.name,
- key: item.id,
- type: item.type, // 类型:1单位分类 2查核单位
- visitType: item.visitType, // 诊别:1门诊 2急诊
- deptType: item.deptType ?? 0, // 单位类型:0普通单位 1职能科室,确保有默认值
- sort: item.sort,
- children: children,
- filterConditionList: item.filterConditionList || [], // 保留查核条件
- };
- });
- setTreeData(transformedData);
- setFilteredTreeData(transformedData); // 初始化过滤数据
- // 默认展开所有父节点
- setExpandedKeys(transformedData.map((item: any) => item.key));
- // 默认选中逻辑:选择第一个叶子节点(没有子节点的节点本身就是叶子节点)
- if (transformedData.length > 0) {
- let defaultSelected = null;
- // 遍历所有节点,找到第一个叶子节点
- for (const parent of transformedData) {
- if (parent.children && parent.children.length > 0) {
- // 如果有子节点,选择第一个子节点
- const firstChild = parent.children[0];
- defaultSelected = {
- ...firstChild,
- parentTitle: parent.title,
- filterConditionList: firstChild.filterConditionList || [],
- };
- break;
- } else {
- // 如果没有子节点,说明它本身就是叶子节点,直接选中
- defaultSelected = {
- ...parent,
- parentTitle: '单位分类',
- filterConditionList: parent.filterConditionList || [],
- };
- break;
- }
- }
- setSelectedDept(defaultSelected);
- }
- } else {
- message.error('获取单位分类树失败');
- }
- } catch (error) {
- console.error('接口调用异常:', error);
- message.error('获取单位分类树失败');
- }
- };
- useEffect(() => {
- fetchDeptClassList();
- }, []);
- // 监听selectedDept变化,加载人员数据
- useEffect(() => {
- if (selectedDept?.key) {
- if (activeTab === 'personnel') {
- tableRef.current?.reload();
- } else if (activeTab === 'checkPoints') {
- checkPointsTableRef.current?.reload();
- }
- }
- }, [selectedDept?.key, activeTab]);
- // 树形数据搜索过滤函数
- const filterTreeData = (data: any[], keywords: string) => {
- if (!keywords.trim()) {
- return data;
- }
- const filtered = data
- .map((parent) => {
- // 检查父节点是否匹配
- const parentMatches = parent.title
- .toLowerCase()
- .includes(keywords.toLowerCase());
- // 过滤子节点
- const filteredChildren = parent.children.filter((child: any) =>
- child.title.toLowerCase().includes(keywords.toLowerCase()),
- );
- // 如果父节点匹配或有匹配的子节点,则保留该父节点
- if (parentMatches || filteredChildren.length > 0) {
- return {
- ...parent,
- children: parentMatches ? parent.children : filteredChildren, // 如果父节点匹配,显示所有子节点;否则只显示匹配的子节点
- };
- }
- return null;
- })
- .filter(Boolean); // 移除 null 值
- return filtered;
- };
- // 处理树形搜索
- const handleTreeSearch = (value: string) => {
- setTreeSearchKeywords(value);
- const filtered = filterTreeData(treeData, value);
- setFilteredTreeData(filtered);
- // 如果有搜索关键词,自动展开所有匹配的父节点
- if (value.trim()) {
- const expandKeys = filtered.map((item: any) => item.key);
- setExpandedKeys(expandKeys);
- } else {
- // 如果清空搜索,恢复默认展开状态
- setExpandedKeys(treeData.map((item: any) => item.key));
- }
- };
- // 获取人员数据
- const getPersonnelData = async (params: any) => {
- try {
- // 如果没有选中的部门,返回空数据
- if (!selectedDept?.key) {
- return {
- data: [],
- success: true,
- total: 0,
- };
- }
- // 调用真实API获取人员列表(不传filter参数,获取全部数据)
- const res = await getDeptEmployee({
- deptId: Number(selectedDept.key), // 当前选中的查核单位ID
- filter: '', // 不传搜索关键词,获取全部数据
- deptType: selectedDept.deptType ?? 0, // 单位类型,使用空值合并操作符,默认为0
- });
- // 尝试多种数据结构格式
- let dataArray: any[] | null = null;
- if (res) {
- if (Array.isArray(res.data)) {
- dataArray = res.data; // { data: [...] }
- } else if (Array.isArray(res.items)) {
- dataArray = res.items; // { items: [...] }
- } else if (res.data && Array.isArray(res.data.items)) {
- dataArray = res.data.items; // { data: { items: [...] } }
- } else if (Array.isArray(res)) {
- dataArray = res; // 直接返回数组
- }
- }
- if (dataArray && dataArray.length >= 0) {
- // 保留接口字段,不做映射,仅把 id 转成字符串,避免 rowKey 警告
- let formattedData = dataArray.map((item: any) => ({
- ...item,
- id: String(item.id),
- }));
- // 前端本地搜索过滤
- if (searchKeywords && searchKeywords.trim()) {
- formattedData = formattedData.filter((item: any) =>
- (item.empCode && item.empCode.includes(searchKeywords)) ||
- (item.empName && item.empName.includes(searchKeywords))
- );
- }
- return {
- data: formattedData,
- success: true,
- total: formattedData.length,
- };
- }
- return {
- data: [],
- success: true,
- total: 0,
- };
- } catch (error) {
- console.error('获取人员列表失败:', error);
- message.error('获取人员列表失败');
- return {
- data: [],
- success: false,
- total: 0,
- };
- }
- };
- // 查核条件表格列定义
- const conditionColumns: ProColumns[] = [
- {
- title: '条件名称',
- dataIndex: 'name',
- width: 200,
- align: 'left' as 'left',
- },
- {
- title: '说明',
- dataIndex: 'description',
- align: 'left' as 'left',
- ellipsis: true,
- },
- ];
- // 人员表格列定义
- const [selectedPersonnelKeys, setSelectedPersonnelKeys] = useState<string[]>(
- [],
- );
- const personnelColumns: ProColumns[] = [
- {
- title: '工号',
- dataIndex: 'empCode',
- width: 120,
- align: 'center',
- },
- {
- title: '姓名',
- dataIndex: 'empName',
- width: 120,
- align: 'center',
- },
- {
- title: '负责人',
- dataIndex: 'isManager',
- width: 120,
- align: 'center',
- render: (_, record) => {
- return (
- <Radio
- checked={record.isManager}
- disabled={settingManagerId === record.id}
- onChange={() => handleSetManager(record)}
- />
- );
- },
- },
- {
- title: '操作',
- key: 'option',
- width: 100,
- align: 'center',
- render: (_, record) => {
- return (
- <Popconfirm
- title="确认删除?"
- okText="确定"
- cancelText="取消"
- onConfirm={() => handleDeletePersonnel(record)}
- >
- <a className="delete-btn">删除</a>
- </Popconfirm>
- );
- },
- },
- ];
- // 处理科室选择
- const handleSelectDept = (dept: string) => {
- setSelectedDept(dept);
- };
- // 处理部门展开/收起
- const toggleExpand = (dept: string) => {
- if (expandedKeys.includes(dept)) {
- setExpandedKeys(expandedKeys.filter((key) => key !== dept));
- } else {
- setExpandedKeys([...expandedKeys, dept]);
- }
- };
- // 人员选择相关状态
- const [employeeSearchKeyword, setEmployeeSearchKeyword] = useState('');
- const [selectedEmployees, setSelectedEmployees] = useState<string[]>([]);
- const [employeeModalVisible, setEmployeeModalVisible] = useState(false);
- const employeeTableRef = useRef<ActionType>();
- // 查核要点相关状态
- const [checkPointsSearchKeyword, setCheckPointsSearchKeyword] = useState('');
- const checkPointsTableRef = useRef<ActionType>();
- // 处理添加人员
- const handleAddPersonnel = () => {
- // 如果没有选择单位,提示先选择单位
- if (!selectedDept?.key) {
- message.warning('请先选择一个查核单位');
- return;
- }
- // 重置状态
- setEmployeeSearchKeyword('');
- setSelectedEmployees([]);
- // 打开选择人员弹窗
- setEmployeeModalVisible(true);
- // 延迟触发表格重新加载,确保弹窗打开后重新请求数据
- setTimeout(() => {
- employeeTableRef.current?.reload();
- }, 100);
- };
- // 获取选择人员列表的数据
- const getEmployeeSelectData = async (params: any) => {
- try {
- // 如果没有选中的部门,返回空数据
- if (!selectedDept?.key) {
- return {
- data: [],
- success: true,
- total: 0,
- };
- }
- // 调用真实API获取可选人员列表
- const res = await getDeptPendingEmployee({
- deptId: Number(selectedDept.key), // 当前选中的查核单位ID
- filter: employeeSearchKeyword || '', // 搜索关键词
- deptType: selectedDept.deptType ?? 0, // 单位类型,使用空值合并操作符,默认为0
- });
- if (res && res.data) {
- // 尝试多种数据结构格式
- let dataArray = null;
- if (Array.isArray(res.data)) {
- // 格式1: { data: [...] }
- dataArray = res.data;
- } else if (res.data.items && Array.isArray(res.data.items)) {
- // 格式2: { data: { items: [...] } }
- dataArray = res.data.items;
- } else if (res.data.list && Array.isArray(res.data.list)) {
- // 格式3: { data: { list: [...] } }
- dataArray = res.data.list;
- }
- if (dataArray && dataArray.length >= 0) {
- // 格式化返回的数据
- const formattedData = dataArray.map((item: any) => ({
- id: String(item.id || item.empId), // 人员ID
- empCode: item.code || item.empCode, // 人员工号
- empName: item.name || item.empName, // 人员姓名
- userId: item.userId, // 人员中台ID
- }));
- return {
- data: formattedData,
- success: true,
- total: formattedData.length,
- };
- }
- } else if (Array.isArray(res)) {
- // 格式4: 直接返回数组
- const formattedData = res.map((item: any) => ({
- id: String(item.id || item.empId), // 人员ID
- empCode: item.code || item.empCode, // 人员工号
- empName: item.name || item.empName, // 人员姓名
- userId: item.userId, // 人员中台ID
- }));
- return {
- data: formattedData,
- success: true,
- total: formattedData.length,
- };
- }
- return {
- data: [],
- success: true,
- total: 0,
- };
- } catch (error) {
- console.error('获取可选人员列表失败:', error);
- message.error('获取可选人员列表失败');
- return {
- data: [],
- success: false,
- total: 0,
- };
- }
- };
- // 处理员工选择
- const handleEmployeeSelect = (employeeId: string, checked: boolean) => {
- if (checked) {
- setSelectedEmployees([...selectedEmployees, employeeId]);
- } else {
- setSelectedEmployees(selectedEmployees.filter((id) => id !== employeeId));
- }
- };
- // 确认添加选择的人员
- const handleConfirmAddEmployees = async () => {
- if (selectedEmployees.length === 0) {
- message.warning('请至少选择一名人员');
- return;
- }
- try {
- // 调用真实API保存添加的人员
- const res = await addDeptEmployee({
- id: selectedDept.key, // 查核单位ID
- type: String(selectedDept.deptType ?? 0), // 单位类型:0普通单位1职能科室
- mapIdList: selectedEmployees, // 人员ID列表
- });
- if (res) {
- message.success(`已添加 ${selectedEmployees.length} 名人员`);
- setEmployeeModalVisible(false);
- // 重置选择状态
- setSelectedEmployees([]);
- // 刷新人员列表
- tableRef.current?.reload();
- } else {
- message.error('添加人员失败');
- }
- } catch (error) {
- console.error('添加人员失败:', error);
- message.error('添加人员失败');
- }
- };
- // 处理搜索
- const handleSearch = (value: string) => {
- setSearchKeywords(value);
- // 使用新接口时,不需要本地过滤,直接重新请求API
- tableRef.current?.reload();
- };
- // 处理标签页切换
- const handleTabChange = (key: string) => {
- setActiveTab(key);
- // 切换tab时清空相关选择状态
- if (key !== 'personnel') {
- setSelectedPersonnelKeys([]);
- }
- if (key !== 'checkPoints') {
- setSelectedCheckPointKeys([]);
- }
- };
- // 获取查核要点数据
- const getCheckPointsData = async (params: any) => {
- try {
- // 如果没有选中的部门,返回空数据
- if (!selectedDept?.key) {
- return {
- data: [],
- success: true,
- total: 0,
- };
- }
- // 模拟数据,后续替换为真实API调用
- const mockData = [
- {
- id: '1',
- pointName: '麻醉科管理规程',
- checkItemName: '审阅麻醉前评估记录内容完整、(10分)',
- rowSpan: 4, // 麻醉科管理规程有4行
- },
- {
- id: '2',
- pointName: '麻醉科管理规程',
- checkItemName: '审阅麻醉记录单内手术时间与用药记录(10分)',
- rowSpan: 0, // 合并到上一行
- },
- {
- id: '3',
- pointName: '麻醉科管理规程',
- checkItemName: '审阅麻醉前评估记录内容完整、(10分)',
- rowSpan: 0, // 合并到上一行
- },
- {
- id: '4',
- pointName: '麻醉科管理规程',
- checkItemName: '审阅麻醉记录单内手术时间与用药记录(10分)',
- rowSpan: 0, // 合并到上一行
- },
- {
- id: '5',
- pointName: '药品管理规程',
- checkItemName: '审阅麻醉前评估记录内容完整、(10分)',
- rowSpan: 2, // 药品管理规程有2行
- },
- {
- id: '6',
- pointName: '药品管理规程',
- checkItemName: '审阅麻醉记录单内手术时间与用药记录(10分)',
- rowSpan: 0, // 合并到上一行
- },
- {
- id: '7',
- pointName: '急救药品管理规程',
- checkItemName: '如果发现冰箱温度不正常,应该如何处理?(15分)',
- rowSpan: 1, // 急救药品管理规程有1行
- },
- ];
- // 根据搜索关键词过滤数据
- const filteredData = checkPointsSearchKeyword
- ? mockData.filter(
- (item) =>
- item.pointName.includes(checkPointsSearchKeyword) ||
- item.checkItemName.includes(checkPointsSearchKeyword),
- )
- : mockData;
- return {
- data: filteredData,
- success: true,
- total: filteredData.length,
- };
- } catch (error) {
- console.error('获取查核要点失败:', error);
- message.error('获取查核要点失败');
- return {
- data: [],
- success: false,
- total: 0,
- };
- }
- };
- // 处理查核要点搜索
- const handleSearchCheckPoints = (value: string) => {
- setCheckPointsSearchKeyword(value);
- checkPointsTableRef.current?.reload();
- };
- // 处理添加查核要点
- const handleAddCheckPoint = () => {
- if (!selectedDept?.key) {
- message.warning('请先选择一个查核单位');
- return;
- }
- // TODO: 实现添加查核要点的弹窗
- message.info('添加查核要点功能待实现');
- };
- // 处理删除查核要点
- const handleDeleteCheckPoint = async (record: any) => {
- try {
- await delDeptCheckpoint([record.id]);
- message.success('删除要点成功');
- checkPointsTableRef.current?.reload();
- } catch (e) {
- message.error('删除要点失败');
- }
- };
- // 获取查核条件列表 - 用于KCIMTable
- const getConditionData = async (params: any) => {
- try {
- const { current = 1, pageSize = 10 } = params;
- // 调用真实API获取条件列表(不传filter,获取所有数据)
- const requestParams = {
- deptClassId: currentNode?.key, // 当前选中的部门分类ID
- conditionType: conditionSearchType === '个案' ? 0 : 1, // 条件类型:0个案1系统
- filter: '', // 不传搜索关键词,获取所有数据
- };
-
- const res = await getDeptClassFilterConditionList(requestParams);
- if (res && res.itemList) {
- // 直接从res中获取数据
- const { itemList = [], mapIdList = [] } = res;
- // 更新已选择的条件ID列表 - 确保ID类型一致
- const selectedIds = (mapIdList || []).map((id: any) => String(id));
- setSelectedConditions(selectedIds);
- // 转换数据格式,保持树形结构
- const transformConditions = (conditions: any[]): any[] => {
- return conditions.map((item: any) => {
- const transformed: any = {
- id: String(item.id), // 确保ID为字符串类型
- name: item.name,
- description: item.description || '暂无说明',
- };
- // 如果有子条件,递归处理
- if (
- item.children &&
- Array.isArray(item.children) &&
- item.children.length > 0
- ) {
- transformed.children = transformConditions(item.children);
- }
- return transformed;
- });
- };
- // 保持树形结构的条件数据
- const allConditions = transformConditions(itemList);
- // 递归搜索树形数据
- const searchInTree = (data: any[], keyword: string): any[] => {
- if (!keyword.trim()) return data;
- const result: any[] = [];
- data.forEach((item) => {
- // 检查当前节点是否匹配
- const currentMatches =
- item.name.includes(keyword) || item.description.includes(keyword);
- // 递归搜索子节点
- let filteredChildren: any[] = [];
- if (item.children && Array.isArray(item.children)) {
- filteredChildren = searchInTree(item.children, keyword);
- }
- // 如果当前节点匹配或有匹配的子节点,则保留
- if (currentMatches || filteredChildren.length > 0) {
- const newItem = { ...item };
- if (filteredChildren.length > 0) {
- newItem.children = filteredChildren;
- } else if (!currentMatches) {
- // 如果当前节点不匹配但有匹配的子节点,保留原有children
- // 这种情况在上面的逻辑中已经处理了
- }
- result.push(newItem);
- }
- });
- return result;
- };
- // 根据搜索关键词过滤(本地搜索)
- const filteredData = searchInTree(
- allConditions,
- conditionSearchKeyword,
- );
- // 前端分页处理
- const startIndex = (current - 1) * pageSize;
- const endIndex = startIndex + pageSize;
- const pageData = filteredData.slice(startIndex, endIndex);
- return {
- data: pageData,
- success: true,
- total: filteredData.length,
- };
- } else {
- return {
- data: [],
- success: true,
- total: 0,
- };
- }
- } catch (error) {
- console.error('进入了catch块,获取条件列表失败:', error);
- message.error('获取条件列表失败');
- return {
- data: [],
- success: false,
- total: 0,
- };
- }
- };
- // 打开条件选择弹窗
- const handleOpenConditionModal = (node: any) => {
- setCurrentNode(node);
- setConditionModalVisible(true);
- setSelectedConditions([]); // 重置选择,实际选择状态会在API调用后更新
- setConditionSearchKeyword(''); // 重置搜索关键词
- setConditionSearchType('个案'); // 重置搜索类型
- // 延迟触发表格重新加载,确保弹窗打开后重新请求数据
- setTimeout(() => {
- conditionTableRef.current?.reload();
- }, 100);
- };
- // 处理条件选择
- const handleConditionSelect = (conditionId: string, checked: boolean) => {
- if (checked) {
- setSelectedConditions([...selectedConditions, conditionId]);
- } else {
- setSelectedConditions(
- selectedConditions.filter((id) => id !== conditionId),
- );
- }
- };
- // 处理级联选择(父子关联)
- const handleConditionSelectWithCascade = (record: any, selected: boolean) => {
- // 获取当前记录及其所有子记录的ID
- const getAllIds = (item: any): string[] => {
- const ids = [item.id];
- if (
- item.children &&
- Array.isArray(item.children) &&
- item.children.length > 0
- ) {
- item.children.forEach((child: any) => {
- ids.push(...getAllIds(child));
- });
- }
- return ids;
- };
- const allIds = getAllIds(record);
- if (selected) {
- // 选中:添加当前记录及其所有子记录
- const newSelectedIds = [...new Set([...selectedConditions, ...allIds])];
- setSelectedConditions(newSelectedIds);
- } else {
- // 取消选中:移除当前记录及其所有子记录
- const newSelectedIds = selectedConditions.filter(
- (id) => !allIds.includes(id),
- );
- setSelectedConditions(newSelectedIds);
- }
- };
- // 确认选择条件
- const handleConfirmConditions = async () => {
- try {
- // 调用保存接口
- const res = await applyDeptClassFilterCondition({
- id: currentNode?.key, // 单位分类ID
- mapIdList: selectedConditions, // 查核条件ID列表
- });
- if (res) {
- message.success(
- `已为 ${currentNode?.title} 保存了 ${selectedConditions.length} 个查核条件`,
- );
- setConditionModalVisible(false);
- // 重新获取列表,更新条件信息
- await fetchDeptClassList();
- // 查询选中的条件名称
- if (res.items && Array.isArray(res.items)) {
- // 如果API返回了条件列表,可以直接从返回值获取条件名称
- const conditionNames = res.items
- .map((item: any) => item.name)
- .join('、');
- // 更新treeData中对应节点的conditions属性
- const updatedTreeData = treeData.map((item: any) => {
- if (item.key === currentNode?.key) {
- return {
- ...item,
- conditions: conditionNames || '手术室、重症加护病房、医学影像',
- };
- }
- return item;
- });
- setTreeData(updatedTreeData);
- setFilteredTreeData(updatedTreeData);
- }
- } else {
- message.error('保存查核条件失败');
- }
- } catch (error) {
- console.error('保存查核条件失败:', error);
- message.error('保存查核条件失败');
- }
- };
- // 处理删除节点
- const handleDeleteNode = (node: any, isParent: boolean) => {
- Modal.confirm({
- title: '确认删除',
- content: `确定要删除${isParent ? '单位分类' : '查核单位'} "${node.title
- }" 吗?`,
- okText: '确定',
- cancelText: '取消',
- onOk: async () => {
- try {
- if (isParent) {
- // 删除单位分类
- const res = await delDeptClass([Number(node.key)]);
- if (res) {
- message.success('删除单位分类成功');
- // 重新获取列表数据
- await fetchDeptClassList();
- } else {
- message.error('删除单位分类失败');
- }
- } else {
- // 删除查核单位
- const res = await delDepartmentByClass({
- deptId: Number(node.key), // 查核单位ID
- deptType: node.deptType ?? 0, // 单位类型:0普通单位 1职能科室
- });
- if (res) {
- message.success('删除查核单位成功');
- // 重新获取列表数据
- await fetchDeptClassList();
- } else {
- message.error('删除查核单位失败');
- }
- }
- } catch (error) {
- message.error('删除失败');
- }
- },
- });
- };
- // 自定义空状态
- const customizeRenderEmpty = () => (
- <div style={{ textAlign: 'center', padding: '50px 0' }}>
- <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无数据" />
- </div>
- );
- // 生成更多按钮的菜单
- const getMoreMenu = (
- node: any,
- isParent: boolean = false,
- parentNode?: any,
- ) => {
- const menuItems = [];
- if (isParent) {
- // 父级节点菜单:新增单位、条件、修改、删除
- menuItems.push(
- <Menu.Item key="addUnit" style={{ padding: 0 }}>
- <ModalForm
- title="新增查核单位"
- trigger={<div style={{ padding: '5px 12px' }}>新增单位</div>}
- width={352}
- onFinish={async (values) => {
- try {
- const { name, sort, deptType } = values;
- const res = await addDepartmentByClass({
- deptClassId: node.key, // 使用当前选中的单位分类ID
- name,
- sort,
- deptType, // 使用表单中用户选择的职能科室值
- });
- if (res) {
- message.success('新增单位成功');
- // 重新获取列表数据
- await fetchDeptClassList();
- return true;
- } else {
- message.error('新增单位失败');
- return false;
- }
- } catch (error) {
- message.error('新增单位失败');
- return false;
- }
- }}
- modalProps={{
- destroyOnClose: true,
- }}
- >
- <ProFormText
- name="name"
- label="单位名称"
- placeholder="请输入"
- rules={[{ required: true, message: '请输入单位名称' }]}
- />
- <ProFormDigit
- name="sort"
- label="序号"
- placeholder="请输入"
- initialValue={0}
- min={0}
- rules={[{ required: true, message: '请输入序号' }]}
- />
- <ProFormRadio.Group
- name="deptType"
- label="职能科室"
- initialValue={0}
- rules={[{ required: true, message: '请选择是否为职能科室' }]}
- options={[
- { label: '否', value: 0 },
- { label: '是', value: 1 },
- ]}
- />
- </ModalForm>
- </Menu.Item>,
- <Menu.Item
- key="condition"
- onClick={() => handleOpenConditionModal(node)}
- >
- 条件
- </Menu.Item>,
- );
- }
- // 公共菜单项:修改、删除
- menuItems.push(
- <Menu.Item key="edit" style={{ padding: 0 }}>
- <ModalForm
- title={isParent ? '修改单位分类' : '修改查核单位'}
- trigger={<div style={{ padding: '5px 12px' }}>修改</div>}
- width={352}
- initialValues={{
- name: node.title,
- depType: node.visitType || 1,
- sort: node.sort || 0,
- deptType: node.deptType ?? 0, // 单位类型:0普通单位 1职能科室
- }}
- onFinish={async (values) => {
- try {
- if (isParent) {
- // 修改单位分类
- const { name, depType } = values;
- const res = await updateDeptClass({
- id: Number(node.key), // 单位分类ID
- name,
- depType, // 门急诊类型:1-门诊 2-急诊
- });
- if (res) {
- message.success('修改单位分类成功');
- } else {
- message.error('修改单位分类失败');
- return false;
- }
- } else {
- // 修改查核单位
- const { name, sort, deptType } = values;
- const res = await updateDepartmentByClass({
- deptClassId: Number(parentNode?.key), // 单位分类ID
- id: Number(node.key), // 查核单位ID
- name,
- sort,
- deptType, // 使用表单中用户选择的职能科室值
- });
- if (res) {
- message.success('修改查核单位成功');
- } else {
- message.error('修改查核单位失败');
- return false;
- }
- }
- // 重新获取列表数据
- await fetchDeptClassList();
- return true;
- } catch (error) {
- message.error('修改失败');
- return false;
- }
- }}
- modalProps={{
- destroyOnClose: true,
- }}
- >
- <ProFormText
- name="name"
- label={isParent ? '单位分类名称' : '单位名称'}
- placeholder="请输入"
- rules={[
- {
- required: true,
- message: `请输入${isParent ? '单位分类名称' : '单位名称'}`,
- },
- ]}
- />
- {isParent ? (
- <ProFormRadio.Group
- name="depType"
- label="诊别"
- rules={[{ required: true, message: '请选择诊别' }]}
- options={[
- { label: '门诊', value: 1 },
- { label: '急诊', value: 2 },
- ]}
- />
- ) : (
- <>
- <ProFormDigit
- name="sort"
- label="序号"
- placeholder="请输入"
- min={0}
- rules={[{ required: true, message: '请输入序号' }]}
- />
- <ProFormRadio.Group
- name="deptType"
- label="职能科室"
- disabled={true} // 编辑时不可修改
- rules={[{ required: true, message: '请选择是否为职能科室' }]}
- options={[
- { label: '否', value: 0 },
- { label: '是', value: 1 },
- ]}
- />
- </>
- )}
- </ModalForm>
- </Menu.Item>,
- <Menu.Item key="delete" onClick={() => handleDeleteNode(node, isParent)}>
- 删除
- </Menu.Item>,
- );
- return <Menu>{menuItems}</Menu>;
- };
- // 新增按钮的菜单
- const menu = (
- <Menu>
- <Menu.Item key="1" style={{ padding: 0 }}>
- <ModalForm
- title="新增单位分类"
- trigger={<div style={{ padding: '5px 12px' }}>新增单位分类</div>}
- width={352}
- onFinish={async (values) => {
- try {
- const { name, depType } = values;
- const res = await addDeptClass({ name, depType });
- if (res) {
- message.success('新增单位分类成功');
- // 重新获取列表数据
- await fetchDeptClassList();
- return true;
- } else {
- message.error('新增失败');
- return false;
- }
- } catch (error) {
- message.error('新增失败');
- return false;
- }
- }}
- modalProps={{
- destroyOnClose: true,
- }}
- >
- <ProFormText
- name="name"
- label="单位分类名称"
- placeholder="请输入"
- rules={[{ required: true, message: '请输入单位分类名称' }]}
- />
- <ProFormRadio.Group
- name="depType"
- label="诊别"
- initialValue={1}
- rules={[{ required: true, message: '请选择诊别' }]}
- options={[
- { label: '门诊', value: 1 },
- { label: '急诊', value: 2 },
- ]}
- />
- </ModalForm>
- </Menu.Item>
- <Menu.Item key="2" style={{ padding: 0 }}>
- <ModalForm
- title="导入系统追踪知识库"
- trigger={<div style={{ padding: '5px 12px' }}>导入系统追踪</div>}
- width={600}
- onFinish={async (values) => {
- try {
- let token = '';
- const userDataStr = localStorage.getItem('userData');
- if (userDataStr) {
- try {
- token = JSON.parse(userDataStr).token || '';
- } catch (e) {
- token = '';
- }
- }
- const formData = new FormData();
- formData.append('type', '1');
- if (values.systemTrackingFile && values.systemTrackingFile[0]?.originFileObj) {
- formData.append('file', values.systemTrackingFile[0].originFileObj);
- } else {
- message.error('请上传文件');
- return false;
- }
- const res = await fetch('/gateway/manager/Department/importPfmKnowledge', {
- method: 'POST',
- headers: {
- token: token,
- },
- body: formData,
- });
- let result = null;
- try {
- result = await res.json();
- } catch (e) {
- message.error('导入失败');
- return false;
- }
- if (result && result.status === 200) {
- message.success('导入成功');
- // 重新获取列表数据,刷新左侧树形结构
- await fetchDeptClassList();
- return true;
- } else {
- message.error(result.errorMessage || '导入失败');
- return false;
- }
- } catch (error) {
- message.error('导入失败');
- return false;
- }
- }}
- modalProps={{
- destroyOnClose: true,
- }}
- >
- <div
- style={{
- display: 'flex',
- justifyContent: 'space-between',
- alignItems: 'center',
- marginBottom: 16,
- }}
- >
- <span style={{ fontSize: 16, fontWeight: 500 }}>文件上传</span>
- <Button type="link" style={{ padding: 0 }} onClick={() => downloadTemplate(1)}>
- 模板下载
- </Button>
- </div>
- <ProFormUploadDragger
- name="systemTrackingFile"
- icon={<InboxOutlined />}
- title="点击或将文件拖拽到这里上传"
- description="支持扩展名:.rar .zip .doc .docx .pdf .jpg..."
- fieldProps={{
- name: 'file',
- multiple: false,
- accept: '.rar,.zip,.doc,.docx,.pdf,.jpg,.jpeg,.png,.xls,.xlsx',
- beforeUpload: () => false, // 阻止自动上传
- }}
- rules={[{ required: true, message: '请上传文件' }]}
- />
- </ModalForm>
- </Menu.Item>
- {/* <Menu.Item key="3" style={{ padding: 0 }}>
- <ModalForm
- title="导入自查督查知识库"
- trigger={<div style={{ padding: '5px 12px' }}>导入自查督查</div>}
- width={600}
- onFinish={async (values) => {
- try {
- let token = '';
- const userDataStr = localStorage.getItem('userData');
- if (userDataStr) {
- try {
- token = JSON.parse(userDataStr).token || '';
- } catch (e) {
- token = '';
- }
- }
- const formData = new FormData();
- formData.append('type', '2');
- if (values.selfInspectionFile && values.selfInspectionFile[0]?.originFileObj) {
- formData.append('file', values.selfInspectionFile[0].originFileObj);
- } else {
- message.error('请上传文件');
- return false;
- }
- const res = await fetch('/manager/Department/importPfmKnowledge', {
- method: 'POST',
- headers: {
- token: token,
- },
- body: formData,
- });
- let result = null;
- try {
- result = await res.json();
- } catch (e) {
- message.error('导入失败');
- return false;
- }
- if (result && result.status === 200) {
- message.success('导入成功');
- return true;
- } else {
- message.error(result.errorMessage || '导入失败');
- return false;
- }
- } catch (error) {
- message.error('导入失败');
- return false;
- }
- }}
- modalProps={{
- destroyOnClose: true,
- }}
- >
- <div
- style={{
- display: 'flex',
- justifyContent: 'space-between',
- alignItems: 'center',
- marginBottom: 16,
- }}
- >
- <span style={{ fontSize: 16, fontWeight: 500 }}>文件上传</span>
- <Button type="link" style={{ padding: 0 }} onClick={() => downloadTemplate(2)}>
- 模板下载
- </Button>
- </div>
- <ProFormUploadDragger
- name="selfInspectionFile"
- icon={<InboxOutlined />}
- title="点击或将文件拖拽到这里上传"
- description="支持扩展名:.rar .zip .doc .docx .pdf .jpg..."
- fieldProps={{
- name: 'file',
- multiple: false,
- accept: '.rar,.zip,.doc,.docx,.pdf,.jpg,.jpeg,.png,.xls,.xlsx',
- beforeUpload: () => false, // 阻止自动上传
- }}
- rules={[{ required: true, message: '请上传文件' }]}
- />
- </ModalForm>
- </Menu.Item> */}
- </Menu>
- );
- // 渲染左侧部门树
- const renderDeptTree = () => {
- return (
- <div className="dept-tree">
- <div className="search-wrapper">
- <Input
- placeholder="单位分类、名称"
- suffix={<SearchOutlined style={{ color: '#99A6BF' }} />}
- className="search-input"
- value={treeSearchKeywords}
- onChange={(e) => handleTreeSearch(e.target.value)}
- allowClear
- />
- <Dropdown
- overlay={menu}
- trigger={['hover']}
- overlayClassName="check-unit-add-dropdown"
- >
- <Button icon={<PlusOutlined />} className="add-button" />
- </Dropdown>
- </div>
- <div className="dept-list">
- {filteredTreeData.map((parent) => {
- // 判断是否有子项
- const hasChildren = parent.children && parent.children.length > 0;
- return (
- <div key={parent.key} className="dept-group">
- {hasChildren ? (
- <div
- className="dept-parent"
- onClick={() => toggleExpand(parent.key)}
- onMouseEnter={() => setHoveredNode(parent.key)}
- onMouseLeave={() => setHoveredNode(null)}
- >
- <Button
- type="text"
- icon={
- expandedKeys.includes(parent.key) ? (
- <IconFont type="icon-shouqi1" />
- ) : (
- <IconFont type="icon-zhankai1" />
- )
- }
- className="toggle-button"
- />
- <Tooltip title={parent.title}>
- <span className="dept-title">{parent.title}</span>
- </Tooltip>
- {(selectedDept?.key === parent.key ||
- hoveredNode === parent.key ||
- openDropdownNode === parent.key) && (
- <Dropdown
- overlay={getMoreMenu(parent, true)}
- trigger={['click']}
- placement="bottomRight"
- overlayClassName="check-unit-add-dropdown"
- onVisibleChange={(visible) => {
- if (visible) {
- setOpenDropdownNode(parent.key);
- } else {
- setOpenDropdownNode(null);
- }
- }}
- >
- <Button
- type="text"
- icon={<MoreOutlined />}
- className="more-button"
- onClick={(e) => e.stopPropagation()}
- />
- </Dropdown>
- )}
- </div>
- ) : (
- <div
- className={`dept-leaf ${selectedDept?.key === parent.key ? 'selected' : ''
- }`}
- onClick={() => {
- // 设置分类自身的信息
- setSelectedDept({
- ...parent,
- parentTitle: '单位分类',
- // 保留原始的filterConditionList数据
- filterConditionList: parent.filterConditionList || [],
- });
- // 不需要手动重新加载,useEffect会监听selectedDept变化
- }}
- onMouseEnter={() => setHoveredNode(parent.key)}
- onMouseLeave={() => setHoveredNode(null)}
- >
- <Tooltip title={parent.title}>
- <span className="dept-title">{parent.title}</span>
- </Tooltip>
- {(selectedDept?.key === parent.key ||
- hoveredNode === parent.key ||
- openDropdownNode === parent.key) && (
- <Dropdown
- overlay={getMoreMenu(parent, true)}
- trigger={['click']}
- placement="bottomRight"
- overlayClassName="check-unit-add-dropdown"
- onVisibleChange={(visible) => {
- if (visible) {
- setOpenDropdownNode(parent.key);
- } else {
- setOpenDropdownNode(null);
- }
- }}
- >
- <Button
- type="text"
- icon={<MoreOutlined />}
- className="more-button"
- onClick={(e) => e.stopPropagation()}
- />
- </Dropdown>
- )}
- </div>
- )}
- {hasChildren && expandedKeys.includes(parent.key) && (
- <div className="dept-children">
- {parent.children.map((child: any) => (
- <div
- key={child.key}
- className={`dept-item ${selectedDept?.key === child.key ? 'selected' : ''
- }`}
- onClick={() => {
- // 添加父节点信息,保留原始查核条件数据
- setSelectedDept({
- ...child,
- parentTitle: parent.title,
- // 保留原始的filterConditionList数据
- filterConditionList:
- child.filterConditionList || [],
- });
- // 不需要手动重新加载,useEffect会监听selectedDept变化
- }}
- onMouseEnter={() => setHoveredNode(child.key)}
- onMouseLeave={() => setHoveredNode(null)}
- >
- <Tooltip title={child.title}>
- <span className="dept-title-text">
- {child.title}
- {child.deptType === 1 && (
- <span
- style={{
- marginLeft: 4,
- fontSize: 12,
- padding: '0 4px',
- background: '#f0f0f0',
- color: '#666',
- borderRadius: 2,
- display: 'inline-block',
- lineHeight: '18px',
- verticalAlign: 'text-top',
- }}
- >
- 职
- </span>
- )}
- </span>
- </Tooltip>
- {(selectedDept?.key === child.key ||
- hoveredNode === child.key ||
- openDropdownNode === child.key) && (
- <Dropdown
- overlay={getMoreMenu(child, false, parent)}
- trigger={['click']}
- placement="bottomRight"
- overlayClassName="check-unit-add-dropdown"
- onVisibleChange={(visible) => {
- if (visible) {
- setOpenDropdownNode(child.key);
- } else {
- setOpenDropdownNode(null);
- }
- }}
- >
- <Button
- type="text"
- icon={<MoreOutlined />}
- className="more-button"
- onClick={(e) => e.stopPropagation()}
- />
- </Dropdown>
- )}
- </div>
- ))}
- </div>
- )}
- </div>
- );
- })}
- </div>
- </div>
- );
- };
- // 处理设置负责人
- const [settingManagerId, setSettingManagerId] = useState<string>('');
- const handleSetManager = async (record: any) => {
- if (record.isManager) return; // 已是负责人
- setSettingManagerId(record.id);
- try {
- await setDeptManager({
- empId: Number(record.empId || record.id),
- empName: record.empName,
- deptId: Number(selectedDept.key),
- deptType: selectedDept.deptType ?? 0, // 使用空值合并操作符,默认为0
- });
- message.success(`已设置 ${record.empName} 为负责人`);
- tableRef.current?.reload();
- } catch (e) {
- message.error('设置负责人失败');
- } finally {
- setSettingManagerId('');
- }
- };
- const handleDeletePersonnel = async (record: any) => {
- try {
- await delDeptEmp([
- { id: String(record.id), type: String(selectedDept.deptType ?? 0) },
- ]);
- message.success('删除成功');
- tableRef.current?.reload();
- } catch (e) {
- message.error('删除失败');
- }
- };
- // Tab下table专用数据获取方法
- const getDeptCheckpointData = async (params: any) => {
- try {
- if (!selectedDept?.key) {
- return { data: [], success: true, total: 0 };
- }
- // 不传搜索关键词,获取全部数据
- const res = await getDeptCheckpoint({
- deptId: selectedDept.key,
- filter: '', // 获取全部数据
- deptType: selectedDept.deptType ?? 0,
- });
- // 这里根据接口返回结构处理数据
- if (Array.isArray(res)) {
- const flatData: any[] = [];
- res.forEach((point: any) => {
- if (
- Array.isArray(point.checkItemList) &&
- point.checkItemList.length > 0
- ) {
- point.checkItemList.forEach((item: any, idx: number) => {
- flatData.push({
- id: idx === 0 ? String(point.id) : `${point.id}_item_${idx}`,
- checkPointName: point.checkPointName, // 直接用接口字段
- checkItemName: item.name,
- rowSpan: idx === 0 ? point.checkItemList.length : 0,
- isFirst: idx === 0,
- });
- });
- } else {
- flatData.push({
- id: String(point.id),
- checkPointName: point.checkPointName, // 直接用接口字段
- checkItemName: '-',
- rowSpan: 1,
- isFirst: true,
- });
- }
- });
- // 前端本地搜索过滤
- let filteredData = flatData;
- if (checkPointsSearchKeyword && checkPointsSearchKeyword.trim()) {
- filteredData = flatData.filter((item: any) =>
- (item.checkPointName && item.checkPointName.includes(checkPointsSearchKeyword)) ||
- (item.checkItemName && item.checkItemName.includes(checkPointsSearchKeyword))
- );
- }
- // 更新当前页数据用于全选逻辑
- setCurrentCheckPointPageData(filteredData);
- return {
- data: filteredData,
- success: true,
- total: filteredData.length,
- };
- }
- return { data: [], success: true, total: 0 };
- } catch (e) {
- return { data: [], success: false, total: 0 };
- }
- };
- // Tab页columns
- const checkPointTabColumns = [
- {
- title: (
- <Checkbox
- indeterminate={
- getCurrentPageCheckPointIds().length > 0 &&
- selectedCheckPointKeys.length > 0 &&
- selectedCheckPointKeys.length < getCurrentPageCheckPointIds().length
- }
- checked={
- getCurrentPageCheckPointIds().length > 0 &&
- selectedCheckPointKeys.length === getCurrentPageCheckPointIds().length
- }
- onChange={(e) => {
- const ids = getCurrentPageCheckPointIds();
- if (e.target.checked) {
- setSelectedCheckPointKeys(Array.from(new Set([...selectedCheckPointKeys, ...ids])));
- } else {
- setSelectedCheckPointKeys(selectedCheckPointKeys.filter((id) => !ids.includes(id)));
- }
- }}
- >
- 要点名称
- </Checkbox>
- ),
- dataIndex: 'checkPointName',
- width: 200,
- align: 'left' as 'left',
- render: (dom: React.ReactNode, record: any) => {
- if (record.rowSpan > 0) {
- return {
- children: (
- <div style={{ display: 'flex', alignItems: 'center' }}>
- <Checkbox
- checked={selectedCheckPointKeys.includes(record.id)}
- onChange={() => {
- if (selectedCheckPointKeys.includes(record.id)) {
- setSelectedCheckPointKeys(
- selectedCheckPointKeys.filter((k) => k !== record.id),
- );
- } else {
- setSelectedCheckPointKeys([
- ...selectedCheckPointKeys,
- record.id,
- ]);
- }
- }}
- />
- <span style={{ marginLeft: 8 }}>{dom}</span>
- </div>
- ),
- props: { rowSpan: record.rowSpan },
- };
- }
- return { children: null, props: { rowSpan: 0 } };
- },
- },
- {
- title: '查核项名称',
- dataIndex: 'checkItemName',
- align: 'left' as 'left',
- },
- {
- title: '操作',
- dataIndex: 'option',
- width: 80,
- align: 'center' as 'center',
- render: (_: any, record: any) => {
- if (record.rowSpan > 0) {
- return {
- children: (
- <Popconfirm
- title="确认删除该要点及其所有查核项?"
- okText="确定"
- cancelText="取消"
- onConfirm={() => handleDeleteCheckPoint(record)}
- >
- <a style={{ color: '#3377ff' }}>删除</a>
- </Popconfirm>
- ),
- props: { rowSpan: record.rowSpan },
- };
- }
- return { children: null, props: { rowSpan: 0 } };
- },
- },
- ];
- // 4. 打开弹窗方法
- const handleOpenCheckPointModal = () => {
- setCheckPointModalVisible(true);
- setSelectedCheckPointKeys([]);
- setTimeout(() => {
- checkPointTableRef?.reload?.();
- }, 100);
- };
- // 选择查核要点弹窗表格数据获取方法
- const getDeptPendingCheckpointData = async (params: any) => {
- try {
- if (!selectedDept?.key) {
- return { data: [], success: true, total: 0 };
- }
- const res = await getDeptPendingCheckpoint({
- deptId: selectedDept.key,
- filter: '',
- deptType: selectedDept.deptType ?? 0,
- });
- if (Array.isArray(res)) {
- const flatData: any[] = [];
- res.forEach((point: any) => {
- if (
- Array.isArray(point.checkItemList) &&
- point.checkItemList.length > 0
- ) {
- point.checkItemList.forEach((item: any, idx: number) => {
- flatData.push({
- id: idx === 0 ? String(point.id) : `${point.id}_item_${idx}`,
- name: point.name,
- checkItemName: item.name,
- rowSpan: idx === 0 ? point.checkItemList.length : 0,
- isFirst: idx === 0,
- });
- });
- } else {
- flatData.push({
- id: String(point.id),
- name: point.name,
- checkItemName: '-',
- rowSpan: 1,
- isFirst: true,
- });
- }
- });
- return {
- data: flatData,
- success: true,
- total: flatData.length,
- };
- }
- return { data: [], success: true, total: 0 };
- } catch (e) {
- return { data: [], success: false, total: 0 };
- }
- };
- // 选择查核要点弹窗"确定"按钮逻辑
- const handleConfirmAddCheckPoints = async () => {
- if (!selectedDept?.key) {
- message.warning('请先选择查核单位');
- return;
- }
- if (selectedCheckPointKeys.length === 0) {
- message.warning('请至少选择一个查核要点');
- return;
- }
- try {
- await addDeptCheckpoint({
- id: String(selectedDept.key),
- type: String(selectedDept.deptType ?? 0),
- mapIdList: selectedCheckPointKeys,
- });
- message.success('添加查核要点成功');
- setCheckPointModalVisible(false);
- // 可选:刷新Tab下表格
- checkPointsTableRef.current?.reload();
- } catch (e) {
- message.error('添加查核要点失败');
- }
- };
- // 弹窗columns
- const checkPointModalColumns = [
- {
- title: '要点名称',
- dataIndex: 'name',
- width: 200,
- align: 'left' as 'left',
- render: (dom: React.ReactNode, record: any) => {
- if (record.rowSpan > 0) {
- return {
- children: (
- <div style={{ display: 'flex', alignItems: 'center' }}>
- <Checkbox
- checked={selectedCheckPointKeys.includes(record.id)}
- onChange={() => {
- if (selectedCheckPointKeys.includes(record.id)) {
- setSelectedCheckPointKeys(
- selectedCheckPointKeys.filter((k) => k !== record.id),
- );
- } else {
- setSelectedCheckPointKeys([
- ...selectedCheckPointKeys,
- record.id,
- ]);
- }
- }}
- />
- <span style={{ marginLeft: 8 }}>{dom}</span>
- </div>
- ),
- props: { rowSpan: record.rowSpan },
- };
- }
- return { children: null, props: { rowSpan: 0 } };
- },
- },
- {
- title: '查核项名称',
- dataIndex: 'checkItemName',
- align: 'left' as 'left',
- },
- ];
- return (
- <KCIMPagecontainer className="check-unit-mana" title={false} style={{ position: 'relative' }}>
- <div className="check-unit-container" style={{ position: 'relative' }}>
- {/* 左侧科室树 */}
- {renderDeptTree()}
- {/* 右侧内容区 */}
- <div className="dept-content" style={{ position: 'relative', paddingBottom: (activeTab === 'personnel' && selectedPersonnelKeys.length > 0) || (activeTab === 'checkPoints' && selectedCheckPointKeys.length > 0) ? 68 : 0 }}>
- <Card bordered={false} ref={cardRef}>
- <div className="dept-header content-padding">
- {selectedDept && (
- <>
- <span className="dept-title">{selectedDept.title}</span>
- <span className="dept-info">
- 单位分类:{selectedDept.parentTitle || '暂无'}
- 分类查核条件:
- {selectedDept.filterConditionList
- ? selectedDept.filterConditionList
- .map((item: any) => item.name)
- .join('、')
- : '手术室、重症加护病房、医学影像'}
- </span>
- </>
- )}
- </div>
- <Tabs activeKey={activeTab} onChange={handleTabChange}>
- <TabPane tab="单位人员" key="personnel">
- <div className="tab-content">
- <div className="toolbar">
- <Input
- placeholder="工号、姓名"
- allowClear
- value={personnelSearchInput}
- suffix={
- <SearchOutlined
- onClick={() => handleSearch(personnelSearchInput)}
- style={{ cursor: 'pointer', color: '#99A6BF' }}
- />
- }
- style={{ width: 250 }}
- onChange={(e) => {
- setPersonnelSearchInput(e.target.value);
- if (e.target.value === '') {
- setSearchKeywords('');
- tableRef.current?.reload();
- }
- }}
- onPressEnter={(e) => handleSearch(e.currentTarget.value)}
- />
- <Button
- type="primary"
- onClick={handleAddPersonnel}
- className="add-btn"
- size="small"
- >
- 添加
- </Button>
- </div>
- <KCIMTable
- actionRef={tableRef}
- columns={personnelColumns}
- request={getPersonnelData}
- rowKey="id"
- search={false}
- rowSelection={{
- selectedRowKeys: selectedPersonnelKeys,
- onChange: (keys) => setSelectedPersonnelKeys(keys as string[]),
- }}
- locale={{ emptyText: customizeRenderEmpty() }}
- pagination={false}
- tableAlertRender={false}
- />
- </div>
- </TabPane>
- <TabPane tab="单位查核要点" key="checkPoints">
- <div className="tab-content">
- <div className="toolbar" style={{ display: 'flex', alignItems: 'center' }}>
- <Input
- placeholder="要点名称"
- allowClear
- suffix={
- <SearchOutlined
- onClick={() => handleSearchCheckPoints(checkPointsSearchKeyword)}
- style={{ cursor: 'pointer', color: '#99A6BF' }}
- />
- }
- style={{ width: 250 }}
- value={checkPointsSearchKeyword}
- onChange={(e) => {
- setCheckPointsSearchKeyword(e.target.value);
- if (e.target.value === '') {
- // 清空搜索时自动刷新
- checkPointsTableRef.current?.reload();
- }
- }}
- onPressEnter={(e) =>
- handleSearchCheckPoints(e.currentTarget.value)
- }
- />
- <Button
- type="primary"
- onClick={handleOpenCheckPointModal}
- className="add-btn"
- size="small"
- style={{ marginLeft: 8 }}
- >
- 添加
- </Button>
- </div>
- <KCIMTable
- actionRef={checkPointsTableRef}
- columns={checkPointTabColumns}
- request={getDeptCheckpointData}
- rowKey="id"
- bordered
- search={false}
- pagination={false}
- tableAlertRender={false}
- scroll={{ y: 360 }}
- />
- </div>
- </TabPane>
- </Tabs>
- </Card>
- </div>
- </div>
- {/* 批量操作栏 - 固定在页面底部,参考empMana样式 */}
- {activeTab === 'personnel' && selectedPersonnelKeys.length > 0 && (
- <div
- style={{
- position: 'absolute',
- bottom: 0,
- left: 0,
- right: 0,
- height: 48,
- background: '#FFFFFF',
- boxShadow: '0px -8px 16px 0px rgba(64,85,128,0.1)',
- display: 'flex',
- justifyContent: 'space-between',
- alignItems: 'center',
- padding: '0 16px',
- zIndex: 1000,
- }}
- >
- <span style={{
- color: '#333333',
- fontSize: 14,
- fontFamily: 'SourceHanSansCN-Normal, SourceHanSansCN',
- fontWeight: 400,
- }}>
- 已选择 <span style={{ color: '#3377ff' }}>{selectedPersonnelKeys.length}</span> 项,将进行批量删除
- </span>
- <div style={{ display: 'flex', gap: 12 }}>
- <div
- onClick={() => {
- setSelectedPersonnelKeys([]);
- }}
- style={{
- cursor: 'pointer',
- display: 'inline-block',
- fontSize: 14,
- fontFamily: 'SourceHanSansCN-Normal, SourceHanSansCN',
- fontWeight: 400,
- color: '#666666',
- lineHeight: '24px',
- padding: '0 14px',
- background: '#ffffff',
- border: '1px solid #dae2f2',
- borderRadius: 4,
- }}
- >
- 取消选择
- </div>
- <Popconfirm
- title="确认批量删除所选人员?"
- okText="确定"
- cancelText="取消"
- onConfirm={async () => {
- try {
- await delDeptEmp(
- selectedPersonnelKeys.map((id) => ({
- id: String(id),
- type: String(selectedDept.deptType ?? 0),
- })),
- );
- message.success('批量删除成功');
- setSelectedPersonnelKeys([]);
- tableRef.current?.reload();
- } catch (e) {
- message.error('批量删除失败');
- }
- }}
- >
- <div
- style={{
- cursor: 'pointer',
- display: 'inline-block',
- fontSize: 14,
- fontFamily: 'SourceHanSansCN-Normal, SourceHanSansCN',
- fontWeight: 400,
- color: '#ffffff',
- lineHeight: '24px',
- padding: '0 14px',
- background: '#3377ff',
- borderRadius: 4,
- }}
- >
- 批量删除
- </div>
- </Popconfirm>
- </div>
- </div>
- )}
- {activeTab === 'checkPoints' && !checkPointModalVisible && selectedCheckPointKeys.length > 0 && (
- <div
- style={{
- position: 'absolute',
- bottom: 0,
- left: 0,
- right: 0,
- height: 48,
- background: '#FFFFFF',
- boxShadow: '0px -8px 16px 0px rgba(64,85,128,0.1)',
- display: 'flex',
- justifyContent: 'space-between',
- alignItems: 'center',
- padding: '0 16px',
- zIndex: 1000,
- }}
- >
- <span style={{
- color: '#333333',
- fontSize: 14,
- fontFamily: 'SourceHanSansCN-Normal, SourceHanSansCN',
- fontWeight: 400,
- }}>
- 已选择 <span style={{ color: '#3377ff' }}>{selectedCheckPointKeys.length}</span> 项,将进行批量删除
- </span>
- <div style={{ display: 'flex', gap: 12 }}>
- <div
- onClick={() => {
- setSelectedCheckPointKeys([]);
- }}
- style={{
- cursor: 'pointer',
- display: 'inline-block',
- fontSize: 14,
- fontFamily: 'SourceHanSansCN-Normal, SourceHanSansCN',
- fontWeight: 400,
- color: '#666666',
- lineHeight: '24px',
- padding: '0 14px',
- background: '#ffffff',
- border: '1px solid #dae2f2',
- borderRadius: 4,
- }}
- >
- 取消选择
- </div>
- <Popconfirm
- title="确认批量删除所选查核要点?"
- okText="确定"
- cancelText="取消"
- onConfirm={async () => {
- try {
- await delDeptCheckpoint(selectedCheckPointKeys);
- message.success('批量删除成功');
- setSelectedCheckPointKeys([]);
- checkPointsTableRef.current?.reload();
- } catch (e) {
- message.error('批量删除失败');
- }
- }}
- >
- <div
- style={{
- cursor: 'pointer',
- display: 'inline-block',
- fontSize: 14,
- fontFamily: 'SourceHanSansCN-Normal, SourceHanSansCN',
- fontWeight: 400,
- color: '#ffffff',
- lineHeight: '24px',
- padding: '0 14px',
- background: '#3377ff',
- borderRadius: 4,
- }}
- >
- 批量删除
- </div>
- </Popconfirm>
- </div>
- </div>
- )}
- {/* 查核条件选择弹窗 */}
- <Modal
- title="选择查核条件(病房)"
- open={conditionModalVisible}
- onCancel={() => setConditionModalVisible(false)}
- width={532}
- footer={[
- <Button key="cancel" onClick={() => setConditionModalVisible(false)}>
- 取消
- </Button>,
- <Button
- key="confirm"
- type="primary"
- onClick={handleConfirmConditions}
- >
- 确定
- {selectedConditions.length > 0
- ? `(${selectedConditions.length})`
- : ''}
- </Button>,
- ]}
- >
- <div style={{ marginBottom: 8 }}>
- <div style={{ display: 'flex', gap: 8, marginBottom: 16 }}>
- <Select
- value={conditionSearchType}
- onChange={(value) => {
- setConditionSearchType(value);
- // 切换类型时重置选择状态和搜索关键词
- setSelectedConditions([]);
- setConditionSearchKeyword('');
- // 切换类型时重新拉取数据
- conditionTableRef.current?.reload();
- }}
- style={{ width: 120 }}
- options={[
- { label: '个案', value: '个案' },
- { label: '系统', value: '系统' },
- ]}
- />
- <Input
- placeholder="条件名称"
- value={conditionSearchKeyword}
- allowClear
- onChange={(e) => {
- setConditionSearchKeyword(e.target.value);
- // 实时搜索,触发表格重新渲染
- conditionTableRef.current?.reload();
- }}
- onPressEnter={() => conditionTableRef.current?.reload()}
- suffix={
- <SearchOutlined
- onClick={() => conditionTableRef.current?.reload()}
- style={{ cursor: 'pointer', color: '#99A6BF' }}
- />
- }
- style={{ flex: 1 }}
- />
- </div>
- </div>
- <KCIMTable
- actionRef={conditionTableRef}
- columns={conditionColumns}
- request={getConditionData}
- rowKey="id"
- search={false}
- expandable={{
- defaultExpandAllRows: true, // 默认展开所有行
- childrenColumnName: 'children', // 指定子数据的字段名
- }}
- pagination={{
- simple: true,
- pageSize: 10,
- size: 'small',
- showTotal: () => null,
- }}
- rowSelection={{
- selectedRowKeys: selectedConditions,
- onChange: (selectedRowKeys) => {
- setSelectedConditions(selectedRowKeys as string[]);
- },
- checkStrictly: false, // 启用父子关联选择
- }}
- tableAlertRender={false}
- scroll={{ y: 360 }}
- />
- </Modal>
- {/* 选择人员弹窗 */}
- <Modal
- title="选择人员(产科病房)"
- open={employeeModalVisible}
- onCancel={() => setEmployeeModalVisible(false)}
- width={372}
- footer={[
- <Button key="cancel" onClick={() => setEmployeeModalVisible(false)}>
- 取消
- </Button>,
- <Button
- key="confirm"
- type="primary"
- onClick={handleConfirmAddEmployees}
- style={{ backgroundColor: '#3377FF', borderColor: '#3377FF' }}
- >
- 确定
- {selectedEmployees.length > 0
- ? ` (${selectedEmployees.length})`
- : ''}
- </Button>,
- ]}
- >
- <div style={{ marginBottom: 8 }}>
- <Input
- placeholder="请输入"
- value={employeeSearchKeyword}
- allowClear
- onChange={(e) => {
- setEmployeeSearchKeyword(e.target.value);
- if (e.target.value === '') {
- // 清空搜索时自动刷新
- employeeTableRef.current?.reload();
- }
- }}
- onPressEnter={() => employeeTableRef.current?.reload()}
- suffix={
- <SearchOutlined
- onClick={() => employeeTableRef.current?.reload()}
- style={{ cursor: 'pointer', color: '#99A6BF' }}
- />
- }
- style={{ width: '100%' }}
- />
- </div>
- <KCIMTable
- actionRef={employeeTableRef}
- columns={[
- {
- title: '工号',
- dataIndex: 'empCode',
- width: 120,
- align: 'left',
- },
- {
- title: '姓名',
- dataIndex: 'empName',
- align: 'left',
- },
- ]}
- request={getEmployeeSelectData}
- rowKey="id"
- search={false}
- pagination={{
- simple: true,
- pageSize: 10,
- size: 'small',
- showTotal: () => null,
- }}
- rowSelection={{
- selectedRowKeys: selectedEmployees,
- onChange: (selectedRowKeys) => {
- setSelectedEmployees(selectedRowKeys as string[]);
- },
- }}
- tableAlertRender={false}
- scroll={{ y: 360 }}
- />
- </Modal>
- {/* 选择查核要点弹窗 */}
- <Modal
- title={`选择查核要点(${selectedDept?.title || ''})`}
- open={checkPointModalVisible}
- onCancel={() => setCheckPointModalVisible(false)}
- width={700}
- footer={[
- <Button key="cancel" onClick={() => setCheckPointModalVisible(false)}>
- 取消
- </Button>,
- <Button
- key="confirm"
- type="primary"
- onClick={handleConfirmAddCheckPoints}
- >
- 确定
- {selectedCheckPointKeys.length > 0
- ? `(${selectedCheckPointKeys.length})`
- : ''}
- </Button>,
- ]}
- >
- {/* fragment 包裹,防止JSX语法错误 */}
- <>
- <KCIMTable
- actionRef={checkPointTableRef}
- columns={checkPointModalColumns}
- request={getDeptPendingCheckpointData}
- rowKey="id"
- bordered
- search={false}
- pagination={{
- simple: true,
- pageSize: 10,
- size: 'small',
- showTotal: () => null,
- }}
- tableAlertRender={false}
- scroll={{ y: 360 }}
- />
- </>
- </Modal>
- </KCIMPagecontainer>
- );
- }
|