浏览代码

feat: information and banner

chenlei 1 年之前
父节点
当前提交
a4e2d1b4fc

+ 3 - 3
package.json

@@ -78,8 +78,8 @@
     "workbox-webpack-plugin": "^6.4.1"
   },
   "scripts": {
-    "start": "cross-env REACT_APP_API_URL=https://sit-shgybwg.4dage.com node scripts/start.js",
-    "build": "cross-env PUBLIC_URL=./ REACT_APP_API_URL=https://sit-shgybwg.4dage.com node scripts/build.js"
+    "start": "cross-env REACT_APP_API_URL=http://192.168.20.61:8059 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"
   },
   "eslintConfig": {
     "extends": [
@@ -159,4 +159,4 @@
       "react-app"
     ]
   }
-}
+}

+ 16 - 0
src/api/banner.ts

@@ -0,0 +1,16 @@
+import { requestByGet, requestByPost } from "@dage/service";
+
+export const bannerApi = {
+  getList() {
+    return requestByGet("/api/cms/poster/getList");
+  },
+  save(data: any) {
+    return requestByPost("/api/cms/poster/save", data);
+  },
+  delete(id: number) {
+    return requestByGet(`/api/cms/poster/remove/${id}`);
+  },
+  getDetail(id: string) {
+    return requestByGet(`/api/cms/poster/detail/${id}`);
+  },
+};

+ 2 - 0
src/api/index.ts

