Browse Source

up-场景审核

shaogen1995 1 year ago
parent
commit
d2dca1d404

+ 122 - 0
src/pages/B2Scene/AuditMo.tsx

@@ -0,0 +1,122 @@
+import React, { useCallback, useEffect, useState } from "react";
+import styles from "./index.module.scss";
+import { Button, Modal, Popconfirm } from "antd";
+import { B1options1 } from "../B1Plan/data";
+import TextArea from "antd/es/input/TextArea";
+import { B2_APIAudit } from "@/store/action/B2Scene";
+import { MessageFu } from "@/utils/message";
+
+type Props = {
+  auditInfo: {
+    oldState: number;
+    id: number;
+    sceneCode: string;
+    auditDesc: string;
+  };
+  colseFu: () => void;
+  upTableFu: (id: number, newState: number, newDesc: string) => void;
+};
+
+function AuditMo({ auditInfo, colseFu, upTableFu }: Props) {
+  // 审核状态
+  const [audit, setAudit] = useState(-1);
+
+  // 备注
+  const [description, setDescription] = useState("");
+
+  useEffect(() => {
+    setAudit(auditInfo.oldState);
+
+    setDescription(auditInfo.auditDesc);
+  }, [auditInfo]);
+
+  // 点击提交
+  const btnOkFu = useCallback(async () => {
+    const res = await B2_APIAudit({
+      audit,
+      description,
+      sceneCode: auditInfo.sceneCode,
+    });
+
+    if (res.code === 0) {
+      MessageFu.success("修改审核状态成功!");
+      upTableFu(auditInfo.id, audit, description);
+      colseFu();
+    }
+  }, [
+    audit,
+    auditInfo.id,
+    auditInfo.sceneCode,
+    colseFu,
+    description,
+    upTableFu,
+  ]);
+
+  return (
+    <Modal
+      wrapClassName={styles.AuditMo}
+      open={true}
+      title="审核"
+      footer={
+        [] // 设置footer为空,去掉 取消 确定默认按钮
+      }
+    >
+      <div className="B2Amain">
+        <div className="B2Arow">
+          <div className="B2Arow1">
+            <span>* </span>审核状态:
+          </div>
+          <div className="B2Arow2">
+            {B1options1.filter((v) => v.label !== "全部").map((v) => (
+              <span className="B2Arow2Btn" key={v.label}>
+                <Button
+                  onClick={() => setAudit(v.value as number)}
+                  type={v.value === audit ? "primary" : "default"}
+                >
+                  {v.label}
+                </Button>
+                &emsp;
+              </span>
+            ))}
+          </div>
+        </div>
+
+        <div className="B2Arow">
+          <div className="B2Arow1">备注:</div>
+          <div className="B2Arow2">
+            <TextArea
+              value={description}
+              onChange={(e) =>
+                setDescription(e.target.value.replace(/\s+/g, ""))
+              }
+              style={{ width: 400 }}
+              placeholder="请输入内容"
+              showCount
+              maxLength={50}
+            />
+          </div>
+        </div>
+
+        <div className="B2Abtn">
+          <Button type="primary" onClick={btnOkFu}>
+            提交
+          </Button>
+          &emsp;
+          <Popconfirm
+            title="放弃编辑后,信息将不会保存!"
+            okText="放弃"
+            cancelText="取消"
+            onConfirm={colseFu}
+            okButtonProps={{ loading: false }}
+          >
+            <Button>取消</Button>
+          </Popconfirm>
+        </div>
+      </div>
+    </Modal>
+  );
+}
+
+const MemoAuditMo = React.memo(AuditMo);
+
+export default MemoAuditMo;

+ 16 - 0
src/pages/B2Scene/data.ts

@@ -0,0 +1,16 @@
+export type B2FromDataType = {
+  auditStatus: string;
+  pmUser: string;
+  searchKey: string;
+  siteLevel: 2;
+  site: undefined | string[];
+  pageSize: number;
+  pageNum: number;
+};
+
+// 计算状态
+export const B2ResNum = {
+  0: "计算中",
+  1: "计算完成",
+  2: "计算失败",
+};

+ 104 - 3
src/pages/B2Scene/index.module.scss

