Explorar el Código

完成所有开发

code4eat hace 7 meses
padre
commit
db0e9ab0b6
Se han modificado 55 ficheros con 6316 adiciones y 761 borrados
  1. 21 6
      .umirc.ts
  2. 16 18
      src/app.tsx
  3. 2 1
      src/components/KCIMLeftList/index.tsx
  4. 2 2
      src/components/KCIMPageContainer/index.tsx
  5. 2 2
      src/components/KCIMPageContainer/style.less
  6. 2 2
      src/constant.ts
  7. 3 1
      src/global.less
  8. 3 3
      src/pages/Home/index.tsx
  9. 78 56
      src/pages/personalCenter/myApplication/index.tsx
  10. 154 8
      src/pages/personalCenter/myApplication/style.less
  11. 65 0
      src/pages/personalCenter/myQualifications/authHisttory/index.tsx
  12. 35 0
      src/pages/personalCenter/myQualifications/authHisttory/style.less
  13. 536 0
      src/pages/personalCenter/myQualifications/index.tsx
  14. 77 0
      src/pages/personalCenter/myQualifications/service.ts
  15. 542 0
      src/pages/personalCenter/myQualifications/style.less
  16. 48 0
      src/pages/personalCenter/myQualifications/tabs/index.tsx
  17. 40 0
      src/pages/personalCenter/myQualifications/tabs/style.less
  18. 65 0
      src/pages/qualificationMana/doctorQualifiAuth/authHisttory/index.tsx
  19. 35 0
      src/pages/qualificationMana/doctorQualifiAuth/authHisttory/style.less
  20. 579 0
      src/pages/qualificationMana/doctorQualifiAuth/index.tsx
  21. 69 0
      src/pages/qualificationMana/doctorQualifiAuth/service.ts
  22. 372 0
      src/pages/qualificationMana/doctorQualifiAuth/style.less
  23. 143 0
      src/pages/qualificationMana/doctorQualifiAuth/transform.tsx
  24. 18 14
      src/pages/qualificationMana/qualifiDicMana/index.tsx
  25. 9 1
      src/pages/qualificationMana/qualifiDicMana/service.ts
  26. 0 1
      src/pages/qualificationMana/qualifiDicMana/style.less
  27. 268 211
      src/pages/qualificationMana/qualificationApproval/index.tsx
  28. 371 308
      src/pages/qualificationMana/qualificationApproval/style.less
  29. 12 5
      src/pages/qualificationMana/qualificationAuth/authHisttory/index.tsx
  30. 29 20
      src/pages/qualificationMana/qualificationAuth/index.tsx
  31. 16 1
      src/pages/qualificationMana/qualificationAuth/style.less
  32. BIN
      src/pages/qualificationMana/qualificationBatchAuth/DoctorSelection/images/renyuantubiao_yellow.png
  33. 114 0
      src/pages/qualificationMana/qualificationBatchAuth/DoctorSelection/index.tsx
  34. 75 0
      src/pages/qualificationMana/qualificationBatchAuth/DoctorSelection/style.less
  35. 522 0
      src/pages/qualificationMana/qualificationBatchAuth/index.tsx
  36. 68 0
      src/pages/qualificationMana/qualificationBatchAuth/service.ts
  37. 311 0
      src/pages/qualificationMana/qualificationBatchAuth/style.less
  38. 143 0
      src/pages/qualificationMana/qualificationBatchAuth/transform.tsx
  39. 67 57
      src/pages/qualificationMana/qualificationClassfiMana/index.tsx
  40. 45 43
      src/pages/qualificationMana/qualificationClassfiMana/style.less
  41. 65 0
      src/pages/qualificationMana/qualificationExperiedMana/authHisttory/index.tsx
  42. 35 0
      src/pages/qualificationMana/qualificationExperiedMana/authHisttory/style.less
  43. 568 0
      src/pages/qualificationMana/qualificationExperiedMana/index.tsx
  44. 52 0
      src/pages/qualificationMana/qualificationExperiedMana/service.ts
  45. 322 0
      src/pages/qualificationMana/qualificationExperiedMana/style.less
  46. 48 0
      src/pages/qualificationMana/qualificationExperiedMana/tabs/index.tsx
  47. 40 0
      src/pages/qualificationMana/qualificationExperiedMana/tabs/style.less
  48. 143 0
      src/pages/qualificationMana/qualificationExperiedMana/transform.tsx
  49. 55 0
      src/utils/format.ts
  50. 31 1
      src/utils/tooljs.ts
  51. BIN
      static/avatar.png
  52. BIN
      static/gerenziliaobeijing.png
  53. BIN
      static/gou_black.png
  54. BIN
      static/gou_white.png
  55. BIN
      static/indexBgCenter.png

