Browse Source

评论审核

shaogen1995 10 months ago
parent
commit
27daa90255

+ 62 - 61
src/components/MyTable/index.tsx

@@ -1,38 +1,38 @@
-import React, { useCallback, useEffect, useMemo } from "react";
-import styles from "./index.module.scss";
-import { Table } from "antd";
-import ImageLazy from "../ImageLazy";
+import React, { useCallback, useEffect, useMemo } from 'react'
+import styles from './index.module.scss'
+import { Table } from 'antd'
+import ImageLazy from '../ImageLazy'
 
 type Props = {
-  yHeight?: number; //设置表格的高度
-  list: any; //表格数据
-  columnsTemp: any[][]; //表格展示
-  total?: number; //总数
-  pageNum?: number;
-  pageSize?: number;
-  pagingInfo?: any | boolean;
-  onChange?: (pageNum: number, pageSize: number) => void;
-  lastBtn?: any;
-  classKey?: string; //一个组件多次使用的时候要传递,分别设置style
+  yHeight?: number //设置表格的高度
+  list: any //表格数据
+  columnsTemp: any[][] //表格展示
+  total?: number //总数
+  pageNum?: number
+  pageSize?: number
+  pagingInfo?: any | boolean
+  onChange?: (pageNum: number, pageSize: number) => void
+  lastBtn?: any
+  classKey?: string //一个组件多次使用的时候要传递,分别设置style
   // 表格简单的合并
-  merge?: { type: string; num: number; loc: "rowSpan" | "colSpan" };
+  merge?: { type: string; num: number; loc: 'rowSpan' | 'colSpan' }
   // 定制化表头
-  myTitle?: { name: string; Com: React.ReactNode };
+  myTitle?: { name: string; Com: React.ReactNode }
   // 为空的定制字段
-  isNull?: string;
-};
+  isNull?: string
+}
 
 // 表格内容定制化
 const tableComObj = (key: string, val: string[]) => {
   const obj = {
     A: (
-      <a href={val[1]} target="_blank" title={val[1]} rel="noreferrer">
+      <a href={val[1]} target='_blank' title={val[1]} rel='noreferrer'>
         {val[0]}
       </a>
-    ),
-  };
-  return Reflect.get(obj, key);
-};
+    )
+  }
+  return Reflect.get(obj, key)
+}
 
 function MyTable({
   yHeight,
@@ -43,33 +43,31 @@ function MyTable({
   pageSize = 10,
   pagingInfo = {
     showQuickJumper: true,
-    position: ["bottomCenter"],
-    showSizeChanger: true,
+    position: ['bottomCenter'],
+    showSizeChanger: true
   },
   onChange,
   lastBtn = [],
-  classKey = "",
+  classKey = '',
   merge,
   myTitle,
-  isNull = "(空)",
+  isNull = '(空)'
 }: Props) {
   useEffect(() => {
-    const dom = document.querySelector(
-      `.MyTable${classKey} .ant-table-body`
-    ) as HTMLDivElement;
+    const dom = document.querySelector(`.MyTable${classKey} .ant-table-body`) as HTMLDivElement
 
-    if (dom && yHeight) dom.style.height = yHeight + "px";
-  }, [classKey, yHeight]);
+    if (dom && yHeight) dom.style.height = yHeight + 'px'
+  }, [classKey, yHeight])
 
   // 页码变化
   const paginationChange = useCallback(
     () => (pageNum: number, pageSize: number) => {
       if (onChange) {
-        onChange(pageNum, pageSize);
+        onChange(pageNum, pageSize)
       }
     },
     [onChange]
-  );
+  )
 
   const dataChangeFu = useCallback(
     (v: any) => {
@@ -82,41 +80,44 @@ function MyTable({
        */
 
       const obj = {
-        index: (_: any, __: any, index: number) =>
-          index + 1 + (pageNum - 1) * pageSize,
+        index: (_: any, __: any, index: number) => index + 1 + (pageNum - 1) * pageSize,
         txt: (item: any) => item[v[2]] || isNull,
         img: (item: any) => (
-          <div className="tableImgAuto">
-            <ImageLazy width={60} height={60} src={item[v[2]] || item.thumb} />
+          <div className='tableImgAuto'>
+            <ImageLazy
+              width={60}
+              height={60}
+              src={item[v[2]] || item.thumb}
+              offline={(item[v[2]] || item.thumb).includes('http')}
+            />
           </div>
         ),
-        txtChange: (item: any) =>
-          Reflect.get(v[3], item[v[2]]) || v[4] || isNull,
+        txtChange: (item: any) => Reflect.get(v[3], item[v[2]]) || v[4] || isNull,
         text: (item: any) => {
-          let tempCom: any = item[v[2]] || isNull;
+          let tempCom: any = item[v[2]] || isNull
 
           if (tempCom.length >= v[3]) {
-            tempCom = tempCom.substring(0, v[3]) + "...";
+            tempCom = tempCom.substring(0, v[3]) + '...'
           }
 
           if (v[4]) {
-            tempCom = tableComObj(v[4], [tempCom, item[v[2]]]);
+            tempCom = tableComObj(v[4], [tempCom, item[v[2]]])
           } else if (item[v[2]].length >= v[3]) {
             tempCom = (
-              <span style={{ cursor: "pointer" }} title={item[v[2]]}>
+              <span style={{ cursor: 'pointer' }} title={item[v[2]]}>
                 {tempCom}
               </span>
-            );
+            )
           }
 
-          return tempCom;
-        },
-      };
+          return tempCom
+        }
+      }
 
-      return Reflect.get(obj, v[0]);
+      return Reflect.get(obj, v[0])
     },
     [isNull, pageNum, pageSize]
