chenlei 5 月之前
父節點
當前提交
3098a53433
共有 30 個文件被更改,包括 10519 次插入10282 次删除
  1. 5 0
      .eslintrc.js
  2. 4 3
      package.json
  3. 8435 9813
      pnpm-lock.yaml
  4. 二進制
      public/favicon.ico
  5. 9 0
      src/api/assessment.ts
  6. 118 7
      src/api/management.ts
  7. 8 4
      src/components/AddIndexModal/index.tsx
  8. 0 1
      src/components/index.ts
  9. 68 30
      src/constants.ts
  10. 151 0
      src/pages/Assessment/Index/CreateOrEdit/components/InspectionEditable/index.tsx
  11. 309 126
      src/pages/Assessment/Index/CreateOrEdit/index.tsx
  12. 6 3
      src/pages/Assessment/Index/components/Container/index.tsx
  13. 4 0
      src/pages/AssessmentDetail/components/OverallAssessment/index.module.scss
  14. 99 87
      src/pages/AssessmentDetail/components/OverallAssessment/index.tsx
  15. 74 12
      src/pages/AssessmentDetail/index.tsx
  16. 106 37
      src/pages/Management/Evaluation/index.tsx
  17. 125 39
      src/pages/Management/Form/index.tsx
  18. 2 8
      src/pages/Management/Index/CreateOrEdit/index.tsx
  19. 81 32
      src/pages/Management/Index/SettingIndex/index.tsx
  20. 184 29
      src/pages/Management/Index/SettingRole/index.tsx
  21. 70 15
      src/components/AddRoleModal/index.tsx
  22. 105 0
      src/pages/Management/Index/components/AddGroupModal/index.tsx
  23. 166 0
      src/pages/Management/Index/components/AllocationOfDataModal/index.tsx
  24. 159 0
      src/pages/Management/Index/components/AllocationOfIndexModal/index.tsx
  25. 4 0
      src/pages/Management/Index/components/index.ts
  26. 94 23
      src/pages/Management/Index/index.tsx
  27. 3 3
      src/router/index.tsx
  28. 9 0
      src/types/assessment.ts
  29. 100 8
      src/types/management.ts
  30. 21 2
      src/utils/index.ts

+ 5 - 0
.eslintrc.js

@@ -0,0 +1,5 @@
+module.exports = {
+  rules: {
+    "react-hooks/exhaustive-deps": "off",
+  },
+};

+ 4 - 3
package.json

@@ -6,8 +6,8 @@
     "@ant-design/icons": "^5.1.4",
     "@ant-design/pro-components": "^2.8.1",
     "@babel/core": "^7.16.0",
-    "@dage/pc-components": "^1.3.4",
-    "@dage/service": "^1.0.3",
+    "@dage/pc-components": "^1.3.5",
+    "@dage/service": "^1.0.5",
     "@dage/utils": "^1.0.2",
     "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",
     "@svgr/webpack": "^5.5.0",