@@ -1,5 +1,106 @@
-.B2Scene{
-  :global{
-    
+.B2Scene {
+  :global {
+    .B2top {
+      display: flex;
+      justify-content: space-between;
+      border-radius: 10px;
+      background-color: #fff;
+      padding: 15px 24px;
+
+      // 级联选择器的 placeholder
+      .ant-select-selection-placeholder {
+        color: black;
+      }
+
+      &>div {
+        display: flex;
+
+        .B2topRow {
+          margin-right: 20px;
+
+          &:last-child {
+            margin-right: 0;
+          }
+        }
+      }
+    }
+
+    .tableMain {
+      border-radius: 10px;
+      margin-top: 15px;
+      height: calc(100% - 80px);
+      background-color: #fff;
+
+      .ant-table-body {
+        height: 625px;
+        overflow-y: auto !important;
+        overflow-y: overlay !important;
+
+        .B2audit {
+          cursor: pointer;
+          color: #1677ff
+        }
+
+        .anticon-question-circle {
+          color: #1677ff;
+        }
+
+        .ant-table-cell {
+          padding: 8px !important;
+        }
+      }
+    }
+  }
+}
+
+.AuditMo {
+  :global {
+
+    .ant-modal-close {
+      display: none;
+    }
+
+    .ant-modal {
+      width: 800px !important;
+    }
+
+    .B2Amain {
+
+      .B2Arow {
+        margin-top: 30px;
+        display: flex;
+
+        .B2Arow1 {
+          width: 100px;
+          text-align: right;
+
+
+          &>span {
+            font-size: 14px;
+            color: #ff4d4f;
+          }
+        }
+
+        .B2Arow2 {
+          width: calc(100% - 100px);
+
+        }
+
+        &:nth-of-type(1) {
+          .B2Arow1 {
+            position: relative;
+            top: 3px;
+          }
+
+        }
+      }
+
+      .B2Abtn {
+        margin-top: 20px;
+        text-align: center;
+      }
+    }
+
+
   }
 }

+ 423 - 5
src/pages/B2Scene/index.tsx

@@ -1,12 +1,430 @@
-import React from "react";
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
 import styles from "./index.module.scss";
- function B2Scene() {
-  
+import {
+  Button,
+  Cascader,
+  Input,
+  Popconfirm,
+  Select,
+  Table,
+  Tooltip,
+} from "antd";
+import { useDispatch, useSelector } from "react-redux";
+import { B2FromDataType, B2ResNum } from "./data";
+import mapDataAll from "../C1User/AddUser/city";
+import { B1options1, B1options1Obj } from "../B1Plan/data";
+import { B2_APIgetlist, B2_APIremove } from "@/store/action/B2Scene";
+import store, { RootState } from "@/store";
+import { B2tableType } from "@/types";
+import { MessageFu } from "@/utils/message";
+import { QuestionCircleOutlined } from "@ant-design/icons";
+import ExportJsonExcel from "js-export-excel";
+import dayjs from "dayjs";
+import AuditMo from "./AuditMo";
+
+function B2Scene() {
+  const dispatch = useDispatch();
+
+  // 筛选和分页
+  const [tableSelect, setTableSelect] = useState<B2FromDataType>({
+    auditStatus: "",
+    pmUser: "",
+    searchKey: "",
+    siteLevel: 2,
+    site: undefined,
+    pageSize: 10,
+    pageNum: 1,
+  });
+
+  // 发送接口的函数
+  const getListFu = useCallback(() => {
+    const obj = {
+      ...tableSelect,
+      site: tableSelect.site ? tableSelect.site[1] : null,
+    };
+    dispatch(B2_APIgetlist(obj));
+  }, [dispatch, tableSelect]);
+
+  useEffect(() => {
+    getListFu();
+  }, [getListFu]);
+
+  // 输入框的改变
+  const txtTimeRef = useRef(-1);
+  const txtChangeFu = useCallback(
+    (txt: string, key: "pmUser" | "searchKey") => {
+      clearTimeout(txtTimeRef.current);
+      txtTimeRef.current = window.setTimeout(() => {
+        setTableSelect({ ...tableSelect, [key]: txt, pageNum: 1 });
+      }, 500);
+    },
+    [tableSelect]
+  );
+
+  // 点击重置
+  const [inputKey, setInputKey] = useState(1);
+  const resetSelectFu = useCallback(() => {
+    // 把2个输入框和时间选择器清空
+    setInputKey(Date.now());
+    setTableSelect({
+      auditStatus: "",
+      pmUser: "",
+      searchKey: "",
+      siteLevel: 2,
+      site: undefined,
+      pageSize: 10,
+      pageNum: 1,
+    });
+  }, []);
+
+  // 从仓库获取列表
+  const B2TableList = useSelector(
+    (state: RootState) => state.B2Scene.B2TableList
+  );
+  // 页码变化
+  const paginationChange = useCallback(
+    () => (pageNum: number, pageSize: number) => {
+      setTableSelect({ ...tableSelect, pageNum, pageSize });
+    },
+    [tableSelect]
+  );
+
+  // 点击删除
+  const delByIdFu = useCallback(
+    async (id: number) => {
+      const res = await B2_APIremove(id);
+      if (res.code === 0) {
+        MessageFu.success("删除成功!");
+        getListFu();
+      }
+    },
+    [getListFu]
+  );
+
+  const columns = useMemo(() => {
+    return [
+      {
+        title: "机房编码",
+        render: (item: B2tableType) => item.roomNum || "(空)",
+      },
+      {
+        title: "站址地区",
+        render: (item: B2tableType) =>
+          !item.province && !item.city
+            ? "(空)"
+            : `${item.province} - ${item.city}`,
+      },
+      {
+        title: "项目经理",
+        render: (item: B2tableType) => {
+          if (item.creatorId === 1) return "管理员";
+          else {
+            return item.pmName || "匿名";
+          }
+        },
+      },
+      {
+        title: "场景名称",
+        render: (item: B2tableType) => item.sceneName || "(空)",
+      },
+      {
+        title: "场景链接",
+        render: (item: B2tableType) =>
+          item.link ? (
+            item.link.length >= 25 ? (
+              <a
+                target="_blank"
+                href={item.link}
+                style={{ cursor: "pointer" }}
+                title={item.link}
+                rel="noreferrer"
+              >
+                {item.link.substring(0, 25) + "..."}
+              </a>
+            ) : (
+              item.link
+            )
+          ) : (
+            "(空)"
+          ),
+      },
+      {
+        title: "场景码",
+        render: (item: B2tableType) => (
+          <>
+            {item.sceneCode || "(空)"}
+            <span
+              style={{ cursor: "pointer" }}
+              hidden={!item.scheduleStatus && item.scheduleStatus !== 0}
+            >
+              <Tooltip title={Reflect.get(B2ResNum, item.scheduleStatus)}>
+                &nbsp;
+                <QuestionCircleOutlined rev={undefined} />
+              </Tooltip>
+            </span>
+          </>
+        ),
+      },
+      {
+        title: "相机SN码",
+        render: (item: B2tableType) => item.cameraSn || "(空)",
+      },
+      {
+        title: "拍摄时间",
+        render: (item: B2tableType) => item.shootTime || "(空)",
+      },
+      {
+        title: "领用单位",
+        render: (item: B2tableType) => item.snapUseDept || "(空)",
+      },
+      {
+        title: "领用人员",
+        render: (item: B2tableType) => item.snapUseName || "(空)",
+      },
+      {
+        title: "审核状态",
+        render: (item: B2tableType) => (
+          <>
+            <span
+              className="B2audit"
+              onClick={() =>
+                setAuditInfo({
+                  oldState: item.auditStatus,
+                  id: item.id,
+                  sceneCode: item.sceneCode,
+                  auditDesc: item.auditDesc,
+                })
+              }
+            >
+              {Reflect.get(B1options1Obj, item.auditStatus) || "(空)"}
+            </span>
+            <span style={{ cursor: "pointer" }} hidden={!item.auditDesc}>
+              <Tooltip title={item.auditDesc}>
+                &nbsp;
+                <QuestionCircleOutlined rev={undefined} />
+              </Tooltip>
+            </span>
+          </>
+        ),
+      },
+      {
+        title: "审核时间",
+        render: (item: B2tableType) => item.auditTime || "(空)",
+      },
+      {
+        title: "操作",
+        render: (item: B2tableType) => (
+          <>
+            <a
+              hidden={!item.filePath}
+              href={item.filePath}
+              download={item.sceneName || item.sceneCode + ".json"}
+            >
+              下载Json
+            </a>
+
+            <Popconfirm
+              title="删除后无法恢复,是否删除?"
+              okText="删除"
+              cancelText="取消"
+              onConfirm={() => delByIdFu(item.id)}
+              okButtonProps={{ loading: false }}
+            >
+              <Button size="small" type="text" danger>
+                删除
+              </Button>
+            </Popconfirm>
+          </>
+        ),
+      },
+    ];
+  }, [delByIdFu]);
+
+  // 点击导出
+  const deriveFu = useCallback(async () => {
+    if (B2TableList.list.length === 0)
+      return MessageFu.warning("当前搜索条件没有数据!");
+    const name = "场景审核" + dayjs(new Date()).format("YYYY-MM-DD HH:mm");
+
+    const option = {
+      fileName: name,
+      datas: [
+        {
+          sheetData: B2TableList.list.map((v) => ({
+            roomNum: v.roomNum || "(空)",
+            myCity:
+              !v.province && !v.city ? "(空)" : `${v.province} - ${v.city}`,
+            pmName: v.creatorId === 1 ? "管理员" : v.pmName || "匿名",
+            sceneName: v.sceneName || "(空)",
+            link: v.link || "(空)",
+            sceneCode: v.sceneCode || "(空)",
+            cameraSn: v.cameraSn || "(空)",
+            shootTime: v.shootTime || "(空)",
+            snapUseDept: v.snapUseDept || "(空)",
+            snapUseName: v.snapUseName || "(空)",
+            auditStatus: Reflect.get(B1options1Obj, v.auditStatus) || "(空)",
+            auditTime: v.auditTime || "(空)",
+          })),
+          sheetName: name,
+          sheetFilter: [
+            "roomNum",
+            "myCity",
+            "pmName",
+            "sceneName",
+            "link",
+            "sceneCode",
+            "cameraSn",
+            "shootTime",
+            "snapUseDept",
+            "snapUseName",
+            "auditStatus",
+            "auditTime",
+          ],
+          sheetHeader: [
+            "机房编码",
+            "站址地区",
+            "项目经理",
+            "场景名称",
+            "场景链接",
+            "场景码",
+            "相机SN码",
+            "拍摄时间",
+            "领用单位",
+            "领用人员",
+            "审核状态",
+            "审核时间",
+          ],
+          columnWidths: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10],
+        },
+      ],
+    };
+
+    const toExcel = new ExportJsonExcel(option); //new
+    toExcel.saveExcel(); //保存
+  }, [B2TableList.list]);
+
+  // 审核弹窗的信息
+  const [auditInfo, setAuditInfo] = useState({
+    oldState: -1,
+    id: 0,
+    sceneCode: "",
+    auditDesc: "",
+  });
+
   return (
     <div className={styles.B2Scene}>
-      <h1>B2Scene</h1>
+      <div className="pageTitle">场景审核</div>
+      {/* 顶部筛选 */}
+      <div className="B2top">
+        {/* 左侧输入框 */}
+        <div className="B2top1">
+          <div className="B2topRow">
+            <span>搜索项:</span>
+            <Input
+              key={inputKey}
+              maxLength={10}
+              style={{ width: 246 }}
+              placeholder="请输入机房编码/场景码,最多10字"
+              allowClear
+              onChange={(e) => txtChangeFu(e.target.value, "searchKey")}
+            />
+          </div>
+
+          <div className="B2topRow">
+            <span>站址地区:</span>
+            <Cascader
+              value={tableSelect.site}
+              style={{ width: 180 }}
+              options={mapDataAll}
+              placeholder="全部"
+              onChange={(e) =>
+                setTableSelect({ ...tableSelect, site: e as string[] })
+              }
+            />
+          </div>
+
+          <div className="B2topRow">
+            <span>项目经理:</span>
+            <Input
+              key={inputKey}
+              maxLength={10}
+              style={{ width: 180 }}
+              placeholder="请输入姓名,最多10字"
+              allowClear
+              onChange={(e) => txtChangeFu(e.target.value, "pmUser")}
+            />
+          </div>
+
+          <div className="B2topRow">
+            <span>审核状态:</span>
+            <Select
+              style={{ width: 140 }}
+              value={tableSelect.auditStatus}
+              onChange={(e) =>
+                setTableSelect({ ...tableSelect, auditStatus: e, pageNum: 1 })
+              }
+              options={B1options1}
+            />
+          </div>
+        </div>
+        {/* 右侧按钮 */}
+        <div className="B2top2">
+          <Button onClick={resetSelectFu}>重置</Button>&emsp;
+          <Button type="primary" onClick={deriveFu}>
+            导出表格
+          </Button>
+        </div>
+      </div>
+
+      {/* 表格主体 */}
+      <div className="tableMain">
+        <Table
+          scroll={{ y: 625 }}
+          dataSource={B2TableList.list}
+          columns={columns}
+          rowKey="id"
+          pagination={{
+            showQuickJumper: true,
+            position: ["bottomCenter"],
+            // showSizeChanger: true,
+            current: tableSelect.pageNum,
+            pageSize: tableSelect.pageSize,
+            total: B2TableList.total,
+            onChange: paginationChange(),
+          }}
+        />
+      </div>
+
+      {/* 点击审核出来的弹窗 */}
+      {auditInfo.id ? (
+        <AuditMo
+          auditInfo={auditInfo}
+          colseFu={() =>
+            setAuditInfo({ oldState: -1, id: 0, sceneCode: "", auditDesc: "" })
+          }
+          upTableFu={(id, newState, newDesc) => {
+            const oldObj = store.getState().B2Scene.B2TableList;
+            const newObj = {
+              list: oldObj.list.map((v) => ({
+                ...v,
+                auditStatus: v.id === id ? newState : v.auditStatus,
+                auditDesc: v.id === id ? newDesc : v.auditDesc,
+              })),
+              total: oldObj.total,
+            };
+
+            store.dispatch({ type: "B2/getList", payload: newObj });
+          }}
+        />
+      ) : null}
     </div>
-  )
+  );
 }
 
 const MemoB2Scene = React.memo(B2Scene);

+ 31 - 0
src/store/action/B2Scene.ts

@@ -0,0 +1,31 @@
+import http from "@/utils/http";
+import { AppDispatch } from "..";
+/**
+ * 获取 进度统计 表格列表(存到仓库)
+ */
+export const B2_APIgetlist = (data: any) => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post("cms/scene/pageList", data);
+    if (res.code === 0) {
+      const obj = {
+        list: res.data.records,
+        total: res.data.total,
+      };
+      dispatch({ type: "B2/getList", payload: obj });
+    }
+  };
+};
+
+/**
+ * 删除 单个表格数据
+ */
+export const B2_APIremove = (id: number) => {
+  return http.get(`cms/scene/remove/${id}`);
+};
+
+/**
+ * 审核
+ */
+export const B2_APIAudit = (data: any) => {
+  return http.post("cms/scene/audit", data);
+};