@@ -15,3 +15,5 @@ export const updatePwd = (data: UpdatePwdRequest) => {
 
 export * from "./log";
 export * from "./user";
+export * from "./banner";
+export * from "./information";

+ 16 - 0
src/api/information.ts

@@ -0,0 +1,16 @@
+import { requestByGet, requestByPost } from "@dage/service";
+
+export const informationApi = {
+  getList(data: any) {
+    return requestByPost("/api/cms/news/pageList", data);
+  },
+  save(data: any) {
+    return requestByPost("/api/cms/news/save", data);
+  },
+  delete(id: number) {
+    return requestByGet(`/api/cms/news/remove/${id}`);
+  },
+  getDetail(id: string) {
+    return requestByGet(`/api/cms/news/detail/${id}`);
+  },
+};

二进制
src/assets/images/menu.png


二进制
src/assets/images/topic.jpg


+ 11 - 3
src/components/Z_RichText/index.tsx

@@ -24,14 +24,19 @@ import { forwardRef, useImperativeHandle } from "react";
 import { message } from "antd";
 
 type Props = {
-  check: boolean; //表单校验,为fasle表示不校验
+  check?: boolean; //表单校验,为fasle表示不校验
   dirCode: string; //文件的code码
   isLook: boolean; //是否是查看进来
   ref: any; //当前自己的ref,给父组件调用
   myUrl: string; //上传的api地址
+  value?: any;
+  onChange?(v: any): void;
 };
 
-function RichText({ check, dirCode, isLook, myUrl }: Props, ref: any) {
+function RichText(
+  { check, dirCode, isLook, myUrl, onChange }: Props,
+  ref: any
+) {
   const [messageApi] = message.useMessage();
 
   // 添加 上传 图片的dom
@@ -173,7 +178,10 @@ function RichText({ check, dirCode, isLook, myUrl }: Props, ref: any) {
           readOnly={isLook}
           placeholder="请输入内容"
           value={editorValue}
-          onChange={(e: any) => setEditorValue(e)}
+          onChange={(e: any) => {
+            setEditorValue(e);
+            onChange?.(e);
+          }}
           imageControls={["remove"]}
         />
       </div>

+ 50 - 7
src/pages/Banner/create-or-edit/index.tsx

@@ -1,11 +1,13 @@
+import { bannerApi } from "@/api";
 import { FormPageFooter, MemoSpinLoding } from "@/components";
 import {
   DageUpload,
   DageUploadConsumer,
   DageUploadProvider,
 } from "@dage/pc-components";
+import { dayjs, formatDate } from "@dage/utils";
 import { DatePicker, Form, FormInstance } from "antd";
-import { useCallback, useRef, useState } from "react";
+import { useCallback, useEffect, useRef, useState } from "react";
 import { useNavigate, useParams } from "react-router-dom";
 
 export default function BannerCreateOrEditPage() {
@@ -14,6 +16,29 @@ export default function BannerCreateOrEditPage() {
   const params = useParams();
   const [loading, setLoading] = useState(false);
 
+  const getDetail = useCallback(async () => {
+    setLoading(true);
+    try {
+      const data = await bannerApi.getDetail(params.id as string);
+      formRef.current?.setFieldsValue({
+        publishDate: dayjs(data.publishDate),
+        fileIds: [
+          {
+            uid: data.id,
+            url: `${process.env.REACT_APP_API_URL}${process.env.REACT_APP_IMG_PUBLIC}${data.filePath}`,
+            name: data.filePath,
+          },
+        ],
+      });
+    } finally {
+      setLoading(false);
+    }
+  }, [params.id]);
+
+  useEffect(() => {
+    !!params.id && getDetail();
+  }, [getDetail, params.id]);
+
   const handleCancel = useCallback(() => {
     navigate(-1);
   }, [navigate]);
@@ -21,12 +46,24 @@ export default function BannerCreateOrEditPage() {
   const handleSubmit = useCallback(async () => {
     if (!(await formRef.current?.validateFields())) return;
 
-    const { banner = [], ...rest } = formRef.current?.getFieldsValue();
+    const {
+      fileIds = [],
+      publishDate,
+      ...rest
+    } = formRef.current?.getFieldsValue();
 
     if (params.id) {
       rest.id = params.id;
     }
 
+    await bannerApi.save({
+      ...rest,
+      publishDate: formatDate(publishDate),
+      filePath: fileIds[0].response
+        ? fileIds[0].response.filePath
+        : fileIds[0].name,
+    });
+
     handleCancel();
   }, [handleCancel, params]);
 
@@ -37,16 +74,22 @@ export default function BannerCreateOrEditPage() {
         <DageUploadConsumer>
           {(data) => (
             <>
-              <Form ref={formRef} labelCol={{ span: 2 }}>
+              <Form
+                ref={formRef}
+                labelCol={{ span: 2 }}
+                initialValues={{
+                  publishDate: dayjs(),
+                }}
+              >
                 <Form.Item
                   label="海报"
-                  name="banner"
+                  name="fileIds"
                   rules={[{ required: true, message: "请上传海报" }]}
                 >
                   <DageUpload
                     tips="支持png、jpg和jpeg格式;最多1张,最大20M"
                     action={
-                      process.env.REACT_APP_API_URL + "/api/cms/history/upload"
+                      process.env.REACT_APP_API_URL + "/api/cms/poster/upload"
                     }
                     maxSize={20}
                     maxCount={1}
@@ -55,10 +98,10 @@ export default function BannerCreateOrEditPage() {
 
                 <Form.Item
                   label="发布日期"
-                  name="date"
+                  name="publishDate"
                   rules={[{ required: true, message: "请选择日期" }]}
                 >
-                  <DatePicker className="w220" />
+                  <DatePicker className="w220" format="YYYY-MM-DD" />
                 </Form.Item>
               </Form>
 

+ 42 - 31
src/pages/Banner/index.tsx

@@ -1,52 +1,72 @@
+import { bannerApi } from "@/api";
 import { DageTableActions } from "@dage/pc-components";
-import { Button, Table } from "antd";
-import { useCallback, useMemo, useState } from "react";
+import { Button, Image, Table } from "antd";
+import { useMemo, useState, useEffect, useCallback } from "react";
 import { useNavigate } from "react-router-dom";
 
-const DEFAULT_PARAMS = {
-  pageNum: 1,
-  pageSize: 20,
-};
-
 export default function BannerPage() {
   const navigate = useNavigate();
   const [list, setList] = useState<[]>([]);
-  const [total, setTotal] = useState(0);
   const [loading, setLoading] = useState(false);
-  const [params, setParams] = useState({
-    ...DEFAULT_PARAMS,
-  });
 
-  const paginationChange = useCallback(
-    () => (pageNum: number, pageSize: number) => {
-      setParams({ ...params, pageNum, pageSize });
-    },
-    [params]
-  );
+  useEffect(() => {
+    getList();
+  }, []);
+
+  const getList = async () => {
+    setLoading(true);
+    try {
+      const data = await bannerApi.getList();
+      setList(data);
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  const handleDelete = useCallback(async (id: number) => {
+    await bannerApi.delete(id);
+    getList();
+  }, []);
 
   const COLUMNS = useMemo(() => {
     return [
       {
         title: "海报",
-        dataIndex: "userName",
+        render: (item: any) => {
+          return (
+            <Image
+              height={100}
+              src={`${process.env.REACT_APP_API_URL}${process.env.REACT_APP_IMG_PUBLIC}${item.filePath}`}
+            />
+          );
+        },
       },
       {
         title: "发布日期",
-        dataIndex: "nickName",
+        dataIndex: "publishDate",
       },
       {
         title: "操作",
         render: (item: any) => {
-          return <DageTableActions onEdit={() => {}} onDelete={() => {}} />;
+          return (
+            <DageTableActions
+              onEdit={() => navigate(`/banner/edit/${item.id}`)}
+              onDelete={handleDelete.bind(undefined, item.id)}
+            />
+          );
         },
       },
     ];
-  }, []);
+  }, [handleDelete, navigate]);
 
   return (
     <div>
       <div style={{ textAlign: "right" }}>
-        <Button type="primary" onClick={() => navigate("/banner/create")}>
+        <Button
+          type="primary"
+          disabled={list.length >= 10}
+          onClick={() => navigate("/banner/create")}
+        >
           新增
         </Button>
       </div>
@@ -57,15 +77,6 @@ export default function BannerPage() {
         dataSource={list}
         columns={COLUMNS}
         rowKey="id"
-        pagination={{
-          showQuickJumper: true,
-          position: ["bottomCenter"],
-          showSizeChanger: true,
-          current: params.pageNum,
-          pageSize: params.pageSize,
-          total,
-          onChange: paginationChange(),
-        }}
       />
     </div>
   );

+ 18 - 0
src/pages/Information/constants.ts

@@ -0,0 +1,18 @@
+export const TYPE_LIST = [
+  {
+    label: "展览",
+    value: "exhibition",
+  },
+  {
+    label: "活动",
+    value: "activity",
+  },
+  {
+    label: "新闻",
+    value: "news",
+  },
+  {
+    label: "通知",
+    value: "notice",
+  },
+];

+ 98 - 15
src/pages/Information/create-or-edit/index.tsx

@@ -5,10 +5,13 @@ import {
   DageUploadProvider,
   DageUploadType,
 } from "@dage/pc-components";
-import { DatePicker, Form, FormInstance, Input } from "antd";
-import { useCallback, useRef, useState } from "react";
+import { DatePicker, Form, FormInstance, Input, Radio } from "antd";
+import { useCallback, useEffect, useRef, useState } from "react";
 import { useNavigate, useParams } from "react-router-dom";
 import RichText from "@/components/Z_RichText";
+import { dayjs, formatDate } from "@dage/utils";
+import { informationApi } from "@/api";
+import { TYPE_LIST } from "../constants";
 
 export default function InformationCreateOrEditPage() {
   const formRef = useRef<FormInstance>(null);
@@ -16,10 +19,48 @@ export default function InformationCreateOrEditPage() {
   const params = useParams();
   const [loading, setLoading] = useState(false);
   const richTxtRef = useRef<any>(null);
-  const [check, setCheck] = useState(false);
   // 文件的code码
   const [dirCode, setDirCode] = useState("");
 
+  const getDetail = useCallback(async () => {
+    setLoading(true);
+    try {
+      setDirCode(params.id as string);
+
+      const { thumb, video, publishDate, richText, ...rest } =
+        await informationApi.getDetail(params.id as string);
+
+      formRef.current?.setFieldsValue({
+        publishDate: dayjs(publishDate),
+        fileIds: [
+          {
+            uid: thumb,
+            url: `${process.env.REACT_APP_API_URL}${process.env.REACT_APP_IMG_PUBLIC}${thumb}`,
+            name: thumb,
+          },
+        ],
+        videoFileIds: video
+          ? [
+              {
+                uid: video,
+                url: `${process.env.REACT_APP_API_URL}${process.env.REACT_APP_IMG_PUBLIC}${video}`,
+                name: video,
+              },
+            ]
+          : [],
+        ...rest,
+      });
+
+      richTxtRef.current.ritxtShowFu(richText);
+    } finally {
+      setLoading(false);
+    }
+  }, [params.id]);
+
+  useEffect(() => {
+    !!params.id && getDetail();
+  }, [getDetail, params.id]);
+
   const handleCancel = useCallback(() => {
     navigate(-1);
   }, [navigate]);
@@ -27,12 +68,36 @@ export default function InformationCreateOrEditPage() {
   const handleSubmit = useCallback(async () => {
     if (!(await formRef.current?.validateFields())) return;
 
-    const { banner = [], ...rest } = formRef.current?.getFieldsValue();
+    const { val, flag } = richTxtRef.current.fatherBtnOkFu();
+    const {
+      fileIds = [],
+      videoFileIds = [],
+      publishDate,
+      richText,
+      ...rest
+    } = formRef.current?.getFieldsValue();
+
+    if (flag) return;
 
     if (params.id) {
       rest.id = params.id;
     }
 
+    if (videoFileIds[0]) {
+      rest.video = videoFileIds[0].response
+        ? videoFileIds[0].response.filePath
+        : videoFileIds[0].name;
+    }
+
+    await informationApi.save({
+      ...rest,
+      publishDate: formatDate(publishDate),
+      richText: val,
+      thumb: fileIds[0].response
+        ? fileIds[0].response.filePath
+        : fileIds[0].name,
+    });
+
     handleCancel();
   }, [handleCancel, params]);
 
@@ -43,10 +108,16 @@ export default function InformationCreateOrEditPage() {
         <DageUploadConsumer>
           {(data) => (
             <>
-              <Form ref={formRef} labelCol={{ span: 2 }}>
+              <Form
+                ref={formRef}
+                labelCol={{ span: 2 }}
+                initialValues={{
+                  publishDate: dayjs(),
+                }}
+              >
                 <Form.Item
                   label="标题"
-                  name="title"
+                  name="name"
                   rules={[{ required: true, message: "请输入内容" }]}
                 >
                   <Input
@@ -57,45 +128,57 @@ export default function InformationCreateOrEditPage() {
                   />
                 </Form.Item>
                 <Form.Item
+                  label="类型"
+                  name="type"
+                  rules={[{ required: true, message: "请选择" }]}
+                >
+                  <Radio.Group>
+                    {TYPE_LIST.map((item) => (
+                      <Radio.Button key={item.value} value={item.value}>
+                        {item.label}
+                      </Radio.Button>
+                    ))}
+                  </Radio.Group>
+                </Form.Item>
+                <Form.Item
                   label="正文"
-                  name="content"
+                  name="richText"
                   rules={[{ required: true, message: "请输入正文" }]}
                 >
                   <RichText
-                    myUrl="cms/goods/upload"
+                    myUrl="/api/cms/news/upload"
                     ref={richTxtRef}
-                    check={check}
                     dirCode={dirCode}
                     isLook={false}
                   />
                 </Form.Item>
                 <Form.Item
                   label="发布日期"
-                  name="date"
+                  name="publishDate"
                   rules={[{ required: true, message: "请选择发布日期" }]}
                 >
-                  <DatePicker className="w220" />
+                  <DatePicker className="w220" format="YYYY-MM-DD" />
                 </Form.Item>
                 <Form.Item
                   label="封面图"
-                  name="banner"
+                  name="fileIds"
                   rules={[{ required: true, message: "请上传封面图" }]}
                 >
                   <DageUpload
                     tips="支持png、jpg和jpeg格式;最多1张,最大20M"
                     action={
-                      process.env.REACT_APP_API_URL + "/api/cms/history/upload"
+                      process.env.REACT_APP_API_URL + "/api/cms/news/upload"
                     }
                     maxSize={20}
                     maxCount={1}
                   />
                 </Form.Item>
-                <Form.Item label="视频" name="video">
+                <Form.Item label="视频" name="videoFileIds">
                   <DageUpload
                     dType={DageUploadType.VIDEO}
                     tips="支持avi,mp4,mkv,wmv等格式;最大200M,最多1个"
                     action={
-                      process.env.REACT_APP_API_URL + "/api/cms/history/upload"
+                      process.env.REACT_APP_API_URL + "/api/cms/news/upload"
                     }
                     maxSize={200}
                     maxCount={1}

+ 57 - 33
src/pages/Information/index.tsx

@@ -1,31 +1,16 @@
 import { Button, Form, FormInstance, Input, Radio, Table } from "antd";
-import { useCallback, useMemo, useRef, useState } from "react";
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
 import { debounce } from "lodash";
 import { DageTableActions } from "@dage/pc-components";
 import { useNavigate } from "react-router-dom";
-
-const TYPE_LIST = [
-  {
-    label: "展览",
-    value: 0,
-  },
-  {
-    label: "活动",
-    value: 1,
-  },
-  {
-    label: "新闻",
-    value: 2,
-  },
-  {
-    label: "通知",
-    value: 3,
-  },
-];
+import { informationApi } from "@/api";
+import { TYPE_LIST } from "./constants";
 
 const DEFAULT_PARAMS = {
   pageNum: 1,
   pageSize: 20,
+  searchKey: "",
+  type: TYPE_LIST[0].value,
 };
 
 export default function InformationPage() {
@@ -38,36 +23,70 @@ export default function InformationPage() {
   });
   const [total, setTotal] = useState(0);
 
+  const getList = useCallback(async () => {
+    setLoading(true);
+    try {
+      const data = await informationApi.getList(params);
+      setList(data.records);
+      setTotal(data.total);
+    } finally {
+      setLoading(false);
+    }
+  }, [params]);
+
+  useEffect(() => {
+    getList();
+  }, [getList]);
+
+  const handleDelete = useCallback(
+    async (id: number) => {
+      await informationApi.delete(id);
+      getList();
+    },
+    [getList]
+  );
+
   const COLUMNS = useMemo(() => {
     return [
       {
         title: "标题",
-        dataIndex: "title",
-      },
-      {
-        title: "正文",
-        dataIndex: "nickName",
+        dataIndex: "name",
       },
+      // {
+      //   title: "正文",
+      //   dataIndex: "richText",
+      // },
       {
         title: "发布日期",
-        dataIndex: "date",
+        dataIndex: "publishDate",
       },
       {
         title: "操作",
         render: (item: any) => {
-          return <DageTableActions onEdit={() => {}} onDelete={() => {}} />;
+          return (
+            <DageTableActions
+              onEdit={() => navigate(`/information/edit/${item.id}`)}
+              onDelete={handleDelete.bind(undefined, item.id)}
+            />
+          );
         },
       },
     ];
-  }, []);
+  }, [navigate, handleDelete]);
 
   const handleReset = useCallback(() => {
-    formRef.current?.resetFields();
+    setParams({ ...DEFAULT_PARAMS });
+    setTimeout(() => {
+      formRef.current?.resetFields();
+    });
   }, [formRef]);
 
   const debounceSearch = useMemo(
-    () => debounce((changedVal: unknown, vals: any) => {}, 500),
-    []
+    () =>
+      debounce((changedVal: unknown, vals: any) => {
+        setParams({ ...params, ...vals });
+      }, 500),
+    [params]
   );
 
   const paginationChange = useCallback(
@@ -79,7 +98,12 @@ export default function InformationPage() {
 
   return (
     <div className="information">
-      <Form ref={formRef} layout="inline" onValuesChange={debounceSearch}>
+      <Form
+        ref={formRef}
+        initialValues={params}
+        layout="inline"
+        onValuesChange={debounceSearch}
+      >
         <Form.Item name="type">
           <Radio.Group>
             {TYPE_LIST.map((item) => (
@@ -89,7 +113,7 @@ export default function InformationPage() {
             ))}
           </Radio.Group>
         </Form.Item>
-        <Form.Item label="搜索项" name="stage">
+        <Form.Item label="搜索项" name="searchKey">
           <Input className="w220" placeholder="请输入标题或正文" allowClear />
         </Form.Item>
         <Form.Item>

+ 14 - 0
src/router/index.tsx

@@ -26,6 +26,12 @@ export const DEFAULT_ADMIN_MENU: DageRouteItem[] = [
         hide: true,
         Component: React.lazy(() => import("../pages/Banner/create-or-edit")),
       },
+      {
+        path: "/banner/edit/:id",
+        title: "编辑",
+        hide: true,
+        Component: React.lazy(() => import("../pages/Banner/create-or-edit")),
+      },
     ],
   },
   {
@@ -42,6 +48,14 @@ export const DEFAULT_ADMIN_MENU: DageRouteItem[] = [
           () => import("../pages/Information/create-or-edit")
         ),
       },
+      {
+        path: "/information/edit/:id",
+        title: "编辑",
+        hide: true,
+        Component: React.lazy(
+          () => import("../pages/Information/create-or-edit")
+        ),
+      },
     ],
   },
   {