-  );
+  )
 
   const columns = useMemo(() => {
     const arr: any = columnsTemp.map((v: any) => ({
@@ -126,21 +127,21 @@ function MyTable({
         merge && v.includes(merge.type)
           ? // {rowSpan:3}
             (item: any, index: number) => ({
-              rowSpan: index === 0 ? merge.num : 0,
+              rowSpan: index === 0 ? merge.num : 0
             })
-          : "",
-    }));
+          : ''
+    }))
 
-    return arr;
-  }, [columnsTemp, dataChangeFu, merge, myTitle]);
+    return arr
+  }, [columnsTemp, dataChangeFu, merge, myTitle])
 
   return (
     <Table
       className={`${styles.MyTable} MyTable${classKey}`}
-      scroll={{ y: yHeight ? yHeight : "" }}
+      scroll={{ y: yHeight ? yHeight : '' }}
       dataSource={list}
       columns={[...columns, ...lastBtn]}
-      rowKey="id"
+      rowKey='id'
       pagination={
         pagingInfo
           ? {
@@ -148,14 +149,14 @@ function MyTable({
               current: pageNum,
               pageSize: pageSize,
               total: total,
-              onChange: paginationChange(),
+              onChange: paginationChange()
             }
           : false
       }
     />
-  );
+  )
 }
 
-const MemoMyTable = React.memo(MyTable);
+const MemoMyTable = React.memo(MyTable)
 
-export default MemoMyTable;
+export default MemoMyTable

+ 7 - 7
src/components/ZupOne/index.tsx

@@ -18,7 +18,7 @@ import { API_upFile } from '@/store/action/layout'
 import { forwardRef, useImperativeHandle } from 'react'
 import MyPopconfirm from '../MyPopconfirm'
 
-type MyTypeType = 'thumb' | 'video' | 'audio' | 'model' | 'pdf' | 'equb'
+type MyTypeType = 'thumb' | 'video' | 'audio' | 'model' | 'pdf' | 'epub'
 
 // 这个组件 只处理 上传 一张图片或者 视频 音频 模型 pdf 的情况
 
@@ -76,8 +76,8 @@ function ZupOne(
             e.target.value = ''
             return MessageFu.warning(`只支持${formatTxt}格式!`)
           }