+ 27 - 0
src/store/reducer/B2Scene.ts

@@ -0,0 +1,27 @@
+import { B2tableType } from "@/types";
+
+// 初始化状态
+const initState = {
+  // 列表数据
+  B2TableList: {
+    list: [] as B2tableType[],
+    total: 0,
+  },
+};
+
+// 定义 action 类型
+type Props = {
+  type: "B2/getList";
+  payload: { list: B2tableType[]; total: number };
+};
+
+// reducer
+export default function Reducer(state = initState, action: Props) {
+  switch (action.type) {
+    // 获取列表数据
+    case "B2/getList":
+      return { ...state, B2TableList: action.payload };
+    default:
+      return state;
+  }
+}

+ 2 - 0
src/store/reducer/index.ts

@@ -6,6 +6,7 @@ import A0Layout from "./layout";
 import A1Camera from "./A1Camera";
 import A2Psychz from "./A2Psychz";
 import B1Plan from "./B1Plan";
+import B2Scene from "./B2Scene";
 import C1User from "./C1User";
 import C2Log from "./C2Log";
 
@@ -15,6 +16,7 @@ const rootReducer = combineReducers({
   A1Camera,
   A2Psychz,
   B1Plan,
+  B2Scene,
   C1User,
   C2Log,
 });

+ 23 - 0
src/types/api/B2Scene.d.ts

@@ -0,0 +1,23 @@
+export type B2tableType = {
+  auditDesc: string;
+  auditStatus: number;
+  auditTime: string;
+  cameraSn: string;
+  city: string;
+  createTime: string;
+  creatorId: number;
+  creatorName: string;
+  filePath: string;
+  id: number;
+  link: string;
+  pmName: string;
+  province: string;
+  roomNum: string;
+  sceneCode: string;
+  sceneName: string;
+  scheduleStatus: number;
+  shootTime: string;
+  snapUseDept: string;
+  snapUseName: string;
+  updateTime: string;
+};

+ 1 - 0
src/types/index.d.ts

@@ -2,5 +2,6 @@ export * from './api/layot'
 export * from './api/A1Camera'
 export * from './api/A2Psychz'
 export * from './api/B1Plan'
+export * from './api/B2Scene'
 export * from './api/C1User'
 export * from './api/C2Log'