@@ -84,7 +84,8 @@
   },
   "scripts": {
     "start": "cross-env REACT_APP_API_URL=http://192.168.20.61:8090 REACT_APP_IMG_PUBLIC=/api node scripts/start.js",
-    "build": "cross-env PUBLIC_URL=./ REACT_APP_API_URL=https://sit-shgybwg.4dage.com REACT_APP_IMG_PUBLIC= node scripts/build.js"
+    "build": "cross-env PUBLIC_URL=./ REACT_APP_API_URL=https://sit-shoubodyh.4dage.com REACT_APP_IMG_PUBLIC= node scripts/build.js",
+    "build:prod": "cross-env PUBLIC_URL=./ REACT_APP_API_URL=http://192.124.82.43:8091 REACT_APP_IMG_PUBLIC= node scripts/build.js"
   },
   "eslintConfig": {
     "extends": [

File diff suppressed because it is too large
+ 8435 - 9813
pnpm-lock.yaml


二進制
public/favicon.ico


+ 9 - 0
src/api/assessment.ts

@@ -5,6 +5,7 @@ import {
   IFileTemplateFormParams,
   IFileTemplateFormResponse,
   IAssTemplateDetail,
+  IAssInspectionItem,
 } from "@/types";
 import { requestByGet, requestByPost } from "@dage/service";
 
@@ -45,6 +46,14 @@ export const deleteAssIndexApi = (ids: string | number) => {
   return requestByGet(`/api/cms/norm/removes/${ids}`);
 };
 
+export const saveAssInspectionApi = (params: IAssInspectionItem[]) => {
+  return requestByPost<number[]>("/api/cms/norm/gist/saveEntity", params);
+};
+
+export const deleteAssInspectionApi = (ids: string | number) => {
+  return requestByGet(`/api/cms/norm/gist/removes/${ids}`);
+};
+
 /**
  * ====================
  * 考核模板 API

+ 118 - 7
src/api/management.ts

@@ -1,5 +1,19 @@
-import { IManageAssessmentIndex, IManageIndexDetail } from "@/types";
-import { requestByGet, requestByPost } from "@dage/service";
+import {
+  IManageDeptMaterialItem,
+  IManageAssessmentIndex,
+  IManageDeptItem,
+  IManageFormDetail,
+  IManageFormItem,
+  IManageFormListParams,
+  IManageIndexDetail,
+  IManageUserItem,
+  PUBLISH_ENUM,
+  ASS_INDEX_TYPE,
+  IManageDeptAllocationOfIndexItem,
+  IManageRoleGroupItem,
+  IManageAssOperationResponse,
+} from "@/types";
+import { requestByGet, requestByPost, requestPagination } from "@dage/service";
 
 export const getManageIndexListApi = (params: any) => {
   return requestByPost("/api/cms/assess/pageList", params);
@@ -17,18 +31,115 @@ export const getManageIndexDetailApi = (id: string | number) => {
   return requestByGet<IManageIndexDetail>(`/api/cms/assess/detail/${id}`);
 };
 
-export const getManageAssFixedList = (
+export const publishManageIndexApi = (
+  id: string | number,
+  status = PUBLISH_ENUM.PUBLISHED
+) => {
+  return requestByGet(`/api/cms/assess/publish/${id}/${status}`);
+};
+
+export const getManageRoleDeptListApi = (id: number | string) => {
+  return requestByGet<IManageDeptItem[]>(`/api/cms/dept/getList/${id}`);
+};
+
+export const getManageUserListApi = () => {
+  return requestByGet<IManageUserItem[]>("/api/cms/dept/getUser");
+};
+
+export const saveManageRoleDeptApi = (params: any) => {
+  return requestByPost("/api/cms/dept/save", params);
+};
+
+export const deleteManageRoleDeptApi = (ids: number | string) => {
+  return requestByGet(`/api/cms/dept/removes/${ids}`);
+};
+
+export const getManageAssFixedListApi = (
   id: number | string,
   searchKey?: string
 ) => {
-  return requestByGet(`/api/cms/assessFixed/getList/${id}`, {
-    searchKey,
-  });
+  return requestByGet<IManageAssessmentIndex[]>(
+    `/api/cms/assessFixed/getList/${id}`,
+    {
+      searchKey,
+    }
+  );
+};
+
+export const getManageAssOperationListApi = (
+  id: number | string,
+  searchKey?: string
+) => {
+  return requestByGet<IManageAssOperationResponse>(
+    `/api/cms/assessOperation/getList/${id}`,
+    {
+      searchKey,
+    }
+  );
 };
 
-export const setManageAssFixed = (id: string | number, indexIds: string[]) => {
+export const setManageAssFixedApi = (
+  id: string | number,
+  indexIds: string[]
+) => {
   return requestByPost<IManageAssessmentIndex[]>(
     `/api/cms/assessFixed/save/${id}`,
     indexIds
   );
 };
+
+export const getManageFormListApi = (params: IManageFormListParams) => {
+  return requestPagination<IManageFormItem>("/api/cms/fill/pageList", params);
+};
+
+export const getManageFormDetailApi = (id: number | string) => {
+  return requestByGet<IManageFormDetail>(`/api/cms/fill/detail/${id}`);
+};
+
+export const getManageEvaluationListApi = (params: IManageFormListParams) => {
+  return requestPagination<IManageFormItem>("/api/cms/review/pageList", params);
+};
+
+export const getManageEvaluationDetailApi = (id: number | string) => {
+  return requestByGet<IManageFormDetail>(`/api/cms/review/detail/${id}`);
+};
+
+export const getManageDeptAllocationOfDataListApi = (id: number | string) => {
+  return requestByGet<null | IManageDeptMaterialItem[]>(
+    `/api/cms/dept/material/getList/${id}`
+  );
+};
+
+export const saveManageDeptAllocationOfDataApi = (params: any) => {
+  return requestByPost("/api/cms/dept/material/save", params);
+};
+
+export const getManageDeptAllocationOfIndexListApi = (
+  assessId: number | string,
+  deptId: number | string,
+  normType: ASS_INDEX_TYPE,
+  // 查看未分配
+  assign?: number
+) => {
+  return requestByGet<IManageDeptAllocationOfIndexItem[]>(
+    `/api/cms/dept/norm/getTree/${assessId}/${deptId}/${normType}`,
+    {
+      assign,
+    }
+  );
+};
+
+export const saveManageDeptAllocationOfIndexApi = (params: any) => {
+  return requestByPost("/api/cms/dept/norm/save", params);
+};
+
+export const getManageRoleGroupListApi = (assessId: string | number) => {
+  return requestByGet(`/api/cms/group/detail/${assessId}`);
+};
+
+export const saveManageRoleGroupApi = (params: {
+  assessId: number | string;
+  userIds: string;
+}) => {
+  return requestByPost<IManageRoleGroupItem>("/api/cms/group/save", params);
+};

+ 8 - 4
src/components/AddIndexModal/index.tsx

@@ -77,7 +77,7 @@ export const AddIndexModal: FC<AddIndexModalProps> = ({
       >
         <Form.Item
           label="采用指标"
-          name="checkedKeys"
+          name="onlyChildKeys"
           required
           rules={[{ required: true, message: "请选择指标" }]}
         >
@@ -87,10 +87,14 @@ export const AddIndexModal: FC<AddIndexModalProps> = ({
             fieldNames={{ title: "name", key: "id" }}
             checkedKeys={_checkedKeys}
             treeData={treeData}
-            onCheck={(checkedKeys) => {
-              setCheckedKeys(checkedKeys as Key[]);
+            onCheck={(checkedKeys, { checkedNodes }) => {
+              const onlyChildKeys = (checkedKeys as Key[]).filter((i) => {
+                const node = checkedNodes.find((n) => n.id === i);
+                return !node?.children.length;
+              });
+              setCheckedKeys(onlyChildKeys);
               form.setFieldsValue({
-                checkedKeys,
+                onlyChildKeys,
               });
             }}
           />

+ 0 - 1
src/components/index.ts

@@ -5,4 +5,3 @@ export * from "./FileTemplateTable";
 export * from "./Search";
 export * from "./AddIndexModal";
 export * from "./AddIndexTemplateModal";
-export * from "./AddRoleModal";

+ 68 - 30
src/constants.ts

@@ -1,9 +1,9 @@
-import { ASS_INDEX_TYPE, PUBLISH_ENUM } from "./types";
+import { ASS_INDEX_TYPE, DEPT_STATUS_ENUM, PUBLISH_ENUM } from "./types";
 
 export const PUBLISH_STATUS_MAP = {
   [PUBLISH_ENUM.PENDING]: {
     label: "待发布",
-    color: "#FF5858",
+    color: "#1677ff",
   },
   [PUBLISH_ENUM.PUBLISHED]: {
     label: "已发布",
@@ -11,48 +11,32 @@ export const PUBLISH_STATUS_MAP = {
   },
   [PUBLISH_ENUM.ENDED]: {
     label: "已结束",
-    color: "#6BC6FF",
+    color: "#909399",
+  },
+  [PUBLISH_ENUM.EVALUATED]: {
+    label: "已评定",
+    color: "#67C23A",
   },
 };
 
 export const PUBLISH_STATUS_OPTIONS = [
   {
     label: "待发布",
-    value: 0,
+    value: PUBLISH_ENUM.PENDING,
   },
   {
     label: "已发布",
-    value: 1,
+    value: PUBLISH_ENUM.PUBLISHED,
   },
   {
     label: "已结束",
-    value: 2,
-  },
-];
-
-/**
- * 考核单状态
- */
-export enum ASSESSMENT_ENUM {
-  PENDING = 0,
-  RETURN = 1,
-  FAIL = 2,
-}
-
-export const ASSESSMENT_STATUS_MAP = {
-  [ASSESSMENT_ENUM.PENDING]: {
-    label: "待填报",
-    color: "#4284ff",
-  },
-  [ASSESSMENT_ENUM.RETURN]: {
-    label: "已退回",
-    color: "#E6A23C",
+    value: PUBLISH_ENUM.ENDED,
   },
-  [ASSESSMENT_ENUM.FAIL]: {
-    label: "未通过",
-    color: "#FF5858",
+  {
+    label: "已评定",
+    value: PUBLISH_ENUM.EVALUATED,
   },
-};
+];
 
 /**
  * 初始化指标
@@ -85,3 +69,57 @@ export const ASSESSMENT_TYPE_OPTIONS = [
     value: ASS_INDEX_TYPE.OPERATION,
   },
 ];
+
+export const DEPT_STATUS_MAP = {
+  [DEPT_STATUS_ENUM.PENDING_SUBMIT]: {
+    label: "待填报",
+    color: "#1677ff",
+  },
+  [DEPT_STATUS_ENUM.PENDING_EXAMINE]: {
+    label: "待审核",
+    color: "#1677ff",
+  },
+  [DEPT_STATUS_ENUM.EXAMINE_REJECT]: {
+    label: "审核未通过",
+    color: "#F56C6C",
+  },
+  [DEPT_STATUS_ENUM.EXAMINE_SUCCESS]: {
+    label: "审核通过",
+    color: "#E6A23C",
+  },
+  [DEPT_STATUS_ENUM.RETURN]: {
+    label: "退回",
+    color: "#F56C6C",
+  },
+  [DEPT_STATUS_ENUM.SUCCESS]: {
+    label: "评定通过",
+    color: "#67C23A",
+  },
+};
+
+export const DEPT_STATUS_OPTIONS = [
+  {
+    label: "待填报",
+    value: DEPT_STATUS_ENUM.PENDING_SUBMIT,
+  },
+  {
+    label: "待审核",
+    value: DEPT_STATUS_ENUM.PENDING_EXAMINE,
+  },
+  {
+    label: "审核未通过",
+    value: DEPT_STATUS_ENUM.EXAMINE_REJECT,
+  },
+  {
+    label: "审核通过",
+    value: DEPT_STATUS_ENUM.EXAMINE_SUCCESS,
+  },
+  {
+    label: "退回",
+    value: DEPT_STATUS_ENUM.RETURN,
+  },
+  {
+    label: "评定通过",
+    value: DEPT_STATUS_ENUM.SUCCESS,
+  },
+];

+ 151 - 0
src/pages/Assessment/Index/CreateOrEdit/components/InspectionEditable/index.tsx

@@ -0,0 +1,151 @@
+import {
+  EditableProTable,
+  EditableProTableProps,
+} from "@ant-design/pro-components";
+import { Input, InputNumber } from "antd";
+import { uniqueId } from "lodash";
+import { forwardRef, Key, useImperativeHandle, useState } from "react";
+
+export interface InspectionEditableProps
+  extends EditableProTableProps<any, any> {}
+
+export interface InspectionEditableMethods {
+  setEditableRowKeys(v: Key[]): void;
+}
+
+const DEFAULT_INSPECTION_ITEM = {
+  name: "",
+  one: "",
+  two: "",
+  three: "",
+};
+
+export const InspectionEditable = forwardRef<
+  InspectionEditableMethods,
+  InspectionEditableProps
+>((props, ref) => {
+  const [editableKeys, setEditableRowKeys] = useState<Key[]>();
+
+  useImperativeHandle(ref, () => ({
+    setEditableRowKeys,
+  }));
+
+  return (
+    <EditableProTable
+      {...props}
+      rowKey="_id"
+      controlled
+      className="mw650"
+      columns={[
+        {
+          title: "要点名称",
+          align: "center",
+          dataIndex: "name",
+          width: 300,
+          formItemProps: () => {
+            return {
+              rules: [{ required: true, message: "此项为必填项" }],
+            };
+          },
+          renderFormItem: () => {
+            return <Input placeholder="请输入内容,最多50字" maxLength={50} />;
+          },
+        },
+        {
+          title: "一级博物馆",
+          align: "center",
+          dataIndex: "one",
+          formItemProps: () => {
+            return {
+              rules: [{ required: true, message: "此项为必填项" }],
+            };
+          },
+          renderFormItem: () => {
+            return (
+              <InputNumber
+                placeholder="请填入正整数"
+                min={0}
+                precision={0}
+                controls={false}
+              />
+            );
+          },
+        },
+        {
+          title: "二级博物馆",
+          align: "center",
+          dataIndex: "two",
+          formItemProps: () => {
+            return {
+              rules: [{ required: true, message: "此项为必填项" }],
+            };
+          },
+          renderFormItem: () => {
+            return (
+              <InputNumber
+                placeholder="请填入正整数"
+                min={0}
+                precision={0}
+                controls={false}
+              />
+            );
+          },
+        },
+        {
+          title: "三级博物馆",
+          align: "center",
+          dataIndex: "three",
+          formItemProps: () => {
+            return {
+              rules: [{ required: true, message: "此项为必填项" }],
+            };
+          },
+          renderFormItem: () => {
+            return (
+              <InputNumber
+                placeholder="请填入正整数"
+                min={0}
+                precision={0}
+                controls={false}
+              />
+            );
+          },
+        },
+        {
+          title: "操作",
+          width: 100,
+          align: "center",
+          valueType: "option",
+          render: (text, record, _, action) => {
+            return (
+              <a
+                key="editable"
+                onClick={() => {
+                  action?.startEditable?.(record.id);
+                }}
+              >
+                编辑
+              </a>
+            );
+          },
+        },
+      ]}
+      editable={{
+        type: "multiple",
+        // editableKeys,
+        actionRender: (row, config, defaultDoms) => {
+          return [defaultDoms.save, defaultDoms.delete];
+        },
+      }}
+      recordCreatorProps={{
+        type: "primary",
+        newRecordType: "dataSource",
+        creatorButtonText: "新增考察要点",
+        record: () => ({
+          _id: uniqueId("insepction"),
+          ...DEFAULT_INSPECTION_ITEM,
+        }),
+      }}
+    />
+  );
+});

+ 309 - 126
src/pages/Assessment/Index/CreateOrEdit/index.tsx

@@ -1,4 +1,4 @@
-import { FC, useEffect, useMemo, useState } from "react";
+import { FC, useEffect, useMemo, useRef, useState } from "react";
 import classNames from "classnames";
 import {
   Col,
@@ -8,6 +8,7 @@ import {
   Radio,
   Row,
   Select,
+  Table,
   TreeSelect,
 } from "antd";
 import { useLocation, useNavigate, useParams } from "react-router-dom";
@@ -23,10 +24,17 @@ import {
   getAssIndexDetailApi,
   getAssIndexTreeApi,
   saveAssIndexApi,
+  saveAssInspectionApi,
 } from "@/api";
 import { CONNECT_WITH_SYMBOL_OPTIONS, SYMBOL_OPTIONS } from "../constants";
-import { isNull } from "lodash";
+import { isNull, isNumber } from "lodash";
 import { DageLoading } from "@dage/pc-components";
+import { getSelectedNodes } from "@/utils";
+import {
+  InspectionEditable,
+  InspectionEditableMethods,
+} from "./components/InspectionEditable";
+import { EditableFormInstance } from "@ant-design/pro-components";
 
 const { TextArea } = Input;
 const CONFIRM_OPTIONS = [
@@ -39,6 +47,10 @@ const CONFIRM_OPTIONS = [
     value: YES_OR_NO.NO,
   },
 ];
+const MUSEUM_LEVEL: Record<number, string> = {
+  1: "二级",
+  2: "三级",
+};
 
 const CreateOrEditIndex: FC = () => {
   const location = useLocation();
@@ -46,6 +58,8 @@ const CreateOrEditIndex: FC = () => {
   const query = new URLSearchParams(location.search);
   const params = useParams();
   const [form] = Form.useForm();
+  const editorFormRef = useRef<EditableFormInstance<any>>();
+  const inspectionRef = useRef<InspectionEditableMethods | null>(null);
   const [loading, setLoading] = useState(false);
   const [values, setValues] = useState<any>({
     isPoint: YES_OR_NO.YES,
@@ -57,40 +71,105 @@ const CreateOrEditIndex: FC = () => {
     [location]
   );
   const [detail, setDetail] = useState<null | IAssIndexDetail>(null);
+  const isFixed = params.type === ASS_INDEX_TYPE.FIXED;
+  const parentId = Form.useWatch("parentId", form);
+  /** 考察要点 */
+  const gistIds = Form.useWatch("gistIds", form);
+  /** 指标分值 */
+  const scores = useMemo(() => {
+    const temp = {
+      id: 0,
+      one: 0,
+      two: 0,
+      three: 0,
+    };
+
+    gistIds?.forEach((item: any) => {
+      if (item.one) temp.one += item.one;
+      if (item.two) temp.two += item.two;
+      if (item.three) temp.three += item.three;
+    });
+
+    return [temp];
+  }, [gistIds]);
+  const parentNode = useMemo(() => {
+    const id = Number(parentId);
+    if (!isNumber(id)) return null;
+
+    const targets = getSelectedNodes([id], treeData, true);
+
+    return targets ? targets[0] : null;
+  }, [parentId, treeData]);
 
   const handleSubmit = async () => {
-    if (!(await form.validateFields())) return;
+    if (
+      !(
+        (await form.validateFields()) ||
+        (await editorFormRef.current?.validateFields())
+      )
+    )
+      return;
 
-    const { materialIds, api, isAdd, score, warnData, ...rest } =
+    const { materialIds, api, isAdd, score, warnData, gistIds, ...rest } =
       form.getFieldsValue();
 
     if (materialIds)
       rest.materialIds = materialIds.map((i: any) => i.id).join(",");
-    if (rest.isPoint === YES_OR_NO.YES) {
-      // 打分点
+    // 定级指标才有打分点
+    if (rest.isPoint === YES_OR_NO.YES && isFixed) {
       rest.jsonPoint = {
         api,
         isAdd,
         score,
       };
     }
+    // 告警阈值
     if (rest.isWarn === YES_OR_NO.YES) {
-      // 告警阈值
       rest.jsonWarn = JSON.stringify(warnData);
     }
+    // 运行指标补全权重
+    if (!isFixed && !rest.weight) rest.weight = 0;
+
+    // 先处理考察要点
+    let data = null;
+    if (Array.isArray(gistIds)) {
+      data = await saveAssInspectionApi(
+        gistIds.map((item) => {
+          const { _id, ...rest } = item;
+          return rest;
+        })
+      );
+    }
 
     await saveAssIndexApi({
       ...rest,
       level: 1,
       type: params.type,
       id: detail?.id,
+      gistIds: Array.isArray(data) ? data.join(",") : undefined,
     });
     navigate(-1);
   };
 
+  const filterTreeData = (data: AssIndexTreeItemType[]) => {
+    return data.map((item) => {
+      const { children, ...rest } = item;
+      const temp: AssIndexTreeItemType = {
+        ...rest,
+        children: [],
+      };
+
+      if (temp.level < 2) {
+        temp.children = filterTreeData(children);
+      }
+
+      return temp;
+    });
+  };
+
   const getAssIndexTree = async () => {
     const data = await getAssIndexTreeApi(params.type as ASS_INDEX_TYPE);
-    setTreeData(data);
+    setTreeData(filterTreeData(data));
   };
 
   const getDetail = async () => {
@@ -98,9 +177,13 @@ const CreateOrEditIndex: FC = () => {
       setLoading(true);
       const data = await getAssIndexDetailApi(Number(params.id));
       const pointData =
-        data.isPoint === YES_OR_NO.YES ? JSON.parse(data.jsonPoint) : null;
+        data.isPoint === YES_OR_NO.YES && data.jsonPoint
+          ? JSON.parse(data.jsonPoint)
+          : null;
       const warnData =
-        data.isWarn === YES_OR_NO.YES ? JSON.parse(data.jsonWarn) : null;
+        data.isWarn === YES_OR_NO.YES && data.jsonWarn
+          ? JSON.parse(data.jsonWarn)
+          : null;
       setDetail(data);
       form.setFieldsValue({
         parentId: data.parentId,
@@ -120,6 +203,17 @@ const CreateOrEditIndex: FC = () => {
         isPoint: data.isPoint,
         isWarn: data.isWarn,
       });
+
+      if (data.gists) {
+        form.setFieldValue(
+          "gistIds",
+          data.gists.map((i) => ({
+            ...i,
+            _id: i.id,
+          }))
+        );
+        // inspectionRef.current?.setEditableRowKeys(data.gists.map((i) => i.id));
+      }
     } finally {
       setLoading(false);
     }
@@ -156,6 +250,11 @@ const CreateOrEditIndex: FC = () => {
             fieldNames={{ label: "name", value: "id" }}
           />
         </Form.Item>
+        {!isFixed && (
+          <Form.Item label="指标级别">
+            {MUSEUM_LEVEL[parentNode?.level as number] || "一级"}
+          </Form.Item>
+        )}
         <Form.Item
           label="指标名称"
           required
@@ -188,133 +287,217 @@ const CreateOrEditIndex: FC = () => {
           />
         </Form.Item>
 
-        <Form.Item label="打分点" name="isPoint" initialValue={values.isPoint}>
-          <Radio.Group
-            options={CONFIRM_OPTIONS}
-            optionType="button"
-            buttonStyle="solid"
-          />
-        </Form.Item>
-        <Form.Item label=" " colon={false} style={{ marginTop: -14 }}>
-          <div className={classNames("mw650", style.panel)}>
-            {Boolean(values.isPoint) ? (
-              <>
-                <Form.Item
-                  required
-                  label="指标分值"
-                  labelCol={{ span: 4 }}
-                  name="score"
-                  rules={[{ required: true, message: "请输入指标分值" }]}
-                >
-                  <InputNumber
-                    precision={0}
-                    placeholder="请输入正整数"
-                    className="w160"
-                  />
-                </Form.Item>
-                <Form.Item label="数据API" labelCol={{ span: 4 }} name="api">
-                  <Input placeholder="请输入地址" style={{ width: 427 }} />
-                </Form.Item>
-                <Form.Item label="加分项" labelCol={{ span: 4 }} colon={false}>
-                  <Form.Item noStyle name="isAdd">
-                    <Radio.Group>
-                      <Radio value={1}>是</Radio>
-                      <Radio value={0}>否</Radio>
-                    </Radio.Group>
-                  </Form.Item>
-                  <span className={style.tips}>
-                    注:设为加分项后,该指标的分值不会参与父级指标的计算
-                  </span>
-                </Form.Item>
-              </>
-            ) : (
-              <Form.Item label="分值:0" labelCol={{ span: 4 }} colon={false}>
-                <span className={style.tips}>
-                  注:当指标不作为打分点时,分值=该指标各分项分值(除加分项)之和
-                </span>
-              </Form.Item>
-            )}
-          </div>
-        </Form.Item>
+        {parentNode?.level === 2 && !isFixed && (
+          <>
+            <Form.Item
+              label="考察要点"
+              required
+              name="gistIds"
+              rules={[{ required: true, message: "至少需要填入一个考查要点" }]}
+            >
+              <InspectionEditable
+                ref={inspectionRef}
+                editableFormRef={editorFormRef}
+              />
+            </Form.Item>
 
-        <Form.Item label="告警阈值" name="isWarn" initialValue={values.isWarn}>
-          <Radio.Group
-            options={CONFIRM_OPTIONS}
-            optionType="button"
-            buttonStyle="solid"
-          />
-        </Form.Item>
-        {Boolean(values.isWarn) ? (
-          <Form.Item label=" " colon={false} style={{ marginTop: -14 }}>
-            <div
-              className={classNames("mw650", style.panel)}
-              style={{ padding: "10px 30px" }}
+            <Form.Item label="指标分值">
+              <Table
+                rowKey="id"
+                dataSource={scores}
+                className="mw650"
+                pagination={false}
+                columns={[
+                  {
+                    title: "一级博物馆",
+                    dataIndex: "one",
+                    align: "center",
+                  },
+                  {
+                    title: "二级博物馆",
+                    dataIndex: "two",
+                    align: "center",
+                  },
+                  {
+                    title: "三级博物馆",
+                    dataIndex: "three",
+                    align: "center",
+                  },
+                ]}
+              />
+              <p className={style.tips}>注:指标分值:=各考查要点分值之和</p>
+            </Form.Item>
+          </>
+        )}
+
+        {isFixed && (
+          <>
+            <Form.Item
+              label="打分点"
+              name="isPoint"
+              initialValue={values.isPoint}
             >
-              <Row gutter={10}>
-                <Col span={8}>
+              <Radio.Group
+                options={CONFIRM_OPTIONS}
+                optionType="button"
+                buttonStyle="solid"
+              />
+            </Form.Item>
+            <Form.Item label=" " colon={false} style={{ marginTop: -14 }}>
+              <div className={classNames("mw650", style.panel)}>
+                {Boolean(values.isPoint) ? (
+                  <>
+                    <Form.Item
+                      required
+                      label="指标分值"
+                      labelCol={{ span: 4 }}
+                      name="score"
+                      rules={[{ required: true, message: "请输入指标分值" }]}
+                    >
+                      <InputNumber
+                        precision={0}
+                        placeholder="请输入正整数"
+                        className="w160"
+                      />
+                    </Form.Item>
+                    <Form.Item
+                      label="数据API"
+                      labelCol={{ span: 4 }}
+                      name="api"
+                    >
+                      <Input placeholder="请输入地址" style={{ width: 427 }} />
+                    </Form.Item>
+                    <Form.Item
+                      label="加分项"
+                      labelCol={{ span: 4 }}
+                      colon={false}
+                    >
+                      <Form.Item noStyle name="isAdd">
+                        <Radio.Group>
+                          <Radio value={1}>是</Radio>
+                          <Radio value={0}>否</Radio>
+                        </Radio.Group>
+                      </Form.Item>
+                      <span className={style.tips}>
+                        注:设为加分项后,该指标的分值不会参与父级指标的计算
+                      </span>
+                    </Form.Item>
+                  </>
+                ) : (
                   <Form.Item
-                    noStyle
-                    name={["warnData", "symbol"]}
-                    rules={[{ required: true, message: "" }]}
+                    label="分值:0"
+                    labelCol={{ span: 4 }}
+                    colon={false}
                   >
-                    <Select placeholder="请选择" options={SYMBOL_OPTIONS} />
+                    <span className={style.tips}>
+                      注:当指标不作为打分点时,分值=该指标各分项分值(除加分项)之和
+                    </span>
                   </Form.Item>
-                </Col>
-                <Col span={12}>
-                  <Form.Item
-                    noStyle
-                    name={["warnData", "num"]}
-                    rules={[{ required: true, message: "" }]}
-                  >
-                    <InputNumber
-                      precision={0}
-                      placeholder="请输入正整数"
-                      className="w100"
+                )}
+              </div>
+            </Form.Item>
+          </>
+        )}
+
+        {(isFixed || parentNode?.level === 2) && (
+          <>
+            <Form.Item
+              label="告警阈值"
+              name="isWarn"
+              initialValue={values.isWarn}
+            >
+              <Radio.Group
+                options={CONFIRM_OPTIONS}
+                optionType="button"
+                buttonStyle="solid"
+              />
+            </Form.Item>
+            {Boolean(values.isWarn) ? (
+              <Form.Item label=" " colon={false} style={{ marginTop: -14 }}>
+                <div
+                  className={classNames("mw650", style.panel)}
+                  style={{ padding: "10px 30px" }}
+                >
+                  <Row gutter={10}>
+                    <Col span={8}>
+                      <Form.Item
+                        noStyle
+                        name={["warnData", "symbol"]}
+                        rules={[{ required: true, message: "" }]}
+                      >
+                        <Select placeholder="请选择" options={SYMBOL_OPTIONS} />
+                      </Form.Item>
+                    </Col>
+                    <Col span={12}>
+                      <Form.Item
+                        noStyle
+                        name={["warnData", "num"]}
+                        rules={[{ required: true, message: "" }]}
+                      >
+                        <InputNumber
+                          precision={0}
+                          placeholder="请输入正整数"
+                          className="w100"
+                        />
+                      </Form.Item>
+                    </Col>
+                    <Col span={4}>
+                      <span className={style.required}>(必填)</span>
+                    </Col>
+                  </Row>
+
+                  <Form.Item noStyle name={["warnData", "and"]}>
+                    <Radio.Group
+                      options={CONNECT_WITH_SYMBOL_OPTIONS}
+                      style={{ margin: "3px 0" }}
                     />
                   </Form.Item>
-                </Col>
-                <Col span={4}>
-                  <span className={style.required}>(必填)</span>
-                </Col>
-              </Row>
-
-              <Form.Item noStyle name={["warnData", "and"]}>
-                <Radio.Group
-                  options={CONNECT_WITH_SYMBOL_OPTIONS}
-                  style={{ margin: "3px 0" }}
-                />
+
+                  <Row gutter={10}>
+                    <Col span={8}>
+                      <Form.Item noStyle name={["warnData", "symbol2"]}>
+                        <Select
+                          allowClear
+                          placeholder="请选择"
+                          options={SYMBOL_OPTIONS}
+                        />
+                      </Form.Item>
+                    </Col>
+                    <Col span={12}>
+                      <Form.Item noStyle name={["warnData", "num2"]}>
+                        <InputNumber
+                          precision={0}
+                          placeholder="请输入正整数"
+                          className="w100"
+                        />
+                      </Form.Item>
+                    </Col>
+                    <Col span={4}></Col>
+                  </Row>
+                </div>
               </Form.Item>
+            ) : (
+              ""
+            )}
 
-              <Row gutter={10}>
-                <Col span={8}>
-                  <Form.Item noStyle name={["warnData", "symbol2"]}>
-                    <Select
-                      allowClear
-                      placeholder="请选择"
-                      options={SYMBOL_OPTIONS}
-                    />
-                  </Form.Item>
-                </Col>
-                <Col span={12}>
-                  <Form.Item noStyle name={["warnData", "num2"]}>
-                    <InputNumber
-                      precision={0}
-                      placeholder="请输入正整数"
-                      className="w100"
-                    />
-                  </Form.Item>
-                </Col>
-                <Col span={4}></Col>
-              </Row>
-            </div>
-          </Form.Item>
-        ) : (
-          ""
+            <Form.Item label="需上传资料" name="materialIds">
+              <FileTemplateTable />
+            </Form.Item>
+          </>
         )}
 
-        <Form.Item label="需上传资料" name="materialIds">
-          <FileTemplateTable />
-        </Form.Item>
+        {(parentNode?.level || 0) < 2 && !isFixed && (
+          <Form.Item required label="指标权重" name="weight">
+            <InputNumber
+              precision={0}
+              min={1}
+              max={100}
+              placeholder="请输入1~100的正整数"
+              className="mw650 w100"
+              addonAfter="%"
+            />
+          </Form.Item>
+        )}
 
         <Form.Item required label="排序值" name="sort" initialValue={999}>
           <InputNumber

+ 6 - 3
src/pages/Assessment/Index/components/Container/index.tsx

@@ -16,7 +16,10 @@ export const Container: FC<ContainerProps> = ({ currentId }) => {
   // 打分点
   const isPoint = detail?.isPoint === YES_OR_NO.YES;
   const point = useMemo(
-    () => (detail && isPoint ? JSON.parse(detail.jsonPoint) : null),
+    () =>
+      detail && isPoint && detail.jsonPoint
+        ? JSON.parse(detail.jsonPoint)
+        : null,
     [detail]
   );
   // 告警阈值
@@ -64,11 +67,11 @@ export const Container: FC<ContainerProps> = ({ currentId }) => {
       </div>
       <div className={style.tableItem}>
         <p className={style.tableItemLabel}>指标编号</p>
-        <div className={style.tableItemInner}>{detail?.num}</div>
+        <div className={style.tableItemInner}>{detail?.num || "-"}</div>
       </div>
       <div className={style.tableItem}>
         <p className={style.tableItemLabel}>指标说明</p>
-        <div className={style.tableItemInner}>{detail?.remark}</div>
+        <div className={style.tableItemInner}>{detail?.remark || "-"}</div>
       </div>
       <div className={style.tableItem}>
         <p className={style.tableItemLabel}>是否为打分点</p>

+ 4 - 0
src/pages/AssessmentDetail/components/OverallAssessment/index.module.scss

@@ -7,6 +7,10 @@
       font-weight: bold;
     }
   }
+
+  h3 {
+    word-break: break-all;
+  }
 }
 
 .fileUploadHeader {

+ 99 - 87
src/pages/AssessmentDetail/components/OverallAssessment/index.tsx

@@ -1,11 +1,15 @@
 import { Button, Form, Input, Table, Tag } from "antd";
-import { FC, useState } from "react";
+import { FC, useMemo, useState } from "react";
 import classNames from "classnames";
 import { DageTableActions } from "@dage/pc-components";
 import { EvaluationModal } from "../EvaluationModal";
 import style from "./index.module.scss";
+import { IManageFormDetail, IManageIndexDetail, YES_OR_NO } from "@/types";
+import { downloadFile } from "@/utils";
+import { getBaseURL } from "@dage/service";
 
 export interface OverallAssessmentProps {
+  detail: IManageIndexDetail | IManageFormDetail | null;
   isReportDetail?: boolean;
   isEvalutionDetail?: boolean;
 }
@@ -13,10 +17,22 @@ export interface OverallAssessmentProps {
 const { TextArea } = Input;
 
 export const OverallAssessment: FC<OverallAssessmentProps> = ({
+  detail,
   isReportDetail,
   isEvalutionDetail,
 }) => {
+  const baseUrl = getBaseURL();
   const [modalVisible, setModelVisible] = useState(false);
+  // 加分项
+  const addList = useMemo(() => {
+    if (!detail || !detail.jsonAdd) return [];
+    return JSON.parse(detail.jsonAdd);
+  }, [detail]);
+  // 减分项
+  const subList = useMemo(() => {
+    if (!detail || !detail.jsonSub) return [];
+    return JSON.parse(detail.jsonSub);
+  }, [detail]);
 
   return (
     <Form
@@ -28,17 +44,7 @@ export const OverallAssessment: FC<OverallAssessmentProps> = ({
       className={classNames(style.form, "mw1125")}
     >
       <Form.Item label="考核说明">
-        <p>
-          一、绩效考核的优势
-          1.鼓励员工增强工作积极性。通过绩效考核,员工可以明确工作目标,把工作分解成具体任务,并制定完成时间和标准。这样可以有针对性地制定工作计划,提高工作效率和工作积极性。
-          2.强化员工责任感和纪律性。通过绩效考核,可以为员工的工作成果负责,提高员工的责任感,使员工更有纪律性,遵循公司的规章制度和业务流程。
-          3.提升企业整体绩效。通过绩效考核,可以及时发现和解决员工工作不足,保证公司的工作效率和整体绩效。
-          二、绩效考核的劣势
-          1.评价标准不合理。有些公司在绩效考核过程中,没有明确的评价标准,导致员工之间评价不公,对于那些表现突出但不符合标准的员工,也可能被低估。
-          2.评价方式不合理。
-          评价方式主要包括逐级评价、360度评价和目标管理等,但这些评价方式大多数针对高级管理人员,对于基层员工基本没有评价。这导致员工对绩效考核过程不满,也不利于员工的提升和发展。
-          3.员工积极性下降。有些公司用相对公正的评价方式,但是考核过程不透明,甚至没有足够的沟通和反馈,导致员工积极性下降,对于公司的发展也不利。
-        </p>
+        <p>{detail?.remark}</p>
       </Form.Item>
 
       {!isReportDetail && (
@@ -47,6 +53,7 @@ export const OverallAssessment: FC<OverallAssessmentProps> = ({
             <Table
               pagination={false}
               className="cus-table"
+              rowKey="id"
               columns={[
                 {
                   title: "部门名称",
@@ -86,65 +93,82 @@ export const OverallAssessment: FC<OverallAssessmentProps> = ({
       )}
 
       <Form.Item label="资料上传">
-        <div className={style.fileUploadHeader}>
-          <div>
-            <Tag>选填</Tag>
-            <h3>这是一段资料名称 | zip,jpg,png</h3>
-          </div>
-          <Button type="primary" ghost>
-            下载模板
-          </Button>
-        </div>
+        {(detail?.materials || []).map((item) => {
+          const isUpload = item.isUpload === YES_OR_NO.YES;
 
-        <Table
-          rowKey="id"
-          className="cus-table"
-          pagination={false}
-          dataSource={[
-            {
-              id: 1,
-              editor: "郑文钧",
-              create_time: "2024-09-22 22:10:08",
-            },
-          ]}
-          columns={[
-            {
-              title: "附件名称",
-              dataIndex: "file",
-              align: "center",
-            },
-            {
-              title: "责任部门",
-              dataIndex: "department",
-              align: "center",
-            },
-            {
-              title: "上传用户",
-              dataIndex: "user",
-              align: "center",
-            },
-            {
-              title: "编辑时间",
-              dataIndex: "create_time",
-              align: "center",
-            },
-            {
-              title: "操作",
-              align: "center",
-              render: () => (
-                <DageTableActions
-                  renderBefore={
-                    <Button size="small" type="link">
-                      下载
-                    </Button>
+          return (
+            <div key={item.id}>
+              <div className={style.fileUploadHeader}>
+                <div>
+                  <Tag color={isUpload ? "red" : ""}>
+                    {isUpload ? "必填" : "选填"}
+                  </Tag>
+                  <h3>
+                    {item.name} | {item.suffix}
+                  </h3>
+                </div>
+                <Button
+                  type="primary"
+                  ghost
+                  onClick={() =>
+                    downloadFile(
+                      baseUrl +
+                        process.env.REACT_APP_IMG_PUBLIC +
+                        item.filePath,
+                      item.fileName
+                    )
                   }
-                  showDelete={isReportDetail}
-                  showEdit={false}
-                />
-              ),
-            },
-          ]}
-        />
+                >
+                  下载模板
+                </Button>
+              </div>
+
+              <Table
+                rowKey="id"
+                className="cus-table"
+                pagination={false}
+                dataSource={[]}
+                columns={[
+                  {
+                    title: "附件名称",
+                    dataIndex: "fileName",
+                    align: "center",
+                  },
+                  {
+                    title: "责任部门",
+                    dataIndex: "deptName",
+                    align: "center",
+                  },
+                  {
+                    title: "上传用户",
+                    dataIndex: "creatorName",
+                    align: "center",
+                  },
+                  {
+                    title: "编辑时间",
+                    dataIndex: "updateTime",
+                    align: "center",
+                  },
+                  {
+                    title: "操作",
+                    align: "center",
+                    render: () => (
+                      <DageTableActions
+                        renderBefore={
+                          <Button size="small" type="link">
+                            下载
+                          </Button>
+                        }
+                        showDelete={isReportDetail}
+                        showEdit={false}
+                      />
+                    ),
+                  },
+                ]}
+              />
+            </div>
+          );
+        })}
       </Form.Item>
 
       {!isReportDetail && (
@@ -153,22 +177,16 @@ export const OverallAssessment: FC<OverallAssessmentProps> = ({
             rowKey="id"
             className="cus-table"
             pagination={false}
-            dataSource={[
-              {
-                id: 1,
-                editor: "郑文钧",
-                create_time: "2024-09-22 22:10:08",
-              },
-            ]}
+            dataSource={addList}
             columns={[
               {
                 title: "加分项名称",
-                dataIndex: "file",
+                dataIndex: "name",
                 align: "center",
               },
               {
                 title: "指标分值",
-                dataIndex: "department",
+                dataIndex: "num",
                 align: "center",
               },
               {
@@ -200,22 +218,16 @@ export const OverallAssessment: FC<OverallAssessmentProps> = ({
             style={{ marginTop: 20 }}
             className="cus-table"
             pagination={false}
-            dataSource={[
-              {
-                id: 1,
-                editor: "郑文钧",
-                create_time: "2024-09-22 22:10:08",
-              },
-            ]}
+            dataSource={subList}
             columns={[
               {
                 title: "减分项名称",
-                dataIndex: "file",
+                dataIndex: "name",
                 align: "center",
               },
               {
                 title: "可扣分值",
-                dataIndex: "department",
+                dataIndex: "num",
                 align: "center",
               },
               {

+ 74 - 12
src/pages/AssessmentDetail/index.tsx

@@ -1,11 +1,20 @@
-import { FC, useRef } from "react";
+import { FC, useEffect, useRef, useState } from "react";
 import { Button, Tabs, Tag } from "antd";
 import { FormPageFooter, PageContainer } from "@/components";
 import { OverallAssessment } from "./components/OverallAssessment";
 import { IndexAssessment } from "./components/IndexAssessment";
 import style from "./index.module.scss";
 import { useHashQuery } from "@/hooks";
-import { ASSESSMENT_STATUS_MAP } from "@/constants";
+import { DEPT_STATUS_MAP, PUBLISH_STATUS_MAP } from "@/constants";
+import { useParams } from "react-router-dom";
+import {
+  getManageEvaluationDetailApi,
+  getManageFormDetailApi,
+  getManageIndexDetailApi,
+} from "@/api";
+import { IManageFormDetail, IManageIndexDetail } from "@/types";
+import { DageLoading } from "@dage/pc-components";
+import { isNumber } from "lodash";
 
 const AssessmentDetailPage: FC = () => {
   // 判断是否为考核填报进入
@@ -14,12 +23,37 @@ const AssessmentDetailPage: FC = () => {
   const isEvalutionDetail = useRef(
     window.location.hash.indexOf("evaluation") > -1
   );
+  // 判断是否为考核管理进入
+  const isIndexDetail = useRef(window.location.hash.indexOf("index") > -1);
   const [tab, setTab] = useHashQuery("tab", "1");
+  const [loading, setLoading] = useState(false);
+  const [detail, setDetail] = useState<
+    IManageIndexDetail | IManageFormDetail | null
+  >(null);
+  const params = useParams();
+
+  const getDetail = async () => {
+    try {
+      setLoading(true);
+      const data = await (isReportDetail.current
+        ? getManageFormDetailApi
+        : isEvalutionDetail.current
+        ? getManageEvaluationDetailApi
+        : getManageIndexDetailApi)(params.id as string);
+      setDetail(data);
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  useEffect(() => {
+    getDetail();
+  }, []);
 
   return (
     <>
       <PageContainer
-        title="考核标题"
+        title={detail?.name || ""}
         style={{
           background: "white",
           borderRadius: 5,
@@ -27,29 +61,56 @@ const AssessmentDetailPage: FC = () => {
           boxShadow: "0px 0px 10px 0px rgba(0,0,0,0.05)",
         }}
         headerSlot={
-          <div style={{ flex: 1 }}>
-            <Tag color={ASSESSMENT_STATUS_MAP[0].color}>
-              {ASSESSMENT_STATUS_MAP[0].label}
-            </Tag>
-          </div>
+          detail ? (
+            <div style={{ flex: 1 }}>
+              {!isIndexDetail.current ? (
+                <Tag
+                  color={
+                    DEPT_STATUS_MAP[(detail as IManageFormDetail).deptStatus]
+                      .color
+                  }
+                >
+                  {
+                    DEPT_STATUS_MAP[(detail as IManageFormDetail).deptStatus]
+                      .label
+                  }
+                </Tag>
+              ) : (
+                <Tag
+                  color={
+                    PUBLISH_STATUS_MAP[(detail as IManageIndexDetail).status]
+                      .color
+                  }
+                >
+                  {
+                    PUBLISH_STATUS_MAP[(detail as IManageIndexDetail).status]
+                      .label
+                  }
+                </Tag>
+              )}
+            </div>
+          ) : undefined
         }
       >
+        {loading && <DageLoading />}
         <div className={style.topContent}>
           <div className={style.topContentLeft}>
             <div className={style.topContentItem}>
               <label>总分值</label>
-              <span>432</span>
+              <span>{isNumber(detail?.score) ? detail?.score : "--"}</span>
             </div>
           </div>
 
           <div className={style.topContentRight}>
             <div className={style.topContentItem}>
               <label>考核周期</label>
-              <span>2020.1.1~2021.1.1</span>
+              <span>
+                {detail?.dateStart}~{detail?.dateEnd}
+              </span>
             </div>
             <div className={style.topContentItem}>
-              <label>钱桂英</label>
-              <span style={{ fontWeight: "normal" }}>2024-09-22 21:19:20</span>
+              <label>{detail?.creatorName}</label>
+              <span style={{ fontWeight: "normal" }}>{detail?.createTime}</span>
             </div>
           </div>
         </div>
@@ -69,6 +130,7 @@ const AssessmentDetailPage: FC = () => {
               label: "总体考核",
               children: (
                 <OverallAssessment
+                  detail={detail}
                   isReportDetail={isReportDetail.current}
                   isEvalutionDetail={isEvalutionDetail.current}
                 />

+ 106 - 37
src/pages/Management/Evaluation/index.tsx

@@ -1,48 +1,103 @@
 import classNames from "classnames";
-import { useState } from "react";
+import { useCallback, useEffect, useMemo, useState } from "react";
 import { Button, Form, Input, Select, Table } from "antd";
 import { useNavigate } from "react-router-dom";
 import { PageContainer } from "@/components";
-import { PUBLISH_STATUS_MAP } from "../../../constants";
+import {
+  ASSESSMENT_TYPE_OPTIONS,
+  PUBLISH_STATUS_MAP,
+  PUBLISH_STATUS_OPTIONS,
+} from "../../../constants";
 import style from "../Form/index.module.scss";
-import { PUBLISH_ENUM } from "@/types";
+import { debounce } from "lodash";
+import { getManageEvaluationListApi } from "@/api";
+import { IManageFormItem, IManageFormListParams } from "@/types";
+
+const DEFAULT_PARAMS: IManageFormListParams = {
+  deptStatus: undefined,
+  searchKey: "",
+  status: undefined,
+  type: undefined,
+  pageNum: 1,
+  pageSize: 20,
+};
 
 const ManagementEvaluationPage = () => {
   const navigate = useNavigate();
-  const [list] = useState([
-    {
-      id: 1,
-      name: "模板名称",
-      a: "定级评估",
-      description: "模板说明",
-      b: "",
-      c: PUBLISH_ENUM.PENDING,
-      d: "",
-      e: "",
-      f: "2024-09-24 16:50:30",
-      g: "钱韵澄",
+  const [list, setList] = useState<IManageFormItem[]>([]);
+  const [loading, setLoading] = useState(false);
+  const [params, setParams] = useState({
+    ...DEFAULT_PARAMS,
+  });
+  const [total, setTotal] = useState(0);
+
+  const getList = useCallback(async () => {
+    setLoading(true);
+    try {
+      const data = await getManageEvaluationListApi(params);
+      setList(data.data);
+      setTotal(data.total);
+    } finally {
+      setLoading(false);
+    }
+  }, [params]);
+
+  const paginationChange = useCallback(
+    () => (pageNum: number, pageSize: number) => {
+      setParams({ ...params, pageNum, pageSize });
     },
-  ]);
+    [params]
+  );
+
+  const debounceSearch = useMemo(
+    () =>
+      debounce((changedVal: unknown, vals: any) => {
+        setParams({ ...params, ...vals });
+      }, 500),
+    [params]
+  );
+
+  useEffect(() => {
+    getList();
+  }, []);
 
   return (
     <PageContainer title="考核评定">
       <div className={style.filter}>
-        <Form layout="inline" className="inline-form">
-          <Form.Item label="搜索">
+        <Form
+          layout="inline"
+          className="inline-form"
+          onValuesChange={debounceSearch}
+        >
+          <Form.Item label="搜索" name="searchKey">
             <Input placeholder="请输入考核名称" className="w160" />
           </Form.Item>
           <Form.Item label="考核类别">
             <div className="w160">
-              <Select />
+              <Form.Item noStyle name="type">
+                <Select
+                  allowClear
+                  placeholder="请选择"
+                  options={ASSESSMENT_TYPE_OPTIONS}
+                />
+              </Form.Item>
             </div>
           </Form.Item>
           <Form.Item label="发布状态">
             <div className="w160">
-              <Select />
+              <Form.Item noStyle name="status">
+                <Select
+                  allowClear
+                  placeholder="请选择"
+                  options={PUBLISH_STATUS_OPTIONS}
+                />
+              </Form.Item>
             </div>
           </Form.Item>
           <Form.Item>
-            <Button type="primary">查询</Button>
+            <Button type="primary" onClick={getList}>
+              查询
+            </Button>
           </Form.Item>
         </Form>
       </div>
@@ -57,54 +112,59 @@ const ManagementEvaluationPage = () => {
             {
               title: "名称",
               dataIndex: "name",
-              key: "name",
               align: "center",
               minWidth: 100,
             },
             {
               title: "类别",
-              dataIndex: "a",
-              key: "a",
               align: "center",
               minWidth: 100,
+              render: (item: IManageFormItem) => {
+                return ASSESSMENT_TYPE_OPTIONS.find(
+                  (i) => i.value === item.type
+                )?.label;
+              },
             },
             {
               title: "说明",
-              dataIndex: "description",
-              key: "description",
+              dataIndex: "remark",
               align: "center",
               minWidth: 100,
             },
             {
               title: "考核周期",
-              dataIndex: "b",
-              key: "b",
               align: "center",
               minWidth: 100,
+              render: (item: IManageFormItem) =>
+                `${item.dateStart}-${item.dateEnd}`,
             },
             {
               title: "发布状态",
               key: "c",
               align: "center",
               minWidth: 100,
-              render: (item: (typeof list)[0]) => {
-                return (
-                  <p style={{ color: PUBLISH_STATUS_MAP[item.c].color }}>
-                    {PUBLISH_STATUS_MAP[item.c].label}
-                  </p>
-                );
-              },
+              render: (item: IManageFormItem) => (
+                <p
+                  style={{
+                    color: PUBLISH_STATUS_MAP[item.publishStatus].color,
+                  }}
+                >
+                  {PUBLISH_STATUS_MAP[item.publishStatus].label}
+                </p>
+              ),
             },
             {
               title: "操作",
               key: "h",
               align: "center",
               fixed: "right",
-              render: (item: (typeof list)[0]) => {
+              render: (item: IManageFormItem) => {
                 return (
                   <Button
                     type="link"
-                    onClick={() => navigate("/management/evaluation/detail")}
+                    onClick={() =>
+                      navigate(`/management/evaluation/detail/${item.id}`)
+                    }
                   >
                     查看
                   </Button>
@@ -112,6 +172,15 @@ const ManagementEvaluationPage = () => {
               },
             },
           ]}
+          pagination={{
+            showQuickJumper: true,
+            position: ["bottomCenter"],
+            showSizeChanger: true,
+            current: params.pageNum,
+            pageSize: params.pageSize,
+            total,
+            onChange: paginationChange(),
+          }}
         />
       </div>
     </PageContainer>

+ 125 - 39
src/pages/Management/Form/index.tsx

@@ -1,59 +1,123 @@
 import classNames from "classnames";
-import { useState } from "react";
+import { useCallback, useEffect, useMemo, useState } from "react";
 import { Button, Form, Input, Select, Table } from "antd";
 import { useNavigate } from "react-router-dom";
 import { PageContainer } from "@/components";
 import style from "./index.module.scss";
-import { PUBLISH_STATUS_MAP } from "../../../constants";
-import { PUBLISH_ENUM } from "@/types";
+import {
+  ASSESSMENT_TYPE_OPTIONS,
+  DEPT_STATUS_MAP,
+  DEPT_STATUS_OPTIONS,
+  PUBLISH_STATUS_MAP,
+  PUBLISH_STATUS_OPTIONS,
+} from "../../../constants";
+import { IManageFormItem, IManageFormListParams } from "@/types";
+import { getManageFormListApi } from "@/api";
+import { debounce } from "lodash";
+
+const DEFAULT_PARAMS: IManageFormListParams = {
+  deptStatus: undefined,
+  searchKey: "",
+  status: undefined,
+  type: undefined,
+  pageNum: 1,
+  pageSize: 20,
+};
 
 const ManagementReportPage = () => {
   const navigate = useNavigate();
-  const [list] = useState([
-    {
-      id: 1,
-      name: "模板名称",
-      a: "定级评估",
-      description: "模板说明",
-      b: "",
-      c: PUBLISH_ENUM.PENDING,
-      d: "",
-      e: "",
-      f: "2024-09-24 16:50:30",
-      g: "钱韵澄",
+  const [loading, setLoading] = useState(false);
+  const [params, setParams] = useState<IManageFormListParams>({
+    ...DEFAULT_PARAMS,
+  });
+  const [total, setTotal] = useState(0);
+  const [list, setList] = useState<IManageFormItem[]>([]);
+
+  const getList = useCallback(async () => {
+    setLoading(true);
+    try {
+      const data = await getManageFormListApi(params);
+      setList(data.data);
+      setTotal(data.total);
+    } finally {
+      setLoading(false);
+    }
+  }, [params]);
+
+  const paginationChange = useCallback(
+    () => (pageNum: number, pageSize: number) => {
+      setParams({ ...params, pageNum, pageSize });
     },
-  ]);
+    [params]
+  );
+
+  const debounceSearch = useMemo(
+    () =>
+      debounce((changedVal: unknown, vals: any) => {
+        setParams({ ...params, ...vals });
+      }, 500),
+    [params]
+  );
+
+  useEffect(() => {
+    getList();
+  }, []);
 
   return (
     <PageContainer title="考核填报">
       <div className={style.filter}>
-        <Form layout="inline" className="inline-form">
-          <Form.Item label="搜索">
+        <Form
+          layout="inline"
+          className="inline-form"
+          onValuesChange={debounceSearch}
+        >
+          <Form.Item label="搜索" name="searchKey">
             <Input placeholder="请输入考核名称" className="w160" />
           </Form.Item>
           <Form.Item label="考核类别">
             <div className="w160">
-              <Select />
+              <Form.Item noStyle name="type">
+                <Select
+                  allowClear
+                  placeholder="请选择"
+                  options={ASSESSMENT_TYPE_OPTIONS}
+                />
+              </Form.Item>
             </div>
           </Form.Item>
           <Form.Item label="发布状态">
             <div className="w160">
-              <Select />
+              <Form.Item noStyle name="status">
+                <Select
+                  allowClear
+                  placeholder="请选择"
+                  options={PUBLISH_STATUS_OPTIONS}
+                />
+              </Form.Item>
             </div>
           </Form.Item>
           <Form.Item label="自评状态">
             <div className="w160">
-              <Select />
+              <Form.Item noStyle name="deptStatus">
+                <Select
+                  allowClear
+                  placeholder="请选择"
+                  options={DEPT_STATUS_OPTIONS}
+                />
+              </Form.Item>
             </div>
           </Form.Item>
           <Form.Item>
-            <Button type="primary">查询</Button>
+            <Button type="primary" onClick={getList}>
+              查询
+            </Button>
           </Form.Item>
         </Form>
       </div>
 
       <div className={style.table}>
         <Table
+          loading={loading}
           className={classNames("cus-table large")}
           dataSource={list}
           rowKey="id"
@@ -62,47 +126,51 @@ const ManagementReportPage = () => {
             {
               title: "名称",
               dataIndex: "name",
-              key: "name",
               align: "center",
               minWidth: 100,
             },
             {
               title: "类别",
-              dataIndex: "a",
-              key: "a",
               align: "center",
               minWidth: 100,
+              render: (item: IManageFormItem) => {
+                return ASSESSMENT_TYPE_OPTIONS.find(
+                  (i) => i.value === item.type
+                )?.label;
+              },
             },
             {
               title: "说明",
-              dataIndex: "description",
-              key: "description",
+              dataIndex: "remark",
               align: "center",
               minWidth: 100,
             },
             {
               title: "考核周期",
-              dataIndex: "b",
-              key: "b",
               align: "center",
               minWidth: 100,
+              render: (item: IManageFormItem) =>
+                `${item.dateStart}-${item.dateEnd}`,
             },
             {
               title: "发布状态",
-              key: "c",
               align: "center",
               minWidth: 100,
-              render: (item: (typeof list)[0]) => {
+              render: (item: IManageFormItem) => {
                 return (
-                  <p style={{ color: PUBLISH_STATUS_MAP[item.c].color }}>
-                    {PUBLISH_STATUS_MAP[item.c].label}
+                  <p
+                    style={{
+                      color: PUBLISH_STATUS_MAP[item.publishStatus].color,
+                    }}
+                  >
+                    {PUBLISH_STATUS_MAP[item.publishStatus].label}
                   </p>
                 );
               },
             },
             {
               title: "责任部门",
-              key: "d",
+              dataIndex: "deptName",
               align: "center",
             },
             {
@@ -110,20 +178,29 @@ const ManagementReportPage = () => {
               key: "e",
               align: "center",
               minWidth: 100,
-              render: (item: (typeof list)[0]) => {
-                return item.e || "/";
+              render: (item: IManageFormItem) => {
+                return (
+                  <p
+                    style={{
+                      color: DEPT_STATUS_MAP[item.deptStatus].color,
+                    }}
+                  >
+                    {DEPT_STATUS_MAP[item.deptStatus].label}
+                  </p>
+                );
               },
             },
             {
               title: "操作",
-              key: "h",
               align: "center",
               fixed: "right",
-              render: (item: (typeof list)[0]) => {
+              render: (item: IManageFormItem) => {
                 return (
                   <Button
                     type="link"
-                    onClick={() => navigate("/management/form/detail")}
+                    onClick={() =>
+                      navigate(`/management/form/detail/${item.id}`)
+                    }
                   >
                     查看
                   </Button>
@@ -131,6 +208,15 @@ const ManagementReportPage = () => {
               },
             },
           ]}
+          pagination={{
+            showQuickJumper: true,
+            position: ["bottomCenter"],
+            showSizeChanger: true,
+            current: params.pageNum,
+            pageSize: params.pageSize,
+            total,
+            onChange: paginationChange(),
+          }}
         />
       </div>
     </PageContainer>

+ 2 - 8
src/pages/Management/Index/CreateOrEdit/index.tsx

@@ -45,17 +45,11 @@ const CreateOrEditManagementIndex: FC = () => {
         deduction: data.jsonSub ? JSON.parse(data.jsonSub) : undefined,
       });
       if (data.jsonAdd) {
-        setBounsEditableKeys(
-          JSON.parse(data.jsonAdd).map(
-            (i: IManageIndexDetail["materials"][number]) => i.id
-          )
-        );
+        setBounsEditableKeys(JSON.parse(data.jsonAdd).map((i: any) => i.id));
       }
       if (data.jsonSub) {
         setDeductionEditableKeys(
-          JSON.parse(data.jsonSub).map(
-            (i: IManageIndexDetail["materials"][number]) => i.id
-          )
+          JSON.parse(data.jsonSub).map((i: any) => i.id)
         );
       }
       setDetail(data);

+ 81 - 32
src/pages/Management/Index/SettingIndex/index.tsx

@@ -1,5 +1,5 @@
 import { FC, Key, useEffect, useRef, useState } from "react";
-import { Button, Form, Space } from "antd";
+import { Button, Form, Space, Table } from "antd";
 import { useParams } from "react-router-dom";
 import { ActionType, EditableProTable } from "@ant-design/pro-components";
 import { PlusOutlined } from "@ant-design/icons";
@@ -10,14 +10,14 @@ import {
   Search,
 } from "@/components";
 // import { uniq, uniqBy } from "lodash";
-import {
-  AssIndexTreeItemType,
-  ASS_INDEX_TYPE,
-  IManageAssessmentIndex,
-} from "@/types";
+import { ASS_INDEX_TYPE, IManageAssessmentIndex } from "@/types";
 import style from "./index.module.scss";
-import { getManageAssFixedList, setManageAssFixed } from "@/api";
-import { DageLoading, DageTableActions } from "@dage/pc-components";
+import {
+  getManageAssFixedListApi,
+  getManageAssOperationListApi,
+  setManageAssFixedApi,
+} from "@/api";
+import { DageLoading } from "@dage/pc-components";
 
 const SettingIndexPage: FC = () => {
   const params = useParams();
@@ -32,14 +32,29 @@ const SettingIndexPage: FC = () => {
   const [loading, setLoading] = useState(false);
   // 设置定级指标
   const isFixed = params.type === ASS_INDEX_TYPE.FIXED;
+  // 总分值
+  const [score, setScore] = useState(0);
+  const [museumScoreList, setMuseumScoreList] = useState<any[]>([]);
 
-  const getList = async () => {
+  const getList = async (searchKey?: string) => {
     try {
       setLoading(true);
-      const data = await (isFixed
-        ? getManageAssFixedList
-        : getManageAssFixedList)(params.id!);
-      form.setFieldValue("list", data);
+
+      if (isFixed) {
+        const data = await getManageAssFixedListApi(params.id!, searchKey);
+        form.setFieldValue("list", data);
+
+        if (!searchKey)
+          setScore(data.reduce((acc, currentVal) => acc + currentVal.score, 0));
+      } else {
+        const data = await getManageAssOperationListApi(params.id!, searchKey);
+        setMuseumScoreList([
+          {
+            id: 1,
+            ...data.gist,
+          },
+        ]);
+      }
     } finally {
       setLoading(false);
     }
@@ -47,7 +62,7 @@ const SettingIndexPage: FC = () => {
 
   const handleAddIndexItem = async (keys: string[]) => {
     if (isFixed) {
-      await setManageAssFixed(params.id!, keys);
+      await setManageAssFixedApi(params.id!, keys);
     }
     getList();
   };
@@ -62,9 +77,16 @@ const SettingIndexPage: FC = () => {
   //   setEditableKeys(uniq([...editableKeys, ...keys]));
   // };
 
-  const handleSearch = () => {};
+  const handleSearch = () => {
+    getList(keyword);
+  };
+
+  const handleReset = () => {
+    setKeyword("");
+    getList("");
+  };
 
-  const handleDelete = (item: IManageAssessmentIndex) => {};
+  // const handleDelete = (item: IManageAssessmentIndex) => {};
 
   useEffect(() => {
     getList();
@@ -79,9 +101,36 @@ const SettingIndexPage: FC = () => {
         className={style.settingForm}
       >
         <Form.Item label="指标总分值">
-          <Button type="primary">计算</Button>
+          <Button type="primary" onClick={() => getList()}>
+            计算
+          </Button>
 
-          <span style={{ paddingLeft: 15 }}>534分</span>
+          {isFixed ? (
+            <span style={{ paddingLeft: 15 }}>{score}分</span>
+          ) : (
+            <Table
+              style={{ marginTop: 20 }}
+              rowKey="id"
+              dataSource={museumScoreList}
+              columns={[
+                {
+                  title: "一级博物馆",
+                  dataIndex: "one",
+                  align: "center",
+                },
+                {
+                  title: "二级博物馆",
+                  dataIndex: "two",
+                  align: "center",
+                },
+                {
+                  title: "三级博物馆",
+                  dataIndex: "three",
+                  align: "center",
+                },
+              ]}
+            />
+          )}
         </Form.Item>
         <Form.Item required label="考核指标">
           <Form.Item noStyle name="list">
@@ -144,19 +193,19 @@ const SettingIndexPage: FC = () => {
                   //   />
                   // ),
                 },
-                {
-                  title: "操作",
-                  align: "center",
-                  valueType: "option",
-                  render: (node, row) => {
-                    return (
-                      <DageTableActions
-                        showEdit={false}
-                        onDelete={handleDelete.bind(undefined, row)}
-                      />
-                    );
-                  },
-                },
+                // {
+                //   title: "操作",
+                //   align: "center",
+                //   valueType: "option",
+                //   render: (node, row) => {
+                //     return (
+                //       <DageTableActions
+                //         showEdit={false}
+                //         onDelete={handleDelete.bind(undefined, row)}
+                //       />
+                //     );
+                //   },
+                // },
               ]}
               headerTitle={
                 <Space>
@@ -183,7 +232,7 @@ const SettingIndexPage: FC = () => {
                   style={{ maxWidth: 335 }}
                   onChange={(v) => setKeyword(v.target.value)}
                   onSearch={handleSearch}
-                  onReset={() => {}}
+                  onReset={handleReset}
                 />,
               ]}
               editable={{

+ 184 - 29
src/pages/Management/Index/SettingRole/index.tsx

@@ -1,48 +1,160 @@
-import { AddRoleModal, PageContainer } from "@/components";
-import { FC, useState } from "react";
+import { PageContainer } from "@/components";
+import { FC, useEffect, useState } from "react";
+import {
+  AddDeptModal,
+  AddGroupModal,
+  AllocationOfDataModal,
+  AllocationOfIndexModal,
+} from "../components";
 import { Pane } from "./components/Pane";
-import { Table } from "antd";
+import { Button, Table, Tag } from "antd";
 import { DageTableActions } from "@dage/pc-components";
+import {
+  deleteManageRoleDeptApi,
+  getManageRoleDeptListApi,
+  getManageRoleGroupListApi,
+} from "@/api";
+import { useParams } from "react-router-dom";
+import {
+  ASS_INDEX_TYPE,
+  IManageDeptItem,
+  IManageRoleGroupItem,
+  PUBLISH_ENUM,
+  YES_OR_NO,
+} from "@/types";
+import style from "../index.module.scss";
 
 const SettingRole: FC = () => {
-  const [addRoleVisible, setAddRoleVisible] = useState(false);
+  const params = useParams();
+  const [addDeptVisible, setAddDeptVisible] = useState(false);
+  const [addGroupVisible, setAddGroupVisible] = useState(false);
+  const [allocationOfDataVisible, setAllocationOfDataVisible] = useState(false);
+  const [allocationOfIndexVisible, setAllocationOfIndexVisible] =
+    useState(false);
+  const [deptLoading, setDeptLoading] = useState(false);
+  const [deptList, setDeptList] = useState<IManageDeptItem[]>([]);
+  const [groupLoading, setGroupLoading] = useState(false);
+  const [groupList, setGroupList] = useState<IManageRoleGroupItem[]>([]);
+  const [checkedItem, setCheckedItem] = useState<null | IManageDeptItem>(null);
+
+  // 获取责任部门列表
+  const getDeptList = async () => {
+    try {
+      setDeptLoading(true);
+      const data = await getManageRoleDeptListApi(params.id as string);
+      setDeptList(data);
+    } finally {
+      setDeptLoading(false);
+    }
+  };
+
+  // 获取评定组列表
+  const getGroupList = async () => {
+    try {
+      setGroupLoading(true);
+      const data = await getManageRoleGroupListApi(params.id as string);
+      // fake array
+      setGroupList([data]);
+    } finally {
+      setGroupLoading(false);
+    }
+  };
+
+  const handleEdit = (item: IManageDeptItem) => {
+    setCheckedItem(item);
+    setAddDeptVisible(true);
+  };
+
+  const handleDelete = async (id: number) => {
+    await deleteManageRoleDeptApi(id);
+    getDeptList();
+  };
+
+  const handleAllocationData = (item: IManageDeptItem) => {
+    setCheckedItem(item);
+    setAllocationOfDataVisible(true);
+  };
+
+  const handleAllocationIndex = (item: IManageDeptItem) => {
+    setCheckedItem(item);
+    setAllocationOfIndexVisible(true);
+  };
+
+  useEffect(() => {
+    getDeptList();
+    getGroupList();
+  }, []);
 
   return (
     <PageContainer title="设置角色">
       <Pane
-        title="自评组"
+        title="责任部门"
         required
         tips="负责填报指标或上传资料的部门或组织"
-        onAdd={() => setAddRoleVisible(true)}
+        onAdd={() => setAddDeptVisible(true)}
       >
         <Table
+          rowKey="id"
+          dataSource={deptList}
+          loading={deptLoading}
           className="cus-table gray"
           columns={[
             {
-              title: "自评组名称",
+              title: "部门名称",
               align: "center",
               dataIndex: "name",
             },
             {
               title: "博物馆级别",
               align: "center",
-              dataIndex: "level",
+              dataIndex: "levelMuseum",
             },
             {
               title: "组别说明",
               align: "center",
-              dataIndex: "description",
+              dataIndex: "remark",
             },
             {
-              title: "自评组成员",
+              title: "自评权限",
               align: "center",
-              dataIndex: "group",
+              render: (item: IManageDeptItem) => {
+                return item.isSelf === YES_OR_NO.YES ? "是" : "否";
+              },
+            },
+            {
+              title: "主管",
+              align: "center",
+              dataIndex: "leaderName",
             },
             {
               title: "操作",
               align: "center",
-              render: (item: any, record, index) => {
-                return <DageTableActions />;
+              render: (item: IManageDeptItem) => {
+                return (
+                  <DageTableActions
+                    renderBefore={
+                      <>
+                        <Button
+                          type="text"
+                          className={style.button}
+                          onClick={handleAllocationData.bind(undefined, item)}
+                        >
+                          分配资料
+                        </Button>
+                        <Button
+                          type="text"
+                          className={style.button}
+                          onClick={handleAllocationIndex.bind(undefined, item)}
+                        >
+                          分配指标
+                        </Button>
+                      </>
+                    }
+                    showDelete={Number(params.status) === PUBLISH_ENUM.PENDING}
+                    onEdit={handleEdit.bind(undefined, item)}
+                    onDelete={handleDelete.bind(undefined, item.id)}
+                  />
+                );
               },
             },
           ]}
@@ -51,31 +163,35 @@ const SettingRole: FC = () => {
 
       <Pane
         title="评定组"
+        required
         tips="负责评定责任部门填报结果的人员"
         style={{ marginTop: 40 }}
+        onAdd={() => setAddGroupVisible(true)}
       >
         <Table
+          rowKey="id"
           className="cus-table gray"
+          dataSource={groupList}
+          loading={groupLoading}
           columns={[
             {
-              title: "评定组名称",
-              align: "center",
-              dataIndex: "name",
-            },
-            {
-              title: "组别说明",
-              align: "center",
-              dataIndex: "description",
-            },
-            {
-              title: "评定组成员",
+              title: "用户",
               align: "center",
-              dataIndex: "group",
+              render: (item: IManageRoleGroupItem) => {
+                const arr = item.userName.split(",") ?? [];
+                return (
+                  <>
+                    {arr.map((i) => (
+                      <Tag key={i}>{i}</Tag>
+                    ))}
+                  </>
+                );
+              },
             },
             {
               title: "操作",
               align: "center",
-              render: (item: any, record, index) => {
+              render: (item) => {
                 return <DageTableActions />;
               },
             },
@@ -83,9 +199,48 @@ const SettingRole: FC = () => {
         />
       </Pane>
 
-      <AddRoleModal
-        open={addRoleVisible}
-        onCancel={() => setAddRoleVisible(false)}
+      <AddDeptModal
+        item={checkedItem}
+        assessId={params.id as string}
+        open={addDeptVisible}
+        onOk={getDeptList}
+        onCancel={() => {
+          setAddDeptVisible(false);
+          setCheckedItem(null);
+        }}
+      />
+
+      <AddGroupModal
+        assessId={params.id as string}
+        open={addGroupVisible}
+        onOk={getDeptList}
+        onCancel={() => {
+          setAddGroupVisible(false);
+        }}
+      />
+
+      <AllocationOfDataModal
+        item={checkedItem}
+        deptList={deptList}
+        assessId={params.id as string}
+        open={allocationOfDataVisible}
+        onOk={getDeptList}
+        onCancel={() => {
+          setAllocationOfDataVisible(false);
+          setCheckedItem(null);
+        }}
+      />
+
+      <AllocationOfIndexModal
+        type={params.type as ASS_INDEX_TYPE}
+        item={checkedItem}
+        assessId={params.id as string}
+        open={allocationOfIndexVisible}
+        onOk={getDeptList}
+        onCancel={() => {
+          setAllocationOfIndexVisible(false);
+          setCheckedItem(null);
+        }}
       />
     </PageContainer>
   );

+ 70 - 15
src/components/AddRoleModal/index.tsx

@@ -1,8 +1,11 @@
-import { FC } from "react";
+import { FC, useEffect, useState } from "react";
 import { Form, Input, Modal, ModalProps, Radio, Select } from "antd";
-import style from "../AddIndexModal/index.module.scss";
+import { getManageUserListApi, saveManageRoleDeptApi } from "@/api";
+import { IManageDeptItem, IManageUserItem } from "@/types";
 
-export interface AddRoleModalProps extends Omit<ModalProps, "onOk"> {
+export interface AddDeptModalProps extends Omit<ModalProps, "onOk"> {
+  assessId: number | string;
+  item?: null | IManageDeptItem;
   onCancel?: () => void;
   onOk?: () => void;
 }
@@ -24,13 +27,28 @@ export const MUSEUM_LEVEL_LIST = [
 
 const { TextArea } = Input;
 
-export const AddRoleModal: FC<AddRoleModalProps> = ({
+export const AddDeptModal: FC<AddDeptModalProps> = ({
+  assessId,
   open,
+  item,
   onOk,
   onCancel,
   ...rest
 }) => {
   const [form] = Form.useForm<any>();
+  const [loading, setLoading] = useState(false);
+  const [userLoading, setUserLoading] = useState(false);
+  const [userList, setUserList] = useState<IManageUserItem[]>([]);
+
+  const getUserList = async () => {
+    try {
+      setUserLoading(true);
+      const data = await getManageUserListApi();
+      setUserList(data);
+    } finally {
+      setUserLoading(false);
+    }
+  };
 
   const handleCancel = () => {
     form.resetFields();
@@ -42,20 +60,45 @@ export const AddRoleModal: FC<AddRoleModalProps> = ({
   };
 
   const handleSubmit = async (values: any) => {
-    onOk?.();
-    handleCancel();
+    try {
+      setLoading(true);
+      await saveManageRoleDeptApi({
+        ...values,
+        assessId,
+        crewUserIds: values.crewUserIds?.join(","),
+        id: item?.id,
+      });
+      onOk?.();
+      handleCancel();
+    } finally {
+      setLoading(false);
+    }
   };
 
+  useEffect(() => {
+    if (open) {
+      !userList.length && getUserList();
+
+      if (item) {
+        const crewUserIds = item.crewUserIds.split(",").map((i) => Number(i));
+        form.setFieldsValue({
+          ...item,
+          crewUserIds,
+        });
+      }
+    }
+  }, [open, item, userList]);
+
   return (
     <Modal
-      className={style.modal}
-      title="新增角色"
+      title={item ? "编辑角色" : "新增角色"}
       okText="提交"
       cancelText="取消"
+      maskClosable={false}
       open={open}
       width={640}
       okButtonProps={{
-        disabled: false,
+        disabled: loading,
       }}
       onOk={handleConfirm}
       onCancel={handleCancel}
@@ -76,7 +119,7 @@ export const AddRoleModal: FC<AddRoleModalProps> = ({
         </Form.Item>
         <Form.Item
           label="博物馆级别"
-          name="level"
+          name="levelMuseum"
           required
           rules={[{ required: true, message: "请选择博物馆级别" }]}
         >
@@ -86,7 +129,7 @@ export const AddRoleModal: FC<AddRoleModalProps> = ({
             buttonStyle="solid"
           />
         </Form.Item>
-        <Form.Item label="组别说明" name="description">
+        <Form.Item label="组别说明" name="remark">
           <TextArea
             rows={4}
             placeholder="请输入内容,最多200字"
@@ -96,15 +139,27 @@ export const AddRoleModal: FC<AddRoleModalProps> = ({
         <Form.Item
           label="部门主管"
           required
+          name="leaderUserId"
           rules={[{ required: true, message: "请选择部门主管" }]}
         >
-          <Select mode="multiple" placeholder="请选择" />
+          <Select
+            placeholder="请选择"
+            loading={userLoading}
+            options={userList}
+            fieldNames={{ label: "realName", value: "id" }}
+          />
         </Form.Item>
-        <Form.Item label="部门成员">
-          <Select mode="multiple" placeholder="请选择" />
+        <Form.Item label="部门成员" name="crewUserIds">
+          <Select
+            mode="multiple"
+            placeholder="请选择"
+            loading={userLoading}
+            options={userList}
+            fieldNames={{ label: "realName", value: "id" }}
+          />
         </Form.Item>
         <Form.Item label="自评权限" required>
-          <Form.Item noStyle name="rating" initialValue={0}>
+          <Form.Item noStyle name="isSelf" initialValue={0}>
             <Radio.Group
               options={[
                 {

+ 105 - 0
src/pages/Management/Index/components/AddGroupModal/index.tsx

@@ -0,0 +1,105 @@
+import { FC, useEffect, useState } from "react";
+import { Form, Modal, ModalProps, Select } from "antd";
+import { getManageUserListApi, saveManageRoleGroupApi } from "@/api";
+import { IManageDeptItem, IManageUserItem } from "@/types";
+
+export interface AddGroupModalProps extends Omit<ModalProps, "onOk"> {
+  assessId: number | string;
+  item?: null | IManageDeptItem;
+  onCancel?: () => void;
+  onOk?: () => void;
+}
+
+export const AddGroupModal: FC<AddGroupModalProps> = ({
+  assessId,
+  open,
+  item,
+  onOk,
+  onCancel,
+  ...rest
+}) => {
+  const [form] = Form.useForm<any>();
+  const [loading, setLoading] = useState(false);
+  const [userLoading, setUserLoading] = useState(false);
+  const [userList, setUserList] = useState<IManageUserItem[]>([]);
+
+  const getUserList = async () => {
+    try {
+      setUserLoading(true);
+      const data = await getManageUserListApi();
+      setUserList(data);
+    } finally {
+      setUserLoading(false);
+    }
+  };
+
+  const handleCancel = () => {
+    form.resetFields();
+    onCancel?.();
+  };
+
+  const handleConfirm = () => {
+    form.submit();
+  };
+
+  const handleSubmit = async (values: any) => {
+    try {
+      setLoading(true);
+      await saveManageRoleGroupApi({
+        assessId: Number(assessId),
+        userIds: values.crewUserIds?.join(","),
+      });
+      onOk?.();
+      handleCancel();
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  useEffect(() => {
+    if (open) {
+      !userList.length && getUserList();
+
+      if (item) {
+        const crewUserIds = item.crewUserIds.split(",").map((i) => Number(i));
+        form.setFieldsValue({
+          ...item,
+          crewUserIds,
+        });
+      }
+    }
+  }, [open, item, userList]);
+
+  return (
+    <Modal
+      title={item ? "编辑评定组" : "新增评定组"}
+      okText="提交"
+      cancelText="取消"
+      maskClosable={false}
+      open={open}
+      width={640}
+      okButtonProps={{
+        disabled: loading,
+      }}
+      onOk={handleConfirm}
+      onCancel={handleCancel}
+      {...rest}
+    >
+      <Form
+        labelCol={{ span: 4, offset: 2 }}
+        form={form}
+        onFinish={handleSubmit}
+      >
+        <Form.Item label="用户" name="crewUserIds">
+          <Select
+            mode="multiple"
+            placeholder="请选择"
+            loading={userLoading}
+            options={userList}
+            fieldNames={{ label: "realName", value: "id" }}
+          />
+        </Form.Item>
+      </Form>
+    </Modal>
+  );
+};

+ 166 - 0
src/pages/Management/Index/components/AllocationOfDataModal/index.tsx

@@ -0,0 +1,166 @@
+import { FC, Key, useEffect, useRef, useState } from "react";
+import { Modal, ModalProps, Select, Tag } from "antd";
+import { IManageDeptMaterialItem, IManageDeptItem, YES_OR_NO } from "@/types";
+import {
+  getManageDeptAllocationOfDataListApi,
+  saveManageDeptAllocationOfDataApi,
+} from "@/api";
+import {
+  EditableProTable,
+  ProForm,
+  ProFormInstance,
+} from "@ant-design/pro-components";
+
+export interface AllocationOfDataModalProps extends Omit<ModalProps, "onOk"> {
+  assessId: number | string;
+  item?: null | IManageDeptItem;
+  deptList: IManageDeptItem[];
+  onCancel?: () => void;
+  onOk?: () => void;
+}
+
+export const AllocationOfDataModal: FC<AllocationOfDataModalProps> = ({
+  assessId,
+  open,
+  deptList,
+  onOk,
+  onCancel,
+  ...rest
+}) => {
+  const formRef = useRef<ProFormInstance<any>>();
+  const [loading, setLoading] = useState(false);
+  const [listLoading, setListLoading] = useState(false);
+  const [editableKeys, setEditableKeys] = useState<Key[]>([]);
+
+  const handleCancel = () => {
+    onCancel?.();
+    formRef.current?.resetFields();
+  };
+
+  const handleConfirm = async () => {
+    if (!(await formRef.current?.validateFields())) return;
+
+    const vals = formRef.current?.getFieldsValue();
+    const temp: Record<number, number> = {};
+
+    vals.table.forEach((i: IManageDeptMaterialItem) => {
+      temp[i.id] = i.deptId as number;
+    });
+
+    handleSubmit(temp);
+  };
+
+  const handleSubmit = async (values: any) => {
+    try {
+      setLoading(true);
+      await saveManageDeptAllocationOfDataApi(values);
+      onOk?.();
+      handleCancel();
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  const getList = async () => {
+    try {
+      setListLoading(true);
+      const data = await getManageDeptAllocationOfDataListApi(assessId);
+      if (data) {
+        formRef.current?.setFieldValue("table", data);
+        setEditableKeys(data.map((i) => i.id));
+      }
+    } finally {
+      setListLoading(false);
+    }
+  };
+
+  useEffect(() => {
+    open && getList();
+  }, [open]);
+
+  return (
+    <Modal
+      title="分配资料"
+      okText="提交"
+      cancelText="取消"
+      maskClosable={false}
+      open={open}
+      width={640}
+      okButtonProps={{
+        disabled: loading,
+      }}
+      onOk={handleConfirm}
+      onCancel={handleCancel}
+      {...rest}
+    >
+      <ProForm
+        labelCol={{ span: 4, offset: 2 }}
+        formRef={formRef}
+        submitter={false}
+      >
+        <EditableProTable<IManageDeptMaterialItem>
+          name="table"
+          rowKey="id"
+          loading={listLoading}
+          recordCreatorProps={{
+            style: {
+              display: "none",
+            },
+            // @ts-ignore
+            record: () => ({}),
+          }}
+          columns={[
+            {
+              title: "标题",
+              dataIndex: "name",
+              editable: false,
+            },
+            {
+              title: "是否必填",
+              editable: false,
+              render: (node, item) => {
+                return item.isUpload === YES_OR_NO.YES ? "是" : "否";
+              },
+            },
+            {
+              title: "文件类型",
+              editable: false,
+              render: (node, item) => {
+                const arr = item.suffix?.split(",") || [];
+                return (
+                  <>
+                    {arr.map((i) => (
+                      <Tag key={i}>{i}</Tag>
+                    ))}
+                  </>
+                );
+              },
+            },
+            {
+              title: "责任部门",
+              dataIndex: "deptId",
+              width: 200,
+              formItemProps: () => {
+                return {
+                  rules: [{ required: true, message: "此项为必填项" }],
+                };
+              },
+              renderFormItem: () => (
+                <Select
+                  allowClear
+                  options={deptList}
+                  fieldNames={{ value: "id", label: "name" }}
+                  placeholder="请选择"
+                />
+              ),
+            },
+          ]}
+          editable={{
+            type: "multiple",
+            editableKeys,
+          }}
+        />
+      </ProForm>
+    </Modal>
+  );
+};

+ 159 - 0
src/pages/Management/Index/components/AllocationOfIndexModal/index.tsx

@@ -0,0 +1,159 @@
+import { FC, Key, useEffect, useState } from "react";
+import { Checkbox, Form, Modal, ModalProps, Tree } from "antd";
+import {
+  IManageDeptAllocationOfIndexItem,
+  ASS_INDEX_TYPE,
+  IManageDeptItem,
+} from "@/types";
+import { DageLoading } from "@dage/pc-components";
+import {
+  getManageDeptAllocationOfIndexListApi,
+  saveManageDeptAllocationOfIndexApi,
+} from "@/api";
+
+export interface AllocationOfIndexModalProps extends Omit<ModalProps, "onOk"> {
+  type: ASS_INDEX_TYPE;
+  assessId: number | string;
+  item?: null | IManageDeptItem;
+  onCancel?: () => void;
+  onOk?: () => void;
+}
+
+export const AllocationOfIndexModal: FC<AllocationOfIndexModalProps> = ({
+  open,
+  type,
+  assessId,
+  item,
+  onOk,
+  onCancel,
+  ...rest
+}) => {
+  const [form] = Form.useForm<any>();
+  const [_checkedKeys, setCheckedKeys] = useState<Key[]>([]);
+  const [treeData, setTreeData] = useState<IManageDeptAllocationOfIndexItem[]>(
+    []
+  );
+  const [loading, setLoading] = useState(false);
+  const assign = Form.useWatch("assign", form);
+
+  const transformTreeData = (data: IManageDeptAllocationOfIndexItem[]) => {
+    return data.map((item) => {
+      const newNode: any = {
+        ...item,
+        disableCheckbox: item.perm,
+      };
+
+      if (item.children && item.children.length > 0) {
+        newNode.children = transformTreeData(item.children);
+      }
+
+      return newNode;
+    });
+  };
+
+  const getAssIndexTree = async (assign?: number) => {
+    try {
+      setLoading(true);
+      const data = await getManageDeptAllocationOfIndexListApi(
+        assessId,
+        item?.id as number,
+        type,
+        assign
+      );
+      setTreeData(assign ? transformTreeData(data) : data);
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  const handleCancel = () => {
+    onCancel?.();
+    form.resetFields();
+    setCheckedKeys([]);
+  };
+
+  const handleConfirm = () => {
+    form.submit();
+  };
+
+  const handleSubmit = async (values: any) => {
+    await saveManageDeptAllocationOfIndexApi({
+      assessId,
+      deptId: item?.id as number,
+      normIds: values.onlyChildKeys,
+    });
+    onOk?.();
+    handleCancel();
+  };
+
+  const handleAfterOpenChange = (open: boolean) => {
+    if (open && !treeData.length) getAssIndexTree();
+  };
+
+  useEffect(() => {
+    if (!Array.isArray(assign)) return;
+    getAssIndexTree(assign[0]);
+    form.resetFields(["onlyChildKeys"]);
+  }, [assign]);
+
+  return (
+    <Modal
+      title="分配指标"
+      okText="提交"
+      cancelText="取消"
+      open={open}
+      width={640}
+      maskClosable={false}
+      okButtonProps={{
+        disabled: false,
+      }}
+      onOk={handleConfirm}
+      onCancel={handleCancel}
+      {...rest}
+      afterOpenChange={handleAfterOpenChange}
+    >
+      <Form
+        labelCol={{ span: 4, offset: 2 }}
+        form={form}
+        onFinish={handleSubmit}
+      >
+        <Form.Item name="assign" label=" " colon={false}>
+          <Checkbox.Group
+            options={[
+              {
+                label: "仅查看尚未分配的指标",
+                value: 1,
+              },
+            ]}
+          />
+        </Form.Item>
+        <Form.Item
+          label="采用指标"
+          name="onlyChildKeys"
+          required
+          rules={[{ required: true, message: "请选择指标" }]}
+        >
+          <Tree
+            checkable
+            defaultExpandAll
+            fieldNames={{ title: "name", key: "id" }}
+            checkedKeys={_checkedKeys}
+            treeData={treeData}
+            onCheck={(checkedKeys, { checkedNodes }) => {
+              const onlyChildKeys = (checkedKeys as Key[]).filter((i) => {
+                const node = checkedNodes.find((n) => n.id === i);
+                return !node?.children.length;
+              });
+              setCheckedKeys(onlyChildKeys);
+              form.setFieldsValue({
+                onlyChildKeys,
+              });
+            }}
+          />
+        </Form.Item>
+      </Form>
+
+      {loading && <DageLoading />}
+    </Modal>
+  );
+};

+ 4 - 0
src/pages/Management/Index/components/index.ts

@@ -0,0 +1,4 @@
+export * from "./AllocationOfDataModal";
+export * from "./AllocationOfIndexModal";
+export * from "./AddGroupModal";
+export * from "./AddDeptModal";

+ 94 - 23
src/pages/Management/Index/index.tsx

@@ -1,6 +1,6 @@
 import classNames from "classnames";
 import { useCallback, useEffect, useMemo, useState } from "react";
-import { Button, Form, Input, Select, Table } from "antd";
+import { Button, Dropdown, Form, Input, Select, Table } from "antd";
 import { PlusOutlined } from "@ant-design/icons";
 import { useNavigate } from "react-router-dom";
 import { PageContainer } from "@/components";
@@ -11,9 +11,13 @@ import {
   ASSESSMENT_TYPE_OPTIONS,
   PUBLISH_STATUS_OPTIONS,
 } from "../../../constants";
-import { deleteManageIndexApi, getManageIndexListApi } from "@/api";
+import {
+  deleteManageIndexApi,
+  getManageIndexListApi,
+  publishManageIndexApi,
+} from "@/api";
 import { debounce } from "lodash";
-import { ASS_INDEX_TYPE, IManageIndexDetail } from "@/types";
+import { ASS_INDEX_TYPE, IManageIndexDetail, PUBLISH_ENUM } from "@/types";
 
 const DEFAULT_PARAMS = {
   pageNum: 1,
@@ -64,6 +68,14 @@ const ManagementIndexPage = () => {
     getList();
   };
 
+  const handlePublish = async (id: number, stop?: boolean) => {
+    await publishManageIndexApi(
+      id,
+      stop ? PUBLISH_ENUM.ENDED : PUBLISH_ENUM.PUBLISHED
+    );
+    getList();
+  };
+
   useEffect(() => {
     getList();
   }, []);
@@ -207,6 +219,13 @@ const ManagementIndexPage = () => {
               align: "center",
               fixed: "right",
               render: (item: IManageIndexDetail) => {
+                const isEnded = item.status === PUBLISH_ENUM.ENDED;
+                const isPending = item.status === PUBLISH_ENUM.PENDING;
+                const showStopBtn = [
+                  PUBLISH_ENUM.EVALUATED,
+                  PUBLISH_ENUM.PUBLISHED,
+                ].includes(item.status);
+
                 return (
                   <DageTableActions
                     onEdit={() =>
@@ -218,30 +237,82 @@ const ManagementIndexPage = () => {
                         <Button
                           type="text"
                           className={style.button}
-                          onClick={() => navigate("/management/index/detail/1")}
-                        >
-                          查看
-                        </Button>
-                        <Button
-                          type="text"
-                          className={style.button}
                           onClick={() =>
-                            navigate(
-                              `/management/index/setting-index/${item.type}/${item.id}`
-                            )
+                            navigate(`/management/index/detail/${item.id}`)
                           }
                         >
-                          设置指标
-                        </Button>
-                        <Button
-                          type="text"
-                          className={style.button}
-                          onClick={() =>
-                            navigate("/management/index/setting-role")
-                          }
-                        >
-                          设置角色
+                          查看
                         </Button>
+                        {isPending && (
+                          <Button
+                            variant="text"
+                            color="primary"
+                            className={style.button}
+                            onClick={handlePublish.bind(
+                              undefined,
+                              item.id,
+                              false
+                            )}
+                          >
+                            发布
+                          </Button>
+                        )}
+                        {showStopBtn && (
+                          <Button
+                            variant="text"
+                            color="danger"
+                            className={style.button}
+                            onClick={handlePublish.bind(
+                              undefined,
+                              item.id,
+                              true
+                            )}
+                          >
+                            终止
+                          </Button>
+                        )}
+                        {!isEnded && (
+                          <Dropdown
+                            placement="bottom"
+                            arrow
+                            menu={{
+                              items: [
+                                {
+                                  key: 1,
+                                  label: (
+                                    <p
+                                      onClick={() =>
+                                        navigate(
+                                          `/management/index/setting-index/${item.type}/${item.id}`
+                                        )
+                                      }
+                                    >
+                                      考核指标
+                                    </p>
+                                  ),
+                                },
+                                {
+                                  key: 2,
+                                  label: (
+                                    <p
+                                      onClick={() =>
+                                        navigate(
+                                          `/management/index/setting-role/${item.type}/${item.id}/${item.status}`
+                                        )
+                                      }
+                                    >
+                                      考核角色
+                                    </p>
+                                  ),
+                                },
+                              ],
+                            }}
+                          >
+                            <Button type="text" className={style.button}>
+                              设置
+                            </Button>
+                          </Dropdown>
+                        )}
                       </>
                     }
                   />

+ 3 - 3
src/router/index.tsx

@@ -98,7 +98,7 @@ export const DEFAULT_MENU: DageRouteItem[] = [
           },
           {
             hide: true,
-            path: "/management/index/setting-role",
+            path: "/management/index/setting-role/:type/:id/:status",
             title: "设置角色",
             Component: React.lazy(
               () => import("../pages/Management/Index/SettingRole")
@@ -133,7 +133,7 @@ export const DEFAULT_MENU: DageRouteItem[] = [
             meta: {
               custom: true,
             },
-            path: "/management/form/detail",
+            path: "/management/form/detail/:id",
             title: "考核详情",
             Component: React.lazy(() => import("../pages/AssessmentDetail")),
           },
@@ -157,7 +157,7 @@ export const DEFAULT_MENU: DageRouteItem[] = [
             meta: {
               custom: true,
             },
-            path: "/management/evaluation/detail",
+            path: "/management/evaluation/detail/:id",
             title: "考核详情",
             Component: React.lazy(() => import("../pages/AssessmentDetail")),
           },

+ 9 - 0
src/types/assessment.ts

@@ -42,6 +42,7 @@ export interface IAssIndexDetail {
   sort: number;
   updateTime: string;
   creatorName: string;
+  gists?: IAssInspectionItem[];
 }
 
 export interface IAssTemplateDetail {
@@ -52,3 +53,11 @@ export interface IAssTemplateDetail {
   creatorName: string;
   normIds: string;
 }
+
+export interface IAssInspectionItem {
+  id: number;
+  name: string;
+  one: number;
+  two: number;
+  three: number;
+}

+ 100 - 8
src/types/management.ts

@@ -1,4 +1,5 @@
-import { YES_OR_NO } from ".";
+import { PaginationParams } from "@dage/service";
+import { IFileTemplateFormParams, YES_OR_NO } from ".";
 import { ASS_INDEX_TYPE } from "./assessment";
 
 /**
@@ -8,6 +9,7 @@ export enum PUBLISH_ENUM {
   PENDING = 0,
   PUBLISHED = 1,
   ENDED = 2,
+  EVALUATED = 3,
 }
 
 export interface IManageIndexDetail {
@@ -17,18 +19,23 @@ export interface IManageIndexDetail {
   dateEnd: string;
   dateStart: string;
   status: PUBLISH_ENUM;
+  score: null | number;
   type: ASS_INDEX_TYPE;
   updateTime: string;
   creatorName: string;
+  createTime: string;
   jsonAdd: string;
   jsonSub: string;
-  materials: {
-    id: number;
-    name: string;
-    fileName: string;
-    filePath: string;
-    suffix: string;
-  }[];
+  materials:
+    | {
+        id: number;
+        name: string;
+        fileName: string;
+        filePath: string;
+        suffix: string;
+        isUpload: YES_OR_NO;
+      }[]
+    | null;
 }
 
 export interface IManageAssessmentIndex {
@@ -39,3 +46,88 @@ export interface IManageAssessmentIndex {
   fill: string;
   name: string;
 }
+
+/**
+ * 自评状态
+ */
+export enum DEPT_STATUS_ENUM {
+  /** 待填报 */
+  PENDING_SUBMIT = 0,
+  /** 待审核 */
+  PENDING_EXAMINE = 1,
+  /** 审核未通过 */
+  EXAMINE_REJECT = 2,
+  /** 审核通过(待评定) */
+  EXAMINE_SUCCESS = 3,
+  RETURN = 4,
+  SUCCESS = 5,
+}
+
+export interface IManageFormListParams extends PaginationParams {
+  deptStatus?: DEPT_STATUS_ENUM;
+  searchKey?: string;
+  status?: PUBLISH_ENUM;
+  type?: ASS_INDEX_TYPE;
+}
+
+export interface IManageFormItem {
+  id: number;
+  name: string;
+  type: ASS_INDEX_TYPE;
+  remark: string;
+  dateStart: string;
+  dateEnd: string;
+  publishStatus: PUBLISH_ENUM;
+  deptName: string;
+  deptStatus: DEPT_STATUS_ENUM;
+}
+
+export interface IManageFormDetail extends Omit<IManageIndexDetail, "status"> {
+  deptStatus: DEPT_STATUS_ENUM;
+}
+
+export interface IManageDeptItem {
+  id: number;
+  name: string;
+  levelMuseum: number;
+  leaderName: string;
+  remark: string;
+  crewUserIds: string;
+  isSelf: YES_OR_NO;
+}
+
+export interface IManageUserItem {
+  id: number;
+  isAdmin: YES_OR_NO;
+  realName: string;
+}
+
+export interface IManageDeptMaterialItem
+  extends Required<IFileTemplateFormParams> {
+  id: number;
+  deptId: null | number;
+}
+
+export interface IManageDeptAllocationOfIndexItem {
+  perm: boolean;
+  id: number;
+  name: string;
+  parentId: number;
+  level: number;
+  disabled?: boolean;
+  children: IManageDeptAllocationOfIndexItem[];
+}
+
+export interface IManageRoleGroupItem {
+  id: number;
+  userName: string;
+  userIds: string;
+}
+
+export interface IManageAssOperationResponse {
+  gist: {
+    one: number;
+    two: number;
+    three: number;
+  };
+}

+ 21 - 2
src/utils/index.ts

@@ -12,13 +12,15 @@ export const logout = async () => {
 
 export const getSelectedNodes = (
   selectedKeys: Key[],
-  treeData: AssIndexTreeItemType[]
+  treeData: AssIndexTreeItemType[],
+  // 任意节点
+  any = false
 ) => {
   let selectedNodes: AssIndexTreeItemType[] = [];
 
   const findNodes = (keys: Key[], data: AssIndexTreeItemType[]) => {
     data.forEach((node) => {
-      if (keys.includes(node.id) && !node.children?.length) {
+      if (keys.includes(node.id) && (any ? true : !node.children?.length)) {
         selectedNodes.push(node);
       }
       if (node.children) {
@@ -33,3 +35,20 @@ export const getSelectedNodes = (
 
 export const getImgFullPath = (path: string) =>
   `${process.env.REACT_APP_API_URL}${process.env.REACT_APP_IMG_PUBLIC}${path}`;
+
+export const downloadFile = async (url: string, name: string) => {
+  try {
+    const response = await fetch(url);
+    const blob = await response.blob();
+    const newUrl = window.URL.createObjectURL(blob);
+    const link = document.createElement("a");
+    link.href = newUrl;
+    link.download = name;
+    document.body.appendChild(link);
+    link.click();
+    document.body.removeChild(link);
+    window.URL.revokeObjectURL(url);
+  } catch (error) {
+    console.error("下载失败:", error);
+  }
+};