+ 21 - 6
.umirc.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-08-02 11:28:57
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-12-03 15:44:40
+ * @LastEditTime: 2024-12-17 10:25:50
  * @FilePath: /MediResourceManaSys/.umirc.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -91,11 +91,11 @@ export default defineConfig({
       path:'/personalCenter',
       name:'个人中心',
       routes:[
-        // {
-        //   name:'我的资质',
-        //   path: '/personalCenter/qualificationClassfiMana',
-        //   component: './qualificationMana/qualificationClassfiMana/index',
-        // },
+        {
+          name:'我的资质',
+          path: '/personalCenter/myQualifications',
+          component: './personalCenter/myQualifications/index',
+        },
         {
           name:'我的申请',
           path: '/personalCenter/myApplication',
@@ -112,6 +112,21 @@ export default defineConfig({
           path: '/qualificationMana/qualificationAuth',
           component: './qualificationMana/qualificationAuth/index',
         },
+        {
+          name:'授权期限管理',
+          path: '/qualificationMana/qualificationExperiedMana',
+          component: './qualificationMana/qualificationExperiedMana/index',
+        },
+        {
+          name:'资质批量授权',
+          path: '/qualificationMana/qualificationBatchAuth',
+          component: './qualificationMana/qualificationBatchAuth/index',
+        },
+        {
+          name:'医生资质授权',
+          path: '/qualificationMana/doctorQualifiAuth',
+          component: './qualificationMana/doctorQualifiAuth/index',
+        },
         {
           name:'资质分类管理',
           path: '/qualificationMana/qualificationClassfiMana',

+ 16 - 18
src/app.tsx

@@ -216,7 +216,7 @@ export const request: RequestConfig = {
   responseInterceptors: [
     (response: AxiosResponse) => {
       // 拦截响应数据,进行个性化处理
-      const { status, data: { status: code, errorMessage, msg,errorCode }, config: { method } } = response;
+      const { status, data: { status: code, errorMessage, msg, errorCode }, config: { method } } = response;
 
       try {
 
@@ -266,7 +266,7 @@ export const request: RequestConfig = {
                 //console.log({code,'response.data':response.data});
                 return response.data
               } else {
-           
+
                 notification.error({
                   top: 72,
                   message: '提示',
@@ -275,7 +275,7 @@ export const request: RequestConfig = {
                   icon: <IconFont type="icon-jinggaotishi" />,
                   style: { padding: 16, borderRadius: 8 }
                 })
-               return false
+                return false
               }
             }
 
@@ -383,8 +383,6 @@ export function patchClientRoutes({ routes }: { routes: any }) {
 
   treeLoop(routes[0]);
 
-  console.log({routes});
-
 }
 
 
@@ -404,19 +402,19 @@ export const layout = ({ initialState, setInitialState }: { initialState: any, s
   };
 
   const checkPermission = (path: string) => {
-    const { memuData = [] } = initialState || {};  
+    const { memuData = [] } = initialState || {};
     // 检查是否为无访问权限页面
     if (path === '/noAccess') {
       return true;
     }
-  
+
     // 检查访问权限
     const hasAccess = checkAccess([...memuData], path);
-  
+
     return hasAccess;
   };
-  
-  
+
+
 
 
   // useEffect(() => {
@@ -425,7 +423,7 @@ export const layout = ({ initialState, setInitialState }: { initialState: any, s
   //       const path = removePrefix(location.location.pathname, '/CostAccountingSys');
   //       const hasPermission = checkPermission(path);
   //       console.log({ hasPermission, path });
-  
+
   //       // 如果hasPermission为true,确保不会跳转到/noAccess
   //       if (!hasPermission && path !== '/noAccess') {
   //         history.push('/noAccess');
@@ -434,12 +432,12 @@ export const layout = ({ initialState, setInitialState }: { initialState: any, s
   //     isMenuClickRef.current = false; // 重置状态
   //   });
   // }, [initialState]);
-  
-  
+
+
 
 
   return {
-    
+
     menuHeaderRender: false,
     disableMobile: true,
     onPageChange: () => { },
@@ -458,7 +456,7 @@ export const layout = ({ initialState, setInitialState }: { initialState: any, s
     },
     collapsed: isCollapsed,
     // fixSiderbar:false,
-    menuItemRender:(item: { path: any; }, dom: string | number | boolean | ReactElement<any, string | JSXElementConstructor<any>> | ReactFragment | ReactPortal | null | undefined) => {
+    menuItemRender: (item: { path: any; }, dom: string | number | boolean | ReactElement<any, string | JSXElementConstructor<any>> | ReactFragment | ReactPortal | null | undefined) => {
       return (
         <a
           onClick={() => {
@@ -470,8 +468,8 @@ export const layout = ({ initialState, setInitialState }: { initialState: any, s
         </a>
       );
     },
-    menu:{
-      request:async ()=>{
+    menu: {
+      request: async () => {
         const userData = localStorage.getItem('userData');
         const currentSelectedTab = localStorage.getItem('currentSelectedTab');
         if (currentSelectedTab) {
@@ -574,7 +572,7 @@ export const layout = ({ initialState, setInitialState }: { initialState: any, s
       //height: '94.5vh',  //以去除顶部导航高度
       borderRadius: '22px',
       background: '#F7F9FC',
-      height: 'calc(100vh - 48px)'
+      height: 'calc(100vh - 80px)'
       // overflow:'scroll',
       // margin:'20px 20px'
     },

+ 2 - 1
src/components/KCIMLeftList/index.tsx

@@ -119,7 +119,7 @@ export const KCIMLeftList = (props: KCIMLeftListProps) => {
         ),
       };
     }
-    return {
+    return {  
       node: node,
       expandedKeys: [node[`${fieldNames.key}`]],
     };
@@ -231,6 +231,7 @@ export const KCIMLeftList = (props: KCIMLeftListProps) => {
               autoExpandParent={autoExpandParent}
               selectedKeys={[currentSelected[`${fieldNames.key}`]]}
               blockNode={true}
+              expandAction={false} 
               showIcon={false}
               treeData={showList as unknown as DataNode[]}
               switcherIcon={(props: any) => {

+ 2 - 2
src/components/KCIMPageContainer/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-08-11 18:00:37
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-11-18 16:39:07
+ * @LastEditTime: 2024-12-24 15:57:09
  * @FilePath: /MediResourceManaSys/src/components/KCIMPageContainer/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -65,7 +65,7 @@ const KCIMPagecontainer = (props: KCIMPagecontainerPropType) => {
         ...header,
         breadcrumb: {},
         style: { padding: 0, },
-        childrenContentStyle: { padding: 0 }
+        childrenContentStyle: { padding: 16 }
       }}
     >
       {children}

+ 2 - 2
src/components/KCIMPageContainer/style.less

@@ -1,7 +1,7 @@
 
 .mrms-ant-pro-page-container {
-    
-    border: 16px solid #F7F9FC;
+      padding: 16px;
+      
 }
 .mrms-ant-pro-page-container .mrms-ant-pro-page-container-warp-page-header~.mrms-ant-pro-grid-content .mrms-ant-pro-page-container-children-content {
     padding-block: 0 !important;

+ 2 - 2
src/constant.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2024-01-12 13:34:17
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-12-06 13:54:19
+ * @LastEditTime: 2024-12-16 16:23:41
  * @FilePath: /CostAccountingSys/src/constant.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -20,5 +20,5 @@ export const  tableColumnsWidObj = {
 }
 
 export const  authTimeType = [
-       {label:'长期授权',value:1},{label:'临授权',value:2},{label:'单次授权',value:3}
+       {label:'长期授权',value:1},{label:'临授权',value:2},{label:'单次授权',value:3}
 ]

+ 3 - 1
src/global.less

@@ -634,7 +634,9 @@ textarea {
 
 .mrms-ant-pro-layout .mrms-ant-pro-layout-container {
     flex: 1;
-    overflow-y: scroll;
+    // overflow-y: scroll;
+    // padding: 16px;
+    // padding-right: 8px;
     background: #F7F9FC !important;
 }
 

+ 3 - 3
src/pages/Home/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2022-12-14 14:14:32
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-08-02 10:43:28
+ * @LastEditTime: 2024-12-19 13:42:52
  * @FilePath: /BudgetManaSystem/src/pages/Home/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 
@@ -19,8 +19,8 @@ const HomePage: React.FC = () => {
   return (
     <KCIMPagecontainer title={false} ghost>
       <div className='HomePage'>
-        <div className='title'>全成本核算系统</div>
-        <div className='titleSub'>以促进医院内部经济、经营管理向正规化的轨道转变,建立规范以及完整的成本管理决策体系,将管理重点转移到经济管理上来,并透过完善的信息化建设,实现对成本管理的支撑。纠正医院的成本管控理念及应用错误,改变现行的“四类三级”成本核算方法。实现医院科室成本核算,支持医院床位动态管理,支持科室实施主诊医师负责制;实现科室真实盈亏计算及盈亏平衡分析,指导科室经营;实现利润敏感性分析,使用国际先进的管理会计理论用以医院经营管理决策。</div>
+        <div className='title'>医资管理系统</div>
+        <div className='titleSub'>医资管理系统是一款专为医疗机构设计的高效信息化管理工具,用于全面、准确地管理医生的执业资质、教育背景、专业技能及培训记录等信息。该系统集成了资质审核、证书管理等功能模块,确保医生队伍的专业性和合规性。通过智能化的数据管理与分析,医疗机构可以实时掌握医生资质状况,优化人力资源配置,提升医疗服务质量。同时,系统还支持多部门协同作业,提高管理效率,保障患者安全与满意度。</div>
         <div className='banner'>
           <img src={require('../../../static/indexBgCenter.png')} alt="" />
         </div>

+ 78 - 56
src/pages/personalCenter/myApplication/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-12-05 10:40:41
+ * @LastEditTime: 2024-12-31 10:28:20
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -26,7 +26,7 @@ import { addData, delData, editData, getTableList, uploadFilesReq, withdrawReq }
 
 import './style.less';
 
-import { renameChildListToChildren } from '@/utils/tooljs';
+
 import QualifiDicMana from '@/pages/qualificationMana/qualifiDicMana';
 import Dragger from 'antd/es/upload/Dragger';
 import { useModel } from '@umijs/max';
@@ -93,7 +93,7 @@ export default function MyApplication() {
     const [drawerTextAreaVal, set_drawerTextAreaVal] = useState<string | undefined>(undefined);
     const [drawerUploadFiles, set_drawerUploadFiles] = useState<any[]>([]);
     const [actionType, set_actionType] = useState<'ADD' | 'EDIT' | 'DETAIL' | undefined>(undefined);
-    const [operationLevel,set_operationLevel] = useState<any[]>([]);
+    const [operationLevel, set_operationLevel] = useState<any[]>([]);
     const columns: ProColumns[] = [
         {
             title: '资质编码',
@@ -348,19 +348,19 @@ export default function MyApplication() {
         }
     }, [drawerVisible]);
 
-    useEffect(()=>{
+    useEffect(() => {
         getOperationLevel();
-    },[])
+    }, [])
 
     return (
         <KCIMPagecontainer className='MyApplication' title={false}>
-            <Drawer destroyOnClose={true} className='applyDrawer' width={actionType == 'ADD' ? 1160 : actionType == 'EDIT' ? 600 : 750}
+            <Drawer destroyOnClose={true} className='MyApplication-applyDrawer' width={actionType == 'ADD' ? 1160 : actionType == 'EDIT' ? 600 : 750}
                 open={drawerVisible} headerStyle={{ display: 'none' }} bodyStyle={{ background: '#F5F7FA', padding: 16 }}
                 afterOpenChange={(bool) => { !bool && set_actionType(undefined) }}
             >
                 <div className='applyDrawer-topBar'>
                     <div className='applyDrawer-topBar-title'>
-                        <IconFont onClick={() => set_drawerVisible(false)} type={'iconquxiao'} style={{ marginRight: 12 }} />{actionType == 'ADD' ? '新增' : actionType == 'DETAIL' ? '详情' : '编辑'}
+                        <div className='closeIcon' onClick={() => set_drawerVisible(false)}><IconFont type={'iconquxiao'} /></div>{actionType == 'ADD' ? '新增' : actionType == 'DETAIL' ? '详情' : '编辑'}
                     </div>
                     {
                         actionType != 'DETAIL' && (
@@ -392,25 +392,37 @@ export default function MyApplication() {
                                                 display: 'inline-flex', height: 20, justifyContent: 'center', padding: '0 12px', marginLeft: 8,
                                                 alignItems: 'center', background: '#E8FCF6', borderRadius: 4, fontSize: 12, color: '#009966'
                                             }}>{
-                                                    (operationLevel.filter((a)=>a.value == currentEditRow?.qualificationInfo?.operationLevelCode)).length>0?(operationLevel.filter((a)=>a.value == currentEditRow?.qualificationInfo?.operationLevelCode))[0].name:''
+                                                    (operationLevel.filter((a) => a.value == currentEditRow?.qualificationInfo?.operationLevelCode)).length > 0 ? (operationLevel.filter((a) => a.value == currentEditRow?.qualificationInfo?.operationLevelCode))[0].name : ''
                                                 }</span>
                                         )
                                     }
                                 </div>
                                 <div className='editContent-header-title-sub'>
-                                    资质编码:{currentEditRow?.qualificationInfo.code}<span style={{ padding: 4 }}></span>资质分类:{currentEditRow?.qualificationInfo.qualificationTypeName}
-                                    <span style={{ padding: 4 }}></span>授权依据:{currentEditRow?.qualificationInfo.standard}
-                                    {actionType == 'DETAIL' && (<><span style={{ padding: 4 }}></span>申请日期:{currentEditRow?.applyDate}</>)}
-
+                                    资质编码:{currentEditRow?.qualificationInfo.code ?? '-'}<span style={{ padding: 8 }}></span>资质分类:{currentEditRow?.qualificationInfo.qualificationTypeName ?? '-'}
+                                    {actionType == 'DETAIL' && (<><span style={{ padding: 8 }}></span>申请日期:{currentEditRow?.applyDate ?? '-'}</>)}
                                 </div>
-                                {(currentEditRow?.applyMemo?.length > 0 && actionType == 'DETAIL') && <div className='editContent-header-title-detail'>{currentEditRow?.applyMemo}</div>}
+                                {currentEditRow?.qualificationInfo.standard.length > 0 && <div className='editContent-header-title-authStandard'>{currentEditRow?.qualificationInfo.standard}</div>}
+
+
+                            </div>
+                        )
+                    }
+                    {
+                        ((actionType == 'EDIT' || actionType == 'DETAIL')&&(currentEditRow?.applyMemo?.length > 0||currentEditRow?.applyAttachment?.length > 0)) && (
+                            <div className='apply-info' >
+                                <div className='apply-info-title'>申请信息</div>
+                                {(currentEditRow?.applyMemo?.length > 0 && actionType == 'DETAIL') &&(
+                                    <div className='apply-info-detail'>
+                                        <div className='apply-info-detail-value'><span>备注:</span><div>{currentEditRow?.applyMemo}</div></div>
+                                    </div>
+                                )}
                                 {actionType == 'DETAIL' && (currentEditRow?.applyAttachment?.length > 0) && <div className='appendix'>
                                     附件:{currentEditRow?.applyAttachment.map((a: any, index: number) => (<span key={index}><IconFont type={'iconfujian'} /><a href={a.url} target='_blank'>{a.fileName}</a></span>))}
                                 </div>}
-
                             </div>
                         )
                     }
+
                     {
                         (actionType == 'DETAIL' && currentEditRow?.deptOpinion) && (
                             <div className='deptOpinion'>
@@ -436,6 +448,16 @@ export default function MyApplication() {
                             </div>
                         )
                     }
+                    {
+                        (actionType == 'DETAIL' && currentEditRow?.applyStatus == 2) && (
+                            <div className='detail-noAuthRecord'>
+                                <img src={require('../../../../static/empty.png')} alt="" />
+                                <div className='detail-noAuthRecord-title'>暂无内容</div>
+                                <div className='detail-noAuthRecord-title-sub'>请耐心等待科主任审核</div>
+                                <div className='backBtn' onClick={() => set_drawerVisible(false)}>返回</div>
+                            </div>
+                        )
+                    }
                     {
                         actionType == 'ADD' && (
                             <div className='applyDrawer-left'>
@@ -469,7 +491,7 @@ export default function MyApplication() {
                                             if (status == 'removed') {
                                                 const temp = [...drawerUploadFiles];
                                                 const result = temp.filter((a) => a.fileName != name);
-                                                console.log({ result });
+
                                                 set_drawerUploadFiles([...result]);
                                             }
                                             if (status === 'done') {
@@ -493,54 +515,54 @@ export default function MyApplication() {
                     }
                 </div>
             </Drawer>
-            <div className='toolBar'>
-                <div className='filter'>
-                    <div className='filterItem'>
-                        <span className='label' style={{ whiteSpace: 'nowrap' }}> 当前状态:</span>
-                        <ProFormSelect noStyle placeholder={'请选择'}
-                            style={{ marginRight: 16, width: 160 }}
-                            options={applyStatus}
-                            fieldProps={{
-                                onChange(value, option) {
-                                    set_tableDataFilterParams({ ...tableDataFilterParams, current: 1, applyStatus: value })
-                                },
-                            }}
-                        />
-                    </div>
-                    <div className='filterItem'>
-                        <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
-                        <Input placeholder={'资质分类、资质名称'} allowClear autoComplete='off'
-                            suffix={
-                                <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('queryCondition')} />
-                            }
-                            onChange={(e) => {
-                                set_tableDataSearchKeywords(e.target.value);
-                                if (e.target.value.length == 0) {
+
+            <div style={{ padding: 16, background: '#fff', borderRadius: 4 }}>
+                <div className='toolBar'>
+                    <div className='filter'>
+                        <div className='filterItem'>
+                            <span className='label' style={{ whiteSpace: 'nowrap' }}> 当前状态:</span>
+                            <ProFormSelect noStyle placeholder={'请选择'}
+                                style={{ marginRight: 16, width: 160 }}
+                                options={applyStatus}
+                                fieldProps={{
+                                    onChange(value, option) {
+                                        set_tableDataFilterParams({ ...tableDataFilterParams, current: 1, applyStatus: value })
+                                    },
+                                }}
+                            />
+                        </div>
+                        <div className='filterItem'>
+                            <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
+                            <Input placeholder={'资质分类、资质名称'} allowClear autoComplete='off'
+                                suffix={
+                                    <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('queryCondition')} />
+                                }
+                                onChange={(e) => {
+                                    set_tableDataSearchKeywords(e.target.value);
+                                    if (e.target.value.length == 0) {
+                                        set_tableDataFilterParams({
+                                            ...tableDataFilterParams,
+                                            current: 1,
+                                            queryCondition: ''
+                                        });
+                                    }
+                                }}
+                                onPressEnter={(e) => {
+
                                     set_tableDataFilterParams({
                                         ...tableDataFilterParams,
                                         current: 1,
-                                        queryCondition: ''
+                                        queryCondition: (e.target as HTMLInputElement).value
                                     });
-                                }
-                            }}
-                            onPressEnter={(e) => {
-
-                                set_tableDataFilterParams({
-                                    ...tableDataFilterParams,
-                                    current: 1,
-                                    queryCondition: (e.target as HTMLInputElement).value
-                                });
-                            }}
+                                }}
 
-                        />
+                            />
+                        </div>
+                    </div>
+                    <div className='btnGroup'>
+                        <a className='add' onClick={() => { set_actionType('ADD') }}>新增</a>
                     </div>
                 </div>
-                <div className='btnGroup'>
-                    <a className='add' onClick={() => { set_actionType('ADD') }}>新增</a>
-                </div>
-            </div>
-
-            <div style={{ marginTop: 16 }}>
                 <KCIMTable columns={columns as ProColumns[]} scroll={{ y: 'calc(100vh - 232px)' }} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
             </div>
         </KCIMPagecontainer>

+ 154 - 8
src/pages/personalCenter/myApplication/style.less

@@ -1,4 +1,4 @@
-.applyDrawer {
+.MyApplication-applyDrawer {
   .applyDrawer-topBar {
     display: flex;
     flex-direction: row;
@@ -10,6 +10,23 @@
       font-weight: 500;
       font-size: 16px;
       color: #17181A;
+
+      .closeIcon {
+        position: relative;
+        top: 2px;
+        display: inline-flex;
+        justify-content: center;
+        align-items: center;
+        width: 24px;
+        height: 24px;
+        cursor: pointer;
+        margin-right: 8px;
+        border-radius: 4px;
+
+        &:hover {
+          background-color: #E6EAF2;
+        }
+      }
     }
 
     .btnGroup {
@@ -45,10 +62,9 @@
   .content {
     display: flex;
     width: 100%;
-    height: calc(100% - 40px);
-    flex-direction: row;
-    justify-content: space-between;
-    align-items: flex-start;
+    height: calc(100vh - 75px);
+    overflow-y: scroll;
+
 
     .editContent-header {
       width: 100%;
@@ -82,6 +98,35 @@
         text-overflow: ellipsis;
       }
 
+      .editContent-header-title-authStandard {
+        position: relative;
+        background: #F7F9FC;
+        border-radius: 4px;
+        min-height: 56px;
+        padding: 6px 12px;
+        padding-right: 64px;
+
+        font-weight: 400;
+        font-size: 14px;
+        color: #17181A;
+        line-height: 18px;
+        margin-top: 12px;
+        border: 1px solid #DAE4F2;
+
+        &::after {
+          position: absolute;
+          content: '';
+          top: 8px;
+          right: 12px;
+          display: inline-block;
+          width: 40px;
+          height: 40px;
+          background: url('../../../../static/shouquanyiju.png');
+          background-size: contain;
+          background-repeat: no-repeat;
+        }
+      }
+
       .editContent-header-title-detail {
         min-height: 32px;
         background: #F7F9FC;
@@ -107,6 +152,55 @@
 
     }
 
+    .apply-info {
+      width: 100%;
+      background: #FFFFFF;
+      border-radius: 4px;
+      padding: 16px;
+      margin-top: 16px;
+
+
+      .apply-info-title {
+        font-weight: 500;
+        font-size: 16px;
+        height: 16px;
+        color: #17181A;
+        line-height: 16px;
+        margin-bottom: 16px;
+      }
+
+      .apply-info-detail {
+        .apply-info-detail-value {
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+          &>span {
+            color: #525866;
+          }
+          &>div {
+            border-radius: 4px;
+            max-height: 72px;
+            overflow: hidden;
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            font-weight: 400;
+            font-size: 14px;
+            color: #17181A;
+            line-height: 18px;
+          }
+        }
+
+      }
+
+      .appendix {
+        margin-top: 12px;
+        font-weight: 400;
+        font-size: 14px;
+        color: #525866;
+      }
+    }
+
     .deptOpinion {
       width: 100%;
       background: #FFFFFF;
@@ -189,8 +283,9 @@
         }
       }
 
-      
+
     }
+
     .masterOpinion {
       width: 100%;
       background: #FFFFFF;
@@ -215,6 +310,56 @@
       }
     }
 
+    .detail-noAuthRecord {
+      display: flex;
+      width: 100%;
+      height: 390px;
+      margin-top: 16px;
+      flex-direction: column;
+      justify-content: center;
+      align-items: center;
+      padding: 16px;
+      background: #FFFFFF;
+      border-radius: 4px;
+
+      &>img {
+        width: 160px;
+        height: 140px;
+      }
+
+      .detail-noAuthRecord-title {
+        font-weight: 500;
+        font-size: 24px;
+        height: 24px;
+        color: #17181A;
+        line-height: 24px;
+        margin-top: 24px;
+        margin-bottom: 16px;
+      }
+
+      .detail-noAuthRecord-title-sub {
+        font-weight: 400;
+        font-size: 14px;
+        height: 14px;
+        color: #7A8599;
+        line-height: 14px;
+      }
+
+      .backBtn {
+        width: 56px;
+        height: 24px;
+        text-align: center;
+        margin-top: 24px;
+        background: #3377FF;
+        border-radius: 4px;
+        font-weight: 400;
+        font-size: 14px;
+        color: #FFFFFF;
+        line-height: 24px;
+        cursor: pointer;
+      }
+    }
+
     // background: #FFFFFF;
     .applyDrawer-left {
       width: 760px;
@@ -263,14 +408,15 @@
 
 .MyApplication {
   padding: 16px;
-  background: #FFFFFF;
-  border-radius: 4px;
+  // background: #FFFFFF;
+  // border-radius: 4px;
 
   .toolBar {
     display: flex;
     flex-direction: row;
     justify-content: space-between;
     align-items: center;
+    margin-bottom: 16px;
 
     .filter {
       display: flex;

+ 65 - 0
src/pages/personalCenter/myQualifications/authHisttory/index.tsx

@@ -0,0 +1,65 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-12-06 14:42:57
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-12-25 15:58:50
+ * @FilePath: /MediResourceManaSys/src/pages/qualificationMana/qualificationAuth/authHisttory/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AEi m z z
+ */
+
+
+import { createFromIconfontCN } from '@ant-design/icons';
+import React, { Children } from 'react'
+import { Timeline } from 'antd'
+import './style.less'
+import { authTimeType } from '@/constant';
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+export default function AuthHisContent({ hisList }: { hisList: any[] }) {
+
+    const getPeriodStr = (code:number)=>{
+        const result = authTimeType.filter((a)=>a.value == code);
+        if(result.length>0){
+            return result[0].label
+        }
+        return undefined
+    }
+
+    const dotNode = (isActive=false)=>{
+        return <div style={{display:'flex',justifyContent:'center',alignItems:'center',width:16,height:16,border:'2px solid #E7EBF2',borderRadius:'50%'}}>
+            {isActive&&<div style={{width:8,height:8,background:'#363F4D',borderRadius:'50%'}}></div>}
+        </div>
+    }
+    return (
+        <div className='AuthHisContent'>
+            <div className='AuthHisContent-title'>
+                <IconFont type={'icon-qingliangtishi'} style={{ paddingRight:12 }} />调整历史
+            </div>
+            <div className='AuthHisContent-content'>
+                <Timeline>
+                    {
+                        hisList.map((a,index)=>{
+                             return (
+                                <Timeline.Item key={index} dot={dotNode(index == 0?true:false)} >
+                                      <div style={{fontWeight:'bold',fontSize:14,color:'#17181A',height:14,lineHeight:'14px',marginBottom:8}}>{`${a.adjustUserName} ${a.adjustTime}`}</div>
+                                      <div style={{height:14,fontSize:12,color:'#176DE6',lineHeight:'14px',marginBottom:8,paddingLeft:6}}>
+                                        <img style={{width:43,height:14,marginRight:4}} src={require('../../../../../static/tiaozhenghou.png')} />{getPeriodStr(a.qualificationPeriodAfter)} {`(${a.beginDateAfter}至${a.endDateAfter})`}
+                                      </div>
+                                      <div style={{height:14,fontSize:12,color:'#525866',lineHeight:'14px',marginBottom:8,paddingLeft:6}}>
+                                        <img style={{width:43,height:14,marginRight:4}} src={require('../../../../../static/tiaozhengqian.png')} />
+                                        {getPeriodStr(a.qualificationPeriodBefore)} {`(${a.beginDateBefore}至${a.endDateBefore})`}
+                                      </div>
+                                      {(a.memo&&a.memo.length>0)&&<div style={{padding:'5px 8px',fontSize:12,color:'#525866',background:'#F7F9FC',borderRadius:4}}>{a.memo}</div>}
+                                </Timeline.Item>
+                             )
+                        })
+                    }
+                </Timeline>
+            </div>
+        </div>
+    )
+}

+ 35 - 0
src/pages/personalCenter/myQualifications/authHisttory/style.less

@@ -0,0 +1,35 @@
+
+
+.AuthHisContent {
+    width: 400px;
+   
+    .AuthHisContent-title {
+        font-weight: 500;
+        font-size: 16px;
+        height: 16px;
+        color: #17181A;
+        line-height: 16px;
+    }
+    .AuthHisContent-content {
+        max-height: 400px;
+        overflow: scroll;
+        overflow-x: hidden;
+        padding-top: 24px;
+
+        .mrms-ant-timeline-item {
+            &.mrms-ant-timeline-item-last {
+                padding-bottom: 0;
+            }
+        }
+        .mrms-ant-timeline-item-tail {
+            left:8px;
+        }
+        .mrms-ant-timeline-item-head-custom {
+            top:0.5px;
+            left:9px;
+        }
+        .mrms-ant-timeline-item-content {
+            margin: 0 0 0 35px;
+        }
+    }
+}

+ 536 - 0
src/pages/personalCenter/myQualifications/index.tsx

@@ -0,0 +1,536 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 11:30:33
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-12-31 13:58:04
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+
+
+
+import KCIMPagecontainer from '@/components/KCIMPageContainer';
+import { KCIMTable } from '@/components/KCIMTable';
+import { createFromIconfontCN, InboxOutlined } from '@ant-design/icons';
+
+import { ActionType, arrayMoveImmutable, ProFormText, ProFormTextArea, useRefFunction } from '@ant-design/pro-components';
+import ProForm, { ModalForm, ProFormCascader, ProFormCheckbox, ProFormDatePicker, ProFormDateRangePicker, ProFormDependency, ProFormDigit, ProFormInstance, ProFormRadio, ProFormSelect, ProFormSwitch, ProFormUploadDragger } from '@ant-design/pro-form'
+import { ProColumns } from '@ant-design/pro-table';
+import { Alert, Drawer, Dropdown, Form, Input, message, Popconfirm, Popover, Radio } from 'antd';
+import { Fragment, Key, useEffect, useRef, useState } from 'react';
+
+
+
+import { addData, delData, editData, getMyInfoReq, getTableDataReq } from './service';
+
+import './style.less';
+
+import { getDicDataBySysId } from '@/services/getDic';
+import { authTimeType, KcimCenterSysId } from '@/constant';
+
+import 'moment/locale/zh-cn';
+import moment from 'moment';
+import { sparse } from 'mathjs';
+import AuthHisContent from './authHisttory';
+import FormTabs from './tabs';
+import { calculateDelayedDate } from '@/utils/tooljs';
+import { debounce } from 'lodash';
+import { useModel } from '@umijs/max';
+
+
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+export default function MyQualifications() {
+    const { initialState, setInitialState } = useModel('@@initialState');
+    const formRef = useRef<ProFormInstance>();
+    const drawerFormRef = useRef<ProFormInstance>();
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
+    const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
+    const [drawerVisible, set_drawerVisible] = useState(false);
+    const [currentEditRow, set_currentEditRow] = useState<any>(undefined);
+
+    const [currentSelectedTableRows, set_currentSelectedTableRows] = useState<any[]>([]);
+
+
+    const tableRef = useRef<ActionType>();
+    const [modalFormVisible, set_modalFormVisible] = useState(false);
+    const [operationLevel, set_operationLevel] = useState<any[]>([]);
+    const [userInfo, set_userInfo] = useState<any>(undefined);
+    const [currentEditAttachment, set_currentEditAttachment] = useState<any>(undefined);
+
+
+    const columns: ProColumns[] = [
+        {
+            title: '资质编码',
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                const { qualification: { code } } = record;
+                return code
+            },
+        },
+        {
+            title: '资质名称',
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                const { qualification: { name } } = record;
+                return name
+            },
+        },
+        {
+            title: '资质分类',
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                const { qualification: { qualificationTypeName } } = record;
+                return qualificationTypeName
+            },
+        },
+        {
+            title: '特殊类别',
+            ellipsis: true,
+            width: 150,
+            renderText(text, record, index, action) {
+                const { qualification: { operationFlag, techFlag, operationLevelCode } } = record;
+                return <div>
+                    {
+                        techFlag == 1 && (
+                            <span style={{
+                                display: 'inline-flex', width: 64, height: 20, justifyContent: 'center',
+                                alignItems: 'center', background: '#FFF5EB', borderRadius: 4, fontSize: 12, color: '#FF8000', marginRight: 4
+                            }}>医疗技术</span>
+                        )
+                    }
+                    {
+                        operationFlag == 1 && operationLevelCode && (
+                            <span style={{
+                                display: 'inline-flex', width: 64, height: 20, justifyContent: 'center',
+                                alignItems: 'center', background: '#E8FCF6', borderRadius: 4, fontSize: 12, color: '#009966'
+                            }}>{
+                                    (operationLevel.filter((a) => a.value == operationLevelCode)).length > 0 ? (operationLevel.filter((a) => a.value == operationLevelCode))[0].name : ''
+                                }</span>
+                        )
+                    }
+                    {
+                        (!operationFlag && !techFlag) && (<Fragment />)
+                    }
+                </div>
+            },
+        },
+        {
+            title: '操作',
+            key: 'option',
+            width: 80,
+            fixed: 'right',
+            valueType: 'option',
+            render: (_: any, record: any) => {
+                return <a key={1} onClick={() => {
+                    set_currentEditRow(record);
+                    set_drawerVisible(true)
+                }}>详情</a>
+            },
+        },
+
+    ];
+
+
+    const getTableData = async (params: any) => {
+        const resp = await getTableDataReq({ ...params });
+        if (resp) {
+            return {
+                data: resp.list,
+                success: true
+            }
+        } else {
+            return []
+        }
+    }
+
+    const getOperationLevelList = async () => {
+        const resp = await getDicDataBySysId(KcimCenterSysId, 'SURGICAL_AND_OPERATIONAL_LEVELS');
+        if (resp) {
+            set_operationLevel(resp.dataVoList);
+        }
+    }
+
+
+    const updateTable = async (formVal: any, type: 'ADD' | 'EDIT') => {
+        try {
+            const { files, memo, id } = formVal;
+            let result = {};
+            if (files[0].response) {
+                const { name, response: { data: { downUrl } } } = files[0];
+                result = {
+                    id: type == 'EDIT' ? id : null,
+                    userId: userInfo.id,
+                    fileName: name,
+                    url: downUrl,
+                    description: memo
+                };
+            } else {
+                const { name ,url} = files[0];
+                result = {
+                    id: type == 'EDIT' ? id : null,
+                    userId: userInfo.id,
+                    fileName: name,
+                    url: url,
+                    description: memo
+                };
+            }
+
+
+            const resp = type == 'ADD' ? await addData(result) : await editData(result);
+            if (resp) {
+
+                set_currentEditAttachment(undefined);
+                getUserInfo();
+                set_modalFormVisible(false);
+                message.success('操作成功!');
+            }
+
+            return true;
+
+        } catch (error) {
+
+            console.log({ error });
+            return false;
+        }
+
+
+
+
+    }
+
+
+    const tableDataSearchHandle = (key: string) => {
+        set_tableDataFilterParams({ ...tableDataFilterParams, current: 1, [key]: tableDataSearchKeywords })
+    }
+    const getAuthPeriod = (code: number) => {
+        const result = authTimeType.filter(a => a.value == code);
+        return result.length > 0 ? result[0].label : '-'
+    }
+
+    const getUserInfo = async () => {
+        const resp = await getMyInfoReq();
+        if (resp) {
+            set_userInfo(resp);
+        }
+    }
+
+    const delUseerAttachmentHandle = async (record: any) => {
+        const resp = await delData(record.id);
+        if (resp) {
+            getUserInfo();
+            set_modalFormVisible(false);
+            message.success('操作成功!');
+        }
+    }
+
+    const drapDownItems = (fileData: any) => [
+        {
+            key: '1',
+            label: (
+                <a onClick={() => {
+                    set_currentEditAttachment(fileData);
+                    set_modalFormVisible(true);
+                }}>编辑</a>
+            ),
+        },
+        {
+            key: '2',
+            label: (
+                <Popconfirm
+                    title="是否确认删除?"
+                    key="del"
+                    onConfirm={() => delUseerAttachmentHandle(fileData)}
+                >
+                    <a>删除</a>
+                </Popconfirm>
+            )
+        },
+    ]
+
+    useEffect(() => {
+        if (drawerVisible) {
+            getOperationLevelList();
+        }
+    }, [drawerVisible]);
+    
+    useEffect(()=>{
+        if(!modalFormVisible){
+            set_currentEditAttachment(undefined);
+        }
+    },[modalFormVisible]);
+
+    useEffect(() => {
+        getUserInfo();
+    }, []);
+    return (
+        <KCIMPagecontainer className='MyQualifications' title={false} >
+            <ModalForm
+                title={currentEditAttachment ? '编辑附件' : '上传附件'}
+                width={352}
+                formRef={formRef}
+                open={modalFormVisible}
+                initialValues={currentEditAttachment ? {
+                    files: [{ uid: currentEditAttachment.id, name: currentEditAttachment.fileName, url: currentEditAttachment.url, status: 'done' }],
+                    memo: currentEditAttachment.description
+                } : {}}
+
+                onFinish={(val) => {
+                    return updateTable(currentEditAttachment ? { ...currentEditAttachment, ...val } : { ...val }, currentEditAttachment ? 'EDIT' : 'ADD');
+                }}
+                modalProps={{ destroyOnClose: true, onCancel: () => set_modalFormVisible(false), }}
+                colProps={{ span: 24 }}
+                grid
+                submitter={{
+                    searchConfig: {
+                        submitText: '确认',
+                        resetText: '取消',
+                    },
+                }}
+            >
+
+                <ProFormUploadDragger
+                    name="files" // 表单字段名
+                    action={'/gateway/centerSys/api/upload'}
+                    max={1} // 最大上传文件数
+                    description={false}
+                    title={<span style={{ fontSize: 14, color: '#17181A' }}>点击或将文件拖拽到这里上传</span>}
+                    fieldProps={{
+                        name: 'file',
+                        height: 140,
+                        multiple: false,
+                        headers: {
+                            token: initialState?.userData.token as string
+                        },
+
+                        // onChange(info) {
+                        //     const { status } = info.file;
+                        //     if (status !== 'uploading') {
+                        //         console.log(info.file, info.fileList);
+                        //     }
+                        //     if (status === 'done') {
+
+                        //         message.success(`${info.file.name} 文件上传成功。`);
+
+                        //     } else if (status === 'error') {
+                        //         message.error(`${info.file.name} 文件上传失败。`);
+                        //     }
+                        // },
+                        // onDrop(e) {
+                        //     console.log('拖拽上传的文件:', e.dataTransfer.files);
+                        // },
+                    }}
+                />
+                <ProFormTextArea name={'memo'} fieldProps={{
+                    style: { height: 85 }
+                }} label='附件说明:' />
+
+            </ModalForm>
+            <Drawer destroyOnClose={true} className='MyQualifications-authDetailDrawer' width={700}
+                open={drawerVisible} headerStyle={{ display: 'none' }} bodyStyle={{ background: '#F5F7FA', padding: 16 }}
+            >
+                <div className='authDetailDrawer-topBar'>
+                    <div className='authDetailDrawer-topBar-title'>
+                        <div className='closeIcon' onClick={() => set_drawerVisible(false)}><IconFont  type={'iconquxiao'} /></div>{'详情'}
+                    </div>
+                </div>
+                <div className='authDetailDrawer-content'>
+                    <div className='authDetailDrawer-info'>
+                        <div className='authDetailDrawer-info-title'>
+                            {currentEditRow?.qualification?.name}
+                            {
+                                currentEditRow?.qualification?.techFlag == 1 && (
+                                    <span style={{
+                                        display: 'inline-flex', height: 20, justifyContent: 'center', marginLeft: 8, padding: '0 12px',
+                                        alignItems: 'center', background: '#FFF5EB', borderRadius: 4, fontSize: 12, color: '#FF8000', marginRight: 4
+                                    }}>医疗技术</span>
+                                )
+                            }
+                            {
+                                currentEditRow?.qualification?.operationFlag == 1 && (
+                                    <span style={{
+                                        display: 'inline-flex', height: 20, justifyContent: 'center', padding: '0 12px', marginLeft: 8,
+                                        alignItems: 'center', background: '#E8FCF6', borderRadius: 4, fontSize: 12, color: '#009966'
+                                    }}>{
+                                            ((operationLevel.filter((a) => a.value == currentEditRow?.qualification?.operationLevelCode))).length > 0 ? ((operationLevel.filter((a) => a.value == currentEditRow?.qualification?.operationLevelCode)))[0].name : ''
+                                        }</span>
+                                )
+                            }
+                        </div>
+                        <div className='authDetailDrawer-info-title-sub'>
+                            资质编码:{currentEditRow?.qualification?.code}<span style={{ padding: '0 8px' }}></span>
+                            资质分类:{currentEditRow?.qualification?.qualificationTypeName}
+                            {currentEditRow?.qualification?.standard.length > 0 && (
+                                <div className='authDetailDrawer-info-standard'>
+                                    {currentEditRow.qualification.standard}
+                                    <img src={require('../../../../static/shouquanyiju.png')} alt="" />
+                                </div>
+                            )}
+                        </div>
+                    </div>
+                    <div className='authHistory'>
+                        <div className='authHistory-title'>授权记录</div>
+                        <div className='historyListWrapper'>
+                            {
+                                currentEditRow?.applyList?.map((a: any, index: number) => {
+                                    return <div className='historyList' key={index}>
+                                        <img src={require(`../../../../static/${index == 0 ? 'gou_black' : 'gou_white'}.png`)} alt="" />
+                                        <div className='historyList-detail'>
+                                            {(authTimeType.filter((b) => b.value == a.qualificationPeriod)).length > 0 ? (authTimeType.filter((b) => b.value == a.qualificationPeriod))[0].label : ''}
+                                            |{`${a.beginDate}至${a.endDate}`}
+                                            {a.applyAdjust.length > 0 && (
+                                                <Popover className='qualificationAuth-popover' overlayInnerStyle={{borderRadius:4}} content={<AuthHisContent hisList={[...a.applyAdjust]} />} title={false} >
+                                                    <IconFont type={'icon-qingliangtishi'} style={{ marginLeft: 10, cursor: 'pointer' }} />
+                                                </Popover>
+                                            )}
+                                        </div>
+                                        <div className={`status ${a.currentStatus == '授权中'?'authing':'expired'}`}>{a.currentStatus}</div>
+                                    </div>
+                                })
+                            }
+
+                        </div>
+                    </div>
+
+                </div>
+
+
+            </Drawer>
+            <div className='pageContent'>
+                <div className='left'>
+                    <div className='pageContent-title'>我的资质</div>
+                    <div className='toolBar'>
+                        <div className='filter'>
+                            <div className='filterItem'>
+                                <span className='label'>手术级别:</span>
+                                <ProFormSelect noStyle
+                                    style={{ width: 160, marginRight: 16 }}
+                                    placeholder={'请选择'}
+                                    request={async () => {
+                                        const resp = await getDicDataBySysId(KcimCenterSysId, 'SURGICAL_AND_OPERATIONAL_LEVELS');
+                                        if (resp) {
+                                            set_operationLevel(resp.dataVoList);
+                                            return resp.dataVoList.map((item: any) => ({ label: item.name, value: item.value }))
+                                        }
+                                    }}
+                                    fieldProps={{
+                                        onChange(value, option) {
+                                            set_tableDataFilterParams({ ...tableDataFilterParams, current: 1, operationLevelCode: value })
+                                        },
+                                    }}
+                                />
+                            </div>
+                            <div className='filterItem'>
+                                <span className='label'>检索:</span>
+                                <Input placeholder={'资质名称'} style={{ width: 160, marginRight: 16 }} allowClear autoComplete='off'
+                                    suffix={
+                                        <IconFont style={{ color: '#99A6BF' }} type="iconsousuo" onClick={() => tableDataSearchHandle('name')} />
+                                    }
+                                    onChange={(e) => {
+                                        set_tableDataSearchKeywords(e.target.value);
+                                        if (e.target.value.length == 0) {
+                                            set_tableDataSearchKeywords('');
+                                            set_tableDataFilterParams({ ...tableDataFilterParams, name: undefined })
+                                        }
+                                    }}
+
+                                    onPressEnter={(e) => {
+                                        tableDataSearchHandle('name')
+                                    }}
+
+                                />
+                            </div>
+                            <div className='filterItem'>
+                                <ProFormCheckbox.Group
+                                    name="checkbox"
+                                    layout='horizontal'
+                                    noStyle
+                                    options={['医疗技术', '手术']}
+                                    fieldProps={{
+                                        onChange(checkedValue) {
+                                            set_tableDataFilterParams({
+                                                ...tableDataFilterParams,
+                                                current: 1,
+                                                techFlag: checkedValue.findIndex((a) => a == '医疗技术') != -1 ? 1 : 0,
+                                                operationFlag: checkedValue.findIndex((a) => a == '手术') != -1 ? 1 : 0,
+                                            })
+                                        },
+                                    }}
+                                />
+                            </div>
+                        </div>
+                        {currentSelectedTableRows.length > 0 && (
+                            <div className='btnGroup'>
+                                <span className='batchAdjust' onClick={() => set_modalFormVisible(true)}>批量调整</span>
+                            </div>
+                        )}
+                    </div>
+                    <div style={{ marginTop: 16 }}>
+                        <KCIMTable scroll={{ y: `calc(100vh - 230px)` }}
+                            actionRef={tableRef} columns={columns as ProColumns[]} rowKey='id'
+                            params={tableDataFilterParams}
+                            request={(params) => getTableData(params)}
+                            // dataSource={showList}
+                            tableAlertRender={false}
+
+
+                        />
+                    </div>
+                </div>
+                <div className='right'>
+                    <div className='avatar-info'>
+                        <img src={require('../../../../static/avatar.png')} alt="" />
+                        <div className='name'>
+                            <div className='name-text'>{userInfo?.name}{userInfo?.gender&&<img src={require(`../../../../static/${userInfo?.gender == '男' ? 'male' : 'female'}.png`)} alt="" />}</div>
+                            <div className='id'>{userInfo?.id}</div>
+                        </div>
+                    </div>
+                    <div className='jobInfo'>
+                        <div className='jobInfo-block'>
+                            <div className='value'>{userInfo?.deptName??'-'}</div>
+                            <div className='label'>科室</div>
+                        </div>
+                        <div className='jobInfo-block'>
+                            <div className='value'>{userInfo?.title??'-'}</div>
+                            <div className='label'>职称</div>
+                        </div>
+                        <div className='jobInfo-block'>
+                            <div className='value'>{userInfo?.jobTitle??'-'}</div>
+                            <div className='label'>职务</div>
+                        </div>
+                    </div>
+                    <div className='qualifi-info-title'><span>资质信息</span></div>
+                    <div className='qualifi-info-detail'>
+                        <div className='qualifi-info-list'>资格证号:<span>{userInfo?.qualificationCertificateNo??'-'}</span></div>
+                        <div className='qualifi-info-list'>执业类别:<span>{userInfo?.practiceCate??'-'}</span></div>
+                        <div className='qualifi-info-list'>执业证号:<span>{userInfo?.practiceCertificateNo??'-'}</span></div>
+                        <div className='qualifi-info-list'>执业专业:<span>{userInfo?.major??'-'}</span></div>
+                        <div className='qualifi-info-list'>医师级别:<span>{userInfo?.doctorLevel??'-'}</span></div>
+                    </div>
+                    <div className='attachment-title'><span>相关附件</span><a onClick={() => set_modalFormVisible(true)}>上传</a></div>
+                    <div className='attachment-detail'>
+                        {
+                            userInfo?.attachments.map((a: any, index: number) => (
+                                <div className='attachment-detail-list' key={index}>
+                                    <img src={require('../../../../static/fileIcon.png')} alt="" />
+                                    <div className='attachment-detail-list-info'>
+                                        <div className='attachment-list-name'>{a.fileName}</div>
+                                        <div className='attachment-list-subText'>{a.description}</div>
+                                    </div>
+                                    <Dropdown trigger={['hover']} menu={{ items: drapDownItems(a) }}><span className='more'>...</span></Dropdown>
+                                </div>
+                            ))
+                        }
+                    </div>
+                </div>
+            </div>
+        </KCIMPagecontainer>
+    )
+}

+ 77 - 0
src/pages/personalCenter/myQualifications/service.ts

@@ -0,0 +1,77 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 16:31:27
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-12-19 16:47:46
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+import { request } from 'umi';
+
+//获取table列表数据
+
+export const getTableDataReq = (params?:any) => {
+  return request<any>('/medical/qualificationManage/listMyAvailableQualification', {
+    method: 'GET',
+    params:{...params}
+  });
+};
+
+//获取登录用户信息
+export const getMyInfoReq = () => {
+  return request<any>('/medical/qualificationManage/getMyInfo', {
+    method: 'GET',
+  });
+};
+
+
+//新增用户附件信息数据
+export type AddTableDataType = {
+       
+}
+
+export const addData = (data:AddTableDataType) => {
+  return request('/medical/qualificationManage/saveDoctorAttachment', {
+    method: 'POST',
+    data
+  });
+};
+
+//编辑y用户附件信息数据
+export type EditTableDataType = {
+       
+}
+
+export const editData = (data:EditTableDataType) => {
+  return request('/medical/qualificationManage/editDoctorAttachment', {
+    method: 'POST',
+    data
+  });
+};
+
+//删除用户附件
+export const delData = (id:number) => {
+  return request('/medical/qualificationManage/deleteDoctorAttachment', {
+    method: 'POST',
+    params:{id}
+  });
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 542 - 0
src/pages/personalCenter/myQualifications/style.less

@@ -0,0 +1,542 @@
+.row-dragging {
+
+  .cost-ant-table-cell {
+    width: 130px;
+  }
+}
+
+.mrms-ant-popover {
+  .mrms-ant-popover-content {
+    .mrms-ant-popover-arrow {
+      display: none;
+    }
+  }
+}
+
+.MyQualifications-authDetailDrawer {
+  .authDetailDrawer-topBar {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 16px;
+
+    .authDetailDrawer-topBar-title {
+      font-weight: 500;
+      font-size: 16px;
+      color: #17181A;
+
+      .closeIcon {
+        position: relative;
+        top:2px;
+        display: inline-flex;
+        justify-content: center;
+        align-items: center;
+        width: 24px;
+        height: 24px;
+        cursor: pointer;
+        margin-right: 8px;
+        border-radius: 4px;
+        &:hover {
+          background-color: #E6EAF2;
+        }
+      }
+    }
+
+    .btnGroup {
+      &>span {
+        display: inline-block;
+        text-align: center;
+        cursor: pointer;
+        width: 56px;
+        height: 24px;
+        line-height: 21px;
+        margin-right: 8px;
+        font-weight: 400;
+        font-size: 14px;
+        color: #17181A;
+        background: #FAFCFF;
+        border-radius: 4px;
+        border: 1px solid #DAE2F2;
+
+        &.reject {
+          width: auto;
+          min-width: 56px;
+          color: #FFFFFF;
+          background: #FF4D6A;
+        }
+
+        &.commit {
+          width: auto;
+          min-width: 56px;
+          color: #FFFFFF;
+          background: #3377FF;
+        }
+
+        &:last-child {
+          margin-right: 0;
+        }
+      }
+    }
+  }
+
+
+  .authDetailDrawer-content {
+    .authDetailDrawer-info {
+      background: #FFFFFF;
+      padding: 16px;
+      border-radius: 4px;
+
+      .authDetailDrawer-info-title {
+        display: flex;
+        width: 100%;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        font-weight: bold;
+        font-size: 20px;
+        height: 20px;
+        line-height: 20px;
+        color: #17181A;
+        margin-bottom: 12px;
+      }
+
+      .authDetailDrawer-info-title-sub {
+        font-weight: 400;
+        font-size: 14px;
+        color: #525866;
+        line-height: 16px;
+
+        .authDetailDrawer-info-standard {
+          position: relative;
+          min-height: 56px;
+          background: #F7F9FC;
+          border-radius: 4px;
+          padding: 6px 12px;
+          font-weight: 400;
+          font-size: 14px;
+          color: #17181A;
+          line-height: 18px;
+          margin-top: 12px;
+          padding-right: 64px;
+          border: 1px solid #DAE4F2;
+
+          &>img {
+            position: absolute;
+            right: 12px;
+            top: 6px;
+            width: 40px;
+            height: 40px;
+
+          }
+        }
+      }
+    }
+
+    .authHistory {
+      background: #FFFFFF;
+      padding: 16px;
+      border-radius: 4px;
+      margin-top: 16px;
+
+      .authHistory-title {
+        font-weight: 500;
+        font-size: 16px;
+        height: 16px;
+        color: #17181A;
+        line-height: 16px;
+        margin-bottom: 12px;
+      }
+
+      .historyListWrapper {
+        .historyList {
+          position: relative;
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+          font-weight: 400;
+          font-size: 14px;
+          color: #17181A;
+          line-height: 21px;
+          height: 40px;
+          border-radius: 4px;
+          padding: 0 12px;
+          margin-bottom: 8px;
+          border: 1px dashed #CFD6E6;
+          background: #F7F8FA;
+
+          .status {
+            position: absolute;
+            top:8px;
+            right: 16px;
+            font-weight: 500;
+            font-size: 14px;
+            color: #17181A;
+            &::before {
+              position: relative;
+              content: '';
+              display: inline-block;
+              width: 8px;
+              height: 8px;
+              top:-1px;
+              border-radius: 50%;
+              margin-right: 4px;
+              background: #FF4D6A;
+            }
+            &.authing {
+              &::before {
+                background: #FFB54D;
+              }
+            }
+          }
+
+          &>img {
+            width: 16px;
+            height: 16px;
+            margin-right: 8px;
+          }
+
+          &:first-child {
+            background: #fff;
+          }
+
+
+        }
+      }
+    }
+  }
+
+}
+
+.MyQualifications {
+
+  .pageContent {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: flex-start;
+    width: 100%;
+
+
+    .left {
+      border-radius: 4px;
+      background: #FFFFFF;
+      padding: 16px;
+      width: calc(100% - 416px);
+      min-width: 675px;
+      height: calc(100vh - 80px);
+
+      .pageContent-title {
+        font-weight: 500;
+        font-size: 16px;
+        height: 16px;
+        color: #17181A;
+        line-height: 16px;
+        margin-bottom: 16px;
+      }
+
+      .toolBar {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+
+        .filter {
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+
+          .filterItem {
+            display: flex;
+            flex-direction: row;
+            justify-content: center;
+            align-items: center;
+          }
+        }
+
+        .btnGroup {
+          .batchAdjust {
+            cursor: pointer;
+            display: inline-block;
+            font-size: 14px;
+            font-weight: 400;
+            color: #FFFFFF;
+            line-height: 24px;
+            padding: 0 14px;
+            background: #3377FF;
+            border-radius: 4px;
+          }
+        }
+
+      }
+    }
+
+    .right {
+      width: 400px;
+      background: #FFFFFF;
+      border-radius: 4px;
+      padding: 16px;
+      padding-top: 24px;
+      margin-left: 16px;
+      background-image: url('../../../../static/gerenziliaobeijing.png');
+      background-position: top top;
+      background-repeat: no-repeat;
+      background-size: contain;
+
+      .avatar-info {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        margin-bottom: 8px;
+
+        &>img {
+          width: 56px;
+          height: 56px;
+          border-radius: 50%;
+          margin-right: 16px;
+          border: 1px solid #FFFFFF;
+        }
+
+        .name {
+          .name-text {
+            font-weight: bold;
+            height: 20px;
+            font-size: 20px;
+            color: #17181A;
+            line-height: 20px;
+            margin-right: 8px;
+            margin-bottom: 6px;
+
+            &>img {
+              position: relative;
+              top: -3px;
+              width: 16px;
+              height: 16px;
+              margin-left: 8px;
+            }
+          }
+
+          &>img {
+            width: 16px;
+            height: 16px;
+          }
+
+          .id {
+            font-weight: 400;
+            font-size: 14px;
+            height: 14px;
+            color: #525866;
+            line-height: 14px;
+          }
+        }
+      }
+
+      .jobInfo {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 8px;
+
+        .jobInfo-block {
+          display: flex;
+          flex-direction: column;
+          width: 120px;
+          height: 70px;
+          justify-content: center;
+          align-items: center;
+
+          .value {
+            font-weight: 500;
+            font-size: 16px;
+            color: #3D6DCC;
+            height: 16px;
+            line-height: 16px;
+            margin-bottom: 8px;
+          }
+
+          .label {
+            font-weight: 400;
+            font-size: 14px;
+            height: 14px;
+            color: #525866;
+            line-height: 14px;
+          }
+
+          &:nth-child(2) {
+            position: relative;
+
+            &::before {
+              position: absolute;
+              left: 0;
+              top: 15px;
+              content: '';
+              display: inline-block;
+              width: 1px;
+              height: 40px;
+              border-left: 1px solid #DAE2F2;
+            }
+
+            &::after {
+              position: absolute;
+              content: '';
+              right: 0;
+              top: 15px;
+              display: inline-block;
+              width: 1px;
+              height: 40px;
+              border-right: 1px solid #DAE2F2;
+            }
+
+          }
+        }
+      }
+
+      .qualifi-info-title {
+        position: relative;
+        margin-bottom: 12px;
+
+        &>span {
+          position: relative;
+          display: inline-block;
+          font-weight: 500;
+          font-size: 16px;
+          height: 16px;
+          color: #17181A;
+          line-height: 16px;
+          z-index: 2;
+        }
+
+        &::after {
+          position: absolute;
+          z-index: 1;
+          left: 0;
+          bottom: 3px;
+          content: '';
+          display: block;
+          width: 80px;
+          height: 6px;
+          background: linear-gradient(90deg, #B3D2FF 0%, #FFFFFF 100%);
+        }
+      }
+
+      .qualifi-info-detail {
+        .qualifi-info-list {
+          font-weight: 400;
+          font-size: 14px;
+          color: #525866;
+          height: 14px;
+          line-height: 14px;
+          padding: 0 12px;
+          margin-bottom: 12px;
+
+          &>span {
+            color: #17181A;
+          }
+
+          &:last-child {
+            margin-bottom: 0;
+          }
+        }
+      }
+
+      .attachment-title {
+        position: relative;
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 12px;
+        margin-top: 24px;
+
+        &>span {
+          position: relative;
+          z-index: 2;
+          display: inline-block;
+          font-weight: 500;
+          font-size: 16px;
+          height: 16px;
+          color: #17181A;
+          line-height: 16px;
+        }
+
+        &>a {}
+
+        &::after {
+          position: absolute;
+          z-index: 1;
+          left: 0;
+          bottom: 3px;
+          content: '';
+          display: block;
+          width: 80px;
+          height: 6px;
+          background: linear-gradient(90deg, #B3D2FF 0%, #FFFFFF 100%);
+        }
+      }
+
+      .attachment-detail {
+        .attachment-detail-list {
+          position: relative;
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+          width: 368px;
+          height: 48px;
+          background: #F7F9FC;
+          border-radius: 4px;
+          padding: 12px;
+          margin-bottom: 8px;
+
+          &>img {
+            width: 20px;
+            height: 20px;
+            margin-right: 8px;
+          }
+
+          .attachment-detail-list-info {
+            .attachment-list-name {
+              font-weight: 500;
+              font-size: 14px;
+              height: 14px;
+              color: #17181A;
+              line-height: 14px;
+              margin-bottom: 4px;
+            }
+
+            .attachment-list-subText {
+              font-weight: 400;
+              font-size: 12px;
+              height: 12px;
+              color: #7A8599;
+              line-height: 12px;
+            }
+          }
+
+          .more {
+            position: absolute;
+            display: inline-block;
+            top: 16px;
+            right: 19px;
+            width: 16px;
+            height: 16px;
+            cursor: pointer;
+            font-size: 18px;
+            color: #17181A;
+            transform: rotate(270deg);
+          }
+
+          &:last-child {
+            margin-bottom: 0px;
+          }
+        }
+      }
+    }
+
+  }
+
+}

+ 48 - 0
src/pages/personalCenter/myQualifications/tabs/index.tsx

@@ -0,0 +1,48 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-12-16 11:34:53
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-12-16 14:11:05
+ * @FilePath: /MediResourceManaSys/src/pages/qualificationMana/qualificationExperiedMana/tabs/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+import React, { useState, FC } from 'react';
+import './style.less';
+
+interface FormTabsProps {
+  value?: string; // 当前选中的值
+  width?:number;
+  onChange?: (value: string) => void; // 值变化的回调函数
+}
+
+const FormTabs: FC<FormTabsProps> = ({ value = 'time', onChange,width=80 }) => {
+  const [activeTab, setActiveTab] = useState<string>(value);
+
+  const handleTabChange = (tab: string) => {
+    setActiveTab(tab);
+    if (onChange) {
+      onChange(tab); // 通知外部表单值更新
+    }
+  };
+
+  return (
+    <div className="form-tabs-container" style={{width:width}}>
+      <div className="tab-buttons">
+        <div
+          className={`tab-button ${activeTab === 'time' ? 'active' : ''}`}
+          onClick={() => handleTabChange('time')}
+        >
+          按授权时间
+        </div>
+        <div
+          className={`tab-button ${activeTab === 'days' ? 'active' : ''}`}
+          onClick={() => handleTabChange('days')}
+        >
+          按延期天数
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default FormTabs;

+ 40 - 0
src/pages/personalCenter/myQualifications/tabs/style.less

@@ -0,0 +1,40 @@
+.form-tabs-container {
+    .tab-buttons {
+        display: flex;
+        width: 100%;
+        flex-direction: row;
+        justify-content: center;
+        align-items: center;
+
+
+        .tab-button {
+            width: 50%;
+            text-align: center;
+            height: 24px;
+            line-height: 21px;
+            font-weight: 400;
+            font-size: 14px;
+            color: #17181A;
+            cursor: pointer;
+            border: 1px solid #DAE2F2;
+
+            &.active {
+                line-height: 24px;
+                color: #FFFFFF;
+                border:none;
+                background: #3377FF;
+            }
+
+            &:nth-child(1){
+                border-right: none;
+                border-top-left-radius: 4px;
+                border-bottom-left-radius: 4px;
+            }
+            &:nth-child(2){
+                border-left: none;
+                border-top-right-radius: 4px;
+                border-bottom-right-radius: 4px;
+            }
+        }
+    }
+}

+ 65 - 0
src/pages/qualificationMana/doctorQualifiAuth/authHisttory/index.tsx

@@ -0,0 +1,65 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-12-06 14:42:57
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-12-10 16:58:39
+ * @FilePath: /MediResourceManaSys/src/pages/qualificationMana/qualificationAuth/authHisttory/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AEi m z z
+ */
+
+
+import { createFromIconfontCN } from '@ant-design/icons';
+import React, { Children } from 'react'
+import { Timeline } from 'antd'
+import './style.less'
+import { authTimeType } from '@/constant';
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+export default function AuthHisContent({ hisList }: { hisList: any[] }) {
+
+    const getPeriodStr = (code:number)=>{
+        const result = authTimeType.filter((a)=>a.value == code);
+        if(result.length>0){
+            return result[0].label
+        }
+        return undefined
+    }
+
+    const dotNode = (isActive=false)=>{
+        return <div style={{display:'flex',justifyContent:'center',alignItems:'center',width:16,height:16,border:'2px solid #E7EBF2',borderRadius:'50%'}}>
+            {isActive&&<div style={{width:8,height:8,background:'#363F4D',borderRadius:'50%'}}></div>}
+        </div>
+    }
+    return (
+        <div className='AuthHisContent'>
+            <div className='AuthHisContent-title'>
+                <IconFont type={'icon-qingliangtishi'} style={{ paddingRight:12 }} />调整历史
+            </div>
+            <div className='AuthHisContent-content'>
+                <Timeline>
+                    {
+                        hisList.map((a,index)=>{
+                             return (
+                                <Timeline.Item key={index} dot={dotNode(index == 0?true:false)} >
+                                      <div style={{fontWeight:'bold',fontSize:14,color:'#17181A',height:14,lineHeight:'14px',marginBottom:8}}>{`${a.adjustUserName} ${a.adjustTime}`}</div>
+                                      <div style={{height:14,fontSize:12,color:'#176DE6',lineHeight:'14px',marginBottom:8,paddingLeft:6}}>
+                                        <img style={{width:43,height:14,marginRight:4}} src={require('../../../../../static/tiaozhenghou.png')} />{getPeriodStr(a.qualificationPeriodAfter)} {`(${a.beginDateAfter}至${a.endDateAfter})`}
+                                      </div>
+                                      <div style={{height:14,fontSize:12,color:'#525866',lineHeight:'14px',marginBottom:8,paddingLeft:6}}>
+                                        <img style={{width:43,height:14,marginRight:4}} src={require('../../../../../static/tiaozhengqian.png')} />
+                                        {getPeriodStr(a.qualificationPeriodBefore)} {`(${a.beginDateBefore}至${a.endDateBefore})`}
+                                      </div>
+                                      {(a.memo&&a.memo.length>0)&&<div style={{padding:'5px 8px',fontSize:12,color:'#525866',background:'#F7F9FC',borderRadius:4}}>{a.memo}</div>}
+                                </Timeline.Item>
+                             )
+                        })
+                    }
+                </Timeline>
+            </div>
+        </div>
+    )
+}

+ 35 - 0
src/pages/qualificationMana/doctorQualifiAuth/authHisttory/style.less

@@ -0,0 +1,35 @@
+
+
+.AuthHisContent {
+    width: 400px;
+   
+    .AuthHisContent-title {
+        font-weight: 500;
+        font-size: 16px;
+        height: 16px;
+        color: #17181A;
+        line-height: 16px;
+    }
+    .AuthHisContent-content {
+        max-height: 400px;
+        overflow: scroll;
+        overflow-x: hidden;
+        padding-top: 24px;
+
+        .mrms-ant-timeline-item {
+            &.mrms-ant-timeline-item-last {
+                padding-bottom: 0;
+            }
+        }
+        .mrms-ant-timeline-item-tail {
+            left:8px;
+        }
+        .mrms-ant-timeline-item-head-custom {
+            top:0.5px;
+            left:9px;
+        }
+        .mrms-ant-timeline-item-content {
+            margin: 0 0 0 35px;
+        }
+    }
+}

+ 579 - 0
src/pages/qualificationMana/doctorQualifiAuth/index.tsx

@@ -0,0 +1,579 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 11:30:33
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-12-31 14:25:56
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+
+
+
+import KCIMPagecontainer from '@/components/KCIMPageContainer';
+import { KCIMTable } from '@/components/KCIMTable';
+import { createFromIconfontCN } from '@ant-design/icons';
+
+import { ActionType, arrayMoveImmutable, ProFormText, ProFormTextArea, useRefFunction } from '@ant-design/pro-components';
+import ProForm, { ModalForm, ProFormCascader, ProFormCheckbox, ProFormDateRangePicker, ProFormDependency, ProFormDigit, ProFormRadio, ProFormSelect, ProFormSwitch } from '@ant-design/pro-form'
+import { ProColumns } from '@ant-design/pro-table';
+import { Drawer, Input, message, Popconfirm, Popover, Switch, Tooltip } from 'antd';
+import { Fragment, Key, useEffect, useRef, useState } from 'react';
+import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
+
+
+import { editData, getDepartmentDataReq, getTableDataReq, reAuthData } from './service';
+
+import './style.less';
+import { KCIMLeftList } from '@/components/KCIMLeftList';
+import { getTableList as getQualClassReq } from '../qualificationClassfiMana/service';
+import { getDicDataBySysId } from '@/services/getDic';
+import { authTimeType, KcimCenterSysId } from '@/constant';
+import TableTransfer from './transform';
+import React from 'react';
+import 'moment/locale/zh-cn';
+import moment from 'moment';
+import AuthHisContent from './authHisttory';
+import { buildTree } from '@/utils/format';
+import { useAccess } from '@umijs/max';
+
+
+
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+
+
+export default function QualificationAuth({ isChildComponent = false, qualifiCode, onTableSelectChange, defaultSelectedKeys }: {
+    isChildComponent: boolean, qualifiCode: string, onTableSelectChange?: (selectedRowKeys: any[], selectedRows: any[], info: any) => void,
+    defaultSelectedKeys?: Key[]
+}) {
+
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
+    const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
+    const [dataSource, set_dataSource] = useState<any[]>([]);
+
+    const SortableItem = SortableElement((props: any) => <tr {...props} />);
+    const SortContainer = SortableContainer((props: any) => <tbody {...props} />);
+    const [currentSelectedType, set_currentSelectedType] = useState<any | undefined>(undefined);
+    const [operationLevel, set_operationLevel] = useState<any[]>([]);
+    const [drawerVisible, set_drawerVisible] = useState(false);
+    const [currentEditRow, set_currentEditRow] = useState<any>(undefined);
+    const [currentPageTableData, set_currentPageTableData] = useState<any[]>([]);
+
+    const tableRef = useRef<ActionType>();
+    const drawerTableRef = useRef<ActionType>();
+    const [drawerTableData, set_drawerTableData] = useState<any[]>([]);
+    const [ifeditQualifiInfo, set_ifeditQualifiInfo] = useState(false);
+
+    const access = useAccess();
+    const tabs = access.whatCanIDoInThisPage(location.pathname.replace('/MediResourceManaSys', ''));
+    const a = tabs.reduce((prev: any, cur: any) => `${prev},${cur.code}`, '');
+
+    const columns: ProColumns[] = [
+        {
+            title: '医生姓名',
+            width: 100,
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                const { userInfo: { name } } = record;
+                return name
+            },
+        },
+        {
+            title: '工号',
+            width: 100,
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                const { userInfo: { id } } = record;
+                return id
+            },
+        },
+        {
+            title: '所在科室',
+            ellipsis: true,
+            width: 120,
+            renderText(text, record, index, action) {
+                const { userInfo: { deptName } } = record;
+                return deptName
+            },
+        },
+        {
+            title: '资质权限',
+            ellipsis: true,
+            dataIndex: 'qualificationList'
+
+        },
+        {
+            title: '操作',
+            key: 'option',
+            width: 60,
+            fixed: 'right',
+            valueType: 'option',
+            render: (_: any, record: any) => {
+                return [
+                    <a key={'detailBtn'} onClick={() => {
+                        set_currentEditRow(record);
+                        set_drawerVisible(true);
+                    }}>详情</a>
+                ]
+            },
+        },
+
+    ];
+    const drawerTablecolumns: ProColumns[] = [
+        {
+            title: '资质编码',
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                const { qualificationInfo: { code } } = record;
+                return code;
+            },
+        },
+        {
+            title: '资质名称',
+            renderText(text, record, index, action) {
+                const { qualificationInfo: { name,standard } } = record;
+                return <>{name}{(standard&&standard.length>0)&&<Tooltip title={`授权依据:${standard}`}><IconFont style={{marginLeft:10,fontSize:16,position:'relative',top:1}} type={'iconchakan'} /></Tooltip>}</>;
+            },
+        },
+        {
+            title: '授权期限',
+            ellipsis: true,
+            width:80,
+            dataIndex: 'qualificationPeriod',
+            renderText(text, record, index, action) {
+                const result = authTimeType.filter((a) => a.value == text);
+                if (result.length > 0) {
+                    return result[0].label
+                }
+            },
+
+        },
+        {
+            title: '授权时间',
+            width: 260,
+            renderText(text, record, index, action) {
+                const { beginDate, endDate, applyAdjust } = record;
+                const content = <AuthHisContent hisList={[...applyAdjust]} />
+
+                return <>{`${beginDate}至${endDate}`}
+                    {applyAdjust.length > 0 && (
+                        <Popover className='qualificationAuth-popover' overlayInnerStyle={{borderRadius:4}} content={content} title={false} >
+                            <IconFont type={'icon-qingliangtishi'} style={{ marginLeft: 10}} />
+                        </Popover>
+                    )}</>;
+            },
+        },
+        {
+            title: '特殊类别',
+            ellipsis: true,
+            width: 150,
+            renderText(text, record, index, action) {
+                const { qualificationInfo: { operationFlag, techFlag, operationLevelCode, operationLevelName } } = record;
+                return <div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center' }}>
+                    {
+                        techFlag == 1 && (
+                            <span style={{
+                                display: 'inline-flex', width: 64, height: 20, justifyContent: 'center',
+                                alignItems: 'center', background: '#FFF5EB', borderRadius: 4, fontSize: 12, color: '#FF8000', marginRight: 4
+                            }}>医疗技术</span>
+                        )
+                    }
+                    {
+                        operationFlag == 1 && (
+                            <span style={{
+                                display: 'inline-flex', width: 64, height: 20, justifyContent: 'center',
+                                alignItems: 'center', background: '#E8FCF6', borderRadius: 4, fontSize: 12, color: '#009966'
+                            }}>{
+                                    operationLevelName
+                                    // (operationLevel.filter((a) => a.value == operationLevelCode)).length>0?(operationLevel.filter((a) => a.value == operationLevelCode))[0].name:''
+                                }</span>
+                        )
+                    }
+                    {
+                        (!operationFlag && !techFlag) && (<Fragment />)
+                    }
+                </div>
+            },
+        },
+        {
+            title: '当前状态',
+            width:80,
+            ellipsis: true,
+            dataIndex: 'currentStatus',
+            renderText(text, record, index, action) {
+                    if (text == '授权中') {
+                        return <><span style={{ display: 'inline-block', width: 8, height: 8, borderRadius: '50%', marginRight: 4, background: '#FFB54D' }}></span>{text}</>
+                    }
+                    if (text == '已过期') {
+                        return <><span style={{ display: 'inline-block', width: 8, height: 8, borderRadius: '50%', marginRight: 4, background: '#FF4D6A' }}></span>{text}</>
+                    }
+            },
+        },
+        {
+            title: '操作',
+            key: 'option',
+            width: 100,
+            hideInTable:a.indexOf('medical-adjust') == -1,
+            fixed: 'right',
+            valueType: 'option',
+            render: (_: any, record: any) => {
+                const { currentStatus,allowReAuthorize } = record;
+                return [
+                    currentStatus == '授权中' ? <UpDataActBtn key={'act'} record={record} type='EDIT' /> :allowReAuthorize == 1&&<UpDataActBtn key={'act'} record={record} type='AUTH' />,
+                ]
+            },
+        },
+
+    ]
+
+
+    const getTableData = async (params: any) => {
+        const { qualificationTypeCode } = params;
+        const resp = await getTableDataReq(params);
+        if (resp) {
+            const data = (resp.list).map((a: any, index: number) => ({ id: index, ...a }));
+            set_currentPageTableData(data);
+            return {
+                data,
+                success: true
+            }
+        } else {
+            return []
+        }
+    }
+
+
+    const updateTable = async (formVal: any, type: 'EDIT' | 'AUTH') => {
+        try {
+            if (type == 'EDIT') {
+
+                const resp = await editData({
+                    qualificationApplyId: formVal.id,
+                    qualificationPeriod: Number(formVal.qualificationPeriod),
+                    beginDate: formVal.timerange[0],
+                    endDate: formVal.timerange[1],
+                    memo: formVal.memo
+                });
+                if (resp) {
+                    tableRef.current?.reload();
+                    message.success('操作成功!');
+                }
+            } else {
+                const resp = await reAuthData({
+                    qualificationApplyId: formVal.id,
+                    qualificationPeriod: Number(formVal.qualificationPeriod),
+                    beginDate: formVal.timerange[0],
+                    endDate: formVal.timerange[1],
+                    memo: formVal.memo
+                });
+                if (resp) {
+                    tableRef.current?.reload();
+                    message.success('操作成功!');
+                }
+            }
+
+            return true;
+
+        } catch (error) {
+
+            console.log({ error });
+            return false;
+        }
+
+
+
+
+    }
+
+    const formRef = useRef();
+    const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'AUTH' }) => {
+        const ref = React.createRef<{ save: any; }>();
+        return (
+            <ModalForm
+                title={type == 'EDIT' ? '调整授权' : '重新授权'}
+                width={352}
+                formRef={formRef}
+                initialValues={{
+                    // memo: record.applyMemo,
+                    qualificationPeriod: 1,
+                    timerange: [moment().startOf("day"), moment().startOf("day")]
+                }}
+                trigger={
+                    type == 'EDIT' ? <a key="edit" >调整</a> : <a className='auth'>重新授权</a>
+                }
+                onFinish={(val) => {
+                    return updateTable(type == 'EDIT' ? { ...record, ...val } : { ...record, ...val }, type);
+                }}
+                modalProps={{ destroyOnClose: true }}
+                colProps={{ span: 24 }}
+                grid
+            >
+
+                <ProFormRadio.Group label='授权期限:' name={'qualificationPeriod'} options={authTimeType} />
+                <ProFormDateRangePicker label='授权时间:' name='timerange' />
+                <ProFormTextArea label='调整原因:' name={'memo'} />
+
+            </ModalForm>
+        )
+    }
+
+    const tableDataSearchHandle = (key: string) => {
+        set_tableDataFilterParams({ ...tableDataFilterParams, current: 1, [key]: tableDataSearchKeywords })
+    }
+
+    const getDepartmentsHandle = async () => {
+        const resp = await getDepartmentDataReq();
+        if (resp) {
+            set_dataSource(resp);
+        }
+    }
+
+    const updateTableSortHandle = async (data: any[]) => {
+
+    }
+
+    const onSortEnd = useRefFunction(
+        ({ oldIndex, newIndex }: { oldIndex: number; newIndex: number }) => {
+            if (oldIndex !== newIndex) {
+                const newData = arrayMoveImmutable({
+                    array: [...dataSource],
+                    fromIndex: oldIndex,
+                    toIndex: newIndex,
+                }).filter((el) => !!el);
+
+                const updatedSortArr = newData.map((item: any, index: number) => ({ ...item, sort: index + 1 }));
+                set_dataSource([...updatedSortArr]);
+                updateTableSortHandle(updatedSortArr);
+            }
+        },
+    );
+
+    const DraggableContainer = (props: any) => (
+        <SortContainer
+            useDragHandle
+            disableAutoscroll
+            helperClass="row-dragging"
+            onSortEnd={onSortEnd}
+            {...props}
+        />
+    );
+
+    const DraggableBodyRow = (props: any) => {
+        const { className, style, ...restProps } = props;
+
+        // function findIndex base on Table rowKey props and should always be a right array index
+        const index = dataSource.findIndex((x) => x.id === restProps['data-row-key']);
+
+        return <SortableItem index={index} {...restProps} />;
+    };
+
+
+    useEffect(() => {
+        if (currentSelectedType && !isChildComponent) {
+            // getTableData({ qualificationTypeCode: currentSelectedType.code });
+            set_tableDataFilterParams({ ...tableDataFilterParams, current: 1, deptCode: currentSelectedType.code })
+        }
+    }, [currentSelectedType]);
+
+    useEffect(() => {
+        if (isChildComponent && qualifiCode) {
+            set_currentSelectedType(true);
+            set_tableDataFilterParams({ ...tableDataFilterParams, current: 1, qualificationTypeCode: qualifiCode })
+        }
+    }, [qualifiCode]);
+
+    useEffect(() => {
+        if (currentEditRow) {
+            set_drawerTableData([
+                ...currentEditRow.applyList,
+            ]);
+        }
+    }, [currentEditRow]);
+
+    useEffect(() => {
+        if (currentPageTableData && drawerVisible) {
+            const needitem = currentPageTableData.filter((a) => a.userInfo.id == currentEditRow.userInfo.id);
+        
+            if (needitem.length > 0) {
+                set_currentEditRow(needitem[0]);
+            }
+
+        }
+    }, [currentPageTableData])
+
+    useEffect(() => {
+        getDepartmentsHandle()
+    }, [])
+
+    return (
+        <KCIMPagecontainer className='QualificationAuth' style={!isChildComponent ? {} : { border: 'none' }} title={false}>
+            <Drawer destroyOnClose={true} className='doctorQualifiAuth-authDetailDrawer' width={1100}
+                open={drawerVisible} headerStyle={{ display: 'none' }} bodyStyle={{ background: '#F5F7FA', padding: 16 }}
+            >
+                <div className='authDetailDrawer-topBar'>
+                    <div className='authDetailDrawer-topBar-title'>
+                        <div className='closeIcon' onClick={() => set_drawerVisible(false)}><IconFont  type={'iconquxiao'} /></div>{'授权详情'}
+                    </div>
+                    {/* <div className='btnGroup'>
+                        <span onClick={() => set_drawerVisible(false)}>取消</span>
+                        <span className='reject' onClick={() => updateTable(2)}>驳回</span>
+                        <span className='commit' onClick={() => updateTable(1)}>通过</span>
+                    </div> */}
+                </div>
+                <div className='authDetailDrawer-content'>
+                    <div className='authDetailDrawer-info'>
+                        <div className='avator'><img src={(currentEditRow?.userInfo?.avatarUrl)?currentEditRow?.userInfo?.avatarUrl:require('../../../../static/avatar.png')} alt="avator" /></div>
+                        <div className='authDetailDrawer-info-detail'>
+                            <div className='authDetailDrawer-info-title'>
+                                {currentEditRow?.userInfo?.name}
+                                <img style={{ width: 16, height: 16, marginLeft: 8 }} src={require(`../../../../static/${currentEditRow?.userInfo?.gender == '男' ? 'male' : 'female'}.png`)} alt="" />
+                            </div>
+                            <div className='authDetailDrawer-info-title-sub'>
+                                工号:{currentEditRow?.userInfo?.id}<span style={{ padding: '0 8px' }}></span>
+                                科室:{currentEditRow?.userInfo?.deptName}<span style={{ padding: '0 8px' }}></span>
+                                职称:{currentEditRow?.userInfo?.jobTitle}<span style={{ padding: '0 8px' }}></span>
+                                职务:{currentEditRow?.userInfo?.title}
+                            </div>
+                        </div>
+
+                    </div>
+                    <div className='authDetailDrawer-qualication-info'>
+                        <div className='authDetailDrawer-qualication-info-title'>资质信息
+                            {/* <span>
+                                {!ifeditQualifiInfo && <a onClick={() => set_ifeditQualifiInfo(true)}>编辑</a>}
+                                {ifeditQualifiInfo && <><a onClick={() => set_ifeditQualifiInfo(true)} style={{ paddingRight: 8 }}>取消</a><a onClick={() => set_ifeditQualifiInfo(true)}>保存</a></>}
+                            </span> */}
+                        </div>
+                        {
+                            !ifeditQualifiInfo && (<>
+                                <div className='authDetailDrawer-qualication-info-tag-wrapper'>
+                                    <div className='qualication-info-tag'>资质证号:<span>{currentEditRow?.userInfo?.qualificationCertificateNo}</span></div>
+                                    <div className='qualication-info-tag'>执业类别:<span>{currentEditRow?.userInfo?.practiceCate}</span></div>
+                                    <div className='qualication-info-tag'>执业证号:<span>{currentEditRow?.userInfo?.practiceCertificateNo}</span></div>
+                                    <div className='qualication-info-tag'>执业专业:<span>{currentEditRow?.userInfo?.major}</span></div>
+                                    <div className='qualication-info-tag'>医师级别:<span>{currentEditRow?.userInfo?.doctorLevel}</span></div>
+
+                                </div>
+                            </>)
+                        }
+                        {
+                            ifeditQualifiInfo && (<>
+                                <ProForm layout='vertical' submitter={false} grid>
+                                    <ProFormText colProps={{ md: 12, xl: 8 }} label='资格证号:' />
+                                    <ProFormText colProps={{ md: 12, xl: 8 }} label='执业类别:' />
+                                    <ProFormText colProps={{ md: 12, xl: 8 }} label='执业证号:' />
+                                    <ProFormText colProps={{ md: 12, xl: 8 }} label='执业专业:' />
+                                    <ProFormText colProps={{ md: 12, xl: 8 }} label='医师级别:' />
+                                </ProForm>
+                            </>)
+                        }
+
+
+                        <div className='authDetailDrawer-qualication-info-certs'>
+                            {
+                                currentEditRow?.userInfo?.attachments?.map((item: any, index: number) => {
+                                    return (
+                                        <div key={index} className='qualificationInfo-fileItem'>
+                                            <img src={require('../../../../static/fileIcon.png')} alt="" />
+                                            <div className='qualificationInfo-fileItem-detail'>
+                                                <div className='qualificationInfo-fileItem-detail-name'>{item.fileName}</div>
+                                                <div className='qualificationInfo-fileItem-detail-sub'>{item.description}</div>
+                                            </div>
+                                            <Tooltip title='下载'>
+                                                <a className='downloadBtn' href={item.url} target='_blank' ><IconFont style={{color:'#17181A'}} type={'iconxiazai'} /></a>
+                                            </Tooltip>
+                                        </div>
+                                    )
+                                })
+                            }
+                        </div>
+                    </div>
+                    <div className='authDetailDrawer-content-table'>
+                        <div className='authDetailDrawer-content-table-title'>授权信息</div>
+                        <KCIMTable
+                            actionRef={drawerTableRef} columns={drawerTablecolumns as ProColumns[]} rowKey='id'
+                            // request={(params) => getTableData(params)}
+                            dataSource={drawerTableData}
+                            tableAlertRender={false}
+                            scroll={{ y: 361 }}
+                        />
+                    </div>
+
+                </div>
+
+
+            </Drawer>
+            <div className='pageContent'>
+                {
+                    !isChildComponent && (
+                        <div className='left'>
+                            <KCIMLeftList searchKey={'name'} dataSource={dataSource} fieldNames={{ title: 'name', key: 'code' }}
+                                defaultSelectType='node'
+                                listType='tree' onChange={(val) => set_currentSelectedType(val)} />
+                        </div>
+                    )
+                }
+                <div className='right' style={isChildComponent ? { width: '100%' } : { width: 'calc(100% - 236px)', padding: 16 }}>
+                    <div className='toolBar'>
+                        <div className='filter'>
+                            <div className='filterItem'>
+                                <span className='label'>检索:</span>
+                                <Input placeholder={'医生名称'} style={{ width: 160, marginRight: 16 }} allowClear autoComplete='off'
+
+                                    suffix={
+                                        <IconFont style={{ color: '#99A6BF' }} type="iconsousuo" onClick={() => tableDataSearchHandle('userName')} />
+                                    }
+                                    onChange={(e) => {
+                                        set_tableDataSearchKeywords(e.target.value);
+                                        if (e.target.value.length == 0) {
+                                            set_tableDataSearchKeywords('');
+                                            set_tableDataFilterParams({...tableDataFilterParams,userName:undefined})
+                                        }
+                                    }}
+
+                                    onPressEnter={(e) => {
+                                        tableDataSearchHandle('userName')
+                                    }}
+
+                                />
+                            </div>
+                        </div>
+                        {/* {!isChildComponent && (
+                            <div className='btnGroup'>
+                                <UpDataActBtn record type='ADD' />
+                            </div>
+                        )} */}
+                    </div>
+                    <div style={{ marginTop: 16 }}>
+                        {currentSelectedType && <KCIMTable scroll={{ y: `calc(100vh - 230px)` }}
+                            actionRef={tableRef} columns={columns as ProColumns[]} rowKey='id'
+                            params={tableDataFilterParams}
+                            request={(params) => getTableData(params)}
+                            // dataSource={showList}
+                            tableAlertRender={false}
+                            rowSelection={isChildComponent ? {
+                                defaultSelectedRowKeys: defaultSelectedKeys,
+                                onChange(selectedRowKeys, selectedRows, info) {
+                                    onTableSelectChange && onTableSelectChange(selectedRowKeys, selectedRows, info)
+                                },
+                            } : false}
+                            components={{
+                                body: {
+                                    wrapper: DraggableContainer,
+                                    row: DraggableBodyRow,
+                                },
+                            }}
+                        />}
+                    </div>
+                </div>
+            </div>
+        </KCIMPagecontainer>
+    )
+}

+ 69 - 0
src/pages/qualificationMana/doctorQualifiAuth/service.ts

@@ -0,0 +1,69 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 16:31:27
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-12-11 10:17:02
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+import { request } from 'umi';
+
+//获取table列表数据
+
+export const getTableDataReq = (params?:any) => {
+  return request<any>('/medical/qualificationManage/listByDoctor', {
+    method: 'GET',
+    params:{...params}
+  });
+};
+
+//获取科室列表
+
+export const getDepartmentDataReq = (params?:any) => {
+  return request<any>('/medical/qualificationManage/listAllDepartment', {
+    method: 'GET',
+    params:{...params}
+  });
+};
+
+
+
+
+
+//编辑表格数据
+
+export type EditTableDataType = {
+ 
+}
+
+export const editData = (data:EditTableDataType) => {
+  return request('/medical/qualificationManage/adjust', {
+    method: 'POST',
+    data
+  });
+};
+//重新授权
+export const reAuthData = (data:EditTableDataType) => {
+  return request('/medical/qualificationManage/reAuthorize', {
+    method: 'POST',
+    data
+  });
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 372 - 0
src/pages/qualificationMana/doctorQualifiAuth/style.less

@@ -0,0 +1,372 @@
+.row-dragging {
+
+  .cost-ant-table-cell {
+    width: 130px;
+  }
+}
+
+.mrms-ant-popover {
+  .mrms-ant-popover-content {
+    .mrms-ant-popover-arrow {
+      display: none;
+    }
+  }
+}
+
+.doctorQualifiAuth-authDetailDrawer {
+  .authDetailDrawer-topBar {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 16px;
+
+    .authDetailDrawer-topBar-title {
+      font-weight: 500;
+      font-size: 16px;
+      color: #17181A;
+      .closeIcon {
+        position: relative;
+        top:2px;
+        display: inline-flex;
+        justify-content: center;
+        align-items: center;
+        width: 24px;
+        height: 24px;
+        cursor: pointer;
+        margin-right: 8px;
+        border-radius: 4px;
+        &:hover {
+          background-color: #E6EAF2;
+        }
+      }
+    }
+
+    .btnGroup {
+      &>span {
+        display: inline-block;
+        text-align: center;
+        cursor: pointer;
+        width: 56px;
+        height: 24px;
+        line-height: 21px;
+        margin-right: 8px;
+        font-weight: 400;
+        font-size: 14px;
+        color: #17181A;
+        background: #FAFCFF;
+        border-radius: 4px;
+        border: 1px solid #DAE2F2;
+
+        &.reject {
+          width: auto;
+          min-width: 56px;
+          color: #FFFFFF;
+          background: #FF4D6A;
+        }
+
+        &.commit {
+          width: auto;
+          min-width: 56px;
+          color: #FFFFFF;
+          background: #3377FF;
+        }
+
+        &:last-child {
+          margin-right: 0;
+        }
+      }
+    }
+  }
+
+  .authDetailDrawer-qualication-info {
+    background: #FFFFFF;
+    padding: 16px;
+    border-radius: 4px;
+    margin-top: 16px;
+
+    .authDetailDrawer-qualication-info-title {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+      font-weight: 500;
+      font-size: 16px;
+      height: 16px;
+      color: #17181A;
+      line-height: 16px;
+      margin-bottom: 16px;
+
+      &>span>a {
+        font-size: 14px;
+      }
+    }
+
+    .authDetailDrawer-qualication-info-tag-wrapper {
+      display: flex;
+      flex-wrap: wrap;
+      width: 100%;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+
+      .qualication-info-tag {
+        width: 32.8%;
+        font-weight: 400;
+        height: 14px;
+        font-size: 14px;
+        color: #525866;
+        line-height: 14px;
+        margin-right: 0.7%;
+        margin-bottom: 12px;
+
+        &>span {
+          color: #17181A;
+        }
+        &:nth-child(3n){
+            margin-right: 0;
+        }
+      }
+    }
+
+    .authDetailDrawer-qualication-info-certs {
+      display: flex;
+      flex-direction: row;
+      flex-wrap: wrap;
+      justify-content: flex-start;
+      align-items: center;
+      margin-top: 4px;
+
+      .qualificationInfo-fileItem {
+        position: relative;
+        display: flex;
+        width: 32.8%;
+        margin-right:0.7%;
+        margin-bottom: 8px;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        height: 48px;
+        background: #F7F9FC;
+        border-radius: 4px;
+        padding: 0 12px;
+
+        &>img {
+          width: 20px;
+          height: 20px;
+        }
+
+        .downloadBtn {
+          display: flex;
+          cursor: pointer;
+          justify-content: center;
+          align-items: center;
+          position: absolute;
+          width: 16px;
+          height: 16px;
+          padding: 2px;
+          top: 16px;
+          right: 12px;
+
+          &:hover {
+            color: #3376FE;
+          }
+        }
+
+        .qualificationInfo-fileItem-detail {
+          margin-left: 8px;
+
+          .qualificationInfo-fileItem-detail-name {
+            font-weight: 500;
+            font-size: 14px;
+            height: 14px;
+            color: #17181A;
+            line-height: 14px;
+            margin-bottom: 4px;
+          }
+
+          .qualificationInfo-fileItem-detail-sub {
+            width: calc(340px - 65px);
+            font-weight: 400;
+            font-size: 12px;
+            height: 12px;
+            color: #7A8599;
+            line-height: 12px;
+            white-space: nowrap;
+            overflow: hidden;
+            text-overflow: ellipsis;
+          }
+        }
+
+        &:nth-child(3n) {
+          margin-right: 0;
+        }
+
+      }
+    }
+  }
+
+  .authDetailDrawer-content {
+    height: calc(100vh - 75px);
+    overflow-y: scroll;
+    .authDetailDrawer-info {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+      background: #FFFFFF;
+      padding: 16px;
+      border-radius: 4px;
+
+      .avator {
+        width: 56px;
+        height: 56px;
+        margin-right: 16px;
+        border-radius: 50%;
+        overflow: hidden;
+        background: #F2F7FF;
+        border: 1px solid #FFFFFF;
+
+        &>img {
+          width: 100%;
+          height: 100%;
+        }
+      }
+
+      .authDetailDrawer-info-detail {
+        
+        .authDetailDrawer-info-title {
+          display: flex;
+          width: 100%;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+          font-weight: bold;
+          font-size: 20px;
+          height: 20px;
+          line-height: 20px;
+          color: #17181A;
+          margin-bottom: 12px;
+        }
+
+        .authDetailDrawer-info-title-sub {
+          font-weight: 400;
+          font-size: 14px;
+          color: #525866;
+          line-height: 16px;
+
+          .authDetailDrawer-info-standard {
+            position: relative;
+            min-height: 56px;
+            background: #F7F9FC;
+            border-radius: 4px;
+            padding: 6px 12px;
+            font-weight: 400;
+            font-size: 14px;
+            color: #17181A;
+            line-height: 18px;
+            margin-top: 12px;
+            padding-right: 64px;
+            border: 1px solid #DAE4F2;
+
+            &>img {
+              position: absolute;
+              right: 12px;
+              top: 6px;
+              width: 40px;
+              height: 40px;
+
+            }
+          }
+        }
+      }
+
+    }
+
+    .authDetailDrawer-content-table {
+      padding: 16px;
+      background: #FFFFFF;
+      border-radius: 4px;
+      margin-top: 16px;
+
+      .authDetailDrawer-content-table-title {
+        font-weight: 500;
+        font-size: 16px;
+        height: 16px;
+        color: #17181A;
+        line-height: 16px;
+        margin-bottom: 16px;
+      }
+
+
+    }
+  }
+
+}
+
+.QualificationAuth {
+  border-radius: 4px;
+
+  .pageContent {
+    display: flex;
+    width: 100%;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: flex-start;
+
+    .left {
+
+      border-radius: 4px;
+      width: 220px;
+      height: calc(100vh - 80px);
+      overflow: hidden;
+      margin-right: 16px;
+      padding-top: 8px;
+      background: #FFFFFF;
+    }
+
+    .right {
+      border-radius: 4px;
+      background: #FFFFFF;
+
+      .toolBar {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+
+        .filter {
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+
+          .filterItem {
+            display: flex;
+            flex-direction: row;
+            justify-content: center;
+            align-items: center;
+          }
+        }
+
+        .btnGroup {
+          .add {
+            cursor: pointer;
+            display: inline-block;
+            font-size: 14px;
+            font-family: SourceHanSansCN-Normal, SourceHanSansCN;
+            font-weight: 400;
+            color: #FFFFFF;
+            line-height: 24px;
+            padding: 0 14px;
+            background: #3377FF;
+            border-radius: 4px;
+          }
+        }
+
+      }
+    }
+  }
+
+
+}

+ 143 - 0
src/pages/qualificationMana/doctorQualifiAuth/transform.tsx

@@ -0,0 +1,143 @@
+import React, { Key, useEffect, useImperativeHandle, useState } from "react";
+import { Transfer } from 'antd'
+import { TransferItem, TransferProps } from 'antd/es/transfer';
+import { ColumnsType } from 'antd/es/table';
+import { difference } from "lodash";
+import { TableRowSelection } from 'antd/es/table/interface';
+import { KCIMTable } from "@/components/KCIMTable";
+import { ProColumns } from "@ant-design/pro-components";
+
+import { log } from "mathjs";
+import { getHasConnectedHisItemDicListReq, getHisItemDicListReq } from "./service";
+
+
+
+interface TableTransferProps extends TransferProps<TransferItem> {
+    leftColumns: ProColumns[];
+    rightColumns: ProColumns[];
+    record: any,
+    onSave: (selectedKeys: Key[], selectedRowKeys: any[]) => void;
+}
+
+const TableTransfer = React.forwardRef(({ leftColumns, rightColumns, record, onSave, ...restProps }: TableTransferProps, ref) => {
+
+    const [_data, _set_data] = useState<any>();
+    const [targetKeys, setTargetKeys] = useState<string[]>([]);
+    const [datasource, set_datasource] = useState<any[]>([]);
+    const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
+    const [queryCondition,set_queryCondition] = useState('');
+    
+    //获取列表
+    const getFuncList = async (params:any) => {
+        let resp = await getHisItemDicListReq({pageSize:500,current:1,...params});
+        if (resp) {
+            set_datasource([...resp.list]);
+            
+        }
+
+    }
+
+    const getDefaultData = async ()=>{
+          const resp = await getHasConnectedHisItemDicListReq({qualificationId:record.id});
+          if(resp){
+               const defaultkeys = resp.list.map((a:any)=>`${a.id}`);
+               setTargetKeys([...targetKeys,...defaultkeys]);
+          }
+    }
+
+    const onChange = (nextTargetKeys: string[]) => {
+        setTargetKeys(nextTargetKeys);
+    };
+
+    const onSelectChange = (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => {
+        //console.log('sourceSelectedKeys:', sourceSelectedKeys,'targetSelectedKeys:',targetSelectedKeys);
+        setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys]);
+    };
+
+    useImperativeHandle(ref, () => ({
+        save: async () => {
+            const items = datasource.filter(a => targetKeys.includes(a.hisItemId));
+            onSave(targetKeys, items);
+        }
+    }));
+
+    useEffect(() => {
+        getFuncList({});
+        getDefaultData();
+    }, [])
+
+    return (
+        <Transfer className='TableTransfer' showSearch
+            titles={['待选项', '已选项']}
+            locale={{
+                itemUnit: '项',
+                itemsUnit: '项',
+                searchPlaceholder: '医嘱编码、医嘱名称',
+            }}
+            oneWay={false}
+            onChange={onChange}
+            onSelectChange={onSelectChange}
+            dataSource={datasource}
+            rowKey={record => record.hisItemId}
+            targetKeys={targetKeys}
+            selectedKeys={selectedKeys}
+            filterOption={(inputValue, item) => {
+                return (item.hisItemName!.indexOf(inputValue) !== -1)||(item.hisItemId!.indexOf(inputValue) !== -1)
+
+            }}
+        >
+            {({
+                direction,
+                filteredItems,
+                onItemSelectAll,
+                onItemSelect,
+                selectedKeys: listSelectedKeys,
+                disabled: listDisabled,
+            }) => {
+
+                // console.log({ filteredItems, listSelectedKeys,direction });
+                const columns = direction === 'left' ? leftColumns : rightColumns;
+
+                const rowSelection: TableRowSelection<TransferItem> = {
+                    getCheckboxProps: (item) => ({ disabled: listDisabled || item.disabled }),
+                    onSelectAll(selected, selectedRows) {
+                        const treeSelectedKeys = selectedRows.map(({ hisItemId }) => hisItemId);
+                        const diffKeys = selected
+                            ? difference(treeSelectedKeys, listSelectedKeys)
+                            : difference(listSelectedKeys, treeSelectedKeys);
+                        onItemSelectAll(diffKeys as string[], selected);
+                    },
+                    onSelect({ hisItemId }, selected) {
+                        onItemSelect(hisItemId as string, selected);
+                    },
+                    selectedRowKeys: listSelectedKeys,
+                };
+
+                return (
+                    <KCIMTable
+                        rowSelection={rowSelection}
+                        columns={columns as TransferItem[]}
+                        dataSource={filteredItems}
+                        size="small"
+                        tableStyle={{border:'none'}}
+                        bordered={false}
+                        rowKey={'hisItemId'}
+                        pagination={{ showTitle: false, pageSize: 9, showLessItems: false, simple: true, showTotal: () => false }}
+                        tableAlertRender={false}
+                        style={{ pointerEvents: listDisabled ? 'none' : undefined }}
+                        onRow={({ code, disabled: itemDisabled }) => ({
+                            onClick: () => {
+                                if (itemDisabled || listDisabled) return;
+                                onItemSelect(code as string, !listSelectedKeys.includes(code as string));
+                            },
+                        })}
+                    />
+                );
+            }}
+        </Transfer>
+    )
+});
+
+export default TableTransfer
+
+

+ 18 - 14
src/pages/qualificationMana/qualifiDicMana/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-12-04 10:45:37
+ * @LastEditTime: 2024-12-24 14:56:28
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -21,11 +21,11 @@ import { ActionType, arrayMoveImmutable, ProFormText, ProFormTextArea, useRefFun
 import { ModalForm, ProFormCascader, ProFormCheckbox, ProFormDependency, ProFormDigit, ProFormSelect, ProFormSwitch } from '@ant-design/pro-form'
 import { ProColumns } from '@ant-design/pro-table';
 import { Input, message, Popconfirm, Switch } from 'antd';
-import { Key, useEffect, useRef, useState } from 'react';
+import { Fragment, Key, useEffect, useRef, useState } from 'react';
 import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
 
 
-import { addData, delData, editData, getTableDataReq, saveConnectTableDataReq } from './service';
+import { addData, delData, editData, getDrawerTableDataReq, getTableDataReq, saveConnectTableDataReq } from './service';
 
 import './style.less';
 import { KCIMLeftList } from '@/components/KCIMLeftList';
@@ -121,7 +121,7 @@ export default function QualifiDicMana({ isChildComponent = false,qualifiCode,on
                         )
                     }
                     {
-                        operationFlag == 1 && (
+                        operationFlag == 1&&operationLevelCode && (
                             <span style={{
                                 display: 'inline-flex', width: 64, height: 20, justifyContent: 'center',
                                 alignItems: 'center', background: '#E8FCF6', borderRadius: 4, fontSize: 12, color: '#009966'
@@ -131,7 +131,7 @@ export default function QualifiDicMana({ isChildComponent = false,qualifiCode,on
                         )
                     }
                     {
-                        (!operationFlag && !techFlag) && ('-')
+                        (!operationFlag && !techFlag) && (<Fragment/>)
                     }
                 </div>
             },
@@ -173,10 +173,7 @@ export default function QualifiDicMana({ isChildComponent = false,qualifiCode,on
 
     const getTableData = async (params: any) => {
         const { qualificationTypeCode } = params;
-        if (!qualificationTypeCode) {
-
-        }
-        const resp = await getTableDataReq(params);
+        const resp = isChildComponent?await getDrawerTableDataReq(params):await getTableDataReq(params);
         if (resp) {
             return {
                 data: resp.list,
@@ -237,6 +234,7 @@ export default function QualifiDicMana({ isChildComponent = false,qualifiCode,on
                 if (resp) {
                     message.success('操作成功!');
                     tableRef.current?.reload();
+                    return true
                 }
     
             }
@@ -254,12 +252,14 @@ export default function QualifiDicMana({ isChildComponent = false,qualifiCode,on
                     enableFlag: formVal.enableFlag ? 1 : 0
                 });
                 if (resp) {
+                
                     tableRef.current?.reload();
                     message.success('操作成功!');
+                    return true
                 }
             }
 
-            return true;
+            return false;
             
         } catch (error) {
             
@@ -391,7 +391,7 @@ export default function QualifiDicMana({ isChildComponent = false,qualifiCode,on
     }
 
     const tableDataSearchHandle = (key: string) => {
-        set_tableDataFilterParams({ ...tableDataFilterParams,current:1, name: tableDataSearchKeywords })
+        set_tableDataFilterParams({ ...tableDataFilterParams,current:1, [key]: tableDataSearchKeywords })
     }
 
     const getQualClassRequest = async () => {
@@ -473,7 +473,7 @@ export default function QualifiDicMana({ isChildComponent = false,qualifiCode,on
     }, [])
 
     return (
-        <KCIMPagecontainer className='QualifiDicMana' style={!isChildComponent?{}:{border:'none'}} title={false}>
+        <KCIMPagecontainer className='QualifiDicMana' style={!isChildComponent?{}:{border:'none',padding:0}} title={false}>
             <div className='pageContent'>
                 {
                     !isChildComponent && (
@@ -509,7 +509,6 @@ export default function QualifiDicMana({ isChildComponent = false,qualifiCode,on
                             <div className='filterItem'>
                                 <span className='label'>检索:</span>
                                 <Input placeholder={'资质名称'} style={{ width: 160, marginRight: 16 }} allowClear autoComplete='off'
-
                                     suffix={
                                         <IconFont style={{ color: '#99A6BF' }} type="iconsousuo" onClick={() => tableDataSearchHandle('name')} />
                                     }
@@ -517,7 +516,7 @@ export default function QualifiDicMana({ isChildComponent = false,qualifiCode,on
                                         set_tableDataSearchKeywords(e.target.value);
                                         if (e.target.value.length == 0) {
                                             set_tableDataSearchKeywords('');
-                                            tableRef.current?.reload();
+                                            set_tableDataFilterParams({...tableDataFilterParams,name:null})
                                         }
                                     }}
 
@@ -562,6 +561,11 @@ export default function QualifiDicMana({ isChildComponent = false,qualifiCode,on
                             tableAlertRender={false}
                             rowSelection={isChildComponent?{
                                   defaultSelectedRowKeys:defaultSelectedKeys,
+                                  getCheckboxProps(record) {
+                                    return {
+                                        disabled: record.allowCheck == 0,
+                                    }
+                                  },
                                   onChange(selectedRowKeys, selectedRows, info) {
                                     onTableSelectChange&&onTableSelectChange(selectedRowKeys,selectedRows,info) 
                                   },

+ 9 - 1
src/pages/qualificationMana/qualifiDicMana/service.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 16:31:27
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-11-21 16:49:20
+ * @LastEditTime: 2024-12-16 17:03:48
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -20,6 +20,14 @@ export const getTableDataReq = (params?:any) => {
   });
 };
 
+//获取资质列表数据
+export const getDrawerTableDataReq = (params?:any) => {
+  return request<any>('/medical/qualificationApply/getQualificationList', {
+    method: 'GET',
+    params:{...params}
+  });
+};
+
 //获取医嘱项目列表数据
 
 export const getHisItemDicListReq = (params?:any) => {

+ 0 - 1
src/pages/qualificationMana/qualifiDicMana/style.less

@@ -55,7 +55,6 @@
             cursor: pointer;
             display: inline-block;
             font-size: 14px;
-            font-family: SourceHanSansCN-Normal, SourceHanSansCN;
             font-weight: 400;
             color: #FFFFFF;
             line-height: 24px;

+ 268 - 211
src/pages/qualificationMana/qualificationApproval/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-12-03 14:05:57
+ * @LastEditTime: 2024-12-26 17:28:50
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -14,7 +14,7 @@ import { KCIMTable } from '@/components/KCIMTable';
 
 import { createFromIconfontCN } from '@ant-design/icons';
 import { ActionType, ProFormDependency, ProFormInstance, ProFormText, ProFormSelect } from '@ant-design/pro-components';
-import { ModalForm, ProFormCheckbox, ProFormDateRangePicker, ProFormDigit, ProFormRadio, ProFormTextArea } from '@ant-design/pro-form'
+import ProForm, { ModalForm, ProFormCheckbox, ProFormDateRangePicker, ProFormDigit, ProFormRadio, ProFormTextArea } from '@ant-design/pro-form'
 import { ProColumns } from '@ant-design/pro-table';
 import { Drawer, Input, message, Popconfirm, Modal, Switch, Tooltip } from 'antd';
 import { useEffect, useRef, useState } from 'react';
@@ -29,6 +29,7 @@ import './style.less';
 import { renameChildListToChildren } from '@/utils/tooljs';
 import { useParams } from '@umijs/max';
 import moment from 'moment';
+import { authTimeType } from '@/constant';
 
 
 const IconFont = createFromIconfontCN({
@@ -95,6 +96,9 @@ export default function QualificationApproval() {
     const [isModalOpen, set_isModalOpen] = useState(false);
     const [batchAuthText, set_batchAuthText] = useState<string | undefined>(undefined);
     const [batchSelectRows, set_batchSelectRows] = useState<any[]>([]);
+    const [batchQualificationPeriod, set_batchQualificationPeriod] = useState('1');
+    const [batchAuthTimeRange, set_batchAuthTimeRange] = useState([`${moment().year()}-${moment().month() + 1}-${moment().date()}`]);
+    const [batchIfNeedMasterAudit, set_batchIfNeedMasterAudit] = useState(false);
 
 
 
@@ -211,7 +215,7 @@ export default function QualificationApproval() {
                 ...result,
                 auditInfo: [{
                     ...result.auditInfo[0],
-                    qualificationPeriod:authType,
+                    qualificationPeriod: authType,
                     beginDate: authTimerange[0],
                     endDate: authTimerange[1],
                     managerOpinion: managerOpinionText,
@@ -247,27 +251,43 @@ export default function QualificationApproval() {
 
         set_tableDataFilterParams({
             ...tableDataFilterParams,
-            current:1,
+            current: 1,
             [`${paramName}`]: tableDataSearchKeywords
         })
 
     }
 
+    const cancelBatchAuthHandle = ()=>{
+        set_batchSelectRows([]);
+    }
+
     const batchAuthHandle = () => {
         set_isModalOpen(true);
     }
 
     const handleOk = async (type: 1 | 2) => {
-        const result = {
+        const result = roleType == '2' ? {
+            role: roleType,
+            auditType: type,
+            auditInfo: batchSelectRows.map((a) => ({
+                id: a.id,
+                managerOpinion: batchAuthText,
+                qualificationPeriod: batchQualificationPeriod,
+                beginDate: batchAuthTimeRange[0],
+                endDate: batchAuthTimeRange[1],
+                needMasterAudit: batchIfNeedMasterAudit ? 1 : 0
+            }))
+        } : {
             role: roleType,
             auditType: type,
             auditInfo: batchSelectRows.map((a) => ({
                 id: a.id,
-                [`${roleType == '1' ? 'deptOpinion' : roleType == '2' ? 'managerOpinion' : 'masterOpinion'}`]: batchAuthText
+                [`${roleType == '1' ? 'deptOpinion' : 'masterOpinion'}`]: batchAuthText
             }))
         }
         const resp = await editData(result);
         if (resp) {
+            set_batchSelectRows([]);
             message.success('批量操作成功!');
             tableRef.current?.reload();
         }
@@ -275,7 +295,7 @@ export default function QualificationApproval() {
 
     useEffect(() => {
         if (roleType) {
-            set_tableDataFilterParams({ ...tableDataFilterParams,current:1, role: roleType });
+            set_tableDataFilterParams({ ...tableDataFilterParams, current: 1, role: roleType });
             set_currentEditRow(undefined);
             set_deptOpinionText(undefined);
             set_managerOpinionText(undefined);
@@ -290,17 +310,17 @@ export default function QualificationApproval() {
 
     useEffect(() => {
         if (currentEditRow) {
-            console.log({currentEditRow});
+
             set_deptOpinionText(currentEditRow.deptOpinion);
             set_managerOpinionText(currentEditRow.managerOpinion);
             set_authTimerange([currentEditRow.beginDate, currentEditRow.endDate]);
-            set_authType(currentEditRow.qualificationPeriod?currentEditRow.qualificationPeriod:1);
+            set_authType(currentEditRow.qualificationPeriod ? currentEditRow.qualificationPeriod : 1);
         }
     }, [currentEditRow]);
 
     return (
         <KCIMPagecontainer className='QualificationApproval' title={false}>
-            <Modal width={352} title="审批意见" open={isModalOpen} destroyOnClose
+            <Modal width={352} title={roleType == '2' ? '批量审批' : '审批意见'} open={isModalOpen} destroyOnClose
                 onCancel={() => set_isModalOpen(false)}
                 footer={[
                     <span style={{
@@ -317,20 +337,53 @@ export default function QualificationApproval() {
                     }} onClick={() => { handleOk(1); set_isModalOpen(false) }}>通过</span>
                 ]}
             >
-                <ProFormTextArea fieldProps={{
-                    autoSize: { minRows: 6 },
-                    onChange: (e) => {
-                        set_batchAuthText(e.target.value);
+                <ProForm submitter={false}>
+                    {
+                        roleType == '2' && (<>
+                            <ProFormRadio.Group label='授权期限:' options={authTimeType}
+                                fieldProps={{
+                                    defaultValue: 1,
+                                    onChange(e) {
+                                        set_batchQualificationPeriod(e.target.value);
+                                    },
+                                }} />
+                            <ProFormDateRangePicker label='授权时间:' fieldProps={{
+                                defaultValue: [moment().startOf('days'), moment().endOf('days')],
+                                onChange(values, formatString) {
+                                    set_batchAuthTimeRange(formatString);
+                                },
+                            }} />
+
+                        </>)
                     }
-                }} />
+                    <ProFormTextArea label='审批意见:' fieldProps={{
+                        autoSize: { minRows: 6 },
+                        onChange: (e) => {
+                            set_batchAuthText(e.target.value);
+                        }
+                    }} />
+                    {roleType != '3' && (
+                        <>
+                            <ProFormCheckbox noStyle fieldProps={{
+
+                                style: { marginRight: 4, marginBottom: 16 },
+                                onChange(e) {
+                                    set_batchIfNeedMasterAudit(e.target.checked)
+                                },
+                            }} />
+                            提交院领导审核
+                        </>
+                    )}
+                </ProForm>
+
             </Modal>
-            <Drawer destroyOnClose={true} className='applyDrawer' width={1100}
+            <Drawer destroyOnClose={true} className='applyDrawer' width={1110}
                 open={drawerVisible} headerStyle={{ display: 'none' }} bodyStyle={{ background: '#F5F7FA', padding: 16 }}
                 afterOpenChange={(bool) => { !bool && set_actionType(undefined) }}
             >
                 <div className='applyDrawer-topBar'>
                     <div className='applyDrawer-topBar-title'>
-                        <IconFont onClick={() => set_drawerVisible(false)} type={'iconquxiao'} style={{ marginRight: 12 }} />{'审批'}
+                        <div className='closeIcon' onClick={() => set_drawerVisible(false)} ><IconFont  type={'iconquxiao'} /></div>{'审批'}
                     </div>
                     <div className='btnGroup'>
                         <span onClick={() => set_drawerVisible(false)}>取消</span>
@@ -338,227 +391,231 @@ export default function QualificationApproval() {
                         <span className='commit' onClick={() => updateTable(1)}>通过</span>
                     </div>
                 </div>
-                <div className='personInfo'>
-                    <div className='avator'><img src={currentEditRow?.userInfo?.avatarUrl} alt="avator" /></div>
-                    <div className='personInfo-detail'>
-                        <div className='name'>{currentEditRow?.userInfo?.name}<img src={require(`../../../../static/${currentEditRow?.userInfo?.gender == '男' ? 'male' : 'female'}.png`)} /></div>
-                        <div className='personInfo-detail-sub'>
-                            工号:{currentEditRow?.userInfo?.id}<span style={{ padding: 4 }} />
-                            科室:{currentEditRow?.userInfo?.deptName}<span style={{ padding: 4 }} />
-                            职称:{currentEditRow?.userInfo?.title}<span style={{ padding: 4 }} />
-                            职务:{currentEditRow?.userInfo?.jobTitle}
+                <div className='drawer-content'>
+                    <div className='personInfo'>
+                        <div className='avator'><img src={(currentEditRow?.userInfo?.avatarUrl)?currentEditRow?.userInfo?.avatarUrl:require('../../../../static/avatar.png')} alt="avator" /></div>
+                        <div className='personInfo-detail'>
+                            <div className='name'>{currentEditRow?.userInfo?.name}<img src={require(`../../../../static/${currentEditRow?.userInfo?.gender == '男' ? 'male' : 'female'}.png`)} /></div>
+                            <div className='personInfo-detail-sub'>
+                                工号:{currentEditRow?.userInfo?.id??'-'}<span style={{ padding: 8 }} />
+                                科室:{currentEditRow?.userInfo?.deptName??'-'}<span style={{ padding: 8 }} />
+                                职称:{currentEditRow?.userInfo?.title??'-'}<span style={{ padding: 8 }} />
+                                职务:{currentEditRow?.userInfo?.jobTitle??'-'}
+                            </div>
                         </div>
                     </div>
-                </div>
-                <div className='qualificationInfo'>
-                    <div className='qualificationInfo-title'>资质信息</div>
-                    <div className='qualificationInfo-tagWrapper'>
-                        <div className='qualificationInfo-tagWrapper-tag'>资格证号:<span>{currentEditRow?.userInfo?.qualificationCertificateNo}</span></div>
-                        <div className='qualificationInfo-tagWrapper-tag'>执业类别:<span>{currentEditRow?.userInfo?.practiceCate}</span></div>
-                        <div className='qualificationInfo-tagWrapper-tag'>执业证号:<span>{currentEditRow?.userInfo?.practiceCertificateNo}</span></div>
-                        <div className='qualificationInfo-tagWrapper-tag'>执业专业:<span>{currentEditRow?.userInfo?.major}</span></div>
-                        <div className='qualificationInfo-tagWrapper-tag'>医师级别:<span>{currentEditRow?.userInfo?.doctorLevel}</span></div>
-                    </div>
-                    <div className='qualificationInfo-fileWrapper'>
-                        {
-                            currentEditRow?.userAttachment?.map((item: any, index: number) => {
-                                return (
-                                    <div key={index} className='qualificationInfo-fileItem'>
-                                        <img src={require('../../../../static/fileIcon.png')} alt="" />
-                                        <div className='qualificationInfo-fileItem-detail'>
-                                            <div className='qualificationInfo-fileItem-detail-name'>{item.fileName}</div>
-                                            <div className='qualificationInfo-fileItem-detail-sub'>{item.description}</div>
+                    <div className='qualificationInfo'>
+                        <div className='qualificationInfo-title'>资质信息</div>
+                        <div className='qualificationInfo-tagWrapper'>
+                            <div className='qualificationInfo-tagWrapper-tag'>资格证号:<span>{currentEditRow?.userInfo?.qualificationCertificateNo??'-'}</span></div>
+                            <div className='qualificationInfo-tagWrapper-tag'>执业类别:<span>{currentEditRow?.userInfo?.practiceCate??'-'}</span></div>
+                            <div className='qualificationInfo-tagWrapper-tag'>执业证号:<span>{currentEditRow?.userInfo?.practiceCertificateNo??'-'}</span></div>
+                            <div className='qualificationInfo-tagWrapper-tag'>执业专业:<span>{currentEditRow?.userInfo?.major??'-'}</span></div>
+                            <div className='qualificationInfo-tagWrapper-tag'>医师级别:<span>{currentEditRow?.userInfo?.doctorLevel??'-'}</span></div>
+                        </div>
+                        <div className='qualificationInfo-fileWrapper'>
+                            {
+                                currentEditRow?.userAttachment?.map((item: any, index: number) => {
+                                    return (
+                                        <div key={index} className='qualificationInfo-fileItem'>
+                                            <img src={require('../../../../static/fileIcon.png')} alt="" />
+                                            <div className='qualificationInfo-fileItem-detail'>
+                                                <div className='qualificationInfo-fileItem-detail-name'>{item.fileName}</div>
+                                                <div className='qualificationInfo-fileItem-detail-sub'>{item.description}</div>
+                                            </div>
+                                            <Tooltip title='下载'>
+                                                <div className='downloadBtn' ><IconFont type={'iconxiazai'} /></div>
+                                            </Tooltip>
                                         </div>
-                                        <Tooltip title='下载'>
-                                            <div className='downloadBtn' ><IconFont type={'iconxiazai'} /></div>
-                                        </Tooltip>
-                                    </div>
-                                )
-                            })
-                        }
-                    </div>
+                                    )
+                                })
+                            }
+                        </div>
 
 
-                </div>
-                {
-                    currentEditRow && (
-                        <div className='qualificationInfo-apply'>
-                            <div className='editContent-header-title'>
-                                <>{currentEditRow?.qualificationInfo?.name}({currentEditRow?.qualificationInfo?.code})</>
-                                <div>
-                                    {
-                                        currentEditRow?.qualificationInfo?.techFlag == 1 && (
-                                            <span style={{
-                                                display: 'inline-flex', height: 20, justifyContent: 'center', marginLeft: 8,padding:'0 12px',
-                                                alignItems: 'center', background: '#FFF5EB', borderRadius: 4, fontSize: 12, color: '#FF8000', marginRight: 4
-                                            }}>医疗技术</span>
-                                        )
-                                    }
-                                    {
-                                        currentEditRow?.qualificationInfo?.operationFlag == 1 && (
-                                            <span style={{
-                                                display: 'inline-flex',height: 20, justifyContent: 'center',padding:'0 12px',
-                                                alignItems: 'center', background: '#E8FCF6', borderRadius: 4, fontSize: 12, color: '#009966'
-                                            }}>{
-                                                    currentEditRow?.qualificationInfo?.qualificationTypeName
-                                                }</span>
-                                        )
-                                    }
-                                </div>
+                    </div>
+                    {
+                        currentEditRow && (
+                            <div className='qualificationInfo-apply'>
+                                <div className='editContent-header-title'>
+                                    <>{currentEditRow?.qualificationInfo?.name}({currentEditRow?.qualificationInfo?.code})</>
+                                    <div>
+                                        {
+                                            currentEditRow?.qualificationInfo?.techFlag == 1 && (
+                                                <span style={{
+                                                    display: 'inline-flex', height: 20, justifyContent: 'center', marginLeft: 8, padding: '0 12px',
+                                                    alignItems: 'center', background: '#FFF5EB', borderRadius: 4, fontSize: 12, color: '#FF8000', marginRight: 4
+                                                }}>医疗技术</span>
+                                            )
+                                        }
+                                        {
+                                            currentEditRow?.qualificationInfo?.operationFlag == 1 && (
+                                                <span style={{
+                                                    display: 'inline-flex', height: 20, justifyContent: 'center', padding: '0 12px',
+                                                    alignItems: 'center', background: '#E8FCF6', borderRadius: 4, fontSize: 12, color: '#009966'
+                                                }}>{
+                                                        currentEditRow?.qualificationInfo?.qualificationTypeName
+                                                    }</span>
+                                            )
+                                        }
+                                    </div>
 
+                                </div>
+                                <div className='editContent-header-title-sub'>
+                                    <div>资质编码:<span>{currentEditRow?.qualificationInfo?.code??'-'}</span></div>
+                                    <div>申请日期:<span>{currentEditRow?.applyDate??'-'}</span></div>
+                                </div>
+                                {currentEditRow?.qualificationInfo?.standard.length > 0 && <div className='editContent-header-title-detail'><span>授权依据:</span><div>{currentEditRow?.qualificationInfo?.standard}</div></div>}
+                                {(currentEditRow?.applyMemo?.length > 0) && <div className='editContent-header-title-detail'>
+                                    <span>备注:</span><div>{currentEditRow?.applyMemo}</div>
+                                </div>}
+                                {currentEditRow?.applyAttachment?.length > 0 && <div className='appendix'>
+                                    附件:{currentEditRow?.applyAttachment?.map((a: any, index: number) => (<span key={index}><IconFont type={'iconfujian'} /><a href={a.url} target='_blank'>{a.fileName}</a></span>))}
+                                </div>}
                             </div>
-                            <div className='editContent-header-title-sub'>
-                                <div>资质编码:<span>{currentEditRow?.qualificationInfo?.code}</span></div>
-                                <div>授权依据:<span>{currentEditRow?.qualificationInfo?.standard}</span></div>
-                                <div>申请日期:<span>{currentEditRow?.applyDate}</span></div>
-                            </div>
-                            {(currentEditRow?.applyMemo?.length > 0) && <div className='editContent-header-title-detail'>
-                                <span>备注:</span><div>{currentEditRow?.applyMemo}</div>
-                            </div>}
-                            {<div className='appendix'>
-                                附件:{currentEditRow?.applyAttachment?.map((a: any, index: number) => (<span key={index}><IconFont type={'iconfujian'} /><a href={a.url} target='_blank'>{a.fileName}</a></span>))}
-                            </div>}
-                        </div>
-                    )
-                }
+                        )
+                    }
 
-                <div className='deptOpinion'>
-                    {roleType != '1' && <div className='deptOpinion-title'>科主任意见</div>}
-                    {roleType == '1' && <div className='deptOpinion-title'>审批意见</div>}
-                    {roleType == '1' && <ProFormTextArea fieldProps={{
-                        onChange: (e) => {
-                            set_deptOpinionText(e.target.value);
-                        }
-                    }} noStyle placeholder={'请输入审批意见'} />}
-                    {roleType != '1' && <div className='deptOpinion-detail'>{deptOpinionText}</div>}
-                </div>
-                {
-                    roleType != '1' && (
-                        <div className='deptOpinion'>
-                            {
-                                roleType == '3' && (
-                                    <>
-                                        <div className='deptOpinion-title'>医务部意见</div>
-                                        <div className='time-info'>
-                                            <div className='info-tag'>
-                                                授权期限:<span>{authTypeList[authType - 1].label}</span>
+                    <div className='deptOpinion'>
+                        {roleType != '1' && <div className='deptOpinion-title'>科主任意见</div>}
+                        {roleType == '1' && <div className='deptOpinion-title'>审批意见</div>}
+                        {roleType == '1' && <ProFormTextArea fieldProps={{
+                            onChange: (e) => {
+                                set_deptOpinionText(e.target.value);
+                            }
+                        }} noStyle placeholder={'请输入审批意见'} />}
+                        {roleType != '1' && <div className='deptOpinion-detail'>{deptOpinionText}</div>}
+                    </div>
+                    {
+                        roleType != '1' && (
+                            <div className='deptOpinion'>
+                                {
+                                    roleType == '3' && (
+                                        <>
+                                            <div className='deptOpinion-title'>医务部意见</div>
+                                            <div className='time-info'>
+                                                <div className='info-tag'>
+                                                    授权期限:<span>{authTypeList[authType - 1].label}</span>
+                                                </div>
+                                                <div className='info-tag'>
+                                                    授权时间:<span>{`${authTimerange[0]}至${authTimerange[1]}`}</span>
+                                                </div>
                                             </div>
-                                            <div className='info-tag'>
-                                                授权时间:<span>{`${authTimerange[0]}至${authTimerange[1]}`}</span>
+                                            <div className='manageOpinion-detail'>
+                                                <span>审批意见:</span>
+                                                <div>{managerOpinionText}</div>
                                             </div>
-                                        </div>
-                                        <div className='manageOpinion-detail'>
-                                            <span>审批意见:</span>
-                                            <div>{managerOpinionText}</div>
-                                        </div>
-                                    </>
-                                )
-                            }
+                                        </>
+                                    )
+                                }
 
-                            {
-                                roleType == '2' && (
-                                    <>
-                                        <div className='deptOpinion-title'>审批信息</div>
-                                        <div className='time-wrapper'>
-                                            <div className='type'>
-                                                <span>授权期限:</span>
-                                                <ProFormRadio.Group noStyle options={authTypeList} fieldProps={{
-                                                    defaultValue: 1,
-                                                    onChange(e) {
-                                                        set_authType(e.target.value);
-                                                    },
-                                                }} />
+                                {
+                                    roleType == '2' && (
+                                        <>
+                                            <div className='deptOpinion-title'>审批信息</div>
+                                            <div className='time-wrapper'>
+                                                <div className='type'>
+                                                    <span>授权期限:</span>
+                                                    <ProFormRadio.Group noStyle options={authTypeList} fieldProps={{
+                                                        defaultValue: 1,
+                                                        onChange(e) {
+                                                            set_authType(e.target.value);
+                                                        },
+                                                    }} />
+                                                </div>
+                                                <div className='time'>
+                                                    <span>授权时间:</span>
+                                                    <ProFormDateRangePicker noStyle fieldProps={{
+                                                        defaultValue: [moment().startOf("day"), moment().endOf("day")],
+                                                        // value:[moment(authTimerange[0],'YYYY-MM-DD'),moment(authTimerange[0],'YYYY-MM-DD')],
+                                                        onChange(values, formatString) {
+                                                            set_authTimerange(formatString)
+                                                        },
+                                                    }} />
+                                                </div>
                                             </div>
-                                            <div className='time'>
-                                                <span>授权时间:</span>
-                                                <ProFormDateRangePicker noStyle fieldProps={{
-                                                    defaultValue: [moment().startOf("day"), moment().endOf("day")],
-                                                    // value:[moment(authTimerange[0],'YYYY-MM-DD'),moment(authTimerange[0],'YYYY-MM-DD')],
-                                                    onChange(values, formatString) {
-                                                        set_authTimerange(formatString)
+                                            <div style={{ height: 14, lineHeight: '14px', fontSize: 14, color: '#17181A', marginBottom: 8 }}>审批意见:</div>
+                                            <ProFormTextArea fieldProps={{
+                                                onChange: (e) => {
+                                                    set_managerOpinionText(e.target.value);
+                                                }
+                                            }} noStyle placeholder={'请输入'} />
+
+                                            <div style={{ marginTop: 17 }}>
+                                                <ProFormCheckbox noStyle fieldProps={{
+                                                    style: { marginRight: 4 },
+                                                    onChange(e) {
+                                                        set_ifNeedMasterAudit(e.target.checked)
                                                     },
-                                                }} />
+                                                }} />提交院领导审核
                                             </div>
-                                        </div>
-                                        <div style={{height:14,lineHeight:'14px',fontSize:14,color:'#17181A',marginBottom:8}}>审批意见:</div>
-                                        <ProFormTextArea fieldProps={{
-                                            onChange: (e) => {
-                                                set_managerOpinionText(e.target.value);
-                                            }
-                                        }} noStyle placeholder={'请输入'} />
-
-                                        <div style={{ marginTop: 17 }}>
-                                            <ProFormCheckbox noStyle fieldProps={{
-                                                style: { marginRight: 4 },
-                                                onChange(e) {
-                                                    set_ifNeedMasterAudit(e.target.checked)
-                                                },
-                                            }} />提交院领导审核
-                                        </div>
-                                    </>
-                                )
-                            }
-
-
-                        </div>
-                    )
-                }
-                {
-                    roleType != '1' && roleType != '2' && (
-                        <div className='deptOpinion'>
-                            <div className='deptOpinion-title'>审批意见</div>
-                            <ProFormTextArea fieldProps={{
-                                onChange: (e) => {
-                                    set_masterOpinionText(e.target.value);
+                                        </>
+                                    )
                                 }
-                            }} noStyle placeholder={'请输入审批意见'} />
-                        </div>
-                    )
-                }
 
+
+                            </div>
+                        )
+                    }
+                    {
+                        roleType != '1' && roleType != '2' && (
+                            <div className='deptOpinion'>
+                                <div className='deptOpinion-title'>审批意见</div>
+                                <ProFormTextArea fieldProps={{
+                                    onChange: (e) => {
+                                        set_masterOpinionText(e.target.value);
+                                    }
+                                }} noStyle placeholder={'请输入审批意见'} />
+                            </div>
+                        )
+                    }
+                </div>
             </Drawer>
 
 
-            <div className='toolBar'>
-                <div className='filter'>
-                    <div className='filterItem'>
-                        <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
-                        <Input placeholder={'申请人、资质分类、资质名称'} allowClear autoComplete='off'
-                            style={{ width: 250 }}
-                            suffix={
-                                <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('queryCondition')} />
-                            }
-                            onChange={(e) => {
-                                set_tableDataSearchKeywords(e.target.value);
-                                if (e.target.value.length == 0) {
+
+
+            <div className='pageContent'>
+                <div className='toolBar'>
+                    <div className='filter'>
+                        <div className='filterItem'>
+                            <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
+                            <Input placeholder={'申请人、资质分类、资质名称'} allowClear autoComplete='off'
+                                style={{ width: 250 }}
+                                suffix={
+                                    <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('queryCondition')} />
+                                }
+                                onChange={(e) => {
+                                    set_tableDataSearchKeywords(e.target.value);
+                                    if (e.target.value.length == 0) {
+                                        set_tableDataFilterParams({
+                                            ...tableDataFilterParams,
+                                            current: 1,
+                                            queryCondition: ''
+                                        });
+                                    }
+                                }}
+                                onPressEnter={(e) => {
+
                                     set_tableDataFilterParams({
                                         ...tableDataFilterParams,
-                                        current:1,
-                                        queryCondition: ''
+                                        current: 1,
+                                        queryCondition: (e.target as HTMLInputElement).value
                                     });
-                                }
-                            }}
-                            onPressEnter={(e) => {
-
-                                set_tableDataFilterParams({
-                                    ...tableDataFilterParams,
-                                    current:1,
-                                    queryCondition: (e.target as HTMLInputElement).value
-                                });
-                            }}
+                                }}
 
-                        />
+                            />
+                        </div>
+                    </div>
+                    <div className='btnGroup'>
+                        {batchSelectRows.length > 0 && <span className='export' onClick={() => cancelBatchAuthHandle()}>取消选择</span>}
+                        {batchSelectRows.length > 0 && <span className='add' onClick={() => batchAuthHandle()}>批量审批({batchSelectRows.length})</span>}
                     </div>
                 </div>
-                <div className='btnGroup'>
-                    <span className='add' onClick={() => batchAuthHandle()}>批量审批</span>
-                </div>
-            </div>
-
-            <div style={{ marginTop: 16 }}>
                 <KCIMTable columns={columns as ProColumns[]} scroll={{ y: 'calc(100vh - 232px)' }}
+                tableAlertRender={false}
                     rowSelection={{
-                        selectedRowKeys:batchSelectRows.map((a)=>a.id),
+                        selectedRowKeys: batchSelectRows.map((a) => a.id),
                         onChange(selectedRowKeys, selectedRows, info) {
                             set_batchSelectRows(selectedRows);
                         },

+ 371 - 308
src/pages/qualificationMana/qualificationApproval/style.less

@@ -7,9 +7,27 @@
     margin-bottom: 16px;
 
     .applyDrawer-topBar-title {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
       font-weight: 500;
       font-size: 16px;
       color: #17181A;
+
+      .closeIcon {
+        display: inline-flex;
+        justify-content: center;
+        align-items: center;
+        width: 24px;
+        height: 24px;
+        border-radius: 4px;
+        margin-right: 8px;
+        cursor: pointer;
+        &:hover {
+            background-color: #E6EAF2;
+        }
+      }
     }
 
     .btnGroup {
@@ -49,420 +67,465 @@
     }
   }
 
-  .personInfo {
-    display: flex;
-    flex-direction: row;
-    justify-content: flex-start;
-    align-items: center;
-    height: 78px;
-    padding: 11px 16px;
-    background: #FFFFFF;
-    border-radius: 4px;
-    margin-bottom: 16px;
+  .drawer-content {
+    max-height: calc(100vh - 72px);
+    overflow-y: scroll;
 
-    .avator {
-      width: 56px;
-      height: 56px;
-      margin-right: 16px;
-      border-radius: 50%;
-      overflow: hidden;
-      background: #F2F7FF;
-      border: 1px solid #FFFFFF;
+    .personInfo {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+      height: 78px;
+      padding: 11px 16px;
+      background: #FFFFFF;
+      border-radius: 4px;
+      margin-bottom: 16px;
 
-      &>img {
-        width: 100%;
-        height: 100%;
+      .avator {
+        width: 56px;
+        height: 56px;
+        margin-right: 16px;
+        border-radius: 50%;
+        overflow: hidden;
+        background: #F2F7FF;
+        border: 1px solid #FFFFFF;
+
+        &>img {
+          width: 100%;
+          height: 100%;
+        }
       }
-    }
 
-    .personInfo-detail {
+      .personInfo-detail {
 
-      .name {
-        font-weight: bold;
-        font-size: 20px;
-        height: 20px;
-        color: #17181A;
-        line-height: 20px;
-        margin-bottom: 12px;
+        .name {
+          font-weight: bold;
+          font-size: 20px;
+          height: 20px;
+          color: #17181A;
+          line-height: 20px;
+          margin-bottom: 12px;
 
-        &>img {
-          position: relative;
-          top: -2px;
-          width: 16px;
-          height: 16px;
-          margin-left: 8px;
+          &>img {
+            position: relative;
+            top: -2px;
+            width: 16px;
+            height: 16px;
+            margin-left: 8px;
+          }
         }
-      }
 
-      .personInfo-detail-sub {
-        font-weight: 400;
-        font-size: 14px;
-        height: 14px;
-        color: #525866;
-        line-height: 14px;
+        .personInfo-detail-sub {
+          font-weight: 400;
+          font-size: 14px;
+          height: 14px;
+          color: #525866;
+          line-height: 14px;
+        }
       }
     }
-  }
-
-  .qualificationInfo {
-    padding: 16px;
-    background: #FFFFFF;
-    border-radius: 4px;
-    margin-bottom: 16px;
-    padding-bottom: 8px;
 
-    .qualificationInfo-title {
-      font-weight: 500;
-      font-size: 16px;
-      height: 16px;
-      color: #17181A;
-      line-height: 16px;
+    .qualificationInfo {
+      padding: 16px;
+      background: #FFFFFF;
+      border-radius: 4px;
       margin-bottom: 16px;
-    }
+      padding-bottom: 8px;
 
-    .qualificationInfo-tagWrapper {
-      display: flex;
-      flex-direction: row;
-      justify-content: flex-start;
-      align-items: center;
-      flex-wrap: wrap;
+      .qualificationInfo-title {
+        font-weight: 500;
+        font-size: 16px;
+        height: 16px;
+        color: #17181A;
+        line-height: 16px;
+        margin-bottom: 16px;
+      }
 
-      .qualificationInfo-tagWrapper-tag {
-        width: 340px;
-        font-weight: 400;
-        height: 14px;
-        font-size: 14px;
-        color: #525866;
-        line-height: 14px;
-        margin-bottom: 12px;
+      .qualificationInfo-tagWrapper {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        flex-wrap: wrap;
 
-        &>span {
-          display: inline-block;
-          color: #17181A;
+        .qualificationInfo-tagWrapper-tag {
+          width: 340px;
+          font-weight: 400;
+          height: 14px;
+          font-size: 14px;
+          color: #525866;
+          line-height: 14px;
+          margin-bottom: 12px;
+          margin-right: 8px;
+
+          &>span {
+            display: inline-block;
+            color: #17181A;
+          }
+
+          &:nth-child(3n) {
+            margin-right: 0;
+          }
         }
       }
-    }
-
-    .qualificationInfo-fileWrapper {
-      display: flex;
-      flex-direction: row;
-      flex-wrap: wrap;
-      justify-content: flex-start;
-      align-items: center;
-      margin-top: 4px;
 
-      .qualificationInfo-fileItem {
-        position: relative;
+      .qualificationInfo-fileWrapper {
         display: flex;
-        width: 100%;
-        margin-right: 8px;
-        margin-bottom: 8px;
         flex-direction: row;
+        flex-wrap: wrap;
         justify-content: flex-start;
         align-items: center;
-        width: 340px;
-        height: 48px;
-        background: #F7F9FC;
-        border-radius: 4px;
-        padding: 0 12px;
+        margin-top: 4px;
 
-        &>img {
-          width: 20px;
-          height: 20px;
-        }
-
-        .downloadBtn {
+        .qualificationInfo-fileItem {
+          position: relative;
           display: flex;
-          cursor: pointer;
-          justify-content: center;
+          width: 100%;
+          margin-right: 8px;
+          margin-bottom: 8px;
+          flex-direction: row;
+          justify-content: flex-start;
           align-items: center;
-          position: absolute;
-          width: 16px;
-          height: 16px;
-          padding: 2px;
-          top: 16px;
-          right: 12px;
+          width: 340px;
+          height: 48px;
+          background: #F7F9FC;
+          border-radius: 4px;
+          padding: 0 12px;
+
+          &>img {
+            width: 20px;
+            height: 20px;
+          }
+
+          .downloadBtn {
+            display: flex;
+            cursor: pointer;
+            justify-content: center;
+            align-items: center;
+            position: absolute;
+            width: 16px;
+            height: 16px;
+            padding: 2px;
+            top: 16px;
+            right: 12px;
+
+            &:hover {
+              color: #3376FE;
+            }
+          }
+
+          .qualificationInfo-fileItem-detail {
+            margin-left: 8px;
+
+            .qualificationInfo-fileItem-detail-name {
+              font-weight: 500;
+              font-size: 14px;
+              height: 14px;
+              color: #17181A;
+              line-height: 14px;
+              margin-bottom: 4px;
+            }
+
+            .qualificationInfo-fileItem-detail-sub {
+              width: 200;
+              font-weight: 400;
+              font-size: 12px;
+              height: 12px;
+              color: #7A8599;
+              line-height: 12px;
+              white-space: nowrap;
+              overflow: hidden;
+              text-overflow: ellipsis;
+            }
+          }
 
-          &:hover {
-            color: #3376FE;
+          &:nth-child(3n) {
+            margin-right: 0;
           }
+
         }
+      }
+    }
+
+    .qualificationInfo-apply {
+      padding: 16px;
+      background: #FFFFFF;
+      border-radius: 4px;
+      margin-top: 16px;
 
-        .qualificationInfo-fileItem-detail {
-          margin-left: 8px;
+      .editContent-header-title {
+        display: flex;
+        width: 100%;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        font-weight: bold;
+        font-size: 16px;
+        height: 16px;
+        line-height: 16px;
+        color: #17181A;
+        margin-bottom: 16px;
 
-          .qualificationInfo-fileItem-detail-name {
-            font-weight: 500;
+       
+      }
+
+      .editContent-header-title-sub {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+
+        &>div {
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+          width: 347px;
+          font-weight: 400;
+          font-size: 14px;
+          height: 14px;
+          color: #525866;
+          line-height: 14px;
+
+          &>span {
+            font-weight: 400;
             font-size: 14px;
             height: 14px;
             color: #17181A;
             line-height: 14px;
-            margin-bottom: 4px;
-          }
-
-          .qualificationInfo-fileItem-detail-sub {
-            width: calc(100% - 65px);
-            font-weight: 400;
-            font-size: 12px;
-            height: 12px;
-            color: #7A8599;
-            line-height: 12px;
             white-space: nowrap;
             overflow: hidden;
             text-overflow: ellipsis;
           }
-        }
 
-        &:nth-child(3n) {
-          margin-right: 0;
         }
-
       }
-    }
-  }
 
-  .qualificationInfo-apply {
-    padding: 16px;
-    background: #FFFFFF;
-    border-radius: 4px;
-    margin-top: 16px;
+      .editContent-header-title-authStandard {
+        position: relative;
+        background: #F7F9FC;
+        border-radius: 4px;
+        min-height: 56px;
+        padding-right: 64px;
+        padding: 6px 12px;
+        font-weight: 400;
+        font-size: 14px;
+        color: #17181A;
+        line-height: 18px;
+        margin-top: 12px;
+        border: 1px solid #DAE4F2;
 
-    .editContent-header-title {
-      display: flex;
-      width: 100%;
-      flex-direction: row;
-      justify-content: space-between;
-      align-items: center;
-      font-weight: bold;
-      font-size: 16px;
-      height: 16px;
-      line-height: 16px;
-      color: #17181A;
-      margin-bottom: 12px;
-    }
+        &::after {
+          position: absolute;
+          content: '';
+          top: 8px;
+          right: 12px;
+          display: inline-block;
+          width: 40px;
+          height: 40px;
+          background: url('../../../../static/shouquanyiju.png');
+          background-size: contain;
+          background-repeat: no-repeat;
+        }
+      }
 
-    .editContent-header-title-sub {
-      display: flex;
-      flex-direction: row;
-      justify-content: flex-start;
-      align-items: center;
-      &>div {
+      .editContent-header-title-detail {
+        position: relative;
+        top: 2px;
         display: flex;
         flex-direction: row;
         justify-content: flex-start;
-        align-items: center;
-        width: 340px;
-        font-weight: 400;
-        font-size: 14px;
-        height: 14px;
-        color: #525866;
-        line-height: 14px;
+        align-items: flex-start;
+        border-radius: 4px;
+        max-height: 72px;
+        margin-top: 12px;
+        margin-bottom: 12px;
 
         &>span {
+          display: inline-block;
           font-weight: 400;
           font-size: 14px;
           height: 14px;
-          color: #17181A;
           line-height: 14px;
-          white-space: nowrap;
+          color: #525866;
+        }
+
+        &>div {
+          position: relative;
+          top: -2px;
           overflow: hidden;
+          white-space: nowrap;
           text-overflow: ellipsis;
+          font-weight: 400;
+          font-size: 14px;
+          color: #17181A;
+          line-height: 18px;
         }
-
       }
-    }
 
-    .editContent-header-title-detail {
-      position: relative;
-      top: 2px;
-      display: flex;
-      flex-direction: row;
-      justify-content: flex-start;
-      align-items: flex-start;
-      border-radius: 4px;
-      max-height: 72px;
-      margin-top: 12px;
-      margin-bottom: 12px;
-
-      &>span {
-        display: inline-block;
+      .appendix {
         font-weight: 400;
-        font-size: 14px;
         height: 14px;
         line-height: 14px;
+        font-size: 14px;
         color: #525866;
       }
+    }
 
-      &>div {
-        position: relative;
-        top: -2px;
-        overflow: hidden;
-        white-space: nowrap;
-        text-overflow: ellipsis;
-        font-weight: 400;
-        font-size: 14px;
+    .deptOpinion {
+      padding: 16px;
+      background: #FFFFFF;
+      border-radius: 4px;
+      margin-top: 16px;
+
+      .deptOpinion-title {
+        font-weight: 500;
+        font-size: 16px;
+        height: 16px;
         color: #17181A;
-        line-height: 18px;
+        line-height: 16px;
+        margin-bottom: 16px;
       }
-    }
 
-    .appendix {
-      font-weight: 400;
-      height: 14px;
-      line-height: 14px;
-      font-size: 14px;
-      color: #525866;
-    }
-  }
+      .time-info {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
 
-  .deptOpinion {
-    padding: 16px;
-    background: #FFFFFF;
-    border-radius: 4px;
-    margin-top: 16px;
+        .info-tag {
+          font-weight: 400;
+          font-size: 14px;
+          height: 14px;
+          line-height: 14px;
+          color: #525866;
 
-    .deptOpinion-title {
-      font-weight: 500;
-      font-size: 16px;
-      height: 16px;
-      color: #17181A;
-      line-height: 16px;
-      margin-bottom: 16px;
-    }
+          &>span {
+            color: #17181A;
+          }
 
-    .time-info {
-      display: flex;
-      flex-direction: row;
-      justify-content: flex-start;
-      align-items: center;
+          &:first-child {
+            margin-right: 214px;
+          }
+        }
+      }
 
-      .info-tag {
-        font-weight: 400;
-        font-size: 14px;
-        height: 14px;
-        line-height: 14px;
-        color: #525866;
+      .time-wrapper {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        margin-bottom: 20px;
 
-        &>span {
-          color: #17181A;
-        }
+        .type,
+        .time {
+          display: flex;
+          flex-direction: column;
+          justify-content: flex-start;
+          align-items: flex-start;
+          margin-right: 61px;
 
-        &:first-child {
-          margin-right: 214px;
+          &>span {
+            font-weight: 400;
+            font-size: 14px;
+            height: 14px;
+            color: #17181A;
+            line-height: 14px;
+            margin-bottom: 12px;
+          }
         }
-      }
-    }
 
-    .time-wrapper {
-      display: flex;
-      flex-direction: row;
-      justify-content: flex-start;
-      align-items: center;
-      margin-bottom: 20px;
+      }
 
-      .type,
-      .time {
+      .manageOpinion-detail {
         display: flex;
-        flex-direction: column;
+        width: 100%;
+        margin-top: 12px;
+        flex-direction: row;
         justify-content: flex-start;
         align-items: flex-start;
-        margin-right: 80px;
 
         &>span {
           font-weight: 400;
-          font-size: 14px;
           height: 14px;
-          color: #17181A;
+          font-size: 14px;
+          color: #525866;
           line-height: 14px;
-          margin-bottom: 12px;
         }
-      }
-
-    }
-
-    .manageOpinion-detail {
-      display: flex;
-      width: 100%;
-      margin-top: 12px;
-      flex-direction: row;
-      justify-content: flex-start;
-      align-items: flex-start;
-
-      &>span {
-        font-weight: 400;
-        height: 14px;
-        font-size: 14px;
-        color: #525866;
-        line-height: 14px;
-      }
 
-      &>div {
-        position: relative;
-        top: -2px;
-        font-weight: 400;
-        font-size: 14px;
-        color: #17181A;
-        line-height: 18px;
+        &>div {
+          position: relative;
+          top: -2px;
+          font-weight: 400;
+          font-size: 14px;
+          color: #17181A;
+          line-height: 18px;
+        }
       }
     }
   }
+
 }
 
 .QualificationApproval {
-  padding: 16px;
-  background: #FFFFFF;
-  border-radius: 4px;
-
 
-  .toolBar {
-    display: flex;
-    flex-direction: row;
-    justify-content: space-between;
-    align-items: center;
+  .pageContent {
+    padding: 16px;
+    background: #FFFFFF;
+    border-radius: 4px;
 
-    .filter {
+    .toolBar {
       display: flex;
       flex-direction: row;
-      justify-content: flex-start;
+      justify-content: space-between;
       align-items: center;
+      margin-bottom: 16px;
 
-      .filterItem {
+      .filter {
         display: flex;
         flex-direction: row;
-        justify-content: center;
+        justify-content: flex-start;
         align-items: center;
+
+        .filterItem {
+          display: flex;
+          flex-direction: row;
+          justify-content: center;
+          align-items: center;
+        }
       }
-    }
 
-    .btnGroup {
+      .btnGroup {
 
-      .import,
-      .export {
-        cursor: pointer;
-        display: inline-block;
-        font-size: 14px;
-        font-weight: 400;
-        color: #17181A;
-        line-height: 24px;
-        padding: 0 14px;
-        margin-right: 8px;
-        background: #FAFCFF;
-        border-radius: 4px;
-        border: 1px solid #DAE2F2;
-      }
+        .import,
+        .export {
+          cursor: pointer;
+          display: inline-block;
+          font-size: 14px;
+          font-weight: 400;
+          color: #17181A;
+          line-height: 24px;
+          padding: 0 14px;
+          margin-right: 8px;
+          background: #FAFCFF;
+          border-radius: 4px;
+          border: 1px solid #DAE2F2;
+        }
 
-      .add {
-        cursor: pointer;
-        display: inline-block;
-        font-size: 14px;
-        font-weight: 400;
-        color: #FFFFFF;
-        line-height: 24px;
-        padding: 0 14px;
-        background: #3377FF;
-        border-radius: 4px;
+        .add {
+          cursor: pointer;
+          display: inline-block;
+          font-size: 14px;
+          font-weight: 400;
+          color: #FFFFFF;
+          line-height: 24px;
+          padding: 0 14px;
+          background: #3377FF;
+          border-radius: 4px;
+        }
       }
-    }
 
+    }
   }
 }

+ 12 - 5
src/pages/qualificationMana/qualificationAuth/authHisttory/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2024-12-06 14:42:57
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-12-06 16:24:11
+ * @LastEditTime: 2024-12-25 16:00:01
  * @FilePath: /MediResourceManaSys/src/pages/qualificationMana/qualificationAuth/authHisttory/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AEi m z z
  */
@@ -12,6 +12,7 @@ import { createFromIconfontCN } from '@ant-design/icons';
 import React, { Children } from 'react'
 import { Timeline } from 'antd'
 import './style.less'
+import { authTimeType } from '@/constant';
 
 const IconFont = createFromIconfontCN({
     scriptUrl: '',
@@ -20,7 +21,13 @@ const IconFont = createFromIconfontCN({
 
 export default function AuthHisContent({ hisList }: { hisList: any[] }) {
 
-   
+    const getPeriodStr = (code:number)=>{
+        const result = authTimeType.filter((a)=>a.value == code);
+        if(result.length>0){
+            return result[0].label
+        }
+        return undefined
+    }
 
     const dotNode = (isActive=false)=>{
         return <div style={{display:'flex',justifyContent:'center',alignItems:'center',width:16,height:16,border:'2px solid #E7EBF2',borderRadius:'50%'}}>
@@ -40,13 +47,13 @@ export default function AuthHisContent({ hisList }: { hisList: any[] }) {
                                 <Timeline.Item key={index} dot={dotNode(index == 0?true:false)} >
                                       <div style={{fontWeight:'bold',fontSize:14,color:'#17181A',height:14,lineHeight:'14px',marginBottom:8}}>{`${a.adjustUserName} ${a.adjustTime}`}</div>
                                       <div style={{height:14,fontSize:12,color:'#176DE6',lineHeight:'14px',marginBottom:8,paddingLeft:6}}>
-                                        <img style={{width:43,height:14,marginRight:4}} src={require('../../../../../static/tiaozhenghou.png')} />{a.qualificationPeriodAfter} {`(${a.beginDateAfter}至${a.endDateAfter})`}
+                                        <img style={{width:43,height:14,marginRight:4}} src={require('../../../../../static/tiaozhenghou.png')} />{getPeriodStr(a.qualificationPeriodAfter)} {`(${a.beginDateAfter}至${a.endDateAfter})`}
                                       </div>
                                       <div style={{height:14,fontSize:12,color:'#525866',lineHeight:'14px',marginBottom:8,paddingLeft:6}}>
                                         <img style={{width:43,height:14,marginRight:4}} src={require('../../../../../static/tiaozhengqian.png')} />
-                                        {a.qualificationPeriodBefore} {`(${a.beginDateBefore}至${a.endDateBefore})`}
+                                        {getPeriodStr(a.qualificationPeriodBefore)} {`(${a.beginDateBefore}至${a.endDateBefore})`}
                                       </div>
-                                      <div style={{padding:'5px 8px',fontSize:12,color:'#525866',background:'#F7F9FC',borderRadius:4}}>{a.memo}</div>
+                                      {(a.memo&&a.memo.length>0)&&<div style={{padding:'5px 8px',fontSize:12,color:'#525866',background:'#F7F9FC',borderRadius:4}}>{a.memo}</div>}
                                 </Timeline.Item>
                              )
                         })

+ 29 - 20
src/pages/qualificationMana/qualificationAuth/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-12-06 17:23:05
+ * @LastEditTime: 2024-12-25 15:46:44
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -17,10 +17,10 @@ import { KCIMTable } from '@/components/KCIMTable';
 import { createFromIconfontCN } from '@ant-design/icons';
 
 import { ActionType, arrayMoveImmutable, ProFormText, ProFormTextArea, useRefFunction } from '@ant-design/pro-components';
-import { ModalForm, ProFormCascader, ProFormCheckbox, ProFormDateRangePicker, ProFormDependency, ProFormDigit, ProFormSelect, ProFormSwitch } from '@ant-design/pro-form'
+import { ModalForm, ProFormCascader, ProFormCheckbox, ProFormDateRangePicker, ProFormDependency, ProFormDigit, ProFormRadio, ProFormSelect, ProFormSwitch } from '@ant-design/pro-form'
 import { ProColumns } from '@ant-design/pro-table';
 import { Drawer, Input, message, Popconfirm, Popover, Switch } from 'antd';
-import { Key, useEffect, useRef, useState } from 'react';
+import { Fragment, Key, useEffect, useRef, useState } from 'react';
 import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
 
 
@@ -33,8 +33,10 @@ import { getDicDataBySysId } from '@/services/getDic';
 import { authTimeType, KcimCenterSysId } from '@/constant';
 import TableTransfer from './transform';
 import React from 'react';
+import 'moment/locale/zh-cn';
 import moment from 'moment';
 import AuthHisContent from './authHisttory';
+import { useAccess } from '@umijs/max';
 
 
 
@@ -62,6 +64,10 @@ export default function QualificationAuth({ isChildComponent = false, qualifiCod
     const [currentEditRow, set_currentEditRow] = useState<any>(undefined);
     const [currentPageTableData,set_currentPageTableData] = useState<any[]>([]);
 
+    const access = useAccess();
+    const tabs = access.whatCanIDoInThisPage(location.pathname.replace('/MediResourceManaSys', ''));
+    const a = tabs.reduce((prev: any, cur: any) => `${prev},${cur.code}`, '');
+
     const tableRef = useRef<ActionType>();
     const drawerTableRef = useRef<ActionType>();
     const [drawerTableData, set_drawerTableData] = useState<any[]>([]);
@@ -124,7 +130,7 @@ export default function QualificationAuth({ isChildComponent = false, qualifiCod
                         )
                     }
                     {
-                        (!operationFlag && !techFlag) && ('-')
+                        (!operationFlag && !techFlag) && (<Fragment/>)
                     }
                 </div>
             },
@@ -190,7 +196,7 @@ export default function QualificationAuth({ isChildComponent = false, qualifiCod
                     return '长期授权'
                 }
                 if (qualificationPeriod == 2) {
-                    return '临授权'
+                    return '临授权'
                 }
                 if (qualificationPeriod == 3) {
                     return '单次授权'
@@ -208,7 +214,7 @@ export default function QualificationAuth({ isChildComponent = false, qualifiCod
                     
                 return <>{`${beginDate}至${endDate}`}
                     {applyAdjust.length > 0 && (
-                        <Popover className='qualificationAuth-popover' content={content} title={false} >
+                        <Popover className='qualificationAuth-popover' overlayInnerStyle={{borderRadius:4}} content={content} title={false} >
                             <IconFont type={'icon-qingliangtishi'} style={{marginLeft:10,cursor:'pointer' }} />
                         </Popover>
                     )}</>;
@@ -230,13 +236,16 @@ export default function QualificationAuth({ isChildComponent = false, qualifiCod
         {
             title: '操作',
             key: 'option',
-            width: 60,
+            hideInTable:a.indexOf('medical-adjust') == -1,
+            width: 100,
             fixed: 'right',
             valueType: 'option',
             render: (_: any, record: any) => {
-                return [
-                    <UpDataActBtn key={'act'} record={record} type='EDIT' />,
-                ]
+                const {currentStatus,allowReAuthorize} = record;
+                    return [
+                        currentStatus == '授权中'?<UpDataActBtn key={'act'} record={record} type='EDIT' />:allowReAuthorize == 1&&<UpDataActBtn key={'act'} record={record} type='AUTH' />,
+                    ]
+                
             },
         },
 
@@ -263,6 +272,7 @@ export default function QualificationAuth({ isChildComponent = false, qualifiCod
 
 
     const updateTable = async (formVal: any, type: 'EDIT' | 'AUTH') => {
+        console.log({formVal});
         try {
             if (type == 'EDIT') {
 
@@ -307,7 +317,6 @@ export default function QualificationAuth({ isChildComponent = false, qualifiCod
     const formRef = useRef();
     const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'AUTH' }) => {
         const ref = React.createRef<{ save: any; }>();
-        console.log({record});
         return (
             <ModalForm
                 title={type == 'EDIT' ? '调整授权' : '重新授权'}
@@ -315,21 +324,21 @@ export default function QualificationAuth({ isChildComponent = false, qualifiCod
                 formRef={formRef}
                 initialValues={{
                     // memo: record.applyMemo,
-                    qualificationPeriod:`1`,
+                    qualificationPeriod:1,
                     timerange:[moment().startOf("day"), moment().startOf("day")]
                 }}
                 trigger={
                     type == 'EDIT' ? <a key="edit" >调整</a> : <a className='auth'>重新授权</a>
                 }
                 onFinish={(val) => {
-                    return updateTable(type == 'EDIT' ? { ...record, ...val } : { ...val }, type);
+                    return updateTable(type == 'EDIT' ? { ...record, ...val } : {...record, ...val }, type);
                 }}
                 modalProps={{ destroyOnClose: true }}
                 colProps={{ span: 24 }}
                 grid
             >
 
-                <ProFormCheckbox.Group label='授权期限:' name={'qualificationPeriod'} options={authTimeType} />
+                <ProFormRadio.Group label='授权期限:' name={'qualificationPeriod'} options={authTimeType} />
                 <ProFormDateRangePicker label='授权时间:' name='timerange' />
                 <ProFormTextArea label='调整原因:' name={'memo'} />
 
@@ -338,7 +347,7 @@ export default function QualificationAuth({ isChildComponent = false, qualifiCod
     }
 
     const tableDataSearchHandle = (key: string) => {
-        set_tableDataFilterParams({ ...tableDataFilterParams, current: 1, name: tableDataSearchKeywords })
+        set_tableDataFilterParams({ ...tableDataFilterParams, current: 1, [key]: tableDataSearchKeywords })
     }
 
     const getQualClassRequest = async () => {
@@ -412,7 +421,7 @@ export default function QualificationAuth({ isChildComponent = false, qualifiCod
     
     useEffect(()=>{
         if(currentPageTableData&&drawerVisible){
-            const needitem = currentPageTableData.filter((a)=>a.userId == currentEditRow.userId);
+            const needitem = currentPageTableData.filter((a)=>a.qualification.id == currentEditRow.qualification.id);
             if(needitem.length>0){
                   set_currentEditRow(needitem[0]);
             }
@@ -428,12 +437,12 @@ export default function QualificationAuth({ isChildComponent = false, qualifiCod
 
     return (
         <KCIMPagecontainer className='QualificationAuth' style={!isChildComponent ? {} : { border: 'none' }} title={false}>
-            <Drawer destroyOnClose={true} className='authDetailDrawer' width={1100}
+            <Drawer destroyOnClose={true} className='qualificationAuth-authDetailDrawer' width={1100}
                 open={drawerVisible} headerStyle={{ display: 'none' }} bodyStyle={{ background: '#F5F7FA', padding: 16 }}
             >
                 <div className='authDetailDrawer-topBar'>
                     <div className='authDetailDrawer-topBar-title'>
-                        <IconFont onClick={() => set_drawerVisible(false)} type={'iconquxiao'} style={{ marginRight: 12 }} />{'授权详情'}
+                        <div className='closeIcon' onClick={() => set_drawerVisible(false)}><IconFont  type={'iconquxiao'} /></div>{'授权详情'}
                     </div>
                     {/* <div className='btnGroup'>
                         <span onClick={() => set_drawerVisible(false)}>取消</span>
@@ -533,7 +542,7 @@ export default function QualificationAuth({ isChildComponent = false, qualifiCod
                                         set_tableDataSearchKeywords(e.target.value);
                                         if (e.target.value.length == 0) {
                                             set_tableDataSearchKeywords('');
-                                            tableRef.current?.reload();
+                                            set_tableDataFilterParams({...tableDataFilterParams,name:undefined})
                                         }
                                     }}
 
@@ -556,7 +565,7 @@ export default function QualificationAuth({ isChildComponent = false, qualifiCod
                                                 current: 1,
                                                 techFlag: checkedValue.findIndex((a) => a == '医疗技术') != -1 ? 1 : 0,
                                                 operationFlag: checkedValue.findIndex((a) => a == '手术') != -1 ? 1 : 0,
-                                                enableFlag: checkedValue.findIndex((a) => a == '已停用') != -1 ? 0 : 1,
+                                                // enableFlag: checkedValue.findIndex((a) => a == '已停用') != -1 ? 0 : 1,
                                             })
                                         },
                                     }}

+ 16 - 1
src/pages/qualificationMana/qualificationAuth/style.less

@@ -13,7 +13,7 @@
    }
 }
 
-.authDetailDrawer {
+.qualificationAuth-authDetailDrawer {
   .authDetailDrawer-topBar {
     display: flex;
     flex-direction: row;
@@ -25,6 +25,21 @@
       font-weight: 500;
       font-size: 16px;
       color: #17181A;
+      .closeIcon {
+        position: relative;
+        top:2px;
+        display: inline-flex;
+        justify-content: center;
+        align-items: center;
+        width: 24px;
+        height: 24px;
+        cursor: pointer;
+        margin-right: 8px;
+        border-radius: 4px;
+        &:hover {
+          background-color: #E6EAF2;
+        }
+      }
     }
 
     .btnGroup {

BIN
src/pages/qualificationMana/qualificationBatchAuth/DoctorSelection/images/renyuantubiao_yellow.png


+ 114 - 0
src/pages/qualificationMana/qualificationBatchAuth/DoctorSelection/index.tsx

@@ -0,0 +1,114 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-12-11 11:21:13
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-12-13 10:01:58
+ * @FilePath: /MediResourceManaSys/src/pages/qualificationMana/qualificationBatchAuth/DoctorSelection/index.tsx
+ * @Description: 从外部传入医生数据,并对外提供选中项的完整数据
+ */
+
+import React, { useState, useMemo, useEffect, ChangeEvent } from 'react';
+import './style.less';
+import { ProFormCheckbox, ProFormText } from '@ant-design/pro-components';
+
+interface Doctor {
+    name: string;
+    id: string;
+    deptName: string;
+}
+
+interface DoctorSelectionProps {
+    doctorsData: Doctor[];
+    // 当选中项变化时的回调,返回完整的选中医生数组
+    onSelectedChange?: (selectedDoctors: Doctor[]) => void;
+    // 新增属性,用于从外部控制清空当前已选中的医生。当此属性从false变为true时清空选择
+    clearSelection?: boolean;
+}
+
+const DoctorSelection: React.FC<DoctorSelectionProps> = ({ doctorsData = [], onSelectedChange, clearSelection }) => {
+    const [searchText, setSearchText] = useState('');
+    const [selectedIds, setSelectedIds] = useState<string[]>([]);
+
+    const filteredDoctors = useMemo(() => {
+        const query = searchText.trim().toLowerCase();
+        return doctorsData.filter(d =>
+            d.name.toLowerCase().includes(query) ||
+            `${d.id}`.toLowerCase().includes(query) ||
+            d.deptName.toLowerCase().includes(query)
+        );
+    }, [searchText, doctorsData]);
+
+    const handleCheck = (code: string) => {
+        setSelectedIds(prev => {
+            if (prev.includes(code)) {
+                return prev.filter(item => item !== code);
+            } else {
+                return [...prev, code];
+            }
+        });
+    };
+
+    const isChecked = (code: string) => selectedIds.includes(code);
+
+    const handleSearchChange = (e: ChangeEvent<HTMLInputElement>) => {
+        setSearchText(e.target.value);
+    };
+
+    // 当 clearSelection 从父组件传入为 true 时清空所有选择
+    useEffect(() => {
+        if (clearSelection === true) {
+            setSelectedIds([]);
+        }
+    }, [clearSelection]);
+
+    // 当 selectedIds 变化时,通过 selectedIds 匹配对应的医生完整数据,将选中数据传递给 onSelectedChange 回调
+    useEffect(() => {
+        const selectedDoctors = doctorsData.filter(d => selectedIds.includes(d.id));
+        onSelectedChange?.(selectedDoctors);
+    }, [selectedIds, doctorsData, onSelectedChange]);
+
+    return (
+        <div className="doctor-selection-container">
+            <div className="doctor-selection-header">选择医生</div>
+            <div className='doctor-selection-filter'>
+                <ProFormText 
+                    noStyle 
+                    placeholder="姓名, 工号, 科室" 
+                    fieldProps={{
+                        value: searchText,
+                        onChange: handleSearchChange,
+                    }} 
+                />
+            </div>
+
+            <div className="doctor-selection-list">
+                {filteredDoctors.map((d, index) => (
+                    <div
+                        key={index}
+                        className={`doctor-selection-item ${isChecked(d.id) ? 'selected' : ''}`}
+                    >
+                        <img 
+                            src={require('./images/renyuantubiao_yellow.png')} 
+                            alt="avatar" 
+                            className="doctor-selection-avatar" 
+                        />
+                        <div className="doctor-selection-info">
+                            <div className="doctor-selection-name">{d.name}</div>
+                            <div className="doctor-selection-subinfo">{d.id} | {d.deptName}</div>
+                        </div>
+                        <ProFormCheckbox  
+                            className="doctor-selection-checkbox" 
+                            noStyle 
+                            fieldProps={{
+                                checked: isChecked(d.id),
+                                onChange: () => handleCheck(d.id)
+                            }} 
+                        />
+                    </div>
+                ))}
+            </div>
+        </div>
+    );
+};
+
+export default DoctorSelection;

+ 75 - 0
src/pages/qualificationMana/qualificationBatchAuth/DoctorSelection/style.less

@@ -0,0 +1,75 @@
+.doctor-selection-container {
+    padding-left: 8px;
+    padding-right: 8px;
+
+    .doctor-selection-header {
+        font-weight: 500;
+        font-size: 16px;
+        height: 16px;
+        color: #17181A;
+        line-height: 16px;
+        margin-top: 8px;
+        margin-bottom: 16px;
+        padding: 0 8px;
+    }
+
+    .doctor-selection-filter {
+        padding: 0 8px;
+    }
+
+    .doctor-selection-list {
+        margin-top: 12px;
+        height: calc(100vh - 173px);
+        overflow-y: auto;
+
+        .doctor-selection-item {
+            display: flex;
+            align-items: center;
+            padding: 8px;
+            border-radius: 4px;
+            padding-right: 16px;
+
+            &.selected {
+                background-color: #F0F2F5;
+            }
+
+            .doctor-selection-avatar {
+                width: 24px;
+                height: 24px;
+                //   border-radius: 4px;
+                margin-right: 8px;
+            }
+
+            .doctor-selection-info {
+                flex: 1;
+                display: flex;
+                flex-direction: column;
+
+                .doctor-selection-name {
+                    font-weight: 500;
+                    font-size: 14px;
+                    height: 14px;
+                    color: #17181A;
+                    line-height: 14px;
+                    margin-bottom: 4px;
+                }
+
+                .doctor-selection-subinfo {
+                    font-weight: 400;
+                    font-size: 12px;
+                    height: 12px;
+                    color: #7A8599;
+                    line-height: 12px;
+                }
+            }
+
+            .doctor-selection-checkbox {
+                margin-left: 10px;
+                // width: 16px;
+                // height: 16px;
+                // border: 1px solid #dae2f2;
+                // border-radius: 2px;
+            }
+        }
+    }
+}

+ 522 - 0
src/pages/qualificationMana/qualificationBatchAuth/index.tsx

@@ -0,0 +1,522 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 11:30:33
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-12-31 13:53:16
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+
+
+
+import KCIMPagecontainer from '@/components/KCIMPageContainer';
+import { KCIMTable } from '@/components/KCIMTable';
+import { createFromIconfontCN } from '@ant-design/icons';
+
+import { ActionType, arrayMoveImmutable, ProFormText, ProFormTextArea, useRefFunction } from '@ant-design/pro-components';
+import ProForm, { ModalForm, ProFormCascader, ProFormCheckbox, ProFormDateRangePicker, ProFormDependency, ProFormDigit, ProFormInstance, ProFormRadio, ProFormSelect, ProFormSwitch } from '@ant-design/pro-form'
+import { ProColumns } from '@ant-design/pro-table';
+import { Alert, Drawer, Input, message } from 'antd';
+import { Key, useEffect, useRef, useState } from 'react';
+
+
+
+import { batchAuthDataCheck, editData, getLeftDataReq, getTableDataReq } from './service';
+
+import './style.less';
+
+import { getDicDataBySysId } from '@/services/getDic';
+import { authTimeType, KcimCenterSysId } from '@/constant';
+
+import 'moment/locale/zh-cn';
+import moment from 'moment';
+import DoctorSelection from './DoctorSelection';
+import { sparse } from 'mathjs';
+
+
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+
+
+export default function QualificationBatchAuth({ isChildComponent = false, qualifiCode, onTableSelectChange, defaultSelectedKeys }: {
+    isChildComponent: boolean, qualifiCode: string, onTableSelectChange?: (selectedRowKeys: any[], selectedRows: any[], info: any) => void,
+    defaultSelectedKeys?: Key[]
+}) {
+    const formRef = useRef<ProFormInstance>();
+    const drawerFormRef = useRef<ProFormInstance>();
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
+    const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
+    const [dataSource, set_dataSource] = useState<any[]>([]);
+    const [operationLevel, set_operationLevel] = useState<any[]>([]);
+    const [drawerVisible, set_drawerVisible] = useState(false);
+    const [currentEditRow, set_currentEditRow] = useState<any>(undefined);
+    const [currentPageTableData, set_currentPageTableData] = useState<any[]>([]);
+    const [currentSelectedLeftRows, set_currentSelectedLeftRows] = useState<any[]>([]);
+    const [currentSelectedTableRows, set_currentSelectedTableRows] = useState<any[]>([]);
+    const [currentSelectedDrawerTableRows, set_currentSelectedDrawerTableRows] = useState<any[]>([]);
+
+    const tableRef = useRef<ActionType>();
+    const drawerTableRef = useRef<ActionType>();
+    const [drawerTableData, set_drawerTableData] = useState<any[]>([]);
+    const [modalFormVisible, set_modalFormVisible] = useState(false);
+    const [clearSelection, set_clearSelection] = useState(false);
+
+    const columns: ProColumns[] = [
+        {
+            title: '资质编码',
+            width: 150,
+            ellipsis: true,
+            dataIndex: 'code'
+        },
+        {
+            title: '资质名称',
+            ellipsis: true,
+            dataIndex: 'name'
+        },
+        {
+            title: '资质分类',
+            ellipsis: true,
+            dataIndex: 'qualificationTypeName'
+        },
+        {
+            title: '授权依据',
+            ellipsis: true,
+            dataIndex: 'standard',
+
+        },
+        {
+            title: '特殊类别',
+            ellipsis: true,
+            width: 150,
+            renderText(text, record, index, action) {
+                const { operationFlag, techFlag, operationLevelCode } = record;
+                return <div>
+                    {
+                        techFlag == 1 && (
+                            <span style={{
+                                display: 'inline-flex', width: 64, height: 20, justifyContent: 'center',
+                                alignItems: 'center', background: '#FFF5EB', borderRadius: 4, fontSize: 12, color: '#FF8000', marginRight: 4
+                            }}>医疗技术</span>
+                        )
+                    }
+                    {
+                        (operationFlag == 1 && operationLevelCode) && (
+                            <span style={{
+                                display: 'inline-flex', width: 64, height: 20, justifyContent: 'center',
+                                alignItems: 'center', background: '#E8FCF6', borderRadius: 4, fontSize: 12, color: '#009966'
+                            }}>{
+                                    operationLevel.filter((a) => a.value == operationLevelCode).length > 0 ? (operationLevel.filter((a) => a.value == operationLevelCode))[0].name : <></>
+                                }</span>
+                        )
+                    }
+                    {/* {
+                        (!operationFlag && !techFlag) && ('-')
+                    } */}
+                </div>
+            },
+        },
+
+
+    ];
+
+    const drawerTablecolumns: ProColumns[] = [
+        {
+            title: '姓名',
+            width: 70,
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                const { userInfo: { name } } = record;
+                return name;
+            },
+        },
+        {
+            title: '工号',
+            ellipsis: true,
+            dataIndex: 'userId'
+        },
+        {
+            title: '所在科室',
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                const { userInfo: { deptName } } = record;
+                return deptName;
+            },
+        },
+        {
+            title: '资质名称',
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                const { qualificationInfo: { name } } = record;
+                return name;
+            },
+
+        },
+        {
+            title: '授权',
+            width: 320,
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                const { qualificationPeriod, beginDate, endDate, applyStatus } = record;
+                // <>{`${beginDate}至${endDate}`}</>
+                if (applyStatus == 2 || applyStatus == 3 || applyStatus == 4) {
+                    return <span style={{ fontSize: 14, color: '#FF8C19' }}>申请中</span>
+                } else {
+                    return `${qualificationPeriod == 1 ? '长期授权' : qualificationPeriod == 2 ? '临时授权' : '单次授权'}(${beginDate}至${endDate})`
+                }
+            },
+
+        },
+    ]
+
+
+    const getTableData = async (params: any) => {
+        const { qualificationTypeCode } = params;
+        if (!qualificationTypeCode) {
+
+        }
+        const resp = await getTableDataReq(params);
+        if (resp) {
+            const data = (resp.list).map((a: any, index: number) => ({ id: index, ...a }));
+            set_currentPageTableData(data);
+            return {
+                data,
+                success: true
+            }
+        } else {
+            return []
+        }
+    }
+
+
+    const updateTable = async (formVal: any, type: 'EDIT_DRAWER' | 'EDIT') => {
+        try {
+            let result: any[] = [];
+            const arr = currentSelectedLeftRows.map((a) => {
+                const qualifis = currentSelectedTableRows.map((b) => ({
+                    qualifisCode: `${a.id}-${b.code}`,
+                    userId: a.id,
+                    qualificationCode: b.code,
+                    qualificationPeriod: Number(formVal.qualificationPeriod),
+                    beginDate: formVal.timerange[0],
+                    endDate: formVal.timerange[1],
+                    managerOpinion: formVal.memo
+                }));
+                return qualifis
+            });
+            if (currentSelectedDrawerTableRows.length > 0) {
+                const keys = currentSelectedDrawerTableRows.map((a) => `${a.userId}-${a.qualificationCode}`);
+                const needDelItems = drawerTableData.filter((a) => !(keys.includes(`${a.userId}-${a.qualificationCode}`)));
+                const needDelItemsKey = needDelItems.map((a) => `${a.userId}-${a.qualificationCode}`);
+                result = arr.flat().filter((a: any) => !(needDelItemsKey.includes(a.qualifisCode)));
+
+            } else {
+                const needDelItemsKey = drawerTableData.map((a) => `${a.userId}-${a.qualificationCode}`);
+
+                result = arr.flat().filter((a: any) => !(needDelItemsKey.includes(a.qualifisCode)));
+            }
+
+            result.forEach(obj => {
+                delete obj.qualifisCode;
+            });
+            const resp = await editData(result);
+            if (resp) {
+
+                set_currentSelectedLeftRows([]);
+                set_currentSelectedDrawerTableRows([]);
+                set_currentSelectedTableRows([]);
+                set_clearSelection(true);
+                setTimeout(() => set_clearSelection(false), 0);
+                set_drawerVisible(false);
+                set_modalFormVisible(false);
+
+
+                tableRef.current?.reload();
+                message.success('操作成功!');
+            }
+
+            return true;
+
+        } catch (error) {
+
+            console.log({ error });
+            return false;
+        }
+
+
+
+
+    }
+
+
+    const tableDataSearchHandle = (key: string) => {
+        set_tableDataFilterParams({ ...tableDataFilterParams, current: 1, [key]: tableDataSearchKeywords })
+    }
+
+    const getLeftDataHandle = async () => {
+        const resp = await getLeftDataReq();
+        if (true) {
+            set_dataSource(resp);
+        }
+    }
+
+
+    const cancelBatchAuthHandle = () => {
+        set_currentSelectedLeftRows([]);
+        set_currentSelectedTableRows([]);
+        set_clearSelection(true);
+        setTimeout(() => set_clearSelection(false), 0);
+    }
+    const batchAuthHandle = async () => {
+        if (currentSelectedLeftRows.length == 0) {
+            message.warn('请选择医生!');
+            return
+        }
+        if (currentSelectedTableRows.length == 0) {
+            message.warn('请选择资质!');
+            return
+        }
+        const result = currentSelectedLeftRows.map((a) => {
+            const qualifis = currentSelectedTableRows.map((b) => ({
+                userId: a.id,
+                qualificationCode: b.code
+            }));
+            return qualifis
+        });
+
+        const resp = await batchAuthDataCheck(result.flat());
+        if (resp) {
+            if (resp.length > 0) {
+                set_drawerTableData(resp);
+                set_drawerVisible(true);
+            } else {
+                set_modalFormVisible(true);
+            }
+        }
+    }
+
+
+    useEffect(() => {
+        if (!modalFormVisible) {
+            set_currentSelectedLeftRows([]);
+            set_currentSelectedDrawerTableRows([]);
+            set_currentSelectedTableRows([]);
+            set_clearSelection(true);
+            setTimeout(() => set_clearSelection(false), 0);
+        }
+    }, [modalFormVisible])
+
+
+    useEffect(() => {
+        if (!isChildComponent) {
+            getLeftDataHandle();
+        }
+    }, [])
+
+    return (
+        <KCIMPagecontainer className='QualificationBatchAuth' style={!isChildComponent ? {} : { border: 'none' }} title={false}>
+            <ModalForm
+                title={''}
+                width={352}
+                formRef={formRef}
+                open={modalFormVisible}
+                initialValues={{
+                    // memo: record.applyMemo,
+                    qualificationPeriod: 1,
+                    timerange: [moment().startOf("day"), moment().startOf("day")]
+                }}
+
+                onFinish={(val) => {
+                    return updateTable({ ...val }, 'EDIT');
+                }}
+                modalProps={{ destroyOnClose: true, onCancel: () => set_modalFormVisible(false), }}
+                colProps={{ span: 24 }}
+                grid
+                submitter={{
+                    searchConfig: {
+                        submitText: '授权',
+                        resetText: '取消',
+                    },
+                }}
+            >
+
+                <ProFormRadio.Group label='授权期限:' name={'qualificationPeriod'} options={authTimeType} />
+                <ProFormDateRangePicker label='授权时间:' name='timerange' />
+                <ProFormTextArea label='审批意见:' name={'memo'} />
+
+            </ModalForm>
+            <Drawer destroyOnClose={true} className='authDetailDrawer' width={900}
+                open={drawerVisible} headerStyle={{ display: 'none' }} bodyStyle={{ background: '#F5F7FA', padding: 16 }}
+            >
+                <div className='authDetailDrawer-topBar'>
+                    <div className='authDetailDrawer-topBar-title'>
+                        <div className='closeIcon' onClick={() => set_drawerVisible(false)}><IconFont  type={'iconquxiao'}  /></div>{'批量授权'}
+                    </div>
+                    <div className='btnGroup'>
+                        <span onClick={() => set_drawerVisible(false)}>取消</span>
+                        {/* <span className='reject' onClick={() => updateTable(2)}>驳回</span> */}
+                        <span className='commit' onClick={() => {
+                            const val = drawerFormRef.current?.getFieldsFormatValue?.();
+                            updateTable({ ...val }, 'EDIT_DRAWER')
+                        }}>授权</span>
+                    </div>
+                </div>
+                <div className='authDetailDrawer-content'>
+                    <div className='authDetailDrawer-content-table'>
+                        <div className='authDetailDrawer-content-table-title'>处理重复授权</div>
+                        <Alert style={{ borderRadius: 4, height: 32, marginBottom: 16 }} message="系统中已有下列授权,请逐一确认。您可以:勾选:用本次授权内容覆盖已有授权;不勾选:保持已有授权,忽略本次授权" type="info" showIcon />
+                        <KCIMTable
+                            actionRef={drawerTableRef} columns={drawerTablecolumns as ProColumns[]} rowKey='id'
+                            // request={(params) => getTableData(params)}
+                            dataSource={drawerTableData}
+                            tableAlertRender={false}
+                            scroll={{ y: 545 }}
+                            rowSelection={{
+                                onChange(selectedRowKeys, selectedRows, info) {
+                                    set_currentSelectedDrawerTableRows(selectedRows);
+                                },
+                            }}
+                        />
+                    </div>
+                    <ProForm formRef={drawerFormRef} submitter={false} initialValues={{
+                        // memo: record.applyMemo,
+                        qualificationPeriod: 1,
+                        timerange: [moment().startOf("day"), moment().startOf("day")]
+                    }}>
+                        <div className='authDetailDrawer-content-form'>
+                            <div className='authDetailDrawer-content-form-title'>批量资质授权</div>
+                            <div className='formWrapper'>
+                                <div>
+                                    <ProFormRadio.Group label='授权期限:' name={'qualificationPeriod'} options={authTimeType} />
+                                    <ProFormDateRangePicker label='授权时间:' name='timerange' />
+                                </div>
+                                <ProFormTextArea name={'memo'} fieldProps={{
+                                    style: { width: 500, height: 85 }
+                                }} label='审批意见:' />
+                            </div>
+
+                        </div>
+
+                    </ProForm>
+                </div>
+
+
+            </Drawer>
+            <div className='pageContent'>
+                {
+                    !isChildComponent && (
+                        <div className='left'>
+                            <DoctorSelection clearSelection={clearSelection} onSelectedChange={(arr) => { set_currentSelectedLeftRows(arr) }} doctorsData={dataSource} />
+                        </div>
+                    )
+                }
+                <div className='right' style={isChildComponent ? { width: '100%' } : { width: 'calc(100% - 236px)', padding: 16 }}>
+                    <div className='right-content-title'>选择资质</div>
+                    <div className='toolBar'>
+                        <div className='filter'>
+                            <div className='filterItem'>
+                                <span className='label'>手术级别:</span>
+                                <ProFormSelect noStyle
+                                    style={{ width: 160, marginRight: 16 }}
+                                    placeholder={'请选择'}
+                                    request={async () => {
+                                        const resp = await getDicDataBySysId(KcimCenterSysId, 'SURGICAL_AND_OPERATIONAL_LEVELS');
+                                        if (resp) {
+                                            set_operationLevel(resp.dataVoList);
+                                            return resp.dataVoList.map((item: any) => ({ label: item.name, value: item.value }))
+                                        }
+                                    }}
+                                    fieldProps={{
+                                        onChange(value, option) {
+                                            set_tableDataFilterParams({ ...tableDataFilterParams, current: 1, operationLevelCode: value })
+                                        },
+                                    }}
+                                />
+                            </div>
+                            <div className='filterItem'>
+                                <span className='label'>检索:</span>
+                                <Input placeholder={'资质名称'} style={{ width: 160, marginRight: 16 }} allowClear autoComplete='off'
+
+                                    suffix={
+                                        <IconFont style={{ color: '#99A6BF' }} type="iconsousuo" onClick={() => tableDataSearchHandle('name')} />
+                                    }
+                                    onChange={(e) => {
+                                        set_tableDataSearchKeywords(e.target.value);
+                                        if (e.target.value.length == 0) {
+                                            set_tableDataSearchKeywords('');
+                                            set_tableDataFilterParams({ ...tableDataFilterParams, name: null })
+                                        }
+                                    }}
+
+                                    onPressEnter={(e) => {
+                                        tableDataSearchHandle('name')
+                                    }}
+
+                                />
+                            </div>
+                            <div className='filterItem'>
+                                <ProFormCheckbox.Group
+                                    name="checkbox"
+                                    layout='horizontal'
+                                    noStyle
+                                    options={['医疗技术', '手术']}
+                                    fieldProps={{
+                                        onChange(checkedValue) {
+                                            set_tableDataFilterParams({
+                                                ...tableDataFilterParams,
+                                                current: 1,
+                                                techFlag: checkedValue.findIndex((a) => a == '医疗技术') != -1 ? 1 : 0,
+                                                operationFlag: checkedValue.findIndex((a) => a == '手术') != -1 ? 1 : 0,
+                                                enableFlag: checkedValue.findIndex((a) => a == '已停用') != -1 ? 0 : 1,
+                                            })
+                                        },
+                                    }}
+                                />
+                            </div>
+                        </div>
+                        {/* {!isChildComponent && (
+                            <div className='btnGroup'>
+                                <UpDataActBtn record type='ADD' />
+                            </div>
+                        )} */}
+                    </div>
+                    <div style={{ marginTop: 16 }}>
+                        <KCIMTable scroll={{ y: `calc(100vh - 263px)` }}
+                            actionRef={tableRef} columns={columns as ProColumns[]} rowKey='id'
+                            params={tableDataFilterParams}
+                            request={(params) => getTableData(params)}
+                            // dataSource={showList}
+                            tableAlertRender={false}
+                            rowSelection={{
+                                selectedRowKeys: currentSelectedTableRows.map((a) => a.id),
+                                onChange(selectedRowKeys, selectedRows, info) {
+                                    set_currentSelectedTableRows(selectedRows);
+                                    onTableSelectChange && onTableSelectChange(selectedRowKeys, selectedRows, info)
+                                },
+                            }}
+
+                        />
+                    </div>
+                </div>
+            </div>
+            {
+                (currentSelectedLeftRows.length > 0 || currentSelectedTableRows.length > 0) && (
+                    <div className='bottom'>
+                        <div className='tags'>已选择医生<span>{currentSelectedLeftRows.length}</span>项,资质<span>{currentSelectedTableRows.length}</span>项</div>
+                        <div className='btn-groups'>
+                            <div className='cancelBtn' onClick={() => cancelBatchAuthHandle()}>取消选择</div>
+                            <div className='batchBtn' onClick={() => batchAuthHandle()}>批量授权</div>
+                        </div>
+
+                    </div>
+                )
+            }
+        </KCIMPagecontainer>
+    )
+}

+ 68 - 0
src/pages/qualificationMana/qualificationBatchAuth/service.ts

@@ -0,0 +1,68 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 16:31:27
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-12-12 14:16:23
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+import { request } from 'umi';
+
+//获取table列表数据
+
+export const getTableDataReq = (params?:any) => {
+  return request<any>('/medical/qualification/getQualificationList?', {
+    method: 'GET',
+    params:{...params}
+  });
+};
+
+//获取医生列表数据
+
+export const getLeftDataReq = (params?:any) => {
+  return request<any>('/medical/qualificationManage/listAllDoctor', {
+    method: 'GET',
+    params:{...params}
+  });
+};
+
+//批量授权校验
+export const batchAuthDataCheck = (data:any) => {
+  return request('/medical/qualificationAudit/saveBatchCheck', {
+    method: 'POST',
+    data
+  });
+};
+
+
+//编辑表格数据
+
+export type EditTableDataType = {
+ 
+}
+
+export const editData = (data:EditTableDataType) => {
+  return request('/medical/qualificationAudit/saveBatch', {
+    method: 'POST',
+    data
+  });
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 311 - 0
src/pages/qualificationMana/qualificationBatchAuth/style.less

@@ -0,0 +1,311 @@
+.row-dragging {
+  .cost-ant-table-cell {
+    width: 130px;
+  }
+}
+
+.mrms-ant-popover {
+  .mrms-ant-popover-content {
+    .mrms-ant-popover-arrow {
+      display: none;
+    }
+  }
+}
+
+
+.authDetailDrawer {
+  .authDetailDrawer-topBar {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 16px;
+
+    .authDetailDrawer-topBar-title {
+      font-weight: 500;
+      font-size: 16px;
+      color: #17181A;
+
+      .closeIcon {
+        position: relative;
+        top:2px;
+        display: inline-flex;
+        justify-content: center;
+        align-items: center;
+        width: 24px;
+        height: 24px;
+        cursor: pointer;
+        margin-right: 8px;
+        border-radius: 4px;
+        &:hover {
+          background-color: #E6EAF2;
+        }
+      }
+    }
+
+    .btnGroup {
+      &>span {
+        display: inline-block;
+        text-align: center;
+        cursor: pointer;
+        width: 56px;
+        height: 24px;
+        line-height: 21px;
+        margin-right: 8px;
+        font-weight: 400;
+        font-size: 14px;
+        color: #17181A;
+        background: #FAFCFF;
+        border-radius: 4px;
+        border: 1px solid #DAE2F2;
+
+        &.reject {
+          width: auto;
+          min-width: 56px;
+          color: #FFFFFF;
+          background: #FF4D6A;
+        }
+
+        &.commit {
+          width: auto;
+          min-width: 56px;
+          color: #FFFFFF;
+          background: #3377FF;
+        }
+
+        &:last-child {
+          margin-right: 0;
+        }
+      }
+    }
+  }
+
+  .authDetailDrawer-content {
+    max-height: calc(100vh - 72px);
+    overflow-y: scroll;
+    .authDetailDrawer-info {
+      background: #FFFFFF;
+      padding: 16px;
+      border-radius: 4px;
+
+      .authDetailDrawer-info-title {
+        display: flex;
+        width: 100%;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+        font-weight: bold;
+        font-size: 20px;
+        height: 20px;
+        line-height: 20px;
+        color: #17181A;
+        margin-bottom: 12px;
+      }
+
+      .authDetailDrawer-info-title-sub {
+        font-weight: 400;
+        font-size: 14px;
+        color: #525866;
+        line-height: 16px;
+
+        .authDetailDrawer-info-standard {
+          position: relative;
+          min-height: 56px;
+          background: #F7F9FC;
+          border-radius: 4px;
+          padding: 6px 12px;
+          font-weight: 400;
+          font-size: 14px;
+          color: #17181A;
+          line-height: 18px;
+          margin-top: 12px;
+          padding-right: 64px;
+          border: 1px solid #DAE4F2;
+
+          &>img {
+            position: absolute;
+            right: 12px;
+            top: 6px;
+            width: 40px;
+            height: 40px;
+
+          }
+        }
+      }
+    }
+
+    .authDetailDrawer-content-table {
+      padding: 16px;
+      background: #FFFFFF;
+      border-radius: 4px;
+
+      .authDetailDrawer-content-table-title {
+        font-weight: 500;
+        font-size: 16px;
+        height: 16px;
+        color: #17181A;
+        line-height: 16px;
+        margin-bottom: 16px;
+      }
+
+
+    }
+
+    .authDetailDrawer-content-form {
+      padding: 16px;
+      background: #FFFFFF;
+      border-radius: 4px;
+      margin-top: 16px;
+
+      .authDetailDrawer-content-form-title {
+        font-weight: 500;
+        font-size: 16px;
+        height: 16px;
+        color: #17181A;
+        line-height: 16px;
+        margin-bottom: 16px;
+      }
+
+      .formWrapper {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: flex-start;
+      }
+    }
+  }
+
+}
+
+.QualificationBatchAuth {
+  position: relative;
+  padding: 16px;
+  border-radius: 4px;
+
+  .pageContent {
+    display: flex;
+    width: 100%;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: flex-start;
+
+    .left {
+
+      border-radius: 4px;
+      width: 336px;
+      height: calc(100vh - 80px);
+      overflow: hidden;
+      margin-right: 16px;
+      padding-top: 8px;
+      background: #FFFFFF;
+    }
+
+    .right {
+      border-radius: 4px;
+      background: #FFFFFF;
+
+      .right-content-title {
+        font-weight: 500;
+        font-size: 16px;
+        height: 16px;
+        color: #17181A;
+        line-height: 16px;
+        margin-bottom: 16px;
+      }
+
+      .toolBar {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+
+        .filter {
+          display: flex;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+
+          .filterItem {
+            display: flex;
+            flex-direction: row;
+            justify-content: center;
+            align-items: center;
+          }
+        }
+
+        .btnGroup {
+          .add {
+            cursor: pointer;
+            display: inline-block;
+            font-size: 14px;
+            font-family: SourceHanSansCN-Normal, SourceHanSansCN;
+            font-weight: 400;
+            color: #FFFFFF;
+            line-height: 24px;
+            padding: 0 14px;
+            background: #3377FF;
+            border-radius: 4px;
+          }
+        }
+
+      }
+    }
+  }
+
+  .bottom {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    padding: 0 16px;
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    width: 100%;
+    height: 48px;
+    background: #FFFFFF;
+    box-shadow: 0px -8px 16px 0px rgba(64, 85, 128, 0.1);
+
+    &>.tags {
+      font-weight: 400;
+      font-size: 14px;
+      color: #17181A;
+
+      &>span {
+        color: #3376FE;
+      }
+    }
+
+    &>.btn-groups {
+      display: flex;
+      flex-direction: row;
+      justify-content: center;
+      align-items: center;
+      .cancelBtn {
+        text-align: center;
+        width: 80px;
+        height: 24px;
+        cursor: pointer;
+        line-height: 24px;
+        border-radius: 4px;
+        font-weight: 400;
+        font-size: 14px;
+        color: #17181A;
+        margin-right: 8px;
+        border:1px solid #dae2f2;
+      }
+      .batchBtn {
+        text-align: center;
+        width: 80px;
+        height: 24px;
+        cursor: pointer;
+        line-height: 24px;
+        background: #3377FF;
+        border-radius: 4px;
+        font-weight: 400;
+        font-size: 14px;
+        color: #FFFFFF;
+      }
+    }
+  }
+}

+ 143 - 0
src/pages/qualificationMana/qualificationBatchAuth/transform.tsx

@@ -0,0 +1,143 @@
+import React, { Key, useEffect, useImperativeHandle, useState } from "react";
+import { Transfer } from 'antd'
+import { TransferItem, TransferProps } from 'antd/es/transfer';
+import { ColumnsType } from 'antd/es/table';
+import { difference } from "lodash";
+import { TableRowSelection } from 'antd/es/table/interface';
+import { KCIMTable } from "@/components/KCIMTable";
+import { ProColumns } from "@ant-design/pro-components";
+
+import { log } from "mathjs";
+import { getHasConnectedHisItemDicListReq, getHisItemDicListReq } from "./service";
+
+
+
+interface TableTransferProps extends TransferProps<TransferItem> {
+    leftColumns: ProColumns[];
+    rightColumns: ProColumns[];
+    record: any,
+    onSave: (selectedKeys: Key[], selectedRowKeys: any[]) => void;
+}
+
+const TableTransfer = React.forwardRef(({ leftColumns, rightColumns, record, onSave, ...restProps }: TableTransferProps, ref) => {
+
+    const [_data, _set_data] = useState<any>();
+    const [targetKeys, setTargetKeys] = useState<string[]>([]);
+    const [datasource, set_datasource] = useState<any[]>([]);
+    const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
+    const [queryCondition,set_queryCondition] = useState('');
+    
+    //获取列表
+    const getFuncList = async (params:any) => {
+        let resp = await getHisItemDicListReq({pageSize:500,current:1,...params});
+        if (resp) {
+            set_datasource([...resp.list]);
+            
+        }
+
+    }
+
+    const getDefaultData = async ()=>{
+          const resp = await getHasConnectedHisItemDicListReq({qualificationId:record.id});
+          if(resp){
+               const defaultkeys = resp.list.map((a:any)=>`${a.id}`);
+               setTargetKeys([...targetKeys,...defaultkeys]);
+          }
+    }
+
+    const onChange = (nextTargetKeys: string[]) => {
+        setTargetKeys(nextTargetKeys);
+    };
+
+    const onSelectChange = (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => {
+        //console.log('sourceSelectedKeys:', sourceSelectedKeys,'targetSelectedKeys:',targetSelectedKeys);
+        setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys]);
+    };
+
+    useImperativeHandle(ref, () => ({
+        save: async () => {
+            const items = datasource.filter(a => targetKeys.includes(a.hisItemId));
+            onSave(targetKeys, items);
+        }
+    }));
+
+    useEffect(() => {
+        getFuncList({});
+        getDefaultData();
+    }, [])
+
+    return (
+        <Transfer className='TableTransfer' showSearch
+            titles={['待选项', '已选项']}
+            locale={{
+                itemUnit: '项',
+                itemsUnit: '项',
+                searchPlaceholder: '医嘱编码、医嘱名称',
+            }}
+            oneWay={false}
+            onChange={onChange}
+            onSelectChange={onSelectChange}
+            dataSource={datasource}
+            rowKey={record => record.hisItemId}
+            targetKeys={targetKeys}
+            selectedKeys={selectedKeys}
+            filterOption={(inputValue, item) => {
+                return (item.hisItemName!.indexOf(inputValue) !== -1)||(item.hisItemId!.indexOf(inputValue) !== -1)
+
+            }}
+        >
+            {({
+                direction,
+                filteredItems,
+                onItemSelectAll,
+                onItemSelect,
+                selectedKeys: listSelectedKeys,
+                disabled: listDisabled,
+            }) => {
+
+                // console.log({ filteredItems, listSelectedKeys,direction });
+                const columns = direction === 'left' ? leftColumns : rightColumns;
+
+                const rowSelection: TableRowSelection<TransferItem> = {
+                    getCheckboxProps: (item) => ({ disabled: listDisabled || item.disabled }),
+                    onSelectAll(selected, selectedRows) {
+                        const treeSelectedKeys = selectedRows.map(({ hisItemId }) => hisItemId);
+                        const diffKeys = selected
+                            ? difference(treeSelectedKeys, listSelectedKeys)
+                            : difference(listSelectedKeys, treeSelectedKeys);
+                        onItemSelectAll(diffKeys as string[], selected);
+                    },
+                    onSelect({ hisItemId }, selected) {
+                        onItemSelect(hisItemId as string, selected);
+                    },
+                    selectedRowKeys: listSelectedKeys,
+                };
+
+                return (
+                    <KCIMTable
+                        rowSelection={rowSelection}
+                        columns={columns as TransferItem[]}
+                        dataSource={filteredItems}
+                        size="small"
+                        tableStyle={{border:'none'}}
+                        bordered={false}
+                        rowKey={'hisItemId'}
+                        pagination={{ showTitle: false, pageSize: 9, showLessItems: false, simple: true, showTotal: () => false }}
+                        tableAlertRender={false}
+                        style={{ pointerEvents: listDisabled ? 'none' : undefined }}
+                        onRow={({ code, disabled: itemDisabled }) => ({
+                            onClick: () => {
+                                if (itemDisabled || listDisabled) return;
+                                onItemSelect(code as string, !listSelectedKeys.includes(code as string));
+                            },
+                        })}
+                    />
+                );
+            }}
+        </Transfer>
+    )
+});
+
+export default TableTransfer
+
+

+ 67 - 57
src/pages/qualificationMana/qualificationClassfiMana/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-12-03 10:33:10
+ * @LastEditTime: 2024-12-24 16:26:31
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -16,7 +16,7 @@ import { createFromIconfontCN } from '@ant-design/icons';
 import { ActionType, ProFormDependency, ProFormInstance, ProFormText, ProFormSelect } from '@ant-design/pro-components';
 import { ModalForm, ProFormDigit, ProFormTextArea } from '@ant-design/pro-form'
 import { ProColumns } from '@ant-design/pro-table';
-import { Input, message, Popconfirm,Popover,Switch,Tooltip } from 'antd';
+import { Input, message, Popconfirm, Popover, Switch, Tooltip } from 'antd';
 import { useEffect, useRef, useState } from 'react';
 
 import 'moment/locale/zh-cn';
@@ -26,7 +26,7 @@ import { addData, delData, editData, getTableList } from './service';
 
 import './style.less';
 
-import {renameChildListToChildren } from '@/utils/tooljs';
+import { renameChildListToChildren } from '@/utils/tooljs';
 
 
 const IconFont = createFromIconfontCN({
@@ -101,21 +101,31 @@ export default function QualificationClassifiMana() {
             title: '操作',
             key: 'option',
             width: 120,
-            fixed:'right',
+            fixed: 'right',
             valueType: 'option',
             render: (_: any, record: any) => {
-                const { code } = record;
-                return code != '0' ?[
+                const { code, allowDelete } = record;
+                return code != '0' ? [
                     <UpDataActBtn key={'act'} record={record} type='ADDCHILD' />,
                     <UpDataActBtn key={'act1'} record={record} type='EDIT' />,
-                    <Popconfirm
-                        title="是否确认删除?"
-                        key="del"
-                        onConfirm={() => delTableData(record)}
-                    >
-                        <a>删除</a>
-                    </Popconfirm>,
-                ]:[
+                    <>
+                        {
+                            allowDelete == 1 ? (
+                                <Popconfirm
+                                    title="是否确认删除?"
+                                    key="del"
+                                    onConfirm={() => delTableData(record)}
+                                >
+                                    <a>删除</a>
+                                </Popconfirm>
+                            ) : (
+                                <Tooltip title="分类下已有资质,不可删除" placement='topRight'>
+                                    <span style={{ color: '#99A6BF', cursor: 'not-allowed' }}>删除</span>
+                                </Tooltip>
+                            )
+                        }
+                    </>,
+                ] : [
                     <UpDataActBtn key={'act'} record={record} type='ADDCHILD' />,
                 ]
             },
@@ -153,13 +163,13 @@ export default function QualificationClassifiMana() {
         try {
 
             if (type == 'ADD' || type == 'ADDCHILD') {
-    
+
                 const resp = await addData(formVal);
                 if (resp) {
                     tableRef.current?.reload();
                     message.success('操作成功!');
                 }
-    
+
             }
             if (type == 'EDIT') {
                 try {
@@ -171,11 +181,11 @@ export default function QualificationClassifiMana() {
                 } catch (error) {
                     console.log({ error });
                 }
-    
+
             }
-            
+
         } catch (error) {
-             console.log('新增/编辑error',error);
+            console.log('新增/编辑error', error);
         }
 
         return true;
@@ -192,7 +202,7 @@ export default function QualificationClassifiMana() {
                 formRef={formRef}
                 initialValues={type == 'EDIT' ? {
                     ...record,
-                } : { selectedSharelevel: 0,sort:0 }}
+                } : { selectedSharelevel: 0, sort: 0 }}
                 trigger={
                     type == 'EDIT' ? <a key="edit" >编辑</a> : type == 'ADDCHILD' ? <a className='add'>添加</a> : <span className='add'>新增</span>
                 }
@@ -214,6 +224,7 @@ export default function QualificationClassifiMana() {
                     name="name"
                 />
                 <ProFormText
+                    disabled={type == 'EDIT'}
                     label="资质分类编码:"
                     rules={[
                         {
@@ -247,7 +258,7 @@ export default function QualificationClassifiMana() {
 
         set_tableDataFilterParams({
             ...tableDataFilterParams,
-            currnt:1,
+            currnt: 1,
             [`${paramName}`]: tableDataSearchKeywords
         })
 
@@ -259,48 +270,47 @@ export default function QualificationClassifiMana() {
 
     return (
         <KCIMPagecontainer className='QualificationClassifiMana' title={false}>
-            <div className='toolBar'>
-                <div className='filter'>
-                    <div className='filterItem'>
-                        <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
-                        <Input placeholder={'分类编码、分类名称'} allowClear autoComplete='off'
-                            suffix={
-                                <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('queryCondition')} />
-                            }
-                            onChange={(e) => {
-                                set_tableDataSearchKeywords(e.target.value);
-                                if (e.target.value.length == 0) {
+            <div className='pageContent'>
+                <div className='toolBar'>
+                    <div className='filter'>
+                        <div className='filterItem'>
+                            <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
+                            <Input placeholder={'分类编码、分类名称'} allowClear autoComplete='off'
+                                suffix={
+                                    <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('queryCondition')} />
+                                }
+                                onChange={(e) => {
+                                    set_tableDataSearchKeywords(e.target.value);
+                                    if (e.target.value.length == 0) {
+                                        set_tableDataFilterParams({
+                                            ...tableDataFilterParams,
+                                            current: 1,
+                                            queryCondition: ''
+                                        });
+                                    }
+                                }}
+                                onPressEnter={(e) => {
+
                                     set_tableDataFilterParams({
                                         ...tableDataFilterParams,
-                                        current:1,
-                                        queryCondition: ''
+                                        current: 1,
+                                        queryCondition: (e.target as HTMLInputElement).value
                                     });
-                                }
-                            }}
-                            onPressEnter={(e) => {
-
-                                set_tableDataFilterParams({
-                                    ...tableDataFilterParams,
-                                    current:1,
-                                    queryCondition: (e.target as HTMLInputElement).value
-                                });
-                            }}
+                                }}
 
-                        />
+                            />
+                        </div>
+                    </div>
+                    <div className='btnGroup'>
+                        {/* <UpDataActBtn record type='ADD' /> */}
                     </div>
                 </div>
-                <div className='btnGroup'>
-                    {/* <UpDataActBtn record type='ADD' /> */}
-                </div>
-            </div>
-
-            <div style={{ marginTop: 16 }}>
-                <KCIMTable pagination={false} columns={columns as ProColumns[]} 
-                scroll={{ y: 'calc(100vh - 232px)' }} actionRef={tableRef} rowKey='code'
-                 expandable={{
-                     defaultExpandedRowKeys:['0']
-                 }}
-                params={tableDataFilterParams} request={(params) => getTableData(params)} />
+                <KCIMTable pagination={false} columns={columns as ProColumns[]}
+                    scroll={{ y: 'calc(100vh - 192px)' }} actionRef={tableRef} rowKey='code'
+                    expandable={{
+                        defaultExpandedRowKeys: ['0']
+                    }}
+                    params={tableDataFilterParams} request={(params) => getTableData(params)} />
             </div>
         </KCIMPagecontainer>
     )

+ 45 - 43
src/pages/qualificationMana/qualificationClassfiMana/style.less

@@ -1,56 +1,58 @@
 .QualificationClassifiMana {
-  padding: 16px;
-  background: #FFFFFF;
-  border-radius: 4px;
 
-
-  .toolBar {
-    display: flex;
-    flex-direction: row;
-    justify-content: space-between;
-    align-items: center;
-
-    .filter {
+  .pageContent {
+    padding: 16px;
+    background: #FFFFFF;
+    border-radius: 4px;
+    .toolBar {
       display: flex;
       flex-direction: row;
-      justify-content: flex-start;
+      justify-content: space-between;
       align-items: center;
-
-      .filterItem {
+      margin-bottom: 16px;
+  
+      .filter {
         display: flex;
         flex-direction: row;
-        justify-content: center;
+        justify-content: flex-start;
         align-items: center;
+  
+        .filterItem {
+          display: flex;
+          flex-direction: row;
+          justify-content: center;
+          align-items: center;
+        }
       }
-    }
-
-    .btnGroup {
-      .import,.export {
-        cursor: pointer;
-        display: inline-block;
-        font-size: 14px;
-        font-weight: 400;
-        color: #17181A;
-        line-height: 24px;
-        padding: 0 14px;
-        margin-right: 8px;
-        background: #FAFCFF;
-        border-radius: 4px;
-        border: 1px solid #DAE2F2;
-      }
-      
-      .add {
-        cursor: pointer;
-        display: inline-block;
-        font-size: 14px;
-        font-weight: 400;
-        color: #FFFFFF;
-        line-height: 24px;
-        padding: 0 14px;
-        background: #3377FF;
-        border-radius: 4px;
+  
+      .btnGroup {
+        .import,.export {
+          cursor: pointer;
+          display: inline-block;
+          font-size: 14px;
+          font-weight: 400;
+          color: #17181A;
+          line-height: 24px;
+          padding: 0 14px;
+          margin-right: 8px;
+          background: #FAFCFF;
+          border-radius: 4px;
+          border: 1px solid #DAE2F2;
+        }
+        
+        .add {
+          cursor: pointer;
+          display: inline-block;
+          font-size: 14px;
+          font-weight: 400;
+          color: #FFFFFF;
+          line-height: 24px;
+          padding: 0 14px;
+          background: #3377FF;
+          border-radius: 4px;
+        }
       }
+  
     }
-
   }
 }

+ 65 - 0
src/pages/qualificationMana/qualificationExperiedMana/authHisttory/index.tsx

@@ -0,0 +1,65 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-12-06 14:42:57
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-12-10 16:58:39
+ * @FilePath: /MediResourceManaSys/src/pages/qualificationMana/qualificationAuth/authHisttory/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AEi m z z
+ */
+
+
+import { createFromIconfontCN } from '@ant-design/icons';
+import React, { Children } from 'react'
+import { Timeline } from 'antd'
+import './style.less'
+import { authTimeType } from '@/constant';
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+export default function AuthHisContent({ hisList }: { hisList: any[] }) {
+
+    const getPeriodStr = (code:number)=>{
+        const result = authTimeType.filter((a)=>a.value == code);
+        if(result.length>0){
+            return result[0].label
+        }
+        return undefined
+    }
+
+    const dotNode = (isActive=false)=>{
+        return <div style={{display:'flex',justifyContent:'center',alignItems:'center',width:16,height:16,border:'2px solid #E7EBF2',borderRadius:'50%'}}>
+            {isActive&&<div style={{width:8,height:8,background:'#363F4D',borderRadius:'50%'}}></div>}
+        </div>
+    }
+    return (
+        <div className='AuthHisContent'>
+            <div className='AuthHisContent-title'>
+                <IconFont type={'icon-qingliangtishi'} style={{ paddingRight:12 }} />调整历史
+            </div>
+            <div className='AuthHisContent-content'>
+                <Timeline>
+                    {
+                        hisList.map((a,index)=>{
+                             return (
+                                <Timeline.Item key={index} dot={dotNode(index == 0?true:false)} >
+                                      <div style={{fontWeight:'bold',fontSize:14,color:'#17181A',height:14,lineHeight:'14px',marginBottom:8}}>{`${a.adjustUserName} ${a.adjustTime}`}</div>
+                                      <div style={{height:14,fontSize:12,color:'#176DE6',lineHeight:'14px',marginBottom:8,paddingLeft:6}}>
+                                        <img style={{width:43,height:14,marginRight:4}} src={require('../../../../../static/tiaozhenghou.png')} />{getPeriodStr(a.qualificationPeriodAfter)} {`(${a.beginDateAfter}至${a.endDateAfter})`}
+                                      </div>
+                                      <div style={{height:14,fontSize:12,color:'#525866',lineHeight:'14px',marginBottom:8,paddingLeft:6}}>
+                                        <img style={{width:43,height:14,marginRight:4}} src={require('../../../../../static/tiaozhengqian.png')} />
+                                        {getPeriodStr(a.qualificationPeriodBefore)} {`(${a.beginDateBefore}至${a.endDateBefore})`}
+                                      </div>
+                                      {(a.memo&&a.memo.length>0)&&<div style={{padding:'5px 8px',fontSize:12,color:'#525866',background:'#F7F9FC',borderRadius:4}}>{a.memo}</div>}
+                                </Timeline.Item>
+                             )
+                        })
+                    }
+                </Timeline>
+            </div>
+        </div>
+    )
+}

+ 35 - 0
src/pages/qualificationMana/qualificationExperiedMana/authHisttory/style.less

@@ -0,0 +1,35 @@
+
+
+.AuthHisContent {
+    width: 400px;
+   
+    .AuthHisContent-title {
+        font-weight: 500;
+        font-size: 16px;
+        height: 16px;
+        color: #17181A;
+        line-height: 16px;
+    }
+    .AuthHisContent-content {
+        max-height: 400px;
+        overflow: scroll;
+        overflow-x: hidden;
+        padding-top: 24px;
+
+        .mrms-ant-timeline-item {
+            &.mrms-ant-timeline-item-last {
+                padding-bottom: 0;
+            }
+        }
+        .mrms-ant-timeline-item-tail {
+            left:8px;
+        }
+        .mrms-ant-timeline-item-head-custom {
+            top:0.5px;
+            left:9px;
+        }
+        .mrms-ant-timeline-item-content {
+            margin: 0 0 0 35px;
+        }
+    }
+}

+ 568 - 0
src/pages/qualificationMana/qualificationExperiedMana/index.tsx

@@ -0,0 +1,568 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 11:30:33
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-12-25 10:36:31
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+
+
+
+import KCIMPagecontainer from '@/components/KCIMPageContainer';
+import { KCIMTable } from '@/components/KCIMTable';
+import { createFromIconfontCN } from '@ant-design/icons';
+
+import { ActionType, arrayMoveImmutable, ProFormText, ProFormTextArea, useRefFunction } from '@ant-design/pro-components';
+import ProForm, { ModalForm, ProFormCascader, ProFormCheckbox, ProFormDatePicker, ProFormDateRangePicker, ProFormDependency, ProFormDigit, ProFormInstance, ProFormRadio, ProFormSelect, ProFormSwitch } from '@ant-design/pro-form'
+import { ProColumns } from '@ant-design/pro-table';
+import { Alert, Drawer, Form, Input, message, Popover, Radio } from 'antd';
+import { Key, useEffect, useRef, useState } from 'react';
+
+
+
+import { editData, getTableDataReq } from './service';
+
+import './style.less';
+
+import { getDicDataBySysId } from '@/services/getDic';
+import { authTimeType, KcimCenterSysId } from '@/constant';
+
+import 'moment/locale/zh-cn';
+import moment from 'moment';
+import { sparse } from 'mathjs';
+import AuthHisContent from './authHisttory';
+import FormTabs from './tabs';
+import { calculateDelayedDate } from '@/utils/tooljs';
+import { debounce } from 'lodash';
+
+
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+const defaultExpiredDate = moment().startOf('days');
+
+export default function QualificationExperiedMana() {
+    const formRef = useRef<ProFormInstance>();
+    const drawerFormRef = useRef<ProFormInstance>();
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
+    const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
+    const [drawerVisible, set_drawerVisible] = useState(false);
+    const [currentEditRow, set_currentEditRow] = useState<any>(undefined);
+    const [currentPageTableData, set_currentPageTableData] = useState<any[]>([]);
+    const [currentSelectedLeftRows, set_currentSelectedLeftRows] = useState<any[]>([]);
+    const [currentSelectedTableRows, set_currentSelectedTableRows] = useState<any[]>([]);
+    const [currentSelectedDrawerTableRows, set_currentSelectedDrawerTableRows] = useState<any[]>([]);
+
+    const tableRef = useRef<ActionType>();
+    const drawerTableRef = useRef<ActionType>();
+    const [drawerTableData, set_drawerTableData] = useState<any[]>([]);
+    const [modalFormVisible, set_modalFormVisible] = useState(false);
+    const [operationLevel, set_operationLevel] = useState<any[]>([]);
+    const [currentTab, set_currentTab] = useState<1 | 2>(1);
+
+
+    const columns: ProColumns[] = [
+        {
+            title: '医生姓名',
+            width: 80,
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                const { userInfo: { name } } = record;
+                return name
+            },
+        },
+        {
+            title: '所在科室',
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                const { userInfo: { deptName } } = record;
+                return deptName
+            },
+        },
+        {
+            title: '资质名称',
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                const { qualificationInfo: { name } } = record;
+                return name
+            },
+        },
+        {
+            title: '资质编码',
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                const { qualificationInfo: { code } } = record;
+                return code
+            },
+
+        },
+        {
+            title: '资质分类',
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                const { qualificationInfo: { qualificationTypeName } } = record;
+                return qualificationTypeName
+            },
+
+        },
+        {
+            title: '到期日期',
+            ellipsis: true,
+            dataIndex: 'endDate'
+
+        },
+        {
+            title: '剩余天数',
+            ellipsis: true,
+            dataIndex: 'daysToExpire',
+
+        },
+        {
+            title: '操作',
+            key: 'option',
+            width: 120,
+            fixed: 'right',
+            valueType: 'option',
+            render: (_: any, record: any) => {
+                return <a key={1} onClick={() => editExperiedHandle(record)}>调整期限</a>
+            },
+        },
+
+    ];
+
+
+    const getTableData = async (params: any) => {
+        const { expireDate = defaultExpiredDate.format('YYYY-MM-DD') } = params;
+        const resp = await getTableDataReq({ ...params, expireDate });
+        if (resp) {
+            const data = (resp.list).map((a: any, index: number) => ({ id: index, ...a }));
+            set_currentPageTableData(data);
+            return {
+                data,
+                success: true
+            }
+        } else {
+            return []
+        }
+        // return {
+        //     data: [
+        //         {
+        //             "id": 82,
+        //             "qualificationCode": "djgfdcgrdsmdzcyk",
+        //             "userId": 31241,
+        //             "qualificationPeriod": 1,
+        //             "applyDate": "2024-12-12 19:51",
+        //             "applyMemo": "医务部批量授权",
+        //             "beginDate": "2024-12-09",
+        //             "endDate": "2024-12-31",
+        //             "applyStatus": 5,
+        //             "userInfo": {
+        //                 "id": 31241,
+        //                 "name": "赵海强",
+        //                 "account": "010101",
+        //                 "gender": "男",
+        //                 "deptCode": "1282",
+        //                 "deptName": "内镜门诊",
+        //                 "title": "医师",
+        //                 "jobTitle": "科主任",
+        //                 "qualificationCertificateNo": "-",
+        //                 "practiceCertificateNo": "-",
+        //                 "doctorLevel": "执业医师",
+        //                 "practiceCate": "临床",
+        //                 "major": "内科专业",
+        //                 "avatarUrl": ""
+        //             },
+        //             "qualificationInfo": {
+        //                 "id": 4,
+        //                 "code": "djgfdcgrdsmdzcyk",
+        //                 "qualificationTypeCode": "erjiuzuu",
+        //                 "qualificationTypeName": "二级手术",
+        //                 "name": "单根导管冠脉造影术",
+        //                 "standard": "依据",
+        //                 "techFlag": 1,
+        //                 "operationFlag": 1,
+        //                 "operationLevelCode": "3",
+        //                 "enableFlag": 1,
+        //                 "allowCheck": 1
+        //             },
+        //             "currentStatus": "授权中",
+        //             "daysToExpire": 18
+        //         },
+        //         {
+        //             "id": 83,
+        //             "qualificationCode": "a",
+        //             "userId": 31240,
+        //             "qualificationPeriod": 1,
+        //             "applyDate": "2024-12-12 20:01",
+        //             "beginDate": "2024-12-13",
+        //             "endDate": "2025-01-31",
+        //             "managerOpinion": "888",
+        //             "applyStatus": 5,
+        //             "userInfo": {
+        //                 "id": 31240,
+        //                 "name": "曾仁",
+        //                 "account": "admin",
+        //                 "gender": "男",
+        //                 "deptCode": "1284",
+        //                 "deptName": "便民门诊",
+        //                 "title": "住院医师",
+        //                 "jobTitle": "院长",
+        //                 "qualificationCertificateNo": "SF230105198406020017",
+        //                 "practiceCertificateNo": "N330182000001",
+        //                 "doctorLevel": "执业医师",
+        //                 "practiceCate": "临床",
+        //                 "major": "内科专业",
+        //                 "avatarUrl": "http://47.97.198.219:9000/center/20240711181142.jpg"
+        //             },
+        //             "qualificationInfo": {
+        //                 "id": 6,
+        //                 "code": "a",
+        //                 "qualificationTypeCode": "BLUX",
+        //                 "qualificationTypeName": "病历书写",
+        //                 "name": "病历书写",
+        //                 "standard": "斌彬彬",
+        //                 "techFlag": 0,
+        //                 "operationFlag": 1,
+        //                 "operationLevelCode": "2",
+        //                 "enableFlag": 1,
+        //                 "allowCheck": 1
+        //             },
+        //             "currentStatus": "授权中",
+        //             "daysToExpire": 49
+        //         },
+        //     ]
+        // }
+    }
+
+    const editExperiedHandle = (record: any) => {
+        set_currentEditRow(record);
+        set_drawerVisible(true);
+    }
+
+    const getOperationLevelList = async () => {
+        const resp = await getDicDataBySysId(KcimCenterSysId, 'SURGICAL_AND_OPERATIONAL_LEVELS');
+        if (resp) {
+            set_operationLevel(resp.dataVoList);
+        }
+    }
+
+
+    const updateTable = async (formVal: any, type: 'EDIT_DRAWER' | 'EDIT') => {
+        console.log({ formVal });
+        try {
+
+            let result: any[] = [];
+            if (type == 'EDIT_DRAWER') {
+                result = [{
+                    qualificationApplyId: currentEditRow.id,
+                    qualificationPeriod: currentEditRow.qualificationPeriod,
+                    beginDate: currentEditRow.beginDate,
+                    endDate: formVal.adjustType == 'days' ? calculateDelayedDate(currentEditRow.endDate, formVal.delayTime) : formVal.dateRange[1],
+                    memo: formVal.memo
+                }]
+            }
+            if (type == 'EDIT') {
+                result = currentSelectedTableRows.map((a) => {
+                    return {
+                        qualificationApplyId: a.id,
+                        qualificationPeriod: a.qualificationPeriod,
+                        beginDate: a.beginDate,
+                        endDate: formVal.adjustType == 'days' ? calculateDelayedDate(a.endDate, formVal.delayTime) : formVal.dateRange[1],
+                        memo: formVal.memo
+                    }
+                })
+            }
+
+            const resp = await editData(result);
+            if (resp) {
+                set_currentSelectedTableRows([]);
+                set_drawerVisible(false);
+
+
+                tableRef.current?.reload();
+                message.success('操作成功!');
+            }
+
+            return true;
+
+        } catch (error) {
+
+            console.log({ error });
+            return false;
+        }
+
+
+
+
+    }
+
+
+    const tableDataSearchHandle = (key: string) => {
+        set_tableDataFilterParams({ ...tableDataFilterParams, current: 1, [key]: tableDataSearchKeywords })
+    }
+    const getAuthPeriod = (code: number) => {
+        const result = authTimeType.filter(a => a.value == code);
+        return result.length > 0 ? result[0].label : '-'
+    }
+
+    useEffect(() => {
+        if (drawerVisible) {
+            getOperationLevelList();
+        }
+    }, [drawerVisible]);
+
+    useEffect(() => {
+        set_tableDataFilterParams({...tableDataFilterParams,expireDate:currentTab == 1?defaultExpiredDate.format('YYYY-MM-DD'):calculateDelayedDate(moment().startOf('day').format('YYYY-MM-DD'),0)})
+    }, [currentTab])
+
+
+    return (
+        <KCIMPagecontainer className='QualificationExperiedMana' title={false}>
+            <ModalForm
+                title={'批量调整'}
+                width={352}
+                formRef={formRef}
+                open={modalFormVisible}
+                initialValues={{
+                    adjustType: 'time',
+                    dateRange: [moment().startOf('days'), moment().startOf('days')]
+                }}
+
+                onFinish={(val) => {
+                    return updateTable({ ...val }, 'EDIT');
+                }}
+                modalProps={{ destroyOnClose: true, onCancel: () => set_modalFormVisible(false), }}
+                colProps={{ span: 24 }}
+                grid
+                submitter={{
+                    searchConfig: {
+                        submitText: '调整',
+                        resetText: '取消',
+                    },
+                }}
+            >
+
+                <Form.Item name="adjustType" >
+                    <FormTabs width={188} />
+                </Form.Item>
+                <ProFormDependency name={['adjustType']}>
+                    {
+                        ({ adjustType }) => {
+                            if (adjustType == 'time') {
+                                return <ProFormDateRangePicker label='按授权时间:' name='dateRange' />
+                            }
+                            if (adjustType == 'days') {
+                                return <ProFormDigit name='delayTime' width={80} label='延期天数:' />
+                            }
+                        }
+                    }
+                </ProFormDependency>
+
+                <ProFormTextArea name={'memo'} fieldProps={{
+                    style: { height: 85 }
+                }} label='调整说明:' />
+
+            </ModalForm>
+            <Drawer destroyOnClose={true} className='QualificationExperiedMana-authDetailDrawer' width={700}
+                open={drawerVisible} headerStyle={{ display: 'none' }} bodyStyle={{ background: '#F5F7FA', padding: 16 }}
+            >
+                <div className='authDetailDrawer-topBar'>
+                    <div className='authDetailDrawer-topBar-title'>
+                        <div className='closeIcon' onClick={() => set_drawerVisible(false)} ><IconFont  type={'iconquxiao'} /></div>{'批量授权'}
+                    </div>
+                    <div className='btnGroup'>
+                        <span onClick={() => set_drawerVisible(false)}>取消</span>
+                        {/* <span className='reject' onClick={() => updateTable(2)}>驳回</span> */}
+                        <span className='commit' onClick={() => {
+                            const val = drawerFormRef.current?.getFieldsFormatValue?.();
+                            updateTable({ ...val }, 'EDIT_DRAWER')
+                        }}>调整</span>
+                    </div>
+                </div>
+                <div className='authDetailDrawer-content'>
+
+                    <div className='authDetailDrawer-info'>
+                        <div className='avator'><img src={(currentEditRow?.userInfo?.avatarUrl.length != 0) ? currentEditRow?.userInfo?.avatarUrl : require('../../../../static/avatar.png')} alt="avator" /></div>
+                        <div className='authDetailDrawer-info-detail'>
+                            <div className='authDetailDrawer-info-title'>
+                                {currentEditRow?.userInfo?.name}
+                                <img style={{ width: 16, height: 16, marginLeft: 8 }} src={require(`../../../../static/${currentEditRow?.userInfo?.gender == '男' ? 'male' : 'female'}.png`)} alt="" />
+                            </div>
+                            <div className='authDetailDrawer-info-title-sub'>
+                                工号:{currentEditRow?.userInfo?.id}<span style={{ padding: '0 8px' }}></span>
+                                科室:{currentEditRow?.userInfo?.deptName}<span style={{ padding: '0 8px' }}></span>
+                                职称:{currentEditRow?.userInfo?.jobTitle}<span style={{ padding: '0 8px' }}></span>
+                                职务:{currentEditRow?.userInfo?.title}
+                            </div>
+                        </div>
+
+                    </div>
+                    <div className='qualification-info'>
+                        <div className='qualification-info-name'>
+                            <div className='name'>{currentEditRow?.qualificationInfo.name}</div>
+                            <div className='tags'>
+                                {
+                                    currentEditRow?.qualificationInfo.techFlag == 1 && (
+                                        <span style={{
+                                            display: 'inline-flex', width: 64, height: 20, justifyContent: 'center',
+                                            alignItems: 'center', background: '#FFF5EB', borderRadius: 4, fontSize: 12, color: '#FF8000', marginRight: 4
+                                        }}>医疗技术</span>
+                                    )
+                                }
+                                {
+                                    currentEditRow?.qualificationInfo.operationFlag == 1 && (
+                                        <span style={{
+                                            display: 'inline-flex', width: 64, height: 20, justifyContent: 'center',
+                                            alignItems: 'center', background: '#E8FCF6', borderRadius: 4, fontSize: 12, color: '#009966'
+                                        }}>{
+                                                operationLevel.filter((a) => a.value == currentEditRow?.qualificationInfo.operationLevelCode).length > 0 ? (operationLevel.filter((a) => a.value == currentEditRow?.qualificationInfo.operationLevelCode))[0].name : <></>
+                                            }</span>
+                                    )
+                                }
+
+                            </div>
+                        </div>
+                        <div className='qualification-info-list'>资质分类:<span>{currentEditRow?.qualificationInfo.qualificationTypeName}</span></div>
+                        <div className='qualification-info-list'>授权依据:<span>{currentEditRow?.qualificationInfo.standard}</span></div>
+                        <div className='qualification-info-list'>授权期限:<span>{getAuthPeriod(currentEditRow?.qualificationPeriod ? currentEditRow?.qualificationPeriod : 1)}</span></div>
+                        <div className='qualification-info-list'>授权时间:
+                            <span>
+                                {`${currentEditRow?.beginDate}至${currentEditRow?.endDate}`}
+                                {currentEditRow?.applyAdjust?.length > 0 && (
+                                    <Popover className='qualificationAuth-popover' overlayInnerStyle={{borderRadius:4}} content={<AuthHisContent hisList={[...currentEditRow?.applyAdjust]} />} title={false} >
+                                        <IconFont type={'icon-qingliangtishi'} style={{ marginLeft: 10, cursor: 'pointer' }} />
+                                    </Popover>
+                                )}
+                            </span>
+                        </div>
+                    </div>
+
+                    <ProForm formRef={drawerFormRef} submitter={false} initialValues={{
+                        adjustType: 'time',
+                        // dateRange:[moment().startOf('days'),moment().startOf('days')]
+                        dateRange: [moment(currentEditRow?.beginDate, 'YYYY-MM-DD'), moment(currentEditRow?.endDate, 'YYYY-MM-DD')],
+                    }}>
+                        <div className='authDetailDrawer-content-form'>
+                            <div className='authDetailDrawer-content-form-title'>调整期限</div>
+                            <div className='formWrapper'>
+                                <Form.Item name="adjustType" >
+                                    <FormTabs width={188} />
+                                </Form.Item>
+                                <ProFormDependency name={['adjustType']}>
+                                    {
+                                        ({ adjustType }) => {
+                                            if (adjustType == 'time') {
+                                                return <ProFormDateRangePicker name='dateRange' />
+                                            }
+                                            if (adjustType == 'days') {
+                                                return <ProFormDigit name='delayTime' width={80} label='延期天数' />
+                                            }
+                                        }
+                                    }
+                                </ProFormDependency>
+
+                                <ProFormTextArea name={'memo'} fieldProps={{
+                                    style: { height: 85 }
+                                }} label='调整说明:' />
+                            </div>
+
+                        </div>
+
+                    </ProForm>
+                </div>
+
+
+            </Drawer>
+            <div className='pageContent'>
+                <div className='toolBar'>
+                    <div className='filter'>
+                        <div className='filterItem'>
+                            <span className='label'>检索:</span>
+                            <Input placeholder={'医生姓名、所在科室、资质分类、资质名称'} style={{ width: 330, marginRight: 16 }} allowClear autoComplete='off'
+
+                                suffix={
+                                    <IconFont style={{ color: '#99A6BF' }} type="iconsousuo" onClick={() => tableDataSearchHandle('queryCondition')} />
+                                }
+                                onChange={(e) => {
+                                    set_tableDataSearchKeywords(e.target.value);
+                                    if (e.target.value.length == 0) {
+                                        set_tableDataSearchKeywords('');
+                                        set_tableDataFilterParams({ ...tableDataFilterParams, queryCondition: null })
+                                    }
+                                }}
+
+                                onPressEnter={(e) => {
+                                    tableDataSearchHandle('queryCondition')
+                                }}
+
+                            />
+                        </div>
+                        <div className='tabSwitcher'>
+                            <div className={currentTab == 1?'tab on':'tab'} onClick={() => set_currentTab(1)}>按日期</div>
+                            <div className={currentTab == 2?'tab on':'tab'} onClick={() => set_currentTab(2)}>按天数</div>
+                        </div>
+                        {currentTab == 1 && <div className='filterItem'>
+                            <span className='label'>到期时间:</span>
+                            <ProFormDatePicker noStyle
+                                allowClear
+                                style={{ width: 160, marginRight: 16 }}
+                                placeholder={'到期日期'}
+                                fieldProps={{
+                                    defaultValue: defaultExpiredDate,
+                                    onChange(value, option) {
+                                        set_tableDataFilterParams({ ...tableDataFilterParams, current: 1, expireDate: value?.format('YYYY-MM-DD') })
+                                    },
+                                }}
+                            />
+                        </div>}
+
+                        {
+                            currentTab == 2 && <div className='filterItem'>
+                                <span className='label' >剩余天数:</span>
+                                <ProFormDigit noStyle
+                                    width={120}
+                                    allowClear
+                                    placeholder={'365'}
+                                    fieldProps={{
+                                        onChange: debounce((value) => {
+                                            set_tableDataFilterParams({ ...tableDataFilterParams, current: 1, expireDate: calculateDelayedDate(moment().startOf('day').format('YYYY-MM-DD'), value ? value : 0) })
+                                        }, 500),
+                                    }}
+                                />
+                            </div>
+                        }
+
+                    </div>
+                    {currentSelectedTableRows.length > 0 && (
+                        <div className='btnGroup'>
+                            <span className='batchAdjust' onClick={() => set_modalFormVisible(true)}>批量调整</span>
+                        </div>
+                    )}
+                </div>
+                <div style={{ marginTop: 16 }}>
+                    <KCIMTable scroll={{ y: `calc(100vh - 230px)` }}
+                        actionRef={tableRef} columns={columns as ProColumns[]} rowKey='id'
+                        params={tableDataFilterParams}
+                        request={(params) => getTableData(params)}
+                        // dataSource={showList}
+                        tableAlertRender={false}
+                        rowSelection={{
+                            selectedRowKeys: currentSelectedTableRows.map((a) => a.id),
+                            onChange(selectedRowKeys, selectedRows, info) {
+                                set_currentSelectedTableRows(selectedRows);
+                            },
+                        }}
+
+                    />
+                </div>
+            </div>
+        </KCIMPagecontainer>
+    )
+}

+ 52 - 0
src/pages/qualificationMana/qualificationExperiedMana/service.ts

@@ -0,0 +1,52 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 16:31:27
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-12-16 10:18:38
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+import { request } from 'umi';
+
+//获取table列表数据
+
+export const getTableDataReq = (params?:any) => {
+  return request<any>('/medical/qualificationManage/listAvailableQualification', {
+    method: 'GET',
+    params:{...params}
+  });
+};
+
+
+
+
+//编辑表格数据
+export type EditTableDataType = {
+       
+}
+
+export const editData = (data:EditTableDataType) => {
+  return request('/medical/qualificationManage/adjustBatch', {
+    method: 'POST',
+    data
+  });
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 322 - 0
src/pages/qualificationMana/qualificationExperiedMana/style.less

@@ -0,0 +1,322 @@
+.row-dragging {
+
+  .cost-ant-table-cell {
+    width: 130px;
+  }
+}
+
+.mrms-ant-popover {
+  .mrms-ant-popover-content {
+    .mrms-ant-popover-arrow {
+      display: none;
+    }
+  }
+}
+
+.QualificationExperiedMana-authDetailDrawer {
+  .authDetailDrawer-topBar {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 16px;
+
+    .authDetailDrawer-topBar-title {
+      font-weight: 500;
+      font-size: 16px;
+      color: #17181A;
+      .closeIcon {
+        position: relative;
+        top:2px;
+        display: inline-flex;
+        justify-content: center;
+        align-items: center;
+        width: 24px;
+        height: 24px;
+        cursor: pointer;
+        margin-right: 8px;
+        border-radius: 4px;
+        &:hover {
+          background-color: #E6EAF2;
+        }
+      }
+    }
+
+    .btnGroup {
+      &>span {
+        display: inline-block;
+        text-align: center;
+        cursor: pointer;
+        width: 56px;
+        height: 24px;
+        line-height: 21px;
+        margin-right: 8px;
+        font-weight: 400;
+        font-size: 14px;
+        color: #17181A;
+        background: #FAFCFF;
+        border-radius: 4px;
+        border: 1px solid #DAE2F2;
+
+        &.reject {
+          width: auto;
+          min-width: 56px;
+          color: #FFFFFF;
+          background: #FF4D6A;
+        }
+
+        &.commit {
+          width: auto;
+          min-width: 56px;
+          color: #FFFFFF;
+          background: #3377FF;
+        }
+
+        &:last-child {
+          margin-right: 0;
+        }
+      }
+    }
+  }
+
+
+  .authDetailDrawer-content {
+    .authDetailDrawer-info {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+      background: #FFFFFF;
+      padding: 16px;
+      border-radius: 4px;
+
+      .avator {
+        width: 56px;
+        height: 56px;
+        margin-right: 16px;
+        border-radius: 50%;
+        overflow: hidden;
+        background: #F2F7FF;
+        border: 1px solid #FFFFFF;
+
+        &>img {
+          width: 100%;
+          height: 100%;
+        }
+      }
+
+      .authDetailDrawer-info-detail {
+
+        .authDetailDrawer-info-title {
+          display: flex;
+          width: 100%;
+          flex-direction: row;
+          justify-content: flex-start;
+          align-items: center;
+          font-weight: bold;
+          font-size: 20px;
+          height: 20px;
+          line-height: 20px;
+          color: #17181A;
+          margin-bottom: 12px;
+        }
+
+        .authDetailDrawer-info-title-sub {
+          font-weight: 400;
+          font-size: 14px;
+          color: #525866;
+          line-height: 16px;
+
+          .authDetailDrawer-info-standard {
+            position: relative;
+            min-height: 56px;
+            background: #F7F9FC;
+            border-radius: 4px;
+            padding: 6px 12px;
+            font-weight: 400;
+            font-size: 14px;
+            color: #17181A;
+            line-height: 18px;
+            margin-top: 12px;
+            padding-right: 64px;
+            border: 1px solid #DAE4F2;
+
+            &>img {
+              position: absolute;
+              right: 12px;
+              top: 6px;
+              width: 40px;
+              height: 40px;
+
+            }
+          }
+        }
+      }
+
+    }
+
+    .qualification-info {
+      background: #FFFFFF;
+      padding: 16px;
+      border-radius: 4px;
+      margin-top: 16px;
+
+      .qualification-info-name {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 16px;
+
+        .name {
+          font-weight: 500;
+          font-size: 16px;
+          height: 16px;
+          color: #17181A;
+          line-height: 16px;
+        }
+
+        .tags {}
+      }
+
+      .qualification-info-list {
+        font-weight: 400;
+        font-size: 14px;
+        height: 14px;
+        color: #525866;
+        line-height: 14px;
+        margin-bottom: 12px;
+
+        &>span {
+          color: #17181A;
+        }
+
+        &:last-child {
+          margin-bottom: 0;
+        }
+      }
+    }
+
+    .authDetailDrawer-content-form {
+      padding: 16px;
+      background: #FFFFFF;
+      border-radius: 4px;
+      margin-top: 16px;
+
+      .authDetailDrawer-content-form-title {
+        font-weight: 500;
+        font-size: 16px;
+        height: 16px;
+        color: #17181A;
+        line-height: 16px;
+        margin-bottom: 16px;
+      }
+
+      .formWrapper {}
+    }
+  }
+
+}
+
+.QualificationExperiedMana {
+
+  .pageContent {
+
+    width: 100%;
+    border-radius: 4px;
+    background: #FFFFFF;
+    padding: 16px;
+
+    .right-content-title {
+      font-weight: 500;
+      font-size: 16px;
+      height: 16px;
+      color: #17181A;
+      line-height: 16px;
+      margin-bottom: 16px;
+    }
+
+    .toolBar {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+
+      .filter {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+
+        .tabSwitcher {
+          display: flex;
+          flex-direction: row;
+          justify-content: center;
+          align-items: center;
+          width: 132px;
+          overflow: hidden;
+          margin-right: 16px;
+          
+
+          .tab {
+            text-align: center;
+            height: 24px;
+            width: 50%;
+            cursor: pointer;
+            font-weight: 400;
+            font-size: 14px;
+            color: #17181A;
+            line-height: 24px;
+        
+            &:first-child {
+              border-top-left-radius: 4px;
+              border-bottom-left-radius: 4px;
+              border:1px solid #DAE2F2;
+              border-right: none;
+              &.on {
+                color: #FFFFFF;
+                background: #3377FF;
+                border: none;
+              }
+            }
+            &:last-child {
+              border-top-right-radius: 4px;
+              border-bottom-right-radius: 4px;
+              border:1px solid #DAE2F2;
+              border-left: none;
+              &.on {
+                color: #FFFFFF;
+                background: #3377FF;
+                border: none;
+              }
+            }
+          }
+        }
+
+        .filterItem {
+          display: flex;
+          flex-direction: row;
+          justify-content: center;
+          align-items: center;
+        }
+      }
+
+      .btnGroup {
+        .batchAdjust {
+          cursor: pointer;
+          display: inline-block;
+          font-size: 14px;
+          font-weight: 400;
+          color: #FFFFFF;
+          line-height: 24px;
+          padding: 0 14px;
+          background: #3377FF;
+          border-radius: 4px;
+        }
+      }
+
+    }
+
+  }
+
+}

+ 48 - 0
src/pages/qualificationMana/qualificationExperiedMana/tabs/index.tsx

@@ -0,0 +1,48 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-12-16 11:34:53
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-12-16 14:11:05
+ * @FilePath: /MediResourceManaSys/src/pages/qualificationMana/qualificationExperiedMana/tabs/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+import React, { useState, FC } from 'react';
+import './style.less';
+
+interface FormTabsProps {
+  value?: string; // 当前选中的值
+  width?:number;
+  onChange?: (value: string) => void; // 值变化的回调函数
+}
+
+const FormTabs: FC<FormTabsProps> = ({ value = 'time', onChange,width=80 }) => {
+  const [activeTab, setActiveTab] = useState<string>(value);
+
+  const handleTabChange = (tab: string) => {
+    setActiveTab(tab);
+    if (onChange) {
+      onChange(tab); // 通知外部表单值更新
+    }
+  };
+
+  return (
+    <div className="form-tabs-container" style={{width:width}}>
+      <div className="tab-buttons">
+        <div
+          className={`tab-button ${activeTab === 'time' ? 'active' : ''}`}
+          onClick={() => handleTabChange('time')}
+        >
+          按授权时间
+        </div>
+        <div
+          className={`tab-button ${activeTab === 'days' ? 'active' : ''}`}
+          onClick={() => handleTabChange('days')}
+        >
+          按延期天数
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default FormTabs;

+ 40 - 0
src/pages/qualificationMana/qualificationExperiedMana/tabs/style.less

@@ -0,0 +1,40 @@
+.form-tabs-container {
+    .tab-buttons {
+        display: flex;
+        width: 100%;
+        flex-direction: row;
+        justify-content: center;
+        align-items: center;
+
+
+        .tab-button {
+            width: 50%;
+            text-align: center;
+            height: 24px;
+            line-height: 21px;
+            font-weight: 400;
+            font-size: 14px;
+            color: #17181A;
+            cursor: pointer;
+            border: 1px solid #DAE2F2;
+
+            &.active {
+                line-height: 24px;
+                color: #FFFFFF;
+                border:none;
+                background: #3377FF;
+            }
+
+            &:nth-child(1){
+                border-right: none;
+                border-top-left-radius: 4px;
+                border-bottom-left-radius: 4px;
+            }
+            &:nth-child(2){
+                border-left: none;
+                border-top-right-radius: 4px;
+                border-bottom-right-radius: 4px;
+            }
+        }
+    }
+}

+ 143 - 0
src/pages/qualificationMana/qualificationExperiedMana/transform.tsx

@@ -0,0 +1,143 @@
+import React, { Key, useEffect, useImperativeHandle, useState } from "react";
+import { Transfer } from 'antd'
+import { TransferItem, TransferProps } from 'antd/es/transfer';
+import { ColumnsType } from 'antd/es/table';
+import { difference } from "lodash";
+import { TableRowSelection } from 'antd/es/table/interface';
+import { KCIMTable } from "@/components/KCIMTable";
+import { ProColumns } from "@ant-design/pro-components";
+
+import { log } from "mathjs";
+import { getHasConnectedHisItemDicListReq, getHisItemDicListReq } from "./service";
+
+
+
+interface TableTransferProps extends TransferProps<TransferItem> {
+    leftColumns: ProColumns[];
+    rightColumns: ProColumns[];
+    record: any,
+    onSave: (selectedKeys: Key[], selectedRowKeys: any[]) => void;
+}
+
+const TableTransfer = React.forwardRef(({ leftColumns, rightColumns, record, onSave, ...restProps }: TableTransferProps, ref) => {
+
+    const [_data, _set_data] = useState<any>();
+    const [targetKeys, setTargetKeys] = useState<string[]>([]);
+    const [datasource, set_datasource] = useState<any[]>([]);
+    const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
+    const [queryCondition,set_queryCondition] = useState('');
+    
+    //获取列表
+    const getFuncList = async (params:any) => {
+        let resp = await getHisItemDicListReq({pageSize:500,current:1,...params});
+        if (resp) {
+            set_datasource([...resp.list]);
+            
+        }
+
+    }
+
+    const getDefaultData = async ()=>{
+          const resp = await getHasConnectedHisItemDicListReq({qualificationId:record.id});
+          if(resp){
+               const defaultkeys = resp.list.map((a:any)=>`${a.id}`);
+               setTargetKeys([...targetKeys,...defaultkeys]);
+          }
+    }
+
+    const onChange = (nextTargetKeys: string[]) => {
+        setTargetKeys(nextTargetKeys);
+    };
+
+    const onSelectChange = (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => {
+        //console.log('sourceSelectedKeys:', sourceSelectedKeys,'targetSelectedKeys:',targetSelectedKeys);
+        setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys]);
+    };
+
+    useImperativeHandle(ref, () => ({
+        save: async () => {
+            const items = datasource.filter(a => targetKeys.includes(a.hisItemId));
+            onSave(targetKeys, items);
+        }
+    }));
+
+    useEffect(() => {
+        getFuncList({});
+        getDefaultData();
+    }, [])
+
+    return (
+        <Transfer className='TableTransfer' showSearch
+            titles={['待选项', '已选项']}
+            locale={{
+                itemUnit: '项',
+                itemsUnit: '项',
+                searchPlaceholder: '医嘱编码、医嘱名称',
+            }}
+            oneWay={false}
+            onChange={onChange}
+            onSelectChange={onSelectChange}
+            dataSource={datasource}
+            rowKey={record => record.hisItemId}
+            targetKeys={targetKeys}
+            selectedKeys={selectedKeys}
+            filterOption={(inputValue, item) => {
+                return (item.hisItemName!.indexOf(inputValue) !== -1)||(item.hisItemId!.indexOf(inputValue) !== -1)
+
+            }}
+        >
+            {({
+                direction,
+                filteredItems,
+                onItemSelectAll,
+                onItemSelect,
+                selectedKeys: listSelectedKeys,
+                disabled: listDisabled,
+            }) => {
+
+                // console.log({ filteredItems, listSelectedKeys,direction });
+                const columns = direction === 'left' ? leftColumns : rightColumns;
+
+                const rowSelection: TableRowSelection<TransferItem> = {
+                    getCheckboxProps: (item) => ({ disabled: listDisabled || item.disabled }),
+                    onSelectAll(selected, selectedRows) {
+                        const treeSelectedKeys = selectedRows.map(({ hisItemId }) => hisItemId);
+                        const diffKeys = selected
+                            ? difference(treeSelectedKeys, listSelectedKeys)
+                            : difference(listSelectedKeys, treeSelectedKeys);
+                        onItemSelectAll(diffKeys as string[], selected);
+                    },
+                    onSelect({ hisItemId }, selected) {
+                        onItemSelect(hisItemId as string, selected);
+                    },
+                    selectedRowKeys: listSelectedKeys,
+                };
+
+                return (
+                    <KCIMTable
+                        rowSelection={rowSelection}
+                        columns={columns as TransferItem[]}
+                        dataSource={filteredItems}
+                        size="small"
+                        tableStyle={{border:'none'}}
+                        bordered={false}
+                        rowKey={'hisItemId'}
+                        pagination={{ showTitle: false, pageSize: 9, showLessItems: false, simple: true, showTotal: () => false }}
+                        tableAlertRender={false}
+                        style={{ pointerEvents: listDisabled ? 'none' : undefined }}
+                        onRow={({ code, disabled: itemDisabled }) => ({
+                            onClick: () => {
+                                if (itemDisabled || listDisabled) return;
+                                onItemSelect(code as string, !listSelectedKeys.includes(code as string));
+                            },
+                        })}
+                    />
+                );
+            }}
+        </Transfer>
+    )
+});
+
+export default TableTransfer
+
+

+ 55 - 0
src/utils/format.ts

@@ -1,3 +1,11 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-09-09 10:07:01
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-12-10 11:00:43
+ * @FilePath: /MediResourceManaSys/src/utils/format.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
 
 // 示例方法,没有实际意义
 export function trim(str: string) {
@@ -27,3 +35,50 @@ export function formatToPercentage(num: number) {
   }).format(num);
 }
 
+
+
+interface TreeNode {
+  id: number | string;
+  parentId: number | string | null;
+  [key: string]: any; // 允许有任意其它属性
+}
+
+interface TreeItem extends TreeNode {
+  children: TreeItem[];
+}
+
+/**
+ * 根据 parentId 将平铺的数据组装成树状结构
+ * @param data 平铺的数据,每项需包含 id 和 parentId 属性
+ * @param rootParentId 作为根节点标识的 parentId 值,通常为0或null
+ * @returns 树状结构的数组
+ */
+export function buildTree<T extends TreeNode>(
+  data: T[],
+  rootParentId: number | string | null = 0
+): TreeItem[] {
+  const map: Record<string | number, TreeItem> = {};
+
+  // 初始化 map,每个节点都拥有 children 字段
+  data.forEach((item) => {
+    map[item.id] = { ...item, children: [] };
+  });
+
+  const tree: TreeItem[] = [];
+
+  data.forEach((item) => {
+    const node = map[item.id];
+    if (item.parentId === rootParentId) {
+      tree.push(node);
+    } else {
+      const parent = map[item.parentId as string | number];
+      if (parent) {
+        parent.children.push(node);
+      }
+    }
+  });
+
+  return tree;
+}
+
+

+ 31 - 1
src/utils/tooljs.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-02-20 14:31:06
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-01-12 20:16:36
+ * @LastEditTime: 2024-12-16 15:54:17
  * @FilePath: /BudgetManaSystem/src/utils/tooljs.js
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -348,6 +348,36 @@ export const  copyToClipboard = (text:string) => {
 }
 
 
+/**
+ * 根据输入日期和延期天数,返回延期后的日期
+ * @param dateStr - 输入日期,格式为 yyyy-mm-dd
+ * @param days - 延期的天数
+ * @returns - 延期后的日期,格式为 yyyy-mm-dd
+ */
+export function calculateDelayedDate(dateStr: string, days: number): string {
+  console.log({dateStr,days});
+  // 将输入日期转换为 Date 对象
+  const inputDate = new Date(dateStr);
+
+  // 检查输入日期是否有效
+  if (isNaN(inputDate.getTime())) {
+      throw new Error("无效的日期格式,请使用 yyyy-mm-dd 格式");
+  }
+
+  // 延期天数的计算
+  inputDate.setDate(inputDate.getDate() + days);
+
+  // 格式化输出为 yyyy-mm-dd
+  const year = inputDate.getFullYear();
+  const month = String(inputDate.getMonth() + 1).padStart(2, "0"); // 月份从 0 开始
+  const day = String(inputDate.getDate()).padStart(2, "0");
+
+  return `${year}-${month}-${day}`;
+}
+
+
+
+
 
 
 

BIN
static/avatar.png


BIN
static/gerenziliaobeijing.png


BIN
static/gou_black.png


BIN
static/gou_white.png


BIN
static/indexBgCenter.png