-        } else if (myType === 'equb') {
-          if (!filesInfo.name.endsWith('.equb')) {
+        } else if (myType === 'epub') {
+          if (!filesInfo.name.endsWith('.epub')) {
             e.target.value = ''
             return MessageFu.warning(`只支持${formatTxt}格式!`)
           }
@@ -97,7 +97,7 @@ function ZupOne(
         const fd = new FormData()
         // 把files添加进FormData对象(‘photo’为后端需要的字段)
         let myTypeRes: string = myType
-        if (['pdf', 'equb'].includes(myTypeRes)) myTypeRes = 'doc'
+        if (['pdf', 'epub'].includes(myTypeRes)) myTypeRes = 'doc'
         fd.append('type', myTypeRes)
         fd.append('dirCode', dirCode)
         fd.append('file', filesInfo)
@@ -147,7 +147,7 @@ function ZupOne(
     else if (myType === 'audio') accept = '.mp3'
     else if (myType === 'model') accept = '.4dage'
     else if (myType === 'pdf') accept = '.pdf'
-    else if (myType === 'equb') accept = '.equb'
+    else if (myType === 'epub') accept = '.epub'
     return accept
   }, [myType])
 
@@ -157,7 +157,7 @@ function ZupOne(
       if (type === 'pdf' || type === 'thumb') {
         // 新窗口打开
         window.open(baseURL + fileUrl.filePath)
-      } else if (type !== 'equb') {
+      } else if (type !== 'epub') {
         store.dispatch({
           type: 'layout/lookDom',
           payload: { src: fileUrl.filePath, type }
@@ -234,7 +234,7 @@ function ZupOne(
           {/* 视频预览 */}
           <div
             className='clearCover'
-            hidden={!fileUrl.filePath || myType === 'equb'}
+            hidden={!fileUrl.filePath || myType === 'epub'}
             onClick={() => lookFileNoImgFu(myType)}
           >
             <EyeOutlined rev={undefined} />

+ 4 - 4
src/pages/A1manage/A1add/index.tsx

@@ -110,7 +110,7 @@ function A1add({
       const ZupTxtRefObj = ZupTxtRef.current?.fileComFileResFu()
       fileName = ZupTxtRefObj.fileName
       filePath = ZupTxtRefObj.filePath
-      if (!filePath) return MessageFu.warning('请上传equb附件!')
+      if (!filePath) return MessageFu.warning('请上传epub附件!')
 
       let storageId: null | number = null
 
@@ -293,10 +293,10 @@ function A1add({
                 dirCode='A1manage'
                 myUrl='cms/book/upload'
                 format={['']}
-                formatTxt='equb'
-                checkTxt='请上传equb附件!'
+                formatTxt='epub'
+                checkTxt='请上传epub附件!'
                 upTxt='最多1个'
-                myType='equb'
+                myType='epub'
               />
             </div>
           </div>

+ 3 - 3
src/pages/A5bookAudit/A5look/index.tsx

@@ -196,10 +196,10 @@ function A5look({ info, closeFuOne, editTableFu }: Props) {
               dirCode='A1manage'
               myUrl='cms/book/upload'
               format={['']}
-              formatTxt='equb'
-              checkTxt='请上传equb附件!'
+              formatTxt='epub'
+              checkTxt='请上传epub附件!'
               upTxt='最多1个'
-              myType='equb'
+              myType='epub'
             />
           </div>
         </div>

+ 108 - 0
src/pages/A6remarkAudit/A6audit.tsx

@@ -0,0 +1,108 @@
+import React, { useCallback, useEffect, useState } from 'react'
+import styles from './index.module.scss'
+import { Button, Modal } from 'antd'
+import { A5selArr1 } from '../A5bookAudit/data'
+import MyPopconfirm from '@/components/MyPopconfirm'
+import { A6tableType } from '@/types'
+import { A6_APIaudit, A6_APIgetInfo } from '@/store/action/A6remarkAudit'
+import { MessageFu } from '@/utils/message'
+
+type Props = {
+  id: number
+  closeFu: () => void
+  editTableFu: () => void
+}
+
+function A6audit({ id, closeFu, editTableFu }: Props) {
+  const [auditStatus, setAuditStatus] = useState<null | 0 | 1 | 2>(null)
+
+  const [info, setInfo] = useState({} as A6tableType)
+
+  const getInfo = useCallback(async (id: number) => {
+    const res = await A6_APIgetInfo(id)
+    if (res.code === 0) {
+      setInfo(res.data)
+      setAuditStatus(res.data.auditStatus)
+    }
+  }, [])
+
+  useEffect(() => {
+    getInfo(id)
+  }, [getInfo, id])
+
+  const btnOk = useCallback(async () => {
+    const obj = {
+      id,
+      auditStatus
+    }
+    const res = await A6_APIaudit(obj)
+
+    if (res.code === 0) {
+      MessageFu.success('审核成功!')
+      closeFu()
+      editTableFu()
+    }
+  }, [auditStatus, closeFu, editTableFu, id])
+
+  return (
+    <Modal
+      wrapClassName={styles.A6audit}
+      open={true}
+      title='审核'
+      footer={
+        [] // 设置footer为空,去掉 取消 确定默认按钮
+      }
+    >
+      <div className='formRow'>
+        <div className='formLeft'>书名:</div>
+        <div className='formRight'>{info.bookName || '(空)'}</div>
+      </div>
+
+      <div className='formRow'>
+        <div className='formLeft'>评论内容:</div>
+        <div className='formRight'>{info.content || '(空)'}</div>
+      </div>
+
+      <div className='formRow'>
+        <div className='formLeft formLeft2'>审核状态:</div>
+        <div className='formRight'>
+          {A5selArr1.filter(v => v.label !== '全部').map(v => (
+            <Button
+              onClick={() => setAuditStatus(v.value as 0)}
+              type={v.value === auditStatus ? 'primary' : 'default'}
+              key={v.value}
+            >
+              {v.label}
+            </Button>
+          ))}
+        </div>
+      </div>
+
+      <div className='formRow'>
+        <div className='formLeft'>
+          <span></span>审核人:
+        </div>
+        <div className='formRight'>{info.creatorName || '(空)'}</div>
+      </div>
+
+      <div className='formRow'>
+        <div className='formLeft'>
+          <span></span>审核时间:
+        </div>
+        <div className='formRight'>{info.auditTime || '(空)'}</div>
+      </div>
+
+      <div className='A6aBtn'>
+        <Button type='primary' onClick={btnOk}>
+          提交
+        </Button>
+        &emsp;
+        <MyPopconfirm txtK='取消' onConfirm={closeFu} />
+      </div>
+    </Modal>
+  )
+}
+
+const MemoA6audit = React.memo(A6audit)
+
+export default MemoA6audit

+ 76 - 2
src/pages/A6remarkAudit/index.module.scss

@@ -1,5 +1,79 @@
-.A6remarkAudit{
-  :global{
+.A6remarkAudit {
+  position: relative;
+  :global {
+    .A6top {
+      border-radius: 10px;
+      background-color: #fff;
+      padding: 15px 24px;
+      display: flex;
+      justify-content: space-between;
+      & > div {
+        display: flex;
+        .A6TopRow {
+          display: flex;
+          align-items: center;
+          margin-right: 20px;
+          .ant-select-selection-placeholder {
+            color: black;
+          }
+        }
+      }
+    }
+    .A6tableBox {
+      border-radius: 10px;
+      overflow: hidden;
+      margin-top: 15px;
+      height: calc(100% - 77px);
+      background-color: #fff;
+    }
+  }
+}
+
+// 审核
+.A6audit {
+  :global {
+    .ant-modal-close {
+      display: none;
+    }
+    .ant-modal {
+      width: 800px !important;
+      // top: 30%;
+    }
+    .ant-modal-body {
+      border-top: 1px solid #ccc;
+      padding-top: 15px !important;
+    }
+
+    .formRow {
+      display: flex;
+      // align-items: center;
+      margin-bottom: 24px;
+
+      .formLeft {
+        width: 80px;
+        text-align: right;
+
+        & > span {
+          color: #ff4d4f;
+        }
+      }
+      .formLeft2 {
+        position: relative;
+        top: 4px;
+      }
+
+      .formRight {
+        width: calc(100% - 80px);
+        position: relative;
+        .ant-btn {
+          margin-right: 15px;
+        }
+      }
+    }
 
+    .A6aBtn {
+      text-align: center;
+      margin-top: 50px;
+    }
   }
 }

+ 113 - 6
src/pages/A6remarkAudit/index.tsx

@@ -1,14 +1,121 @@
-import React from "react";
-import styles from "./index.module.scss";
- function A6remarkAudit() {
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
+import styles from './index.module.scss'
+import { A5FromDataType, A5selArr1 } from '../A5bookAudit/data'
+import { useDispatch, useSelector } from 'react-redux'
+import { A6_APIdel, A6_APIgetList } from '@/store/action/A6remarkAudit'
+import { RootState } from '@/store'
+import { MessageFu } from '@/utils/message'
+import { A6tableType } from '@/types'
+import { Button, Select } from 'antd'
+import MyPopconfirm from '@/components/MyPopconfirm'
+import MyTable from '@/components/MyTable'
+import { A6tableC } from '@/utils/tableData'
+import A6audit from './A6audit'
+
+type A6FromDataType = Omit<A5FromDataType, 'searchKey' | 'num'>
+
+const fromDataBase: A6FromDataType = {
+  auditStatus: '',
+  pageNum: 1,
+  pageSize: 10
+}
+
+function A6remarkAudit() {
+  const dispatch = useDispatch()
+
+  const [fromData, setFromData] = useState(fromDataBase)
+
+  const getListFu = useCallback(() => {
+    dispatch(A6_APIgetList(fromData))
+  }, [dispatch, fromData])
+
+  useEffect(() => {
+    getListFu()
+  }, [getListFu])
+
+  // 点击重置
+  const resetSelectFu = useCallback(() => {
+    setFromData({ ...fromDataBase })
+  }, [])
+
+  const tableInfo = useSelector((state: RootState) => state.A6remarkAudit.tableInfo)
+
+  const delTableFu = useCallback(
+    async (id: number) => {
+      const res = await A6_APIdel(id)
+      if (res.code === 0) {
+        MessageFu.success('删除成功!')
+        getListFu()
+      }
+    },
+    [getListFu]
+  )
+
+  const tableLastBtn = useMemo(() => {
+    return [
+      {
+        title: '操作',
+        render: (item: A6tableType) => (
+          <>
+            <Button size='small' type='text' onClick={() => setAuditId(item.id)}>
+              审核
+            </Button>
+
+            <MyPopconfirm txtK='删除' onConfirm={() => delTableFu(item.id)} />
+          </>
+        )
+      }
+    ]
+  }, [delTableFu])
+
+  // 审核弹窗id
+  const [auditId, setAuditId] = useState(0)
 
   return (
     <div className={styles.A6remarkAudit}>
-      <h1>A6remarkAudit</h1>
+      <div className='pageTitle'>评论审核</div>
+
+      {/* 顶部筛选 */}
+      <div className='A6top'>
+        <div>
+          <div className='A6TopRow'>
+            <span>审核状态:</span>
+            <Select
+              placeholder='全部'
+              style={{ width: 180 }}
+              value={fromData.auditStatus}
+              onChange={e => setFromData({ ...fromData, pageNum: 1, auditStatus: e })}
+              options={A5selArr1}
+            />
+          </div>
+        </div>
+        <div>
+          <Button onClick={resetSelectFu}>重置</Button>&emsp;
+        </div>
+      </div>
+
+      {/* 表格主体 */}
+      <div className='A6tableBox'>
+        <MyTable
+          yHeight={625}
+          list={tableInfo.list}
+          columnsTemp={A6tableC}
+          lastBtn={tableLastBtn}
+          pageNum={fromData.pageNum}
+          pageSize={fromData.pageSize}
+          total={tableInfo.total}
+          onChange={(pageNum, pageSize) => setFromData({ ...fromData, pageNum, pageSize })}
+        />
+      </div>
+
+      {/* 点击审核 */}
+      {auditId ? (
+        <A6audit id={auditId} closeFu={() => setAuditId(0)} editTableFu={getListFu} />
+      ) : null}
     </div>
   )
 }
 
-const MemoA6remarkAudit = React.memo(A6remarkAudit);
+const MemoA6remarkAudit = React.memo(A6remarkAudit)
 
-export default MemoA6remarkAudit;
+export default MemoA6remarkAudit

+ 39 - 0
src/store/action/A6remarkAudit.ts

@@ -0,0 +1,39 @@
+import http from '@/utils/http'
+import { AppDispatch } from '..'
+
+/**
+ *评论审核-列表
+ */
+
+export const A6_APIgetList = (data: any): any => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post('cms/message/pageList', data)
+    if (res.code === 0) {
+      const obj = {
+        list: res.data.records,
+        total: res.data.total
+      }
+      dispatch({ type: 'A6/getList', payload: obj })
+    }
+  }
+}
+/**
+ * 评论审核-删除
+ */
+export const A6_APIdel = (id: number) => {
+  return http.get(`cms/message/remove/${id}`)
+}
+
+/**
+ * 评论审核-获取详情
+ */
+export const A6_APIgetInfo = (id: number) => {
+  return http.get(`cms/message/detail/${id}`)
+}
+
+/**
+ * 评论审核-审核
+ */
+export const A6_APIaudit = (data: any) => {
+  return http.post('cms/message/audit', data)
+}

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

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

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

@@ -8,6 +8,7 @@ import A2classify from './A2classify'
 import A3recommend from './A3recommend'
 import A4iosUser from './A4iosUser'
 import A5bookAudit from './A5bookAudit'
+import A6remarkAudit from './A6remarkAudit'
 import Z1user from './Z1user'
 import Z2log from './Z2log'
 
@@ -19,6 +20,7 @@ const rootReducer = combineReducers({
   A3recommend,
   A4iosUser,
   A5bookAudit,
+  A6remarkAudit,
   Z1user,
   Z2log
 })

+ 13 - 0
src/types/api/A6remarkAudit.ts

@@ -0,0 +1,13 @@
+export type A6tableType = {
+  bookName: string
+  auditBy: any
+  auditStatus: number
+  auditTime: any
+  bookId: number
+  content: string
+  createBy: string
+  createTime: string
+  creatorName: string
+  id: number
+  updateTime: string
+}

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

@@ -4,5 +4,6 @@ export * from './api/A2classify'
 export * from './api/A3recommend'
 export * from './api/A4iosUser'
 export * from './api/A5bookAudit'
+export * from './api/A6remarkAudit'
 export * from './api/Z1user'
 export * from './api/Z2log'

+ 8 - 0
src/utils/tableData.ts

@@ -84,6 +84,14 @@ export const A5tableC = [
   ['text', '审核备注', 'auditDesc', 50]
 ]
 
+export const A6tableC = [
+  ['txt', '书名', 'bookName'],
+  ['text', '评论内容', 'content', 50],
+  ['txtChange', '审核状态', 'auditStatus', { 0: '待审核', 1: '审核通过', 2: '审核驳回' }],
+  ['txt', '提交人', 'createBy'],
+  ['txt', '提交时间', 'createTime']
+]
+
 export const Z1tableC = [
   ['txt', '用户名', 'userName'],
   ['txtChange', '角色', 'isAdmin', { 1: '管理员', 0: '普通成员' }],