shaogen1995 hai 1 ano
pai
achega
0f4bb1b243

+ 16 - 4
src/components/MyTable/index.tsx

@@ -4,7 +4,7 @@ import { Table } from "antd";
 import ImageLazy from "../ImageLazy";
 
 type Props = {
-  yHeight: number; //设置表格的高度
+  yHeight?: number; //设置表格的高度
   list: any; //表格数据
   columnsTemp: any[][]; //表格展示
   total?: number; //总数
@@ -14,6 +14,7 @@ type Props = {
   onChange?: (pageNum: number, pageSize: number) => void;
   lastBtn?: any;
   classKey?: string; //一个组件多次使用的时候要传递,分别设置style
+  merge?: { type: string; num: number; loc: "rowSpan" | "colSpan" };
 };
 
 function MyTable({
@@ -31,13 +32,14 @@ function MyTable({
   onChange,
   lastBtn = [],
   classKey = "",
+  merge,
 }: Props) {
   useEffect(() => {
     const dom = document.querySelector(
       `.MyTable${classKey} .ant-table-body`
     ) as HTMLDivElement;
 
-    if (dom) dom.style.height = yHeight + "px";
+    if (dom && yHeight) dom.style.height = yHeight + "px";
   }, [classKey, yHeight]);
 
   // 页码变化
@@ -92,19 +94,29 @@ function MyTable({
     [pageNum, pageSize]
   );
 
+
+
   const columns = useMemo(() => {
     const arr: any = columnsTemp.map((v: any) => ({
       title: v[1],
       render: dataChangeFu(v),
+      onCell:
+        merge && v.includes(merge.type)
+          ?
+          // {rowSpan:3} 
+          (item: any, index: number) => ({
+              rowSpan: index === 0 ? merge.num : 0,
+            })
+          : "",
     }));
 
     return arr;
-  }, [columnsTemp, dataChangeFu]);
+  }, [columnsTemp, dataChangeFu, merge]);
 
   return (
     <Table
       className={`${styles.MyTable} MyTable${classKey}`}
-      scroll={{ y: yHeight }}
+      scroll={{ y: yHeight ? yHeight : "" }}
       dataSource={list}
       columns={[...columns, ...lastBtn]}
       rowKey="id"

+ 1 - 0
src/pages/A1wxuser/A1add/A1aEdit.tsx

@@ -68,6 +68,7 @@ function A1aEdit({ editInfo, closeFu, upTableFu }: Props) {
               // min={-num}
               // max={99999 - num}
               value={inputNum}
+              precision={0}
               onChange={(e) => setInputNum(e)}
               placeholder={`请输入${-editInfo.num}至${
                 99999 - editInfo.num

+ 2 - 2
src/pages/A1wxuser/index.tsx

@@ -94,13 +94,13 @@ function A1wxuser() {
       {/* 顶部筛选 */}
       <div className="A1top">
         <div>
-          <span>搜索项:</span>
+          <span>昵称:</span>
           <Input
             key={inputKey}
             maxLength={10}
             showCount
             style={{ width: 300 }}
-            placeholder="请输入名称"
+            placeholder="请输入"
             allowClear
             onChange={(e) => fromKeyChangeFu(e, "searchKey")}
           />

+ 125 - 0
src/pages/A2integral/A2edit.tsx

@@ -0,0 +1,125 @@
+import React, { useCallback, useEffect, useMemo, useState } from "react";
+import styles from "./index.module.scss";
+import { Button, Input, Modal } from "antd";
+import { A2editInfoType } from "@/types";
+import MyPopconfirm from "@/components/MyPopconfirm";
+import { MessageFu } from "@/utils/message";
+import { A2_APIsave } from "@/store/action/A2integral";
+
+type Props = {
+  editInfo: A2editInfoType;
+  closeFu: () => void;
+  upTableFu: () => void;
+};
+
+function A2edit({ editInfo, closeFu, upTableFu }: Props) {
+  const [day, setDay] = useState(0);
+  const [score, setScore] = useState(0);
+
+  useEffect(() => {
+    setDay(editInfo.day || 1);
+    setScore(editInfo.score);
+  }, [editInfo.day, editInfo.score]);
+
+  // 点击确定
+  const btnOkFu = useCallback(async () => {
+    const obj = {
+      id: editInfo.id,
+      cycle: day,
+      score,
+    };
+
+    const res = await A2_APIsave(obj);
+
+    if (res.code === 0) {
+      MessageFu.success("编辑成功!");
+      upTableFu();
+      closeFu();
+    }
+  }, [closeFu, day, editInfo.id, score, upTableFu]);
+
+  // 禁用按钮
+  const inputNumRes = useMemo(() => {
+    let flag = false;
+    if (!day) flag = true;
+    if (!score) flag = true;
+    return flag;
+  }, [day, score]);
+
+  const inputChange = useCallback(
+    (val: React.ChangeEvent<HTMLInputElement>, type: "day" | "score") => {
+      let txt = val.target.value.replace(/^(0+)|[^\d]+/g, "");
+      let txtNum = Number(txt);
+      if (type === "day") {
+        txtNum = txtNum > 99 ? 99 : txtNum;
+        setDay(txtNum);
+      } else {
+        txtNum = txtNum > 9999 ? 9999 : txtNum;
+        setScore(txtNum);
+      }
+    },
+    []
+  );
+
+  return (
+    <Modal
+      wrapClassName={styles.A2edit}
+      open={true}
+      title={`${editInfo.type === "user" ? "用户活跃" : "爱心林场"} - 编辑`}
+      footer={
+        [] // 设置footer为空,去掉 取消 确定默认按钮
+      }
+    >
+      <div className="A2eMain">
+        <div className="A2eRow">
+          <div className="A2eRow1 A2eRow3">
+            {editInfo.type === "user" ? "行为:" : "动植物:"}
+          </div>
+          <div className="A2eRow2">{editInfo.name}</div>
+        </div>
+
+        {editInfo.type === "game" ? (
+          <div className="A2eRow">
+            <div className="A2eRow1">
+              <span>* </span>成熟周期(天):
+            </div>
+            <div className="A2eRow2">
+              <Input
+                style={{ width: 160 }}
+                placeholder="请输入1~99整数"
+                value={day}
+                onChange={(e) => inputChange(e, "day")}
+              />
+            </div>
+          </div>
+        ) : null}
+
+        <div className="A2eRow">
+          <div className="A2eRow1">
+            <span>* </span>奖励爱心币:
+          </div>
+          <div className="A2eRow2">
+            <Input
+              style={{ width: 160 }}
+              placeholder="请输入1~9999整数"
+              value={score}
+              onChange={(e) => inputChange(e, "score")}
+            />
+          </div>
+        </div>
+
+        <div className="A2eBtn">
+          <Button type="primary" onClick={btnOkFu} disabled={inputNumRes}>
+            提交
+          </Button>
+          &emsp;
+          <MyPopconfirm txtK="取消" onConfirm={closeFu} />
+        </div>
+      </div>
+    </Modal>
+  );
+}
+
+const MemoA2edit = React.memo(A2edit);
+
+export default MemoA2edit;

+ 67 - 3
src/pages/A2integral/index.module.scss

@@ -1,5 +1,69 @@
-.A2integral{
-  :global{
-    
+.A2integral {
+  background-color: #fff;
+  border-radius: 10px;
+  overflow-y: auto;
+  padding-bottom: 20px;
+
+  :global {
+    .A2tit {
+      margin-top: 20px;
+      padding: 0px 24px;
+      font-size: 20px;
+      font-weight: 700;
+      margin-bottom: 20px;
+    }
+  }
+}
+
+
+// 编辑弹窗
+.A2edit {
+  :global {
+    .ant-modal-close {
+      display: none;
+    }
+
+    .ant-modal {
+      width: 800px !important;
+    }
+
+    .ant-modal-body {
+      border-top: 1px solid #ccc;
+    }
+
+    .A2eMain {
+      padding-top: 15px;
+
+      .A2eRow {
+        display: flex;
+        margin-bottom: 24px;
+
+        .A2eRow1 {
+          position: relative;
+          top: 3px;
+          width: 130px;
+          text-align: right;
+
+          &>span {
+            color: #ff4d4f;
+          }
+        }
+
+        .A2eRow2 {
+          width: calc(100% - 130px);
+
+          .ant-input-number {
+            width: 100%;
+          }
+        }
+        .A2eRow3{
+          top: 0;
+        }
+      }
+
+      .A2eBtn {
+        text-align: center;
+      }
+    }
   }
 }

+ 79 - 1
src/pages/A2integral/index.tsx

@@ -1,9 +1,87 @@
-import React from "react";
+import React, { useCallback, useEffect, useState } from "react";
 import styles from "./index.module.scss";
+import { useDispatch, useSelector } from "react-redux";
+import { A2_APIgetList } from "@/store/action/A2integral";
+import MyTable from "@/components/MyTable";
+import { RootState } from "@/store";
+import { A2tableC1, A2tableC2 } from "@/utils/tableData";
+import { A2editInfoType, A2tableType } from "@/types";
+import { Button } from "antd";
+import A2edit from "./A2edit";
+
 function A2integral() {
+  const dispatch = useDispatch();
+
+  const getListFu = useCallback(() => {
+    dispatch(A2_APIgetList());
+  }, [dispatch]);
+
+  useEffect(() => {
+    getListFu();
+  }, [getListFu]);
+
+  const tableInfo = useSelector(
+    (state: RootState) => state.A2integral.tableInfo
+  );
+
+  const tableLastBtn = useCallback((type: "user" | "game") => {
+    return [
+      {
+        title: "操作",
+        render: (item: A2tableType) => (
+          <Button
+            size="small"
+            type="text"
+            onClick={() =>
+              setEditInfo({
+                id: item.id,
+                type,
+                name: item.name,
+                day: item.day,
+                score: item.score,
+              })
+            }
+          >
+            编辑
+          </Button>
+        ),
+      },
+    ];
+  }, []);
+
+  const [editInfo, setEditInfo] = useState({} as A2editInfoType);
+
   return (
     <div className={styles.A2integral}>
       <div className="pageTitle">积分管理</div>
+      <div className="A2tit">用户活跃</div>
+      <div className="A1tableBox">
+        <MyTable
+          list={tableInfo.list1}
+          columnsTemp={A2tableC1}
+          lastBtn={tableLastBtn("user")}
+          pagingInfo={false}
+        />
+      </div>
+
+      <div className="A2tit">爱心林场</div>
+      <div className="A1tableBox">
+        <MyTable
+          list={tableInfo.list2}
+          columnsTemp={A2tableC2}
+          lastBtn={tableLastBtn("game")}
+          pagingInfo={false}
+          merge={{ type: "说明", num: tableInfo.list2.length, loc: "rowSpan" }}
+        />
+      </div>
+
+      {editInfo.id ? (
+        <A2edit
+          editInfo={editInfo}
+          closeFu={() => setEditInfo({} as A2editInfoType)}
+          upTableFu={() => getListFu()}
+        />
+      ) : null}
     </div>
   );
 }

+ 9 - 0
src/pages/A3record/data.ts

@@ -0,0 +1,9 @@
+export const A3select=[
+  { value: "", label: "全部" },
+  { value: "登录", label: "登录" },
+  { value: "注册", label: "注册" },
+  { value: "打卡", label: "打卡" },
+  { value: "爱心林场", label: "爱心林场" },
+  { value: "兑换", label: "兑换" },
+  { value: "编辑", label: "编辑" },
+]

+ 24 - 0
src/pages/A3record/index.module.scss

@@ -0,0 +1,24 @@
+.A3record{
+  :global{
+    .A3top {
+      padding: 15px 24px;
+      border-radius: 10px;
+      background-color: #fff;
+      display: flex;
+      justify-content: space-between;
+      &>div{
+        display: flex;
+        .A3row{
+          margin-right: 20px;
+        }
+      }
+    }
+    .A3tableBox {
+      border-radius: 10px;
+      overflow: hidden;
+      margin-top: 15px;
+      height: calc(100% - 77px);
+      background-color: #fff;
+    }
+  }
+}

+ 136 - 0
src/pages/A3record/index.tsx

@@ -0,0 +1,136 @@
+import React, { useCallback, useEffect, useRef, useState } from "react";
+import styles from "./index.module.scss";
+import { useDispatch, useSelector } from "react-redux";
+import { A3_APIgetList } from "@/store/action/A3record";
+import { RootState } from "@/store";
+import { Button, DatePicker, Input, Select } from "antd";
+import MyTable from "@/components/MyTable";
+import { A3tableC } from "@/utils/tableData";
+import { A3select } from "./data";
+const { RangePicker } = DatePicker;
+
+function A3record() {
+  const dispatch = useDispatch();
+
+  const [fromData, setFromData] = useState({
+    pageNum: 1,
+    pageSize: 10,
+    searchKey: "",
+    startTime: "",
+    endTime: "",
+    type: "",
+  });
+
+  const getListFu = useCallback(() => {
+    dispatch(A3_APIgetList(fromData));
+  }, [dispatch, fromData]);
+
+  useEffect(() => {
+    getListFu();
+  }, [getListFu]);
+
+  const [inputKey, setInputKey] = useState(1);
+
+  // 标题的输入
+  const timeRef = useRef(-1);
+  const fromKeyChangeFu = useCallback(
+    (e: React.ChangeEvent<HTMLInputElement>, key: "searchKey") => {
+      clearTimeout(timeRef.current);
+      timeRef.current = window.setTimeout(() => {
+        setFromData({ ...fromData, [key]: e.target.value, pageNum: 1 });
+      }, 500);
+    },
+    [fromData]
+  );
+
+  // 时间选择器改变
+  const timeChange = useCallback(
+    (date: any, dateString: any) => {
+      let startTime = "";
+      let endTime = "";
+      if (dateString[0] && dateString[1]) {
+        startTime = dateString[0] + " 00:00:00";
+        endTime = dateString[1] + " 23:59:59";
+      }
+      setFromData({ ...fromData, startTime, endTime, pageNum: 1 });
+    },
+    [fromData]
+  );
+
+  // 点击重置
+  const resetSelectFu = useCallback(() => {
+    setInputKey(Date.now());
+    setFromData({
+      pageNum: 1,
+      pageSize: 10,
+      searchKey: "",
+      startTime: "",
+      endTime: "",
+      type: "",
+    });
+  }, []);
+
+  const tableInfo = useSelector((state: RootState) => state.A3record.tableInfo);
+
+  return (
+    <div className={styles.A3record}>
+      <div className="pageTitle">积分记录</div>
+
+      {/* 顶部筛选 */}
+      <div className="A3top">
+        <div>
+          <div className="A3row">
+            <span>日期:</span>
+            <RangePicker onChange={timeChange} key={inputKey} />
+          </div>
+          <div className="A3row">
+            <span>用户名:</span>
+            <Input
+              key={inputKey}
+              maxLength={10}
+              showCount
+              style={{ width: 240 }}
+              placeholder="请输入"
+              allowClear
+              onChange={(e) => fromKeyChangeFu(e, "searchKey")}
+            />
+          </div>
+          <div className="A3row">
+            <span>类型:</span>
+            <Select
+              style={{ width: 120 }}
+              value={fromData.type}
+              onChange={(e) =>
+                setFromData({ ...fromData, type: e, pageNum: 1 })
+              }
+              options={A3select}
+            />
+          </div>
+        </div>
+        <div>
+          <Button onClick={resetSelectFu}>重置</Button>
+        </div>
+      </div>
+
+      {/* 表格主体 */}
+      <div className="A3tableBox">
+        <MyTable
+          yHeight={625}
+          list={tableInfo.list}
+          columnsTemp={A3tableC}
+          // lastBtn={tableLastBtn}
+          pageNum={fromData.pageNum}
+          pageSize={fromData.pageSize}
+          total={tableInfo.total}
+          onChange={(pageNum, pageSize) =>
+            setFromData({ ...fromData, pageNum, pageSize })
+          }
+        />
+      </div>
+    </div>
+  );
+}
+
+const MemoA3record = React.memo(A3record);
+
+export default MemoA3record;

+ 54 - 0
src/pages/A4store/A3Edit/index.module.scss

@@ -0,0 +1,54 @@
+.A3Edit {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  z-index: 12;
+  top: 0;
+  left: 0;
+  background-color: #fff;
+  border-radius: 10px;
+  padding: 24px;
+
+  :global {
+    .A3Emain {
+      width: 100%;
+      height: 100%;
+      overflow-y: auto;
+
+      .ant-form {
+        width: 800px;
+
+        .ant-input-number {
+          width: 400px;
+        }
+
+        .formRow {
+          display: flex;
+
+          .formLeft {
+            position: relative;
+            top: 3px;
+            width: 100px;
+            text-align: right;
+
+            &>span {
+              color: #ff4d4f;
+            }
+          }
+
+          .formRight {
+            width: calc(100% - 100px);
+          }
+        }
+
+        .A4Ebtn {
+          position: absolute;
+          z-index: 10;
+          left: 1200px;
+          top: 50%;
+          transform: translateY(-50%);
+        }
+      }
+    }
+  }
+}

+ 238 - 0
src/pages/A4store/A3Edit/index.tsx

@@ -0,0 +1,238 @@
+import React, { useCallback, useEffect, useRef, useState } from "react";
+import styles from "./index.module.scss";
+import {
+  Button,
+  DatePicker,
+  Form,
+  FormInstance,
+  Input,
+  InputNumber,
+  Select,
+} from "antd";
+import MyPopconfirm from "@/components/MyPopconfirm";
+import { MessageFu } from "@/utils/message";
+import dayjs from "dayjs";
+import { A4_APIgetInfo, A4_APIsave } from "@/store/action/A4store";
+import ZupOne from "@/components/ZupOne";
+import ZRichText from "@/components/ZRichText";
+
+type Props = {
+  editInfo: { id: number; type: "新增" | "编辑" };
+  closeFu: () => void;
+  upTableFu: () => void;
+  addTableFu: () => void;
+};
+
+function A3Edit({ editInfo, closeFu, upTableFu, addTableFu }: Props) {
+  // 表单的ref
+  const FormBoxRef = useRef<FormInstance>(null);
+
+  // 文件的code码
+  const [dirCode, setDirCode] = useState("");
+
+  // 封面图的ref
+  const ZupOneRef1 = useRef<any>(null);
+  // 富文本的ref
+  const ZRichTextRef = useRef<any>(null);
+
+  const getInfoFu = useCallback(async (id: number) => {
+    const res = await A4_APIgetInfo(id);
+    if (res.code === 0) {
+      const data = res.data;
+
+      ZRichTextRef.current?.ritxtShowFu(data.rtf);
+
+      setDirCode(data.dirCode);
+
+      FormBoxRef.current?.setFieldsValue({
+        ...data,
+        myTime: dayjs(data.releaseDate),
+      });
+
+      // 设置封面图
+      ZupOneRef1.current?.setFileComFileFu({
+        fileName: "",
+        filePath: data.thumb,
+      });
+    }
+  }, []);
+
+  useEffect(() => {
+    if (editInfo.id > 0) {
+      // 编辑
+      getInfoFu(editInfo.id);
+    } else {
+      setDirCode(Date.now() + "");
+      // 新增
+      FormBoxRef.current?.setFieldsValue({
+        myTime: dayjs(Date.now()),
+        isEnabled: 1,
+      });
+    }
+  }, [editInfo.id, getInfoFu]);
+
+  // 附件 是否 已经点击过确定
+  const [fileCheck, setFileCheck] = useState(false);
+
+  // 没有通过校验
+  const onFinishFailed = useCallback(() => {
+    setFileCheck(true);
+  }, []);
+
+  //  通过校验点击确定
+  const onFinish = useCallback(
+    async (values: any) => {
+      setFileCheck(true);
+
+      const coverUrl1 = ZupOneRef1.current?.fileComFileResFu();
+      // 没有传 封面图
+      if (!coverUrl1.filePath) return;
+      // 发布日期
+      const releaseDate = dayjs(values.myTime).format("YYYY-MM-DD");
+
+      const rtf = ZRichTextRef.current?.fatherBtnOkFu();
+
+      const obj = {
+        ...values,
+        id: editInfo.id > 0 ? editInfo.id : null,
+        releaseDate,
+        thumb: coverUrl1.filePath,
+        rtf: rtf.val,
+      };
+      const res = await A4_APIsave(obj);
+      if (res.code === 0) {
+        MessageFu.success(editInfo.id > 0 ? "编辑成功!" : "新增成功!");
+        editInfo.id > 0 ? upTableFu() : addTableFu();
+        closeFu();
+      }
+    },
+    [addTableFu, closeFu, editInfo.id, upTableFu]
+  );
+
+  return (
+    <div className={styles.A3Edit}>
+      <div className="A3Emain">
+        <Form
+          ref={FormBoxRef}
+          name="basic"
+          labelCol={{ span: 3 }}
+          onFinish={onFinish}
+          onFinishFailed={onFinishFailed}
+          autoComplete="off"
+          scrollToFirstError
+        >
+          <Form.Item
+            label="奖品名称"
+            name="name"
+            rules={[{ required: true, message: "请输入奖品名称!" }]}
+            getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
+          >
+            <Input maxLength={20} showCount placeholder="请输入内容" />
+          </Form.Item>
+
+          <Form.Item
+            label="所需爱心币"
+            name="score"
+            rules={[{ required: true, message: "请输入所需爱心币!" }]}
+          >
+            <InputNumber
+              min={1}
+              max={99999}
+              precision={0}
+              placeholder="请输入数字,1~99999"
+            />
+          </Form.Item>
+
+          <Form.Item
+            label="库存"
+            name="stock"
+            rules={[{ required: true, message: "请输入库存!" }]}
+          >
+            <InputNumber
+              min={1}
+              max={99999}
+              precision={0}
+              placeholder="请输入数字,1~99999"
+            />
+          </Form.Item>
+
+          <Form.Item
+            label="登记日期"
+            name="myTime"
+            rules={[{ required: true, message: "请选择发布日期!" }]}
+          >
+            <DatePicker />
+          </Form.Item>
+
+          <Form.Item
+            label="上架状态"
+            name="isEnabled"
+            rules={[{ required: true, message: "请选择上架状态!" }]}
+          >
+            <Select
+              placeholder="请选择"
+              style={{ width: 200 }}
+              options={[
+                { value: 1, label: "上架" },
+                { value: 0, label: "下架" },
+              ]}
+            />
+          </Form.Item>
+          {/* 封面 */}
+          <div className="formRow">
+            <div className="formLeft">
+              <span>* </span>
+              封面图:
+            </div>
+            <div className="formRight">
+              <ZupOne
+                ref={ZupOneRef1}
+                isLook={false}
+                fileCheck={fileCheck}
+                size={2}
+                dirCode={dirCode}
+                myUrl="cms/prize/upload"
+                format={["image/jpeg", "image/png"]}
+                formatTxt="png、jpg和jpeg"
+                checkTxt="请上传封面图"
+                upTxt="最多1张"
+                myType="thumb"
+              />
+            </div>
+          </div>
+
+          {/* 富文本 */}
+          <div className="formRow">
+            <div className="formLeft">
+              <span> </span>
+              产品简介:
+            </div>
+            <div className="formRight">
+              <ZRichText
+                check={false}
+                dirCode={dirCode}
+                isLook={false}
+                ref={ZRichTextRef}
+                myUrl="cms/prize/upload"
+              />
+            </div>
+          </div>
+
+          {/* 确定和取消按钮 */}
+          <Form.Item className="A4Ebtn">
+            <Button type="primary" htmlType="submit">
+              提交
+            </Button>
+            <br />
+            <br />
+            <MyPopconfirm txtK="取消" onConfirm={closeFu} />
+          </Form.Item>
+        </Form>
+      </div>
+    </div>
+  );
+}
+
+const MemoA3Edit = React.memo(A3Edit);
+
+export default MemoA3Edit;

+ 92 - 0
src/pages/A4store/A3set.tsx

@@ -0,0 +1,92 @@
+import React, { useCallback, useEffect, useState } from "react";
+import styles from "./index.module.scss";
+import { Button, Modal, Select } from "antd";
+import MyPopconfirm from "@/components/MyPopconfirm";
+import TextArea from "antd/es/input/TextArea";
+import { A4_APIgetInfoSet, A4_APIsetInfoSet } from "@/store/action/A4store";
+import { MessageFu } from "@/utils/message";
+
+type Props = {
+  closeFu: () => void;
+};
+
+function A3set({ closeFu }: Props) {
+  const [isEnabled, setIsEnabled] = useState(1);
+  const [rtf, setRtf] = useState("");
+
+  const getInfoSetFu = useCallback(async () => {
+    const res = await A4_APIgetInfoSet();
+    if (res.code === 0) {
+      setIsEnabled(res.data.display);
+      setRtf(res.data.rtf);
+      // console.log(123, res);
+    }
+  }, []);
+
+  useEffect(() => {
+    getInfoSetFu();
+  }, [getInfoSetFu]);
+
+  // 点击确定
+  const btnOkFu = useCallback(async () => {
+    const obj = { isEnabled, rtf };
+    const res = await A4_APIsetInfoSet(obj);
+    if (res.code === 0) {
+      MessageFu.success("编辑成功!");
+      closeFu();
+    }
+  }, [closeFu, isEnabled, rtf]);
+
+  return (
+    <Modal
+      wrapClassName={styles.A3set}
+      open={true}
+      title="商城设置"
+      footer={
+        [] // 设置footer为空,去掉 取消 确定默认按钮
+      }
+    >
+      <div className="A3Smain">
+        <div className="A3Srow">
+          <div className="A3Srow1">客服联系方式:</div>
+          <div className="A3Srow2">
+            <TextArea
+              value={rtf}
+              onChange={(e) => setRtf(e.target.value)}
+              placeholder="请输入内容,用户在有疑问时,将进行咨询"
+              showCount
+              maxLength={50}
+            />
+          </div>
+        </div>
+
+        <div className="A3Srow">
+          <div className="A3Srow1">商城状态:</div>
+          <div className="A3Srow2">
+            <Select
+              style={{ width: 120 }}
+              value={isEnabled}
+              onChange={(e) => setIsEnabled(e)}
+              options={[
+                { value: 1, label: "关闭" },
+                { value: 0, label: "开启" },
+              ]}
+            />
+          </div>
+        </div>
+
+        <div className="A3Sbtn">
+          <Button type="primary" onClick={btnOkFu}>
+            提交
+          </Button>
+          &emsp;
+          <MyPopconfirm txtK="取消" onConfirm={closeFu} />
+        </div>
+      </div>
+    </Modal>
+  );
+}
+
+const MemoA3set = React.memo(A3set);
+
+export default MemoA3set;

+ 70 - 0
src/pages/A4store/index.module.scss

@@ -0,0 +1,70 @@
+.A4store {
+  border-radius: 10px;
+  background-color: #fff;
+  padding: 15px 0;
+  position: relative;
+
+  :global {
+    .A4top {
+      padding: 0 24px;
+      display: flex;
+      justify-content: space-between;
+    }
+
+    .A4tableBox {
+      border-radius: 10px;
+      overflow: hidden;
+      margin-top: 15px;
+      height: calc(100% - 32px);
+    }
+  }
+}
+
+// 商城设置
+.A3set {
+  :global {
+    .ant-modal-close {
+      display: none;
+    }
+
+    .ant-modal {
+      width: 800px !important;
+    }
+
+    .ant-modal-body {
+      border-top: 1px solid #ccc;
+    }
+
+    .A3Smain {
+      padding-top: 15px;
+
+      .A3Srow {
+        display: flex;
+        margin-bottom: 24px;
+
+        .A3Srow1 {
+          position: relative;
+          top: 3px;
+          width: 110px;
+          text-align: right;
+
+          &>span {
+            color: #ff4d4f;
+          }
+        }
+
+        .A3Srow2 {
+          width: calc(100% - 110px);
+
+          .ant-input-number {
+            width: 100%;
+          }
+        }
+      }
+
+      .A3Sbtn {
+        text-align: center;
+      }
+    }
+  }
+}

+ 137 - 0
src/pages/A4store/index.tsx

@@ -0,0 +1,137 @@
+import React, { useCallback, useEffect, useMemo, useState } from "react";
+import styles from "./index.module.scss";
+import { useDispatch, useSelector } from "react-redux";
+import { A4_APIgetList } from "@/store/action/A4store";
+import { RootState } from "@/store";
+import { A4tableType } from "@/types";
+import { Button } from "antd";
+import MyPopconfirm from "@/components/MyPopconfirm";
+import MyTable from "@/components/MyTable";
+import { A4tableC } from "@/utils/tableData";
+import A3set from "./A3set";
+import A3Edit from "./A3Edit";
+function A4store() {
+  const dispatch = useDispatch();
+
+  const [fromData, setFromData] = useState({
+    pageNum: 1,
+    pageSize: 10,
+  });
+
+  const getListFu = useCallback(() => {
+    dispatch(A4_APIgetList(fromData));
+  }, [dispatch, fromData]);
+
+  useEffect(() => {
+    getListFu();
+  }, [getListFu]);
+
+  // 点击重置
+  const resetSelectFu = useCallback(() => {
+    setFromData({
+      pageNum: 1,
+      pageSize: 10,
+    });
+  }, []);
+
+  const tableInfo = useSelector((state: RootState) => state.A4store.tableInfo);
+
+  // 点击删除
+  const delTableFu = useCallback(async (id: number) => {}, []);
+
+  const tableLastBtn = useMemo(() => {
+    return [
+      {
+        title: "操作",
+        render: (item: A4tableType) => (
+          <>
+            <Button
+              size="small"
+              type="text"
+              onClick={() => setEditInfo({ id: item.id, type: "编辑" })}
+            >
+              编辑
+            </Button>
+            <MyPopconfirm txtK="删除" onConfirm={() => delTableFu(item.id)} />
+          </>
+        ),
+      },
+    ];
+  }, [delTableFu]);
+
+  const [editInfo, setEditInfo] = useState<{
+    id: number;
+    type: "" | "新增" | "编辑" | "商城设置";
+  }>({ id: 0, type: "" });
+
+  const topTit = useMemo(() => {
+    let txt = "";
+    if (editInfo.type !== "商城设置") txt = editInfo.type;
+    return txt;
+  }, [editInfo.type]);
+
+  return (
+    <div className={styles.A4store}>
+      <div className="pageTitle">
+        积分商城
+        {topTit ? ` - ${topTit}` : ""}
+      </div>
+      {/* 顶部筛选 */}
+      <div className="A4top">
+        <div></div>
+        <div>
+          <Button
+            type="primary"
+            onClick={() => setEditInfo({ id: -1, type: "商城设置" })}
+          >
+            商城设置
+          </Button>
+          &emsp;
+          <Button
+            type="primary"
+            onClick={() => setEditInfo({ id: -1, type: "新增" })}
+          >
+            新增
+          </Button>
+        </div>
+      </div>
+
+      {/* 表格主体 */}
+      <div className="A4tableBox">
+        <MyTable
+          yHeight={640}
+          list={tableInfo.list}
+          columnsTemp={A4tableC}
+          lastBtn={tableLastBtn}
+          pageNum={fromData.pageNum}
+          pageSize={fromData.pageSize}
+          total={tableInfo.total}
+          onChange={(pageNum, pageSize) =>
+            setFromData({ ...fromData, pageNum, pageSize })
+          }
+        />
+      </div>
+
+      {/* 商城设置 */}
+      {editInfo.id ? (
+        editInfo.type === "商城设置" ? (
+          <A3set closeFu={() => setEditInfo({ id: 0, type: "" })} />
+        ) : (
+          <A3Edit
+            editInfo={{
+              id: editInfo.id,
+              type: editInfo.type as "新增" | "编辑",
+            }}
+            closeFu={() => setEditInfo({ id: 0, type: "" })}
+            upTableFu={() => getListFu()}
+            addTableFu={() => resetSelectFu()}
+          />
+        )
+      ) : null}
+    </div>
+  );
+}
+
+const MemoA4store = React.memo(A4store);
+
+export default MemoA4store;

+ 14 - 0
src/pages/Layout/data.ts

@@ -20,6 +20,20 @@ const tabLeftArr: RouterType = [
         Com: React.lazy(() => import("../A2integral")),
         done: true,
       },
+      {
+        id: "1.3",
+        name: "积分记录",
+        path: "/record",
+        Com: React.lazy(() => import("../A3record")),
+        done: true,
+      },
+      {
+        id: "1.4",
+        name: "积分商城",
+        path: "/store",
+        Com: React.lazy(() => import("../A4store")),
+        done: true,
+      },
     ],
   },
   {

+ 19 - 12
src/pages/Layout/index.tsx

@@ -29,6 +29,11 @@ function Layout() {
   // 左侧菜单 和 路由 信息
   const [list, setList] = useState([] as RouterType);
 
+  // useEffect(()=>{
+  //   console.log(123,list);
+    
+  // },[list])
+
   useEffect(() => {
     const arr = [...tabLeftArr];
 
@@ -125,18 +130,20 @@ function Layout() {
             >
               {/* 这个项目没有一级目录 */}
               {/* <div className="layoutLRowBoxTxt">{v.name}</div> */}
-              {v.son.map((v2) => (
-                <div
-                  key={v2.id}
-                  className={classNames(
-                    "layoutLRowBoxRow",
-                    path === v2.path ? "active" : ""
-                  )}
-                  onClick={() => pathCutFu(v2.path)}
-                >
-                  {v2.name}
-                </div>
-              ))}
+              {v.son
+                .filter((c2) => c2.done)
+                .map((v2) => (
+                  <div
+                    key={v2.id}
+                    className={classNames(
+                      "layoutLRowBoxRow",
+                      path === v2.path ? "active" : ""
+                    )}
+                    onClick={() => pathCutFu(v2.path)}
+                  >
+                    {v2.name}
+                  </div>
+                ))}
             </div>
           ))}
         </div>

+ 26 - 0
src/store/action/A2integral.ts

@@ -0,0 +1,26 @@
+import http from "@/utils/http";
+import { AppDispatch } from "..";
+import { A2tableType } from "@/types";
+/**
+ * 获取 积分管理(用户活跃、爱心林场) 列表
+ */
+export const A2_APIgetList = () => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.get("cms/rule/getList");
+    if (res.code === 0) {
+      const list: A2tableType[] = res.data;
+      const obj = {
+        list1: list.filter((v) => v.type === "user"),
+        list2: list.filter((v) => v.type === "game"),
+      };
+      dispatch({ type: "A2/getList", payload: obj });
+    }
+  };
+};
+
+/**
+ * 编辑爱心币和天数
+ */
+export const A2_APIsave = (data:any) => {
+  return http.post('cms/rule/save',data);
+};

+ 17 - 0
src/store/action/A3record.ts

@@ -0,0 +1,17 @@
+import http from "@/utils/http";
+import { AppDispatch } from "..";
+/**
+ * 获取 积分记录 列表
+ */
+export const A3_APIgetList = (data: any) => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post("cms/pointLog/pageList", data);
+    if (res.code === 0) {
+      const obj = {
+        list: res.data.records,
+        total: res.data.total,
+      };
+      dispatch({ type: "A3/getList", payload: obj });
+    }
+  };
+};

+ 45 - 0
src/store/action/A4store.ts

@@ -0,0 +1,45 @@
+import http from "@/utils/http";
+import { AppDispatch } from "..";
+/**
+ * 获取 积分商城 列表
+ */
+export const A4_APIgetList = (data: any) => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post("cms/prize/pageList", data);
+    if (res.code === 0) {
+      const obj = {
+        list: res.data.records,
+        total: res.data.total,
+      };
+      dispatch({ type: "A4/getList", payload: obj });
+    }
+  };
+};
+
+/**
+ * 获取商城设置详情
+ */
+export const A4_APIgetInfoSet = () => {
+  return http.post("cms/prize/getRuleConfig");
+};
+
+/**
+ * 商城设置编辑
+ */
+export const A4_APIsetInfoSet = (data: any) => {
+  return http.post("cms/prize/editRule", data);
+};
+
+/**
+ * 编辑获取详情
+ */
+export const A4_APIgetInfo = (id: number) => {
+  return http.get(`cms/prize/detail/${id}`);
+};
+
+/**
+ * 新增、修改
+ */
+export const A4_APIsave = (data: any) => {
+  return http.post("cms/prize/save", data);
+};

+ 1 - 1
src/store/reducer/A1wxuser.ts

@@ -15,7 +15,7 @@ type Props = {
   payload: { list: A1tableType[]; total: number };
 };
 
-// 频道 reducer
+// reducer
 export default function Reducer(state = initState, action: Props) {
   switch (action.type) {
     // 获取列表数据

+ 28 - 0
src/store/reducer/A2integral.ts

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

+ 28 - 0
src/store/reducer/A3record.ts

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

+ 28 - 0
src/store/reducer/A4store.ts

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

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

@@ -4,6 +4,9 @@ import { combineReducers } from "redux";
 // 导入 登录 模块的 reducer
 import A0Layout from "./layout";
 import A1wxuser from "./A1wxuser";
+import A2integral from "./A2integral";
+import A3record from "./A3record";
+import A4store from "./A4store";
 import Z1user from "./Z1user";
 import Z2log from "./Z2log";
 
@@ -11,6 +14,9 @@ import Z2log from "./Z2log";
 const rootReducer = combineReducers({
   A0Layout,
   A1wxuser,
+  A2integral,
+  A3record,
+  A4store,
   Z1user,
   Z2log,
 });

+ 20 - 0
src/types/api/A2integral.d.ts

@@ -0,0 +1,20 @@
+export type A2tableType = {
+  createTime: string;
+  creatorName: string;
+  day: number;
+  description: string;
+  id: number;
+  name: string;
+  rtf: string;
+  score: number;
+  type: "user" | "game";
+  updateTime: string;
+}
+
+export type A2editInfoType = {
+  id: number;
+  type: "user" | "game";
+  name:string
+  day: number;
+  score: number;
+};

+ 13 - 0
src/types/api/A3record.d.ts

@@ -0,0 +1,13 @@
+export type A3tableType = {
+  createTime: string;
+  creatorName: string;
+  cycle: number;
+  day: number;
+  description: string;
+  id: number;
+  name: string;
+  rtf: string;
+  score: number;
+  type: string;
+  updateTime: string;
+};

+ 13 - 0
src/types/api/A4store.d.ts

@@ -0,0 +1,13 @@
+export type A4tableType={
+	createTime: string;
+	creatorId: number;
+	creatorName: string;
+	id: number;
+	isEnabled: number;
+	name: string;
+	rtf: string;
+	score: number;
+	stock: number;
+	thumb: string;
+	updateTime: string;
+}

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

@@ -1,4 +1,7 @@
 export * from './api/layot'
 export * from './api/A1wxuser'
+export * from './api/A2integral'
+export * from './api/A3record'
+export * from './api/A4store'
 export * from './api/Z1user'
 export * from './api/Z2log'

+ 1 - 1
src/utils/http.ts

@@ -29,7 +29,7 @@ declare module "axios" {
 // 创建 axios 实例
 const http = axios.create({
   baseURL: `${baseURL}${baseFlag ? "/api/" : ""}`,
-  timeout: 5000,
+  timeout: 10000,
 });
 
 let axajInd = 0;

+ 28 - 18
src/utils/tableData.ts

@@ -27,19 +27,37 @@ export const A1tableClook = [
   ["txt", "时间", "createTime"],
   ["txt", "类型", "type"],
   ["txt", "爱心币", "score"],
+  ["text", "说明", "description", 50],
+];
+
+export const A2tableC1 = [
+  ["txt", "行为", "name"],
+  ["txt", "奖励爱心币", "score"],
   ["txt", "说明", "description"],
 ];
 
-// export const A5tableC = [
-//   ["txt", "名称", "name"],
-//   ["img", "封面", "thumb"],
-//   ["txt", "分类", "dictType"],
-//   ["txt", "时代", "dictAge"],
-//   ["txt", "级别", "dictLevel"],
-//   ["txt", "尺寸", "dictSize"],
-//   ["txt", "点赞", "pcs"],
-//   ["txt", "发布日期", "releaseDate"],
-// ];
+export const A2tableC2 = [
+  ["txt", "动植物", "name"],
+  ["txt", "成熟周期(天)", "cycle"],
+  ["txt", "奖励爱心币", "score"],
+  ["txt", "说明", "description"],
+];
+
+export const A3tableC = [
+  ["txt", "时间", "createTime"],
+  ["txt", "用户名", "creatorName"],
+  ["txt", "类型", "type"],
+  ["text", "说明", "description", 50],
+];
+
+export const A4tableC = [
+  ["txt", "奖品名称", "name"],
+  ["img", "封面", "thumb"],
+  ["txt", "所需爱心币", "score"],
+  ["txt", "库存", "stock"],
+  ["txt", "登记日期", "createTime"],
+  ["txtChange", "状态", "isEnabled", { 0: "下架", 1: "上架" }],
+];
 
 export const Z1tableC = [
   ["txt", "用户名", "userName"],
@@ -56,11 +74,3 @@ export const Z2tableC = [
   ["txt", "操作模块", "type"],
   ["txt", "操作事件", "description"],
 ];
-
-// export const A6QtableC = [
-//   ["txt", "标题", "name"],
-//   ["txt", "题目数量", "pcsQuestion"],
-//   ["txt", "已收集份数", "pcsGather"],
-//   ["txt", "发布日期", "publishDate"],
-//   ["txtChange", "问卷状态", "display",{1:'开启',0:'关闭'}],
